feat: remplace le sprite SVG OKI par les icônes Lucide

- Ajoute @lucide/svelte et le composant Icon avec son mapping
- Adapte chaque icône au sens du texte (flag, unlock, handshake, shield,
  landmark, briefcase, music, clapperboard, mic, file-text, etc.)
- Remplace tous les <use href='/icons.svg#...'> par <Icon name='...' />
- Met à jour BrandIcon pour utiliser Lucide Mail
- Supprime static/icons.svg devenu inutile
- Ajuste les styles scoped avec :global() pour cibler les SVG Lucide
- Met à jour README.md et CONTRIBUTING.md
This commit is contained in:
2026-08-09 09:07:53 +04:00
parent 4d1885b543
commit ace58186c0
25 changed files with 180 additions and 169 deletions
+1 -1
View File
@@ -94,7 +94,7 @@ Les liens de contact sont regroupés dans `src/lib/i18n/fr/contact.json` (et `en
- Sections de l'accueil : `src/lib/components/sections/`
- Layout : `Nav.svelte`, `Footer.svelte`, `Seo.svelte`
- Motion : `src/lib/components/motion/` (KineticText, ScrollProgressBar)
- Icônes : sprite `static/icons.svg` (set OKI, charte §4) et `src/lib/components/icons/BrandIcon.svelte` (logos de marques)
- Icônes : `@lucide/svelte` via `src/lib/components/icons/Icon.svelte` (mapping sémantique dans `lucide-map.ts`) et `src/lib/components/icons/BrandIcon.svelte` (logos de marques non disponibles dans Lucide)
Après toute modification d'un composant, passez l'autofixer (voir `svelte-5_code_writer.md`) :
+1 -1
View File
@@ -49,7 +49,7 @@ src/
offline/ # page hors-ligne (cible navigateFallback du SW)
+error.svelte # 404/erreurs designée (microcopy KA)
static/
fonts/ icons.svg images/ assets/press/ theme.js lang-redirect.js
fonts/ images/ assets/press/ theme.js lang-redirect.js
manifest.webmanifest 404.html robots.txt sitemap.xml _headers .htaccess
```
+10
View File
@@ -11,6 +11,7 @@
"dependencies": {
"@fontsource/archivo": "^5.3.0",
"@fontsource/inter": "^5.3.0",
"@lucide/svelte": "^1.30.0",
"gsap": "^3.15.0",
"lenis": "^1.3.25"
},
@@ -2285,6 +2286,15 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
"node_modules/@lucide/svelte": {
"version": "1.30.0",
"resolved": "https://registry.npmjs.org/@lucide/svelte/-/svelte-1.30.0.tgz",
"integrity": "sha512-KtVrqWT3BD41kf1CPaP4QTAyofw0xm5hw/JGwd76+wMk1l0ZcXskA2Wi9ANVWCsk7mGrpFo2SqL3Hl29xTkV3w==",
"license": "ISC",
"peerDependencies": {
"svelte": "^5"
}
},
"node_modules/@napi-rs/wasm-runtime": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.6.tgz",
+1
View File
@@ -25,6 +25,7 @@
"dependencies": {
"@fontsource/archivo": "^5.3.0",
"@fontsource/inter": "^5.3.0",
"@lucide/svelte": "^1.30.0",
"gsap": "^3.15.0",
"lenis": "^1.3.25"
}
+7 -14
View File
@@ -2,6 +2,7 @@
import { page } from '$app/state';
import { resolve } from '$app/paths';
import { onMount } from 'svelte';
import Icon from '$lib/components/icons/Icon.svelte';
import { alternatePath, type Bundle, type Locale } from '$lib/i18n';
let { t, locale }: { t: Bundle; locale: Locale } = $props();
@@ -124,13 +125,8 @@
title={t.ui.theme_toggle}
onclick={toggleTheme}
>
<svg class="theme-icon theme-icon-dark" viewBox="0 0 24 24" aria-hidden="true">
<path d="M20 14.5A8.5 8.5 0 0 1 9.5 4 8.5 8.5 0 1 0 20 14.5Z" />
</svg>
<svg class="theme-icon theme-icon-light" viewBox="0 0 24 24" aria-hidden="true">
<circle cx="12" cy="12" r="4.5" />
<path d="M12 2v3M12 19v3M2 12h3M19 12h3M4.5 4.5l2 2M17.5 17.5l2 2M19.5 4.5l-2 2M6.5 17.5l-2 2" />
</svg>
<Icon name="moon" class="theme-icon theme-icon-dark" />
<Icon name="sun" class="theme-icon theme-icon-light" />
</button>
<button
@@ -270,24 +266,21 @@
border-color: var(--or-oki);
}
.theme-icon {
.theme-toggle :global(.theme-icon) {
width: 1.1rem;
height: 1.1rem;
fill: none;
stroke: currentColor;
stroke-width: 2;
stroke-linecap: square;
}
.theme-icon-light {
.theme-toggle :global(.theme-icon-light) {
display: none;
}
:global(html.light-theme) .theme-icon-dark {
:global(html.light-theme .theme-toggle .theme-icon-dark) {
display: none;
}
:global(html.light-theme) .theme-icon-light {
:global(html.light-theme .theme-toggle .theme-icon-light) {
display: block;
}
+5 -9
View File
@@ -1,4 +1,6 @@
<script lang="ts">
import Mail from '@lucide/svelte/icons/mail';
interface BrandPath {
d: string;
fillRule?: 'evenodd';
@@ -40,14 +42,6 @@
}
]
},
email: {
viewBox: '0 0 24 24',
paths: [
{
d: 'M20 4H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 4l-8 5-8-5V6l8 5 8-5v2z'
}
]
},
gitea: {
viewBox: '5.67 143.05 628.65 387.55',
paths: [
@@ -165,7 +159,9 @@
{/if}
{/snippet}
{#if def}
{#if name === 'email'}
<Mail class={className} size="1em" />
{:else if def}
<svg
viewBox={def.viewBox}
fill="currentColor"
+19
View File
@@ -0,0 +1,19 @@
<script lang="ts">
import { LUCIDE_ICONS } from './lucide-map';
interface Props {
/** Nom d'une icône Lucide enregistrée dans lucide-map. */
name: string;
class?: string;
size?: number | string;
strokeWidth?: number;
}
let { name, class: className = '', size = '1em', strokeWidth = 2 }: Props = $props();
const Icon = $derived(LUCIDE_ICONS[name]);
</script>
{#if Icon}
<Icon class={className} {size} {strokeWidth} />
{/if}
+63
View File
@@ -0,0 +1,63 @@
import type { Component } from 'svelte';
import BadgePercent from '@lucide/svelte/icons/badge-percent';
import BookOpen from '@lucide/svelte/icons/book-open';
import Briefcase from '@lucide/svelte/icons/briefcase';
import CircleHelp from '@lucide/svelte/icons/circle-help';
import CircleX from '@lucide/svelte/icons/circle-x';
import Clapperboard from '@lucide/svelte/icons/clapperboard';
import Code from '@lucide/svelte/icons/code';
import Coffee from '@lucide/svelte/icons/coffee';
import FileText from '@lucide/svelte/icons/file-text';
import Flag from '@lucide/svelte/icons/flag';
import Globe from '@lucide/svelte/icons/globe';
import Handshake from '@lucide/svelte/icons/handshake';
import Heart from '@lucide/svelte/icons/heart';
import Landmark from '@lucide/svelte/icons/landmark';
import Megaphone from '@lucide/svelte/icons/megaphone';
import MessageCircle from '@lucide/svelte/icons/message-circle';
import Mic from '@lucide/svelte/icons/mic';
import Moon from '@lucide/svelte/icons/moon';
import Music from '@lucide/svelte/icons/music';
import Music2 from '@lucide/svelte/icons/music-2';
import Newspaper from '@lucide/svelte/icons/newspaper';
import Plus from '@lucide/svelte/icons/plus';
import Shield from '@lucide/svelte/icons/shield';
import Sprout from '@lucide/svelte/icons/sprout';
import Star from '@lucide/svelte/icons/star';
import Sun from '@lucide/svelte/icons/sun';
import Unlock from '@lucide/svelte/icons/unlock';
import WifiOff from '@lucide/svelte/icons/wifi-off';
export const LUCIDE_ICONS: Record<string, Component> = {
'badge-percent': BadgePercent,
'book-open': BookOpen,
briefcase: Briefcase,
'circle-help': CircleHelp,
'circle-x': CircleX,
clapperboard: Clapperboard,
code: Code,
coffee: Coffee,
'file-text': FileText,
flag: Flag,
globe: Globe,
handshake: Handshake,
heart: Heart,
landmark: Landmark,
megaphone: Megaphone,
'message-circle': MessageCircle,
mic: Mic,
moon: Moon,
music: Music,
'music-2': Music2,
newspaper: Newspaper,
plus: Plus,
shield: Shield,
sprout: Sprout,
star: Star,
sun: Sun,
unlock: Unlock,
'wifi-off': WifiOff
};
export type LucideIconName = keyof typeof LUCIDE_ICONS;
+3 -2
View File
@@ -1,4 +1,5 @@
<script lang="ts">
import Icon from '$lib/components/icons/Icon.svelte';
import type { Bundle } from '$lib/i18n';
/**
@@ -22,7 +23,7 @@
<div class="marquee-group">
{#each items as item, i (i)}
<span class="marquee-item">{item}</span>
<svg class="icon marquee-star" aria-hidden="true"><use href="/icons.svg#zetwal" /></svg>
<Icon name="star" class="icon marquee-star" />
{/each}
</div>
{/each}
@@ -75,7 +76,7 @@
color: var(--or-oki);
}
.marquee-star {
:global(.marquee-star) {
width: 1rem;
height: 1rem;
color: var(--or-oki);
+3 -2
View File
@@ -1,5 +1,6 @@
<script lang="ts">
// {@html} sur contenu first-party (JSON i18n du dépôt), aucune donnée utilisateur.
import Icon from '$lib/components/icons/Icon.svelte';
import BrandIcon from '$lib/components/icons/BrandIcon.svelte';
import FlagChip from '$lib/components/motion/FlagChip.svelte';
import KineticText from '$lib/components/motion/KineticText.svelte';
@@ -50,7 +51,7 @@
<div class="contact-socials-group" use:reveal={i}>
<h3 class="contact-socials-title">
{#if title.icon}
<svg class="icon" aria-hidden="true"><use href="/icons.svg#{title.icon}" /></svg>
<Icon name={title.icon} class="icon" />
{/if}
{title.text}
</h3>
@@ -123,7 +124,7 @@
gap: 0.4rem;
}
.contact-socials-title .icon {
.contact-socials-title :global(.icon) {
width: 1.1em;
height: 1.1em;
}
+3 -4
View File
@@ -1,5 +1,6 @@
<script lang="ts">
// {@html} sur contenu first-party (JSON i18n du dépôt), aucune donnée utilisateur.
import Icon from '$lib/components/icons/Icon.svelte';
import FlagChip from '$lib/components/motion/FlagChip.svelte';
import KineticText from '$lib/components/motion/KineticText.svelte';
import ResponsiveImage from '$lib/components/ResponsiveImage.svelte';
@@ -73,9 +74,7 @@
{#each t.djangokam.faits as fait, i (fait.chiffre)}
<div class="djangokam-fact-card" use:reveal={i}>
<div class="djangokam-fact-icon reveal-pop" use:reveal={i + 1}>
<svg class="icon" aria-hidden="true"
><use href="/icons.svg#{pictoFor(fait.icon)}" /></svg
>
<Icon name={pictoFor(fait.icon)} class="icon" />
</div>
<h3>{fait.chiffre}</h3>
<!-- Contenu éditorial du bundle i18n (liens internes balisés). -->
@@ -297,7 +296,7 @@
margin-bottom: 1rem;
}
.djangokam-fact-icon .icon {
.djangokam-fact-icon :global(.icon) {
width: 2rem;
height: 2rem;
}
@@ -1,4 +1,5 @@
<script lang="ts">
import Icon from '$lib/components/icons/Icon.svelte';
import FlagChip from '$lib/components/motion/FlagChip.svelte';
import KineticText from '$lib/components/motion/KineticText.svelte';
import type { Bundle, Locale } from '$lib/i18n';
@@ -23,9 +24,7 @@
{#each t.engagement.cards as card, i (card.title)}
<div class="engagement-card" use:reveal={i}>
<div class="engagement-icon reveal-pop" use:reveal={i + 1}>
<svg class="icon" aria-hidden="true"
><use href="/icons.svg#{pictoFor(card.icon)}" /></svg
>
<Icon name={pictoFor(card.icon)} class="icon" />
</div>
<h3>{card.title}</h3>
<p>{card.text}</p>
@@ -77,7 +76,7 @@
margin-bottom: 1rem;
}
.engagement-icon .icon {
.engagement-icon :global(.icon) {
width: 2.25rem;
height: 2.25rem;
}
+4 -4
View File
@@ -1,4 +1,5 @@
<script lang="ts">
import Icon from '$lib/components/icons/Icon.svelte';
import FlagChip from '$lib/components/motion/FlagChip.svelte';
import KineticText from '$lib/components/motion/KineticText.svelte';
import type { Bundle, Locale } from '$lib/i18n';
@@ -23,7 +24,7 @@
<details class="faq-item" use:reveal={i}>
<summary class="faq-question">
<span>{item.question}</span>
<span class="faq-icon" aria-hidden="true">+</span>
<Icon name="plus" class="faq-icon" size={22} />
</summary>
<div class="faq-answer">
<p>{item.answer}</p>
@@ -98,14 +99,13 @@
color: var(--or-oki);
}
.faq-icon {
font-size: 1.4rem;
:global(.faq-icon) {
color: var(--or-oki);
flex-shrink: 0;
transition: transform var(--dur-tanbou) var(--ease-ka);
}
.faq-item[open] .faq-icon {
.faq-item[open] :global(.faq-icon) {
transform: rotate(45deg);
}
+2 -1
View File
@@ -1,4 +1,5 @@
<script lang="ts">
import Icon from '$lib/components/icons/Icon.svelte';
import type { Bundle, Locale } from '$lib/i18n';
import { splitLeadingEmoji } from './pictos';
@@ -25,7 +26,7 @@
{@const tag = splitLeadingEmoji(rawTag)}
<span class="tag">
{#if tag.icon}
<svg class="icon" aria-hidden="true"><use href="/icons.svg#{tag.icon}" /></svg>
<Icon name={tag.icon} class="icon" />
{/if}
{tag.text}
</span>
+3 -4
View File
@@ -1,4 +1,5 @@
<script lang="ts">
import Icon from '$lib/components/icons/Icon.svelte';
import FlagChip from '$lib/components/motion/FlagChip.svelte';
import KineticText from '$lib/components/motion/KineticText.svelte';
import type { Bundle, Locale } from '$lib/i18n';
@@ -24,9 +25,7 @@
{#each t.values as value, i (value.title)}
<div class="value-card" use:reveal={i}>
<div class="value-icon reveal-pop" use:reveal={i + 1}>
<svg class="icon" aria-hidden="true"
><use href="/icons.svg#{pictoFor(value.icon)}" /></svg
>
<Icon name={pictoFor(value.icon)} class="icon" />
</div>
<h3>{value.title}</h3>
<p>{value.description}</p>
@@ -88,7 +87,7 @@
margin-bottom: 1rem;
}
.value-icon .icon {
.value-icon :global(.icon) {
width: 2rem;
height: 2rem;
}
+3 -4
View File
@@ -1,4 +1,5 @@
<script lang="ts">
import Icon from '$lib/components/icons/Icon.svelte';
import FlagChip from '$lib/components/motion/FlagChip.svelte';
import KineticText from '$lib/components/motion/KineticText.svelte';
import type { Bundle, Locale } from '$lib/i18n';
@@ -28,9 +29,7 @@
use:reveal={i}
>
<div class="project-icon reveal-pop" use:reveal={i + 1}>
<svg class="icon" aria-hidden="true"
><use href="/icons.svg#{pictoFor(item.icon)}" /></svg
>
<Icon name={pictoFor(item.icon)} class="icon" />
</div>
<h3>{item.name}</h3>
<p class="project-domain">{item.domain}</p>
@@ -82,7 +81,7 @@
margin-bottom: 1rem;
}
.project-icon .icon {
.project-icon :global(.icon) {
width: 2.5rem;
height: 2.5rem;
}
+3 -4
View File
@@ -1,4 +1,5 @@
<script lang="ts">
import Icon from '$lib/components/icons/Icon.svelte';
import FlagChip from '$lib/components/motion/FlagChip.svelte';
import KineticText from '$lib/components/motion/KineticText.svelte';
import type { Bundle, Locale } from '$lib/i18n';
@@ -23,9 +24,7 @@
{#each t.publics.items as item, i (item.title)}
<div class="public-card" use:reveal={i}>
<div class="public-icon reveal-pop" use:reveal={i + 1}>
<svg class="icon" aria-hidden="true"
><use href="/icons.svg#{pictoFor(item.icon)}" /></svg
>
<Icon name={pictoFor(item.icon)} class="icon" />
</div>
<h3>{item.title}</h3>
<p class="public-description">{item.description}</p>
@@ -97,7 +96,7 @@
margin-bottom: 1rem;
}
.public-icon .icon {
.public-icon :global(.icon) {
width: 2.5rem;
height: 2.5rem;
}
+24 -21
View File
@@ -1,42 +1,45 @@
/**
* Mapping emojis legacy → pictos du sprite OKI (`/icons.svg`).
* Mapping emojis legacy → noms d'icônes Lucide.
* Charte §4 : zéro emoji décoratif en production.
* Les clés sont normalisées (sans sélecteur de variation U+FE0F
* ni modificateur de teint U+1F3FBU+1F3FF) pour fiabiliser la
* correspondance avec les chaînes des JSON i18n.
*
* Le choix des icônes est guidé par le sens du texte associé,
* pas par la traduction littérale de l'emoji.
*/
const PICTOS: Record<string, string> = {
'🌐': 'lanme', // web, liens internationaux
'📢': 'lambi', // annonces, chaînes
'💬': 'pawol', // communauté, discussion
'💻': 'kle', // code, open-source
'✊': 'glo', // luttes, tarifs solidaires
'💸': 'glo', // tarifs préférentiels / solidaires
'🔓': 'kle', // liberté, open-source
'🤝': 'jaden', // solidarité
'🛡': 'mawon', // souveraineté
'💼': 'zetwal', // entreprises responsables
'🏛': 'kannen', // collectifs, patrimoine
'🎵': 'mizik-note', // sorties musicales
'🎶': 'mizik-note', // transcriptions musicales (PAWOL.NU)
'🎬': 'zetwal', // clips / plateforme multimédia
'🎤': 'glo', // artistes engagés
'📝': 'pawol', // paroles & traductions
'📚': 'kannen' // documents historiques (GONG.GP)
'🌐': 'globe', // web, liens internationaux
'📢': 'megaphone', // annonces, chaînes
'💬': 'message-circle', // communauté, discussion
'💻': 'code', // code, open-source
'✊': 'flag', // luttes, engagement militant
'💸': 'badge-percent', // tarifs préférentiels / solidaires
'🔓': 'unlock', // liberté, open-source
'🤝': 'handshake', // solidarité
'🛡': 'shield', // souveraineté
'💼': 'briefcase', // entreprises responsables
'🏛': 'landmark', // collectifs, patrimoine
'🎵': 'music', // sorties musicales
'🎶': 'music-2', // transcriptions musicales (PAWOL.NU)
'🎬': 'clapperboard', // clips / plateforme multimédia
'🎤': 'mic', // artistes engagés
'📝': 'file-text', // paroles & traductions
'📚': 'book-open' // documents historiques (GONG.GP)
};
/** Picto du sprite correspondant à un emoji legacy (`ka` en repli). */
/** Nom d'icône Lucide correspondant à un emoji legacy (`circle-help` en repli). */
export function pictoFor(icon: string): string {
const key = icon.replace(/\uFE0E|\uFE0F/g, '').replace(/[\u{1F3FB}-\u{1F3FF}]/gu, '');
return PICTOS[key] ?? 'ka';
return PICTOS[key] ?? 'circle-help';
}
const LEADING_EMOJI = /^(?<emoji>\p{Extended_Pictographic}\uFE0F?[\u{1F3FB}-\u{1F3FF}]?)\s*/u;
/**
* Sépare un emoji en tête d'une chaîne de contenu (tags hero, etc.) :
* l'emoji devient un picto du sprite, le texte reste intact.
* l'emoji devient un nom d'icône Lucide, le texte reste intact.
*/
export function splitLeadingEmoji(raw: string): { icon: string | null; text: string } {
const match = raw.match(LEADING_EMOJI);
+3 -2
View File
@@ -1,6 +1,7 @@
<script lang="ts">
import { page } from '$app/state';
import { resolve } from '$app/paths';
import Icon from '$lib/components/icons/Icon.svelte';
const status = $derived(page.status);
const is404 = $derived(status === 404);
@@ -12,7 +13,7 @@
</svelte:head>
<section class="error-page container">
<svg class="icon error-icon" aria-hidden="true"><use href="/icons.svg#ka" /></svg>
<Icon name="circle-x" class="icon error-icon" size={96} />
<h1>{status}</h1>
{#if is404}
<p class="ka" lang="gcf">« Paj la rivé périyòd… »</p>
@@ -33,7 +34,7 @@
padding: var(--space-5) var(--space-4);
}
.error-icon {
:global(.error-icon) {
width: 6rem;
height: 6rem;
color: var(--or-oki);
+5 -8
View File
@@ -1,5 +1,6 @@
<script lang="ts">
// {@html} sur contenu first-party (JSON i18n du dépôt), aucune donnée utilisateur.
import Icon from '$lib/components/icons/Icon.svelte';
import Seo from '$lib/components/Seo.svelte';
import donations from '$lib/data/donations.json';
import { getBundle } from '$lib/i18n';
@@ -41,7 +42,7 @@
<div class="donation-panels">
<div class="support-panel support-panel--primary">
<h2>
<svg class="icon" aria-hidden="true"><use href="/icons.svg#lakanmou" /></svg>
<Icon name="heart" class="icon" />
{t.support.one_time_title}
</h2>
@@ -130,9 +131,7 @@
rel="external noopener noreferrer"
class="alt-donation-card alt-donation-card--liberapay"
>
<svg class="icon alt-donation-icon" aria-hidden="true"
><use href="/icons.svg#jaden" /></svg
>
<Icon name="sprout" class="icon alt-donation-icon" />
<h3>{t.support.liberapay_title}</h3>
<p>{t.support.liberapay_text}</p>
</a>
@@ -143,9 +142,7 @@
rel="external noopener noreferrer"
class="alt-donation-card alt-donation-card--kofi"
>
<svg class="icon alt-donation-icon" aria-hidden="true"
><use href="/icons.svg#lakanmou" /></svg
>
<Icon name="coffee" class="icon alt-donation-icon" />
<h3>{t.support.kofi_title}</h3>
<p>{t.support.kofi_text}</p>
</a>
@@ -394,7 +391,7 @@
--card-accent: var(--or-oki);
}
.alt-donation-icon {
:global(.alt-donation-icon) {
width: 2rem;
height: 2rem;
color: var(--card-accent, var(--or-oki));
+5 -8
View File
@@ -1,5 +1,6 @@
<script lang="ts">
// {@html} sur contenu first-party (JSON i18n du dépôt), aucune donnée utilisateur.
import Icon from '$lib/components/icons/Icon.svelte';
import Seo from '$lib/components/Seo.svelte';
import donations from '$lib/data/donations.json';
import { getBundle } from '$lib/i18n';
@@ -41,7 +42,7 @@
<div class="donation-panels">
<div class="support-panel support-panel--primary">
<h2>
<svg class="icon" aria-hidden="true"><use href="/icons.svg#lakanmou" /></svg>
<Icon name="heart" class="icon" />
{t.support.one_time_title}
</h2>
@@ -130,9 +131,7 @@
rel="external noopener noreferrer"
class="alt-donation-card alt-donation-card--liberapay"
>
<svg class="icon alt-donation-icon" aria-hidden="true"
><use href="/icons.svg#jaden" /></svg
>
<Icon name="sprout" class="icon alt-donation-icon" />
<h3>{t.support.liberapay_title}</h3>
<p>{t.support.liberapay_text}</p>
</a>
@@ -143,9 +142,7 @@
rel="external noopener noreferrer"
class="alt-donation-card alt-donation-card--kofi"
>
<svg class="icon alt-donation-icon" aria-hidden="true"
><use href="/icons.svg#lakanmou" /></svg
>
<Icon name="coffee" class="icon alt-donation-icon" />
<h3>{t.support.kofi_title}</h3>
<p>{t.support.kofi_text}</p>
</a>
@@ -394,7 +391,7 @@
--card-accent: var(--or-oki);
}
.alt-donation-icon {
:global(.alt-donation-icon) {
width: 2rem;
height: 2rem;
color: var(--card-accent, var(--or-oki));
+3 -2
View File
@@ -1,5 +1,6 @@
<script lang="ts">
import { asset } from '$app/paths';
import Icon from '$lib/components/icons/Icon.svelte';
import ResponsiveImage from '$lib/components/ResponsiveImage.svelte';
import Seo from '$lib/components/Seo.svelte';
import KineticText from '$lib/components/motion/KineticText.svelte';
@@ -23,7 +24,7 @@
/>
<section class="press-hero">
<svg class="icon hero-icon" aria-hidden="true"><use href="/icons.svg#lambi" /></svg>
<Icon name="newspaper" class="icon hero-icon" />
<h1>{t.press.title} <span class="accent">{t.press.title_accent}</span></h1>
<p class="press-lede">{t.press.lede}</p>
</section>
@@ -93,7 +94,7 @@
border-bottom: 1px solid var(--line);
}
.hero-icon {
:global(.hero-icon) {
width: 2.5rem;
height: 2.5rem;
margin: 0 auto var(--space-2);
+3 -2
View File
@@ -1,5 +1,6 @@
<script lang="ts">
import { resolve } from '$app/paths';
import Icon from '$lib/components/icons/Icon.svelte';
</script>
<svelte:head>
@@ -8,7 +9,7 @@
</svelte:head>
<section class="offline-page container">
<svg class="icon offline-icon" aria-hidden="true"><use href="/icons.svg#lanme" /></svg>
<Icon name="wifi-off" class="icon offline-icon" size={96} />
<h1>Hors ligne</h1>
<p class="ka" lang="gcf">« Konèksyon an koupé. »</p>
<p class="fr">
@@ -29,7 +30,7 @@
padding: var(--space-5) var(--space-4);
}
.offline-icon {
:global(.offline-icon) {
width: 6rem;
height: 6rem;
color: var(--or-oki);
+3 -2
View File
@@ -1,5 +1,6 @@
<script lang="ts">
import { asset } from '$app/paths';
import Icon from '$lib/components/icons/Icon.svelte';
import ResponsiveImage from '$lib/components/ResponsiveImage.svelte';
import Seo from '$lib/components/Seo.svelte';
import KineticText from '$lib/components/motion/KineticText.svelte';
@@ -23,7 +24,7 @@
/>
<section class="press-hero">
<svg class="icon hero-icon" aria-hidden="true"><use href="/icons.svg#lambi" /></svg>
<Icon name="newspaper" class="icon hero-icon" />
<h1>{t.press.title} <span class="accent">{t.press.title_accent}</span></h1>
<p class="press-lede">{t.press.lede}</p>
</section>
@@ -93,7 +94,7 @@
border-bottom: 1px solid var(--line);
}
.hero-icon {
:global(.hero-icon) {
width: 2.5rem;
height: 2.5rem;
margin: 0 auto var(--space-2);
-70
View File
@@ -1,70 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg">
<!-- Set iconographique OKI — charte §4 : viewBox 24×24, stroke 2 px, angles nets, currentColor -->
<symbol id="ka" viewBox="0 0 24 24">
<!-- tambour ka : collerette hexagonale, fût conique, sangles en zigzag -->
<path d="M4 7 L20 7 L22 9 L20 11 L4 11 L2 9 Z" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="square" stroke-linejoin="miter"/>
<path d="M4 11 L7 21 L17 21 L20 11" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="square" stroke-linejoin="miter"/>
<path d="M8 11 L10.5 16 L9 21 M16 11 L13.5 16 L15 21" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="square" stroke-linejoin="miter"/>
</symbol>
<symbol id="lambi" viewBox="0 0 24 24">
<!-- conque lambi : dome en spirale, lèvre angulaire -->
<path d="M4 14 C4 8 9 4 14 4 C18 4 21 7 21 11 L17 14 L20 18 L13 20 C8 21 4 18 4 14 Z" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="square" stroke-linejoin="miter"/>
<path d="M11 14 C11 12.5 13.5 12.5 13.5 14 C13.5 16 9.5 16 9.5 13 C9.5 9.5 14 8.5 16 10.5" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="square" stroke-linejoin="miter"/>
</symbol>
<symbol id="zetwal" viewBox="0 0 24 24">
<!-- étoile 4 branches -->
<path d="M12 3 L14.5 9.5 L21 12 L14.5 14.5 L12 21 L9.5 14.5 L3 12 L9.5 9.5 Z" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="square" stroke-linejoin="miter"/>
</symbol>
<symbol id="mawon" viewBox="0 0 24 24">
<!-- brisure de chaîne : deux demi-maillons octogonaux, connexion rompue -->
<path d="M9 7 L5 7 L3 9 L3 15 L5 17 L9 17" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="square" stroke-linejoin="miter"/>
<path d="M15 7 L19 7 L21 9 L21 15 L19 17 L15 17" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="square" stroke-linejoin="miter"/>
<path d="M12 9.5 L12 11 M12 13 L12 14.5" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="square" stroke-linejoin="miter"/>
</symbol>
<symbol id="lakanmou" viewBox="0 0 24 24">
<!-- flamme : contour angulaire à base courbe, languette interne -->
<path d="M12 3 L15 8 L18 12 C19 15 18 18 15.5 20 L12 21 L8.5 20 C6 18 5 15 6 12 L9 8 Z" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="square" stroke-linejoin="miter"/>
<path d="M12 12 L14 14.5 C14.3 16.5 13 18 12 18 C11 18 9.7 16.5 10 14.5 Z" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="square" stroke-linejoin="miter"/>
</symbol>
<symbol id="jaden" viewBox="0 0 24 24">
<!-- pousse : tige et deux feuilles angulaires en cerf-volant -->
<path d="M12 21 L12 10" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="square" stroke-linejoin="miter"/>
<path d="M12 13 L3 5 L6 12 L10 16 Z" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="square" stroke-linejoin="miter"/>
<path d="M12 13 L21 5 L18 12 L14 16 Z" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="square" stroke-linejoin="miter"/>
</symbol>
<symbol id="kannen" viewBox="0 0 24 24">
<!-- canne à sucre : tige segmentée, trois lames au sommet -->
<path d="M10 21 L10 6 L14 6 L14 21 Z" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="square" stroke-linejoin="miter"/>
<path d="M10 17 L14 17 M10 13 L14 13 M10 9 L14 9" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="square" stroke-linejoin="miter"/>
<path d="M10 6 L5 3 M14 6 L19 3 M12 6 L12 2" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="square" stroke-linejoin="miter"/>
</symbol>
<symbol id="lanme" viewBox="0 0 24 24">
<!-- vague angulaire : trois lignes brisées superposées -->
<path d="M2 8 L7 4 L12 8 L17 4 L22 8" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="square" stroke-linejoin="miter"/>
<path d="M2 14 L7 10 L12 14 L17 10 L22 14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="square" stroke-linejoin="miter"/>
<path d="M2 20 L7 16 L12 20 L17 16 L22 20" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="square" stroke-linejoin="miter"/>
</symbol>
<symbol id="glo" viewBox="0 0 24 24">
<!-- poing levé géométrique : bloc poing + avant-bras, doigts segmentés, pouce -->
<path d="M8 20 L8 15 L6 15 L6 6 L8 4 L18 4 L18 15 L16 15 L16 20" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="square" stroke-linejoin="miter"/>
<path d="M6 9 L18 9" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="square" stroke-linejoin="miter"/>
<path d="M9 4 L9 9 M12 4 L12 9 M15 4 L15 9 M6 12 L10 12" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="square" stroke-linejoin="miter"/>
</symbol>
<symbol id="kle" viewBox="0 0 24 24">
<!-- cadenas ouvert : corps rectangulaire, anse angulaire levée -->
<path d="M5 11 L19 11 L19 21 L5 21 Z" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="square" stroke-linejoin="miter"/>
<path d="M8 11 L8 6 L10 4 L14 4 L16 6 L16 8" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="square" stroke-linejoin="miter"/>
<path d="M12 14.5 L12 17.5" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="square" stroke-linejoin="miter"/>
</symbol>
<symbol id="pawol" viewBox="0 0 24 24">
<!-- bulle de parole angulaire : rectangle à queue, deux lignes de texte -->
<path d="M3 4 L21 4 L21 15 L13 15 L8 20 L8 15 L3 15 Z" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="square" stroke-linejoin="miter"/>
<path d="M7 8 L17 8 M7 11.5 L13 11.5" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="square" stroke-linejoin="miter"/>
</symbol>
<symbol id="mizik-note" viewBox="0 0 24 24">
<!-- double croche : deux tiges reliées par un croc, têtes en losange -->
<path d="M9 6 L9 19 M19 4 L19 17 M9 6 L19 4" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="square" stroke-linejoin="miter"/>
<path d="M9 16.5 L11.5 19 L9 21.5 L6.5 19 Z" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="square" stroke-linejoin="miter"/>
<path d="M19 14.5 L21.5 17 L19 19.5 L16.5 17 Z" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="square" stroke-linejoin="miter"/>
</symbol>
</svg>

Before

Width:  |  Height:  |  Size: 6.2 KiB