refactor(ui): AppShell = TopNav + content slot (drop left drawer/v-main)

This commit is contained in:
2026-05-15 23:14:20 -04:00
parent 18ad61265e
commit 9bb801a566
+6 -68
View File
@@ -1,78 +1,16 @@
<template>
<v-navigation-drawer permanent :width="220" class="fc-nav">
<div class="fc-wordmark px-4 py-4">
<span class="fc-wordmark__text">FabledCurator</span>
</div>
<v-list nav density="compact">
<v-list-item
v-for="r in navRoutes"
:key="r.name"
:to="{ name: r.name }"
:title="r.meta.title"
:prepend-icon="iconFor(r.name)"
class="fc-nav-item"
/>
</v-list>
<template #append>
<div class="px-4 py-3 fc-status">
<v-icon size="x-small" :color="health.color">{{ health.icon }}</v-icon>
<span class="text-caption fc-status__label">{{ health.label }}</span>
</div>
</template>
</v-navigation-drawer>
<v-main>
<TopNav />
<main class="fc-content">
<slot />
</v-main>
</main>
</template>
<script setup>
import { computed, onMounted } from 'vue'
import { useSystemStore } from '../stores/system.js'
import router from '../router.js'
const system = useSystemStore()
onMounted(() => system.refreshHealth())
const navRoutes = computed(() =>
router.getRoutes().filter(r => r.meta?.title)
)
function iconFor(name) {
const map = {
gallery: 'mdi-image-multiple',
showcase: 'mdi-view-dashboard-variant',
tags: 'mdi-tag-multiple',
settings: 'mdi-cog',
subscriptions: 'mdi-rss',
credentials: 'mdi-key-variant',
downloads: 'mdi-download'
}
return map[name] ?? 'mdi-circle-small'
}
const health = computed(() => {
if (system.healthy === null) return { icon: 'mdi-circle-outline', color: 'on-surface', label: 'checking…' }
if (system.healthy === true) return { icon: 'mdi-circle', color: 'success', label: 'healthy' }
return { icon: 'mdi-alert-circle', color: 'error', label: 'unreachable' }
})
import TopNav from './TopNav.vue'
</script>
<style scoped>
.fc-wordmark__text {
font-family: 'Fraunces', Georgia, serif;
font-size: 20px;
font-weight: 500;
/* Accent color comes from the Vuetify theme via CSS var */
color: rgb(var(--v-theme-accent));
}
.fc-nav-item.v-list-item--active {
/* "you are here" indicator uses the accent per FabledDesignSystem */
color: rgb(var(--v-theme-accent));
}
.fc-status {
display: flex;
align-items: center;
gap: 6px;
.fc-content {
min-height: 100vh;
}
</style>