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:
sucupira
2026-07-21 08:00:16 -04:00
parent d0fc7207f2
commit d0d80a105e
175 changed files with 15603 additions and 5911 deletions
+252
View File
@@ -0,0 +1,252 @@
<script lang="ts">
import ResponsiveImage from '$lib/components/ResponsiveImage.svelte';
import Seo from '$lib/components/Seo.svelte';
import KineticText from '$lib/components/motion/KineticText.svelte';
import { getBundle } from '$lib/i18n';
import sheToldMe from '$lib/assets/images/djangokam-she-told-me.webp?format=avif;webp&w=400;800&as=picture';
import iWantYouGirl from '$lib/assets/images/djangokam-i-want-you-girl.webp?format=avif;webp&w=400;800&as=picture';
import ishMwenKute from '$lib/assets/images/djangokam-ish-mwen-kute.jpg?format=avif;webp;jpg&w=400;800&as=picture';
const t = getBundle('en');
// Order aligned with t.press.visuals (i18n/en/press.json).
const pictures = [sheToldMe, iWantYouGirl, ishMwenKute];
</script>
<Seo
title="Press"
description="Press resources for DJANGOKAM, the first Caribbean AI artist produced by ORGANISATION KA INTERNATIONALE (OKI) — HD visuals and listening links."
path="/en/press/"
locale="en"
/>
<section class="press-hero">
<svg class="icon hero-icon" aria-hidden="true"><use href="/icons.svg#lambi" /></svg>
<h1>{t.press.title} <span class="accent">{t.press.title_accent}</span></h1>
<p class="press-lede">{t.press.lede}</p>
</section>
<section class="press-facts">
<div class="press-container">
<KineticText text={t.press.facts_title} as="h2" class="press-section-title" />
<div class="press-facts-list">
{#each t.press.facts as fact (fact.label)}
<div class="press-fact">
<span class="press-fact-label">{fact.label}</span>
<span>{fact.value}</span>
</div>
{/each}
</div>
</div>
</section>
<section class="press-visuals">
<div class="press-container">
<KineticText text={t.press.visuals_title} as="h2" class="press-section-title" />
<p class="press-visuals-intro">{t.press.visuals_intro}</p>
<div class="press-visual-grid">
{#each t.press.visuals as visual, i (visual.pdf)}
<div class="press-visual">
<a href={pictures[i].img.src} target="_blank" rel="noopener noreferrer">
<ResponsiveImage picture={pictures[i]} alt={visual.caption} loading="lazy" />
<span class="press-visual-caption">{visual.caption}</span>
</a>
<a href="/assets/press/{visual.pdf}" class="press-visual-pdf-link">
{t.press.visual_pdf_label}
</a>
</div>
{/each}
</div>
<div class="press-visuals-pdf">
<a href="/assets/press/{t.press.visuals_pdf_file}" class="btn btn-solid">
{t.press.visuals_pdf_label}
</a>
</div>
</div>
</section>
<section class="press-links">
<div class="press-container">
<KineticText text={t.press.links_title} as="h2" class="press-section-title" />
<div class="press-links-list">
{#each t.press.links as link (link.url)}
<a href={link.url} target="_blank" rel="noopener noreferrer">{link.text}</a>
{/each}
</div>
</div>
</section>
<section class="press-contact">
<div class="press-container">
<KineticText text={t.press.contact_title} as="h2" class="press-section-title" />
<p class="press-contact-text">{t.press.contact_text}</p>
<a href="mailto:{t.press.contact_email}" class="btn btn-solid">{t.press.contact_email}</a>
</div>
</section>
<style>
.press-hero {
padding: 9rem var(--space-4) 3rem;
text-align: center;
border-bottom: 1px solid var(--line);
}
.hero-icon {
width: 2.5rem;
height: 2.5rem;
margin: 0 auto var(--space-2);
color: var(--or-oki);
}
.press-hero h1 {
font-size: clamp(2rem, 5vw, 3rem);
margin-bottom: var(--space-2);
}
.accent {
color: var(--or-oki);
}
.press-lede {
max-width: 700px;
margin: 0 auto;
font-size: 1.1rem;
line-height: 1.6;
color: var(--muted);
}
.press-container {
max-width: var(--container);
margin: 0 auto;
padding: 0 var(--space-4);
}
.press-facts,
.press-visuals,
.press-contact {
padding: var(--space-5) 0;
background: var(--noir-profond);
}
.press-links {
padding: var(--space-5) 0;
}
.press-contact {
padding-bottom: calc(var(--space-5) + var(--space-4));
text-align: center;
}
:global(.press-section-title) {
text-align: center;
font-size: clamp(1.75rem, 4vw, 2rem);
margin-bottom: var(--space-4);
}
.press-facts-list {
max-width: 800px;
margin: 0 auto;
display: grid;
gap: var(--space-2);
}
.press-fact {
display: grid;
grid-template-columns: 160px 1fr;
gap: var(--space-2);
padding: var(--space-2) 0;
border-bottom: 1px solid var(--line);
}
.press-fact-label {
color: var(--or-oki);
font-weight: 700;
font-size: 0.9rem;
text-transform: uppercase;
letter-spacing: 0.04em;
}
.press-visuals-intro {
text-align: center;
max-width: 700px;
margin: 0 auto var(--space-4);
color: var(--muted);
}
.press-visual-grid {
max-width: 1000px;
margin: 0 auto;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: var(--space-3);
}
.press-visual a {
display: block;
color: inherit;
}
.press-visual :global(img) {
width: 100%;
aspect-ratio: 1 / 1;
object-fit: cover;
border-radius: var(--radius-md);
border: 1px solid var(--line);
}
.press-visual-caption {
display: block;
margin-top: 0.5rem;
font-size: 0.85rem;
color: var(--muted);
}
.press-visual-pdf-link {
display: inline-block;
margin-top: 0.5rem;
font-size: 0.8rem;
color: var(--or-oki);
border-bottom: 1px solid currentColor;
}
.press-visuals-pdf {
text-align: center;
margin-top: var(--space-4);
}
.press-links-list {
max-width: 600px;
margin: 0 auto;
display: grid;
gap: var(--space-1);
}
.press-links-list a {
display: block;
color: var(--blanc-creme);
padding: 0.9rem 1.25rem;
background: var(--card-bg);
border: var(--border-card);
border-left: 4px solid var(--vert-oki);
border-radius: var(--radius-md);
transition: border-color var(--dur-tanbou) var(--ease-ka);
}
.press-links-list a:hover {
border-color: var(--vert-oki);
}
.press-contact-text {
max-width: 600px;
margin: 0 auto var(--space-3);
color: var(--muted);
}
@media (max-width: 600px) {
.press-fact {
grid-template-columns: 1fr;
gap: 0.25rem;
}
}
</style>