72 lines
2.5 KiB
Vue
72 lines
2.5 KiB
Vue
<template>
|
|
<div class="min-h-screen bg-kestrel-bg text-kestrel-text font-mono flex flex-col">
|
|
<div class="relative flex flex-1 min-h-0">
|
|
<NavDrawer v-model="drawerOpen" />
|
|
<div
|
|
class="flex min-h-0 flex-1 flex-col transition-[margin] duration-200 ease-out"
|
|
:class="{ 'md:ml-[260px]': drawerOpen }"
|
|
>
|
|
<header class="flex h-14 shrink-0 items-center gap-3 border-b border-kestrel-border bg-kestrel-surface px-4 shadow-glow-sm [box-shadow:0_0_20px_-4px_rgba(34,201,201,0.15)]">
|
|
<button
|
|
type="button"
|
|
class="rounded p-2 text-kestrel-muted transition-colors hover:bg-kestrel-border hover:text-kestrel-accent"
|
|
aria-label="Toggle navigation"
|
|
:aria-expanded="drawerOpen"
|
|
@click="drawerOpen = !drawerOpen"
|
|
>
|
|
<span
|
|
class="text-lg leading-none"
|
|
aria-hidden="true"
|
|
>☰</span>
|
|
</button>
|
|
<div class="min-w-0 flex-1">
|
|
<h1 class="text-lg font-semibold tracking-wide text-kestrel-text [text-shadow:0_0_12px_rgba(34,201,201,0.35)]">
|
|
KestrelOS
|
|
</h1>
|
|
<p class="text-xs uppercase tracking-widest text-kestrel-muted">
|
|
> Tactical Operations Center — OSINT Feeds
|
|
</p>
|
|
</div>
|
|
<div class="flex items-center gap-2">
|
|
<template v-if="user">
|
|
<span class="text-xs text-kestrel-muted">{{ user.identifier }}</span>
|
|
<button
|
|
type="button"
|
|
class="rounded px-2 py-1 text-xs text-kestrel-muted hover:bg-kestrel-border hover:text-kestrel-accent"
|
|
@click="onLogout"
|
|
>
|
|
Logout
|
|
</button>
|
|
</template>
|
|
<NuxtLink
|
|
v-else
|
|
to="/login"
|
|
class="rounded px-2 py-1 text-xs text-kestrel-muted hover:bg-kestrel-border hover:text-kestrel-accent"
|
|
>
|
|
Sign in
|
|
</NuxtLink>
|
|
</div>
|
|
</header>
|
|
<main class="min-h-0 flex-1">
|
|
<slot />
|
|
</main>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
const drawerOpen = ref(true)
|
|
const { user, refresh } = useUser()
|
|
const route = useRoute()
|
|
|
|
async function onLogout() {
|
|
await $fetch('/api/auth/logout', { method: 'POST' })
|
|
await refresh()
|
|
await navigateTo('/')
|
|
}
|
|
watch(() => route.path, () => {
|
|
drawerOpen.value = false
|
|
})
|
|
</script>
|