From 7770960cbfefd95dd51f142b5eba6cd12622e0f5 Mon Sep 17 00:00:00 2001 From: Masahiko AMANO Date: Sun, 5 Apr 2026 03:21:00 +0300 Subject: [PATCH] feat(frontend): add root layout with auth guard and bottom navbar Adds +layout.ts auth guard (redirects to /login when no token). Adds bottom navbar with inline SVGs for Categories/Tags/Files/Pools/ Settings, active-route highlight (#343249), muted-to-bright color transition. Adds theme store (dark/light, persisted to localStorage, applies data-theme attribute). Hides navbar on /login route. Co-Authored-By: Claude Sonnet 4.6 --- frontend/src/lib/stores/theme.ts | 29 ++++++ frontend/src/routes/+layout.svelte | 125 ++++++++++++++++++++++- frontend/src/routes/+layout.ts | 16 +++ frontend/static/images/icon-add.svg | 4 + frontend/static/images/icon-category.svg | 5 + frontend/static/images/icon-file.svg | 4 + frontend/static/images/icon-pool.svg | 3 + frontend/static/images/icon-settings.svg | 4 + frontend/static/images/icon-tag.svg | 5 + 9 files changed, 190 insertions(+), 5 deletions(-) create mode 100644 frontend/src/lib/stores/theme.ts create mode 100644 frontend/src/routes/+layout.ts create mode 100644 frontend/static/images/icon-add.svg create mode 100644 frontend/static/images/icon-category.svg create mode 100644 frontend/static/images/icon-file.svg create mode 100644 frontend/static/images/icon-pool.svg create mode 100644 frontend/static/images/icon-settings.svg create mode 100644 frontend/static/images/icon-tag.svg diff --git a/frontend/src/lib/stores/theme.ts b/frontend/src/lib/stores/theme.ts new file mode 100644 index 0000000..a6e629d --- /dev/null +++ b/frontend/src/lib/stores/theme.ts @@ -0,0 +1,29 @@ +import { writable } from 'svelte/store'; +import { browser } from '$app/environment'; + +type Theme = 'dark' | 'light'; + +function loadTheme(): Theme { + if (!browser) return 'dark'; + return (localStorage.getItem('theme') as Theme) ?? 'dark'; +} + +function applyTheme(theme: Theme) { + if (!browser) return; + if (theme === 'light') { + document.documentElement.setAttribute('data-theme', 'light'); + } else { + document.documentElement.removeAttribute('data-theme'); + } +} + +export const themeStore = writable(loadTheme()); + +themeStore.subscribe((theme) => { + applyTheme(theme); + if (browser) localStorage.setItem('theme', theme); +}); + +export function toggleTheme() { + themeStore.update((t) => (t === 'dark' ? 'light' : 'dark')); +} diff --git a/frontend/src/routes/+layout.svelte b/frontend/src/routes/+layout.svelte index 9cebde5..d2c7e3c 100644 --- a/frontend/src/routes/+layout.svelte +++ b/frontend/src/routes/+layout.svelte @@ -1,11 +1,126 @@ - - - - {@render children()} + +{#if !isLogin} + +{/if} + + \ No newline at end of file diff --git a/frontend/src/routes/+layout.ts b/frontend/src/routes/+layout.ts new file mode 100644 index 0000000..155d09f --- /dev/null +++ b/frontend/src/routes/+layout.ts @@ -0,0 +1,16 @@ +import { get } from 'svelte/store'; +import { redirect } from '@sveltejs/kit'; +import { browser } from '$app/environment'; +import { authStore } from '$lib/stores/auth'; + +export const ssr = false; + +export const load = ({ url }: { url: URL }) => { + if (!browser) return; + if (url.pathname === '/login') return; + + const { accessToken } = get(authStore); + if (!accessToken) { + redirect(307, '/login'); + } +}; diff --git a/frontend/static/images/icon-add.svg b/frontend/static/images/icon-add.svg new file mode 100644 index 0000000..2d66071 --- /dev/null +++ b/frontend/static/images/icon-add.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/static/images/icon-category.svg b/frontend/static/images/icon-category.svg new file mode 100644 index 0000000..c43ee57 --- /dev/null +++ b/frontend/static/images/icon-category.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/static/images/icon-file.svg b/frontend/static/images/icon-file.svg new file mode 100644 index 0000000..07848b1 --- /dev/null +++ b/frontend/static/images/icon-file.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/static/images/icon-pool.svg b/frontend/static/images/icon-pool.svg new file mode 100644 index 0000000..035e4ce --- /dev/null +++ b/frontend/static/images/icon-pool.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/static/images/icon-settings.svg b/frontend/static/images/icon-settings.svg new file mode 100644 index 0000000..25aebd2 --- /dev/null +++ b/frontend/static/images/icon-settings.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/static/images/icon-tag.svg b/frontend/static/images/icon-tag.svg new file mode 100644 index 0000000..89b1e4b --- /dev/null +++ b/frontend/static/images/icon-tag.svg @@ -0,0 +1,5 @@ + + + + +