# tapper-widget

This is widget that changes images when you tap or click it. It's basically a timeline sequence that just reacts to a tap or click.

Dependencies needed: node-sass and sass-loader.

# props

progressBarBackgroundColor String (optional) background color of progress bar

progressBarOrientation String (optional) horizontal/vertical. Location of where the progress bar will be placed, either underneath image or on the side using CSS Grid. default: horizontal

slides Array (required) Image slides. Example: { active: true, src: '/assets/modules/brain-1.svg', message: 'This is the message' }

tapsPerSlide Number (optional) How many taps needed to advance to the next slide. Default: 1

resetButtonOnComplete Boolean (optional) Show refresh button on widget completion. default: false

debug Boolean (optional) Show outline around the widget for CSS debugging. default: false

# Events

@onComplete emits when last slide shows

# Example

<template>
    <div>
        <TapperWidget
            :progressBarOrientation="'vertical'"
            :slides="[
                {
                    active: true,
                    src: '/assets/modules/brain-1.svg',
                    message: 'Tap (and keep tapping) to see how nicotine affects the brain and rewires us for addiction.'
                },
                {
                    active: false,
                    src: '/assets/modules/brain-2.svg',
                    message: 'Nicotine salts make it easier to take bigger hits.'
                },
                {
                    active: false,
                    src: '/assets/modules/brain-3.svg',
                    message: ' This puts vapers at risk for extremely high doses of nicotine with every hit.'
                },
                {
                    active: false,
                    src: '/assets/modules/brain-4.svg',
                    message: 'It also makes it easier to hit a vape more frequently.'
                },
                {
                    active: false,
                    src: '/assets/modules/brain-5.svg',
                    message: 'Putting vapers at high risk for nicotine addiction.'
                }
            ]" />
    </div>
</template>

<script>
    import { TapperWidget } from '@rescue/vue-modules';
    
    export default {
        components: {
            TapperWidget
        }
    };
</script>
Tap (and keep tapping) to see how nicotine affects the brain and rewires us for addiction.



# Source Code

<template>
    <div 
        :class="[{ debug }, { vertical: progressBarOrientation === 'vertical' }]"
        class="tapper-widget">
        <div class="grid">
            <div class="slides">
                <button @click="onClick">
                    <img 
                        v-for="(slide, i) in slides"
                        v-show="slide.active"
                        :key="i"
                        :src="slide.src" />
                </button>
            </div>
            <div class="progress-bar">
                <div   
                    v-if="progressBarOrientation === 'horizontal'"
                    class="horizontal">
                    <span :style="`
                        width: ${ getProgress };
                        background: ${ progressBarBackgroundColor }`">
                    </span>
                </div>
                <div 
                    v-if="progressBarOrientation === 'vertical'"
                    class="vertical">
                    <span :style="`
                        height: ${ getProgress };
                        background: ${ progressBarBackgroundColor }`">
                    </span>
                </div>
            </div>
        </div>
        <button 
            v-show="resetButtonOnComplete && showResetButton"
            @click="reset"
            class="reset-button">
            <i class="fas fa-redo"></i>
        </button>
        <div 
            v-if="typeof activeSlide.message === 'string'"
            v-html="activeSlide.message"
            class="message">
        </div>
        <div 
            v-if="typeof activeSlide.instructions === 'string'"
            v-html="activeSlide.instructions"
            class="instructions">
        </div>
    </div>
</template>

<script>
    export default {
        props: {
            progressBarBackgroundColor: {
                default: "rgb(100, 100, 100)",
                type: String
            },
            progressBarOrientation: {
                default: "horizontal",
                type: String
            },
            slides: {
                default: [],
                type: Array
            },
            tapsPerSlide: {
                default: 2,
                type: Number
            },
            resetButtonOnComplete: {
                default: true,
                type: Boolean
            },
            debug: {
                default: false,
                type: Boolean
            }
        },
        computed: {
            getProgress() {
                return ((this.activeIndex / (this.slides.length - 1)) * 100) + "%";
            },
            activeSlide() {
                return this.slides[this.activeIndex];
            }
        },
        data() {
            return {
                numberOfTaps: 0,
                activeIndex: 0,
                showResetButton: false
            }
        },
        methods: {
            onClick() {
                this.numberOfTaps++;

                if (this.numberOfTaps >= this.tapsPerSlide) {
                    this.nextSlide();
                    this.numberOfTaps = 0;
                }
            },
            nextSlide() {
                for (let i = 0; i < this.slides.length; i++) {
                    if (this.slides[i].active && i < this.slides.length - 1) {
                        this.slides[i].active = false;
                        this.slides[i + 1].active = true;
                        this.activeIndex = i + 1;

                        if (this.activeIndex === this.slides.length - 1) {
                            // Widget Completed
                            this.$emit("onComplete");
                            
                            if (this.resetButtonOnComplete) {
                                this.showResetButton = true;
                            }
                        }

                        break;
                    }
                }

                this.$forceUpdate();
            },
            reset() {
                this.slides.forEach(slide => {
                    slide.active = false;
                });

                this.slides[0].active = true;
                this.activeIndex = 0;
                this.numberOfTaps = 0;
                this.showResetButton = false;
            }
        }
    }
</script>

<style lang="scss" scoped>
    .tapper-widget {
        position : relative;

        &.debug * {
            outline : 1px solid red;
        }

        &.vertical {
            .grid {
                display               : grid;
                grid-template-columns : 1fr 30px;
                grid-gap              : 15px;
            }
        }

        .grid {
            .slides {
                button {
                    background : none;
                    border     : none;
                    cursor     : pointer;

                    &:focus,
                    &:hover,
                    &:active {
                        outline : none;
                    }

                    &:active {
                        transform : scale(0.975);
                    }
                }
            }

            .progress-bar {
                .horizontal {
                    margin-top : 15px;
                    width      : 100%;
                    height     : 30px;
                    border     : 1px solid rgb(39, 39, 39);

                    span {
                        height     : 100%;
                        display    : block;
                        width      : 0%;
                        transition : width 0.15s ease-in-out;
                    }
                }

                .vertical {
                    height    : 100%;
                    width     : 30px;
                    border    : 1px solid rgb(39, 39, 39);
                    transform : rotate(180deg);

                    span {
                        width      : 100%;
                        display    : block;
                        height     : 0%;
                        transition : height 0.15s ease-in-out;
                    }
                }
            }
        }

        .reset-button {
            position      : absolute;
            bottom        : 0px;
            left          : 0px;
            width         : 30px;
            height        : 30px;
            border-radius : 15px;
            background    : white;
            font-size     : 0.8em;
            box-shadow    : 0px 4px 10px rgba(0, 0, 0, 0.1);
            cursor        : pointer;

            &:focus,
            &:hover,
            &:active {
                outline : none;
            }

            &:active {
                transform : scale(0.975);
            }

            i {
                top      : 1px;
                position : relative;
            }
        }

        .message {
            position : absolute;
            top      : 105%;
        }

        .instructions {
            position : absolute;
            top      : 105%;
        }
    }
</style>