feat: migre le site vers SvelteKit (Svelte 5, statique, zéro tiers)
- Rebuild complet SvelteKit 2 + Svelte 5 runes + TypeScript, adapter-static - Images self-hébergées optimisées au build (vite-imagetools), fonts Archivo/Inter en woff2 local — BunnyCDN et Google Fonts supprimés (corrige les 403 d'images) - Tokens charte OKI, thème sombre par défaut / clair opt-in, zéro emoji (set SVG) - Motion : KineticText (stagger syncopé gwoka), ScrollProgressBar, View Transitions - Village SVG isométrique pour les services hébergés + fallback accessible - PWA (manifest + SW hors-ligne), 404 en KA, CSP nettoyée (.htaccess + _headers) - Lighthouse mobile : 91/100/100/100 — JS initial 67 Ko gzip
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
<script lang="ts">
|
||||
import '$lib/styles/oki-tokens.css';
|
||||
import '$lib/styles/base.css';
|
||||
|
||||
import { afterNavigate, onNavigate } from '$app/navigation';
|
||||
import { page } from '$app/state';
|
||||
import Footer from '$lib/components/Footer.svelte';
|
||||
import Nav from '$lib/components/Nav.svelte';
|
||||
import ScrollProgressBar from '$lib/components/motion/ScrollProgressBar.svelte';
|
||||
import { getBundle, localeFromPath } from '$lib/i18n';
|
||||
import { prefersReducedMotion } from '$lib/motion/tokens';
|
||||
|
||||
let { children } = $props();
|
||||
|
||||
const locale = $derived(localeFromPath(page.url.pathname));
|
||||
const t = $derived(getBundle(locale));
|
||||
|
||||
// PageTransition légère : View Transitions API, durée lue depuis les tokens.
|
||||
// Navigateurs sans support : navigation instantanée (fallback sobre).
|
||||
onNavigate((navigation) => {
|
||||
if (prefersReducedMotion()) return;
|
||||
if (!document.startViewTransition) return;
|
||||
return new Promise((resolve) => {
|
||||
document.startViewTransition(async () => {
|
||||
resolve();
|
||||
await navigation.complete;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Focus déplacé sur le contenu après chaque transition de route (playbook §6)
|
||||
afterNavigate(({ type, to }) => {
|
||||
if (type === 'enter') return;
|
||||
if (to?.url.hash) return;
|
||||
document.getElementById('contenu')?.focus({ preventScroll: true });
|
||||
});
|
||||
</script>
|
||||
|
||||
<a href="#contenu" class="skip-link">{locale === 'en' ? 'Skip to content' : 'Aller au contenu'}</a>
|
||||
<ScrollProgressBar />
|
||||
<Nav {t} {locale} />
|
||||
<main id="contenu" tabindex="-1">
|
||||
{@render children()}
|
||||
</main>
|
||||
<Footer {t} {locale} />
|
||||
|
||||
<style>
|
||||
main {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
::view-transition-old(root),
|
||||
::view-transition-new(root) {
|
||||
animation-duration: var(--dur-mesure);
|
||||
animation-timing-function: var(--ease-ka);
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user