P1 fondation : tokens layerés, reset, thèmes (base/renovation/aep/tmip), 9 primitives Astro, pont Tailwind 4, démo kitchen sink

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-19 18:31:52 +02:00
commit 795ca7ed4e
28 changed files with 8043 additions and 0 deletions

316
src/demo/KitchenSink.astro Normal file
View File

@@ -0,0 +1,316 @@
---
/**
* KitchenSink — page démo partagée par /demo, /demo/renovation, /demo/aep.
* Rend toutes les primitives + les tokens, en clair et sombre (toggle).
* Chaque page ne diffère que par le theme/*.css qu'elle importe.
*/
import BaseLayout from "../../components/BaseLayout.astro";
import Nav from "../../components/Nav.astro";
import Footer from "../../components/Footer.astro";
import Button from "../../components/Button.astro";
import Card from "../../components/Card.astro";
import Prose from "../../components/Prose.astro";
import Section from "../../components/Section.astro";
import Container from "../../components/Container.astro";
import Reveal from "../../components/Reveal.astro";
interface Props {
themeName: string;
}
const { themeName } = Astro.props;
const navLinks = [
{ href: "/demo", label: "Neutre" },
{ href: "/demo/renovation", label: "Renovation" },
{ href: "/demo/aep", label: "AEP" },
];
const colorRoles = [
"bg", "bg-alt", "surface", "surface-2",
"text", "text-muted", "text-subtle",
"border", "border-strong",
"primary", "primary-hover", "on-primary",
"accent", "on-accent", "link", "link-hover",
"focus-ring", "success", "warning", "danger",
];
const typeScale = ["xs", "sm", "base", "lg", "xl", "2xl", "3xl", "4xl"];
---
<BaseLayout
title={`Démo — thème ${themeName} — @transformer/ui`}
description="Kitchen sink du design system trans-former.fr : tokens, thèmes, primitives."
>
<Nav slot="header" links={navLinks}>
<a slot="brand" href="/demo">@transformer/ui</a>
<Fragment slot="actions">
<button class="ks-theme-btn" type="button" onclick="tfSetTheme('light')">Clair</button>
<button class="ks-theme-btn" type="button" onclick="tfSetTheme('dark')">Sombre</button>
<button class="ks-theme-btn" type="button" onclick="tfSetTheme('auto')">Auto</button>
</Fragment>
</Nav>
<Section>
<Container>
<p class="ks-kicker">Thème actif : {themeName}</p>
<h1 class="ks-h1">Le design system de la constellation trans-former.fr</h1>
<p class="ks-lead">
Tokens, thèmes et primitives partagés. Changer de thème = changer un seul
import CSS. Cette page rend tout le système d'un coup d'œil.
</p>
<div class="ks-row">
<Button href="#boutons">Voir les boutons</Button>
<Button variant="secondary" href="#prose">Voir la prose</Button>
</div>
</Container>
</Section>
<Section alt id="couleurs">
<Container>
<h2 class="ks-h2">Couleurs — rôles</h2>
<div class="ks-swatches">
{
colorRoles.map((role) => (
<div class="ks-swatch">
<span class="ks-swatch__chip" style={`background: var(--${role})`} />
<code>--{role}</code>
</div>
))
}
</div>
</Container>
</Section>
<Section id="typo">
<Container>
<h2 class="ks-h2">Typographie — échelle fluide</h2>
<div class="ks-type">
{
typeScale.map((s) => (
<p style={`font-size: var(--fs-${s})`}>
<code>--fs-{s}</code> — Transformer l'habitat, pas le remplacer.
</p>
))
}
</div>
</Container>
</Section>
<Section alt id="boutons">
<Container>
<h2 class="ks-h2">Boutons — variantes × tailles × états</h2>
<div class="ks-row">
<Button>Primary</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="link">Link</Button>
</div>
<div class="ks-row">
<Button size="sm">Small</Button>
<Button size="md">Medium</Button>
<Button size="lg">Large</Button>
</div>
<div class="ks-row">
<Button disabled>Désactivé</Button>
<Button variant="secondary" disabled>Désactivé</Button>
<Button href="#boutons" variant="secondary">Lien-bouton</Button>
<Button href="#boutons" disabled>Lien désactivé</Button>
</div>
<p class="ks-note">
Focus visible : naviguer au clavier (Tab) pour voir l'anneau
<code>--focus-ring</code>. Cibles tactiles ≥ 44px.
</p>
</Container>
</Section>
<Section id="cards">
<Container>
<h2 class="ks-h2">Cards</h2>
<div class="ks-grid">
<Card href="#cards">
<svg slot="media" viewBox="0 0 320 180" role="img" aria-label="Visuel de démonstration">
<rect width="320" height="180" fill="var(--surface-2)"></rect>
<circle cx="160" cy="90" r="48" fill="var(--primary)"></circle>
</svg>
<h3>Carte cliquable</h3>
<p>Toute la surface est le lien. Hover : élévation légère, pas de border accent.</p>
</Card>
<Card>
<h3>Carte statique</h3>
<p>Surface, bordure fine, rayon large. Le contenu vit dans le slot par défaut.</p>
<div><Button variant="link" href="#cards">Action locale</Button></div>
</Card>
<Card>
<h3>États système</h3>
<p>
<span class="ks-dot" style="background: var(--success)"></span> succès ·
<span class="ks-dot" style="background: var(--warning)"></span> avertissement ·
<span class="ks-dot" style="background: var(--danger)"></span> erreur
</p>
</Card>
</div>
</Container>
</Section>
<Section alt id="prose">
<Container>
<h2 class="ks-h2">Prose — contenu long</h2>
<Prose>
<h3>Rénover plutôt que construire</h3>
<p>
Le bâti existant est un gisement. Une rénovation performante mobilise
<a href="#prose">l'isolation</a>, la ventilation et le pilotage des
apports — dans cet ordre.
</p>
<ul>
<li>Isolation des parois opaques</li>
<li>Menuiseries et étanchéité à l'air</li>
<li>Ventilation double flux si pertinent</li>
</ul>
<blockquote>
La maison la plus écologique est celle qui existe déjà.
<cite>Adage de la rénovation</cite>
</blockquote>
<p>
Un extrait de code s'écrit <code>var(--primary)</code> en ligne, ou en bloc :
</p>
<pre><code>import '@transformer/ui/tokens.css';
import '@transformer/ui/theme/renovation.css';</code></pre>
<table>
<thead>
<tr><th>Poste</th><th>Gain</th></tr>
</thead>
<tbody>
<tr><td>Isolation toiture</td><td>2530 %</td></tr>
<tr><td>Menuiseries</td><td>1015 %</td></tr>
</tbody>
</table>
</Prose>
</Container>
</Section>
<Section id="reveal">
<Container>
<h2 class="ks-h2">Reveal — apparition au scroll</h2>
<p class="ks-note">
Fade + translate 12px, désactivé sous <code>prefers-reduced-motion</code>.
Sans JS, rien n'est masqué.
</p>
<div class="ks-grid">
<Reveal><Card><h3>Bloc 1</h3><p>Apparaît en entrant dans le viewport.</p></Card></Reveal>
<Reveal delay={80}><Card><h3>Bloc 2</h3><p>Décalé de 80 ms.</p></Card></Reveal>
<Reveal delay={160}><Card><h3>Bloc 3</h3><p>Décalé de 160 ms.</p></Card></Reveal>
</div>
</Container>
</Section>
<Footer slot="footer">
<div>
<strong>@transformer/ui</strong>
<p>Design system de la constellation trans-former.fr.</p>
</div>
<Fragment slot="legal">v0.1.0 — démo kitchen sink. Testée à 360 / 768 / 1280.</Fragment>
</Footer>
</BaseLayout>
<style>
.ks-kicker {
color: var(--text-subtle);
font-size: var(--fs-sm);
text-transform: uppercase;
letter-spacing: 0.08em;
}
.ks-h1 {
font-size: var(--fs-4xl);
margin-block: var(--space-sm) var(--space-md);
max-width: 22ch;
}
.ks-lead {
font-size: var(--fs-lg);
color: var(--text-muted);
max-width: 55ch;
margin-block-end: var(--space-lg);
}
.ks-h2 {
font-size: var(--fs-2xl);
margin-block-end: var(--space-lg);
}
.ks-row {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--space-sm);
margin-block-end: var(--space-md);
}
.ks-note {
color: var(--text-subtle);
font-size: var(--fs-sm);
margin-block-end: var(--space-md);
}
.ks-swatches {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(9.5rem, 1fr));
gap: var(--space-sm);
}
.ks-swatch {
display: flex;
align-items: center;
gap: var(--space-xs);
font-size: var(--fs-xs);
}
.ks-swatch__chip {
inline-size: 2rem;
block-size: 2rem;
flex-shrink: 0;
border-radius: var(--radius-sm);
border: 1px solid var(--border-strong);
}
.ks-type {
display: flex;
flex-direction: column;
gap: var(--space-sm);
}
.ks-grid {
display: grid;
grid-template-columns: 1fr;
gap: var(--space-lg);
}
@media (min-width: 48rem) {
.ks-grid {
grid-template-columns: repeat(3, 1fr);
}
}
.ks-dot {
display: inline-block;
inline-size: 0.75rem;
block-size: 0.75rem;
border-radius: var(--radius-full);
}
.ks-theme-btn {
min-height: 2.75rem;
padding-inline: var(--space-sm);
background: none;
border: 1px solid var(--border);
border-radius: var(--radius-md);
font-size: var(--fs-sm);
cursor: pointer;
}
.ks-theme-btn:hover {
background: var(--surface-2);
}
</style>

6
src/pages/demo.astro Normal file
View File

@@ -0,0 +1,6 @@
---
// Démo — thème NEUTRE : aucun theme/*.css importé, tokens.css seul.
import KitchenSink from "../demo/KitchenSink.astro";
---
<KitchenSink themeName="neutre (tokens seuls)" />

7
src/pages/demo/aep.astro Normal file
View File

@@ -0,0 +1,7 @@
---
// Démo — thème AEP (sombre par défaut, accent rouge).
import KitchenSink from "../../demo/KitchenSink.astro";
import "../../../theme/aep.css";
---
<KitchenSink themeName="AEP (sombre par défaut)" />

View File

@@ -0,0 +1,9 @@
---
// Démo — thème RENOVATION. Un seul import CSS change tout le look.
// tokens.css est layeré (@layer tf-tokens) : le thème gagne toujours,
// quel que soit l'ordre de bundling.
import KitchenSink from "../../demo/KitchenSink.astro";
import "../../../theme/renovation.css";
---
<KitchenSink themeName="renovation (Brunswick green)" />