Restructure /admin into tabbed area with password gate

Backups moves under /admin/backups; new Reports and Categories tabs join
it (categories migrated from the top-level /categories route). The
dashboard's SKU/low-stock/inventory-value cards move into Reports, which
also adds sales totals and a top-selling parts list.

A 5-minute sliding-cookie password gate (27182818) now wraps every
/admin request, including the backup download endpoint, via a
hooks.server.js auth check. The login page sits at /admin/login and
escapes the admin tab chrome via a layout reset.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
David Beccue
2026-05-16 15:47:42 +05:00
parent df64de4255
commit c882ab5d43
17 changed files with 517 additions and 207 deletions

View File

@ -0,0 +1,61 @@
<script>
import { page } from '$app/stores';
import { t } from '$lib/i18n/store.js';
const tabs = [
{ href: '/admin/reports', key: 'admin.tabs.reports' },
{ href: '/admin/categories', key: 'admin.tabs.categories' },
{ href: '/admin/backups', key: 'admin.tabs.backups' }
];
$: current = $page.url.pathname;
function isActive(href) {
return current === href || current.startsWith(href + '/');
}
</script>
<h1>{$t('admin.title')}</h1>
<nav class="tabs" aria-label="Admin sections">
{#each tabs as tab}
<a href={tab.href} class:active={isActive(tab.href)} aria-current={isActive(tab.href) ? 'page' : undefined}>
{$t(tab.key)}
</a>
{/each}
</nav>
<div class="tab-panel">
<slot />
</div>
<style>
h1 { margin-bottom: 0.75rem; }
.tabs {
display: flex;
gap: 0.25rem;
border-bottom: 2px solid #e5e8ee;
margin-bottom: 1.5rem;
flex-wrap: wrap;
}
.tabs a {
padding: 0.55rem 1rem;
text-decoration: none;
color: #1d2330;
border: 1px solid transparent;
border-bottom: none;
border-radius: 6px 6px 0 0;
margin-bottom: -2px;
font-weight: 500;
background: transparent;
}
.tabs a:hover {
background: #eef1f6;
color: #1d2330;
}
.tabs a.active {
background: #fff;
border-color: #e5e8ee;
border-bottom-color: #fff;
color: #006a4e;
}
</style>