feat: migrate frontend React 18 → Svelte 5 + SvelteKit
All checks were successful
CI/CD — Build & Deploy / Build & Deploy (push) Successful in 22s
All checks were successful
CI/CD — Build & Deploy / Build & Deploy (push) Successful in 22s
Core logic portable (economy, balance, cosmetics, migrateSave) — zero rewrite. 136 tests green, identiques. Backend inchangé. - Svelte 5 runes stores (game, auth, toast) remplacent Zustand - SvelteKit adapter-static SPA (dist/ output, fallback index.html) - Tailwind v4 conservé, design system .gp-* porté - Transitions natives : slide, fly, scale, fade sur toute l'UI - Sidebar tabbée (Production/Evolution/Collection) + CollapsiblePanel - Mobile bottom sheet avec FAB toggle + backdrop blur - Click particles réactifs Svelte (plus de DOM impératif) - TadpoleSprite bounce + glow ring au clic - Guide refait en accordéon, Achievements avec filtres - a11y : focus-visible, Escape modals, aria-current, aria-labels - CI/CD adapté (tests + build + rsync) - Build 504K (vs ~1.2MB React)
This commit is contained in:
64
Frontend/src/lib/stores/auth.svelte.ts
Normal file
64
Frontend/src/lib/stores/auth.svelte.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
// auth.svelte.ts — Auth store (Svelte 5 runes)
|
||||
// Cookie-based auth with SuperOAuth PKCE
|
||||
|
||||
import { apiFetch } from '$lib/api';
|
||||
|
||||
export interface User {
|
||||
id: number;
|
||||
nickname: string;
|
||||
avatar_url?: string;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
let user = $state<User | null>(null);
|
||||
let loading = $state(true);
|
||||
|
||||
async function refresh() {
|
||||
try {
|
||||
const data = await apiFetch('/auth/me');
|
||||
user = data as User;
|
||||
} catch {
|
||||
user = null;
|
||||
}
|
||||
}
|
||||
|
||||
async function init() {
|
||||
await refresh();
|
||||
loading = false;
|
||||
|
||||
// Listen for expired session
|
||||
if (typeof window !== 'undefined') {
|
||||
window.addEventListener('auth:expired', () => {
|
||||
user = null;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function logout() {
|
||||
try {
|
||||
await apiFetch('/auth/logout', { method: 'POST' });
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
user = null;
|
||||
}
|
||||
|
||||
async function editUser(updatedFields: Record<string, unknown>) {
|
||||
if (!user) return;
|
||||
const data = await apiFetch(`/users/${user.id}`, {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify(updatedFields),
|
||||
});
|
||||
if (data?.user) {
|
||||
user = { ...user, ...data.user };
|
||||
}
|
||||
}
|
||||
|
||||
export const authStore = {
|
||||
get user() { return user; },
|
||||
get loading() { return loading; },
|
||||
init,
|
||||
refresh,
|
||||
logout,
|
||||
editUser,
|
||||
};
|
||||
Reference in New Issue
Block a user