All checks were successful
CI/CD — Build & Deploy / Build & Deploy (push) Successful in 29s
Backend: 5 modules (auth, user, work, list, health), AniList GraphQL proxy, SuperOAuth PKCE introspection, XP system, migrations TypeORM. Frontend: SvelteKit adapter-node, PWA manifest, dark theme, pages home/search/list/profile/callback. Infra: CI/CD Gitea vps-runner, Apache vhost SSL, pm2 sakuin-backend + sakuin-frontend, port 4002. License: BSL 1.1 (Apache 2.0 en 2028).
114 lines
2.3 KiB
Svelte
114 lines
2.3 KiB
Svelte
<script lang="ts">
|
|
import '../app.css';
|
|
import { login, logout } from '$lib/auth';
|
|
|
|
let { children } = $props();
|
|
let user = $state<any>(null);
|
|
let loading = $state(true);
|
|
|
|
async function loadUser() {
|
|
try {
|
|
const { api } = await import('$lib/api');
|
|
user = await api.me();
|
|
} catch {
|
|
user = null;
|
|
} finally {
|
|
loading = false;
|
|
}
|
|
}
|
|
|
|
$effect(() => {
|
|
loadUser();
|
|
});
|
|
</script>
|
|
|
|
<nav class="navbar">
|
|
<div class="container nav-inner">
|
|
<a href="/" class="logo">索引 <span>Sakuin</span></a>
|
|
|
|
<div class="nav-links">
|
|
<a href="/search">Rechercher</a>
|
|
{#if user}
|
|
<a href="/list">Ma Liste</a>
|
|
<a href="/profile">Profil</a>
|
|
<div class="user-badge">
|
|
{#if user.avatarUrl}
|
|
<img src={user.avatarUrl} alt="" class="avatar" />
|
|
{/if}
|
|
<span class="username">{user.username}</span>
|
|
<span class="level badge badge-accent">Lv.{user.level}</span>
|
|
<button class="btn-ghost btn-sm" onclick={logout}>Déconnexion</button>
|
|
</div>
|
|
{:else if !loading}
|
|
<button class="btn-primary" onclick={login}>Connexion</button>
|
|
{/if}
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
|
|
<main class="container main-content">
|
|
{@render children()}
|
|
</main>
|
|
|
|
<style>
|
|
.navbar {
|
|
background: var(--bg-secondary);
|
|
border-bottom: 1px solid var(--border);
|
|
padding: 0.75rem 0;
|
|
position: sticky;
|
|
top: 0;
|
|
z-index: 100;
|
|
}
|
|
.nav-inner {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
}
|
|
.logo {
|
|
font-size: 1.25rem;
|
|
font-weight: 700;
|
|
color: var(--text-primary);
|
|
}
|
|
.logo span {
|
|
color: var(--accent);
|
|
}
|
|
.nav-links {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 1rem;
|
|
}
|
|
.nav-links a {
|
|
color: var(--text-secondary);
|
|
font-size: 0.875rem;
|
|
font-weight: 500;
|
|
}
|
|
.nav-links a:hover {
|
|
color: var(--text-primary);
|
|
}
|
|
.user-badge {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
}
|
|
.avatar {
|
|
width: 28px;
|
|
height: 28px;
|
|
border-radius: 50%;
|
|
}
|
|
.username {
|
|
font-size: 0.875rem;
|
|
font-weight: 500;
|
|
}
|
|
.level {
|
|
font-size: 0.7rem;
|
|
}
|
|
.btn-sm {
|
|
padding: 0.25rem 0.5rem;
|
|
font-size: 0.75rem;
|
|
}
|
|
.main-content {
|
|
padding-top: 2rem;
|
|
padding-bottom: 4rem;
|
|
}
|
|
</style>
|