refactor(admin): replace tab bar with sidebar layout
Some checks failed
CI / Backend (push) Successful in 38s
CI / UI (push) Successful in 42s
Release / Test backend (push) Successful in 40s
Release / Check ui (push) Successful in 33s
CI / Backend (pull_request) Successful in 28s
Release / Docker / caddy (push) Successful in 1m11s
CI / UI (pull_request) Successful in 29s
Release / Docker / ui (push) Successful in 1m54s
Release / Docker / runner (push) Successful in 4m27s
Release / Docker / backend (push) Failing after 5m11s
Release / Gitea Release (push) Has been skipped
Some checks failed
CI / Backend (push) Successful in 38s
CI / UI (push) Successful in 42s
Release / Test backend (push) Successful in 40s
Release / Check ui (push) Successful in 33s
CI / Backend (pull_request) Successful in 28s
Release / Docker / caddy (push) Successful in 1m11s
CI / UI (pull_request) Successful in 29s
Release / Docker / ui (push) Successful in 1m54s
Release / Docker / runner (push) Successful in 4m27s
Release / Docker / backend (push) Failing after 5m11s
Release / Gitea Release (push) Has been skipped
Move admin navigation from a two-row tab strip into a persistent left sidebar with grouped sections (Pages / Tools). Consolidate Scrape and Audio entries in the global top nav into a single Admin link.
This commit is contained in:
@@ -260,15 +260,9 @@
|
|||||||
{#if data.user?.role === 'admin'}
|
{#if data.user?.role === 'admin'}
|
||||||
<a
|
<a
|
||||||
href="/admin/scrape"
|
href="/admin/scrape"
|
||||||
class="hidden sm:block text-sm transition-colors {page.url.pathname.startsWith('/admin/scrape') ? 'text-zinc-100 font-medium' : 'text-zinc-400 hover:text-zinc-100'}"
|
class="hidden sm:block text-sm transition-colors {page.url.pathname.startsWith('/admin') ? 'text-zinc-100 font-medium' : 'text-zinc-400 hover:text-zinc-100'}"
|
||||||
>
|
>
|
||||||
Scrape
|
Admin
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
href="/admin/audio"
|
|
||||||
class="hidden sm:block text-sm transition-colors {page.url.pathname.startsWith('/admin/audio') ? 'text-zinc-100 font-medium' : 'text-zinc-400 hover:text-zinc-100'}"
|
|
||||||
>
|
|
||||||
Audio
|
|
||||||
</a>
|
</a>
|
||||||
{/if}
|
{/if}
|
||||||
<a
|
<a
|
||||||
@@ -356,23 +350,9 @@
|
|||||||
<a
|
<a
|
||||||
href="/admin/scrape"
|
href="/admin/scrape"
|
||||||
onclick={() => (menuOpen = false)}
|
onclick={() => (menuOpen = false)}
|
||||||
class="px-3 py-2.5 rounded-lg text-sm font-medium transition-colors {page.url.pathname.startsWith('/admin/scrape') ? 'bg-zinc-800 text-zinc-100' : 'text-zinc-400 hover:bg-zinc-800 hover:text-zinc-100'}"
|
class="px-3 py-2.5 rounded-lg text-sm font-medium transition-colors {page.url.pathname.startsWith('/admin') ? 'bg-zinc-800 text-zinc-100' : 'text-zinc-400 hover:bg-zinc-800 hover:text-zinc-100'}"
|
||||||
>
|
>
|
||||||
Scrape tasks
|
Admin panel
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
href="/admin/audio"
|
|
||||||
onclick={() => (menuOpen = false)}
|
|
||||||
class="px-3 py-2.5 rounded-lg text-sm font-medium transition-colors {page.url.pathname === '/admin/audio' ? 'bg-zinc-800 text-zinc-100' : 'text-zinc-400 hover:bg-zinc-800 hover:text-zinc-100'}"
|
|
||||||
>
|
|
||||||
Audio cache
|
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
href="/admin/audio-jobs"
|
|
||||||
onclick={() => (menuOpen = false)}
|
|
||||||
class="px-3 py-2.5 rounded-lg text-sm font-medium transition-colors {page.url.pathname.startsWith('/admin/audio-jobs') ? 'bg-zinc-800 text-zinc-100' : 'text-zinc-400 hover:bg-zinc-800 hover:text-zinc-100'}"
|
|
||||||
>
|
|
||||||
Audio jobs
|
|
||||||
</a>
|
</a>
|
||||||
{/if}
|
{/if}
|
||||||
<div class="my-1 border-t border-zinc-700/60"></div>
|
<div class="my-1 border-t border-zinc-700/60"></div>
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { page } from '$app/state';
|
import { page } from '$app/state';
|
||||||
|
|
||||||
const adminTabs = [
|
const internalLinks = [
|
||||||
{ href: '/admin/scrape', label: 'Scrape' },
|
{ href: '/admin/scrape', label: 'Scrape' },
|
||||||
{ href: '/admin/audio', label: 'Audio' }
|
{ href: '/admin/audio', label: 'Audio' }
|
||||||
];
|
];
|
||||||
|
|
||||||
const toolTabs = [
|
const externalLinks = [
|
||||||
{ href: 'https://feedback.libnovel.cc', label: 'Feedback' },
|
{ href: 'https://feedback.libnovel.cc', label: 'Feedback' },
|
||||||
{ href: 'https://errors.libnovel.cc', label: 'Errors' },
|
{ href: 'https://errors.libnovel.cc', label: 'Errors' },
|
||||||
{ href: 'https://analytics.libnovel.cc', label: 'Analytics' },
|
{ href: 'https://analytics.libnovel.cc', label: 'Analytics' },
|
||||||
@@ -21,36 +21,51 @@
|
|||||||
let { children }: Props = $props();
|
let { children }: Props = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- Admin nav: internal pages + external tools -->
|
<div class="flex min-h-[calc(100vh-4rem)] gap-0">
|
||||||
<div class="mb-6 flex flex-wrap items-center gap-3">
|
<!-- Sidebar -->
|
||||||
<!-- Internal admin pages -->
|
<aside class="w-48 shrink-0 border-r border-zinc-800 px-3 py-6 flex flex-col gap-6">
|
||||||
<div class="flex gap-1 bg-zinc-800 rounded-lg p-1 border border-zinc-700">
|
<!-- Internal pages -->
|
||||||
{#each adminTabs as tab}
|
<div>
|
||||||
|
<p class="px-2 mb-2 text-xs font-semibold text-zinc-600 uppercase tracking-widest">Pages</p>
|
||||||
|
<nav class="flex flex-col gap-0.5">
|
||||||
|
{#each internalLinks as link}
|
||||||
<a
|
<a
|
||||||
href={tab.href}
|
href={link.href}
|
||||||
class="px-4 py-1.5 rounded-md text-sm font-medium transition-colors
|
class="px-2 py-1.5 rounded-md text-sm font-medium transition-colors
|
||||||
{page.url.pathname.startsWith(tab.href)
|
{page.url.pathname.startsWith(link.href)
|
||||||
? 'bg-zinc-700 text-zinc-100'
|
? 'bg-zinc-800 text-zinc-100'
|
||||||
: 'text-zinc-400 hover:text-zinc-200'}"
|
: 'text-zinc-400 hover:bg-zinc-800/60 hover:text-zinc-200'}"
|
||||||
>
|
>
|
||||||
{tab.label}
|
{link.label}
|
||||||
</a>
|
</a>
|
||||||
{/each}
|
{/each}
|
||||||
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- External tools (open in new tab) -->
|
<!-- External tools -->
|
||||||
<div class="flex gap-1 bg-zinc-800 rounded-lg p-1 border border-zinc-700">
|
<div>
|
||||||
{#each toolTabs as tool}
|
<p class="px-2 mb-2 text-xs font-semibold text-zinc-600 uppercase tracking-widest">Tools</p>
|
||||||
|
<nav class="flex flex-col gap-0.5">
|
||||||
|
{#each externalLinks as link}
|
||||||
<a
|
<a
|
||||||
href={tool.href}
|
href={link.href}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
class="px-4 py-1.5 rounded-md text-sm font-medium text-zinc-400 hover:text-zinc-200 transition-colors"
|
class="px-2 py-1.5 rounded-md text-sm font-medium text-zinc-400 hover:bg-zinc-800/60 hover:text-zinc-200 transition-colors flex items-center justify-between"
|
||||||
>
|
>
|
||||||
{tool.label} ↗
|
{link.label}
|
||||||
|
<svg class="w-3 h-3 shrink-0 opacity-50" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||||
|
d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" />
|
||||||
|
</svg>
|
||||||
</a>
|
</a>
|
||||||
{/each}
|
{/each}
|
||||||
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</aside>
|
||||||
|
|
||||||
{@render children?.()}
|
<!-- Main content -->
|
||||||
|
<main class="flex-1 min-w-0 px-8 py-6">
|
||||||
|
{@render children?.()}
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user