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:
316
src/demo/KitchenSink.astro
Normal file
316
src/demo/KitchenSink.astro
Normal 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>25–30 %</td></tr>
|
||||
<tr><td>Menuiseries</td><td>10–15 %</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
6
src/pages/demo.astro
Normal 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
7
src/pages/demo/aep.astro
Normal 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)" />
|
||||
9
src/pages/demo/renovation.astro
Normal file
9
src/pages/demo/renovation.astro
Normal 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)" />
|
||||
Reference in New Issue
Block a user