<template> <div class="container" @click="blur" > <transition name="slide"> <Sidebar v-if="showSidebar" @sidebar="showSidebar = false" /> </transition> <Header /> <div ref="content" class="content" > <slot @scroll="scroll" /> </div> <BottomNavigation class="nav" @sidebar="showSidebar = true" /> <div ref="feedbackContainer" class="feedback-container" > <div v-if="feedback" ref="feedbackBubble" class="feedback" :class="{ [feedback.type]: true }" >{{ feedback.message }}</div> </div> </div> </template> <script setup> import { ref, onMounted, nextTick } from 'vue'; import events from '#/src/events.js'; import Header from '#/components/header/header.vue'; import Sidebar from '#/components/sidebar/sidebar.vue'; import BottomNavigation from '#/components/footer/navigation.vue'; const content = ref(null); const feedback = ref(null); const feedbackContainer = ref(null); const feedbackBubble = ref(null); const showSidebar = ref(false); function blur() { events.emit('blur'); } onMounted(() => { events.on('scrollUp', () => { content.value.scrollTop = 0; }); events.on('feedback', async (event) => { console.log(event); feedback.value = event; await nextTick(); feedbackBubble.value.animate([ { visibility: 'visible', transform: 'scaleY(0)', opacity: 1, }, { transform: 'scaleY(1)', opacity: 1, offset: 0.002, }, { transform: 'scaleY(1)', opacity: 1, offset: 0.5, }, { opacity: 0, }, ], { duration: 3000, easing: 'ease-in-out', }); }); }); </script> <style> .scroller { height: 30rem; overflow-y: auto; } .item { height: 32px; padding: 0 12px; display: flex; align-items: center; } .slide-enter-active, .slide-leave-active { &.sidebar-container { transition: background .15s ease-in-out; } .sidebar { transition: transform .15s ease-in-out; } } .slide-enter-from, .slide-leave-to { &.sidebar-container { background: transparent; } .sidebar { transform: translate(100%, 0); } } </style> <style scoped> .container { height: 100%; display: flex; flex-direction: column; overflow: hidden; } .content { display: flex; flex-direction: column; flex-grow: 1; overflow-y: auto; } .nav { display: none; } .feedback-container { width: 100%; display: flex; justify-content: center; position: fixed; bottom: 1rem;; z-index: 1000; pointer-events: none; } .feedback { padding: .5rem 1rem; margin: 0 .5rem; border-radius: 1rem; box-shadow: 0 0 3px var(--shadow-weak-10); background: var(--grey-dark-40); color: var(--text-light); font-size: .9rem; visibility: hidden; line-height: 1.5; &.success { background: var(--success); } &.error { background: var(--error); } &.remove { background: var(--warn); } } @media(--small-10) { .nav { display: flex; } .feedback-container { bottom: 4rem; } } </style>