BpDismissable is a renderless vue component for dismissable content such as alerts and banners. It exposes a single method to its slot, dismiss, that hides the content. It requires a single parameter, storage-key, which is used to uniquely identify the instance. It also has optional parameters for when content changes or whether the dismissal should only last for a fixed amount of time.

<bp-dismissable storage-key="example-alert" v-slot="{ dismiss }">
    <div class="banner">
        <div class="banner__container container">
            <div class="banner__messsage">
                Sit quisquam error ipsum atque odit ex At eum eius autem perspiciatis sit! Sint ab!
            </div>
            <button class="banner__dismiss" @click="dismiss">
                <svg xmlns="http://www.w3.org/2000/svg" class="banner__dismissIcon" viewBox="0 0 24 24" stroke-width="1.5" stroke="#2c3e50" fill="none" stroke-linecap="round" stroke-linejoin="round">
                    <line x1="18" y1="6" x2="6" y2="18" />
                    <line x1="6" y1="6" x2="18" y2="18" />
                </svg>
            </button>
        </div>
    </div>
</bp-dismissable>
  • Content:
    <script>
    
    /**
     * Renderless component for dismissable content.
     *
     * @param storageKey (required) - used to identify a specific instance of this
     *     component to tell if it's already dismissed or not.
     * @param hash - optional second component for telling if content has changed
     *     and the component should be re-displayed even if it was already
     *     dismissed.
     * @param expiration - optional duration for how long to hide the content
     *     before displaying it again. Defaults to a week. If set to 0, stays
     *     dimissed permanently.
     */
    export default {
        props: {
            storageKey: {
                type: String,
                required: true,
            },
            hash: {
                type: String,
                default: '',
            },
            expiration: {
                type: Number,
                default: 604800000,
            },
        },
        data: () => ({
            isDismissed: true,
        }),
    
        mounted () {
            const now = (new Date()).getTime()
            if (this.storageKey in localStorage) {
                const { hash, expiration } = JSON.parse(localStorage[this.storageKey])
    
                if (hash === this.hash && (expiration === 0 || expiration > now)) {
                    return
                }
            }
    
            this.isDismissed = false
        },
    
        methods: {
            dismiss () {
                const now = (new Date()).getTime()
                this.isDismissed = true
    
                localStorage[this.storageKey] = JSON.stringify({
                    expiration: this.expiration === 0 ? 0 : now + this.expiration,
                    hash: this.hash,
                })
            },
        },
        render () {
            return this.isDismissed
                ? ''
                : this.$scopedSlots.default({
                    dismiss: this.dismiss,
                    isDismissed: this.isDismissed,
                })
        },
    }
    </script>
    
  • URL: /components/raw/dismissable/BpDismissable.vue
  • Filesystem Path: resources/styles/utilities/dismissable/BpDismissable.vue
  • Size: 1.8 KB