97 lines
2.0 KiB
Vue
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>
|