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:
51
Frontend/src/lib/components/CollapsiblePanel.svelte
Normal file
51
Frontend/src/lib/components/CollapsiblePanel.svelte
Normal file
@@ -0,0 +1,51 @@
|
||||
<script lang="ts">
|
||||
import { slide } from 'svelte/transition';
|
||||
import { quintOut } from 'svelte/easing';
|
||||
import type { Snippet } from 'svelte';
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
badge?: string;
|
||||
accentClass?: string;
|
||||
defaultOpen?: boolean;
|
||||
children: Snippet;
|
||||
}
|
||||
|
||||
let { title, badge = '', accentClass = '', defaultOpen = true, children }: Props = $props();
|
||||
|
||||
let open = $state(defaultOpen);
|
||||
</script>
|
||||
|
||||
<div class="gp overflow-hidden">
|
||||
<button
|
||||
class="flex items-center justify-between w-full cursor-pointer group"
|
||||
onclick={() => open = !open}
|
||||
>
|
||||
<div class="flex items-center gap-2">
|
||||
<svg
|
||||
class="w-3 h-3 transition-transform duration-200 text-white/50 group-hover:text-white/80"
|
||||
class:rotate-90={open}
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="3"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<polyline points="9 18 15 12 9 6" />
|
||||
</svg>
|
||||
<span class="gp-title {accentClass}">{title}</span>
|
||||
</div>
|
||||
{#if badge}
|
||||
<span class="gp-label">{badge}</span>
|
||||
{/if}
|
||||
</button>
|
||||
|
||||
{#if open}
|
||||
<div transition:slide={{ duration: 250, easing: quintOut }}>
|
||||
<div class="flex flex-col gap-[var(--spacing-gp-gap)] pt-1">
|
||||
{@render children()}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
Reference in New Issue
Block a user