Files
dating-app-frontend/src/components/layout/AppShell.vue
2026-06-08 15:09:53 +03:00

97 lines
2.0 KiB
Vue

<template>
<div class="shell" :class="{ 'shell--tauri': isTauri }">
<!-- Grain texture overlay (fixed, pointer-events none) -->
<div class="shell__grain" aria-hidden="true" />
<!-- Tauri custom titlebar -->
<TauriTitlebar />
<div class="shell__body">
<!-- Desktop sidebar navigation -->
<SideNav v-if="showNav" class="shell__sidenav" />
<!-- Main content area -->
<main class="shell__main" :class="{ 'shell__main--no-nav': !showNav }">
<slot />
</main>
</div>
<!-- Mobile bottom navigation -->
<BottomNav v-if="showNav" class="shell__bottom-nav" />
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { useRoute } from 'vue-router'
import { useAuth } from '@/composables/useAuth'
import BottomNav from './BottomNav.vue'
import SideNav from './SideNav.vue'
import TauriTitlebar from './TauriTitlebar.vue'
const route = useRoute()
const authStore = useAuth()
const isTauri = typeof window !== 'undefined' && !!window.__TAURI__
// Hide nav on auth/onboarding routes
const showNav = computed(() =>
authStore.isAuthenticated
&& !['login', 'register', 'setup'].includes(route.name as string),
)
</script>
<style scoped lang="scss">
.shell {
height: 100dvh;
display: flex;
flex-direction: column;
background: var(--color-base);
overflow: hidden;
position: relative;
&__grain {
position: fixed;
inset: 0;
z-index: var(--z-tooltip);
pointer-events: none;
background-image: url('@/assets/grain.svg');
background-repeat: repeat;
opacity: 0.35;
mix-blend-mode: overlay;
}
&__body {
flex: 1;
display: flex;
overflow: hidden;
}
&__sidenav {
// Desktop only
@include mobile {
display: none;
}
}
&__main {
flex: 1;
overflow-y: auto;
overflow-x: hidden;
position: relative;
scroll-behavior: smooth;
&--no-nav {
width: 100%;
}
}
&__bottom-nav {
// Mobile only
@include tablet {
display: none;
}
}
}
</style>