card-01-ghost-icon
card-07-transactions
Carte transaction — identité + ligne de valeur
Poser un intitulé de flux (badge + titre + acteurs) en haut d'une carte blanche et sa ligne de valeur unique sur aplat doux collée en bas, sans jamais faire de la carte un tableau.
cardslideweb748×208px8 benchmarks
Le fragment RÉEL, dans son propre document, sur le sol de sa charte — pas une image. Ce que vous voyez est exactement ce que vous collerez.
Employer quand
Bloc « dernière opération » ou « flux en cours » d'un dashboard : une identité, un groupe d'acteurs, une seule paire chiffrée. La pile d'avatars qui se recouvre signale un échange entre plusieurs parties.
Éviter quand
Il y a plus d'une ligne de valeur à montrer : au-delà d'une, ce n'est plus cette carte mais une LISTE, qui demande un séparateur et un rythme propres. Et sans acteurs à représenter, la pile d'avatars devient un ornement vide.
Notes
Le margin-top:auto de la ligne de valeur est ce qui la scelle au bas de la carte quelle que soit la hauteur de l'en-tête : un benchmark vérifie que son bas touche bien la marge basse. Le recouvrement des avatars (marge négative) est mesuré, pas relu à l'œil — c'est lui qui distingue un GROUPE d'une simple file. Les avatars sont des dégradés de tokens (menthe / lilas) à la place des photos de la source : un pattern doit rester rejouable sur n'importe quelle charte, une photo en dur l'en empêcherait.
Mots-clés
Benchmarks — la géométrie, en assertions vérifiables
Rejouables par node bin/check.mjs card-07-transactions : le pattern se prouve, il ne se croit pas.
| assertion | mesure | attendu |
|---|---|---|
| marges intérieures ≈ 4,9 % de la largeur | num('.vl-txn','paddingLeft') / W | 0.049 ± 0.02 |
| badge carré (largeur ≈ hauteur) | Math.abs(box('.vl-txn__badge').w - box('.vl-txn__badge').h) | ≤ 1 |
| les avatars se RECOUVREENT (le 2e commence avant la fin du 1er) | box('.vl-txn__av--2').left - box('.vl-txn__av--1').right | ≤ -2 |
| ligne de valeur collée en bas (son bas touche la marge basse, ± 3 px) | Math.abs((H - num('.vl-txn','paddingBottom')) - box('.vl-txn__row').bottom) | ≤ 3 |
| le libellé de paire occupe la largeur restante (flex:1 → > 55 % de la carte) | box('.vl-txn__pair').w / W | ≥ 0.55 |
| contraste du titre ≥ 7 (il nomme le flux) | contrast('.vl-txn__title') | ≥ 7 |
| contraste de la valeur sur l'aplat doux ≥ 4,5 (petit corps, seuil plein) | contrast('.vl-txn__pair') | ≥ 4.5 |
| aucun débordement du contenu hors de la carte | overflow('.vl-txn') | ≤ 0 |
Le code
patterns/card-07-transactions.html
Télécharger<!-- card-07-transactions — fragment autonome. Couleurs via --vl-* uniquement, aucune valeur en dur. -->
<div class="vl-txn">
<div class="vl-txn__head">
<div class="vl-txn__id">
<span class="vl-txn__badge">
<svg viewBox="0 0 24 24" fill="none" stroke="var(--vl-ink-invert)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 8h13l-3-3M20 16H7l3 3"/></svg>
</span>
<div>
<h2 class="vl-txn__title">Recent Transactions</h2>
<p class="vl-txn__sub">Sell currency</p>
</div>
</div>
<div class="vl-txn__avatars">
<span class="vl-txn__av vl-txn__av--1"></span>
<span class="vl-txn__av vl-txn__av--2"></span>
<span class="vl-txn__menu">···</span>
</div>
</div>
<div class="vl-txn__row">
<span class="vl-txn__coin">
<svg viewBox="0 0 24 24" fill="none" stroke="var(--vl-ink-invert)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M9 8h5a2.5 2.5 0 0 1 0 5H9zM9 13h6a2.5 2.5 0 0 1 0 5H9zM10 6v12"/></svg>
</span>
<span class="vl-txn__pair">12,53 ETH/I BTC</span>
<span class="vl-txn__dots">⋮</span>
</div>
</div>
<style>
/* Carte de transaction : en-tête (badge + identité + pile d'avatars) en haut, UNE ligne de
valeur sur aplat doux collée en bas par margin-top:auto. La pile d'avatars se recouvre en
marge négative — c'est ce chevauchement qui la lit comme un groupe et non comme une file. */
.vl-txn {
width: 748px; height: 208px;
background: var(--vl-surface-light); color: var(--vl-ink);
border-radius: var(--vl-radius-card); padding: 26px;
display: flex; flex-direction: column;
font-family: Inter, -apple-system, "Helvetica Neue", Arial, sans-serif;
}
.vl-txn__head { display: flex; justify-content: space-between; align-items: flex-start; }
.vl-txn__id { display: flex; gap: 14px; align-items: center; }
.vl-txn__badge {
width: 42px; height: 42px; border-radius: 13px; background: var(--vl-surface-dark);
display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto;
}
.vl-txn__badge svg { width: 20px; height: 20px; }
.vl-txn__title { margin: 0; font-size: 18px; font-weight: 600; letter-spacing: -0.01em; }
.vl-txn__sub { margin: 2px 0 0; font-size: 11px; font-weight: 500; color: var(--vl-ink-muted); }
.vl-txn__avatars { display: flex; align-items: center; }
.vl-txn__av { width: 38px; height: 38px; border-radius: 50%; border: 2px solid var(--vl-surface-light); margin-left: -10px; }
.vl-txn__av:first-child { margin-left: 0; }
.vl-txn__av--1 { background: linear-gradient(135deg, var(--vl-mint), var(--vl-mint-deep)); }
.vl-txn__av--2 { background: linear-gradient(135deg, var(--vl-lilac), var(--vl-lilac-deep)); }
.vl-txn__menu {
width: 38px; height: 38px; border-radius: 50%; background: var(--vl-lilac); color: var(--vl-surface-dark);
margin-left: -10px; display: inline-flex; align-items: center; justify-content: center; font-weight: 700; letter-spacing: 1px;
}
.vl-txn__row {
margin-top: auto; display: flex; align-items: center; gap: 14px;
background: var(--vl-surface-soft); border-radius: var(--vl-radius-sub); padding: 16px 20px;
}
.vl-txn__coin {
width: 34px; height: 34px; border-radius: 50%; background: var(--vl-surface-dark);
display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto;
}
.vl-txn__coin svg { width: 16px; height: 16px; }
.vl-txn__pair { flex: 1; font-size: 15px; font-weight: 600; }
.vl-txn__dots { font-weight: 700; color: var(--vl-ink-muted); letter-spacing: 1px; }
</style>
systems/ref-11-finance-dashboard-mint.json
Télécharger:root {
--vl-bg: #E6EAE4;
--vl-board: #E6EAE4;
--vl-surface-light: #FFFFFF;
--vl-surface-soft: #F1F2EF;
--vl-surface-dark: #141414;
--vl-mint: #B4E3A0;
--vl-mint-deep: #8FCE72;
--vl-lilac: #B6ABE6;
--vl-lilac-deep: #9A8ADE;
--vl-ink: #181A17;
--vl-ink-muted: #7C817A;
--vl-ink-on-mint: #3D5A30;
--vl-ink-on-lilac: #3E3270;
--vl-ink-invert: #FFFFFF;
--vl-ink-invert-muted: #9CA09A;
--vl-hairline: #E3E5E1;
--vl-hairline-invert: #333333;
--vl-radius-card: 26px;
--vl-radius-sub: 20px;
--vl-radius-chip: 14px;
--vl-gap: 20px;
}
les métadonnées — patterns/card-07-transactions.json (télécharger)
{
"name": "Carte transaction — identité + ligne de valeur",
"family": "card",
"ref": "ref-11-finance-dashboard-mint",
"intent": "Poser un intitulé de flux (badge + titre + acteurs) en haut d'une carte blanche et sa ligne de valeur unique sur aplat doux collée en bas, sans jamais faire de la carte un tableau.",
"when_to_use": "Bloc « dernière opération » ou « flux en cours » d'un dashboard : une identité, un groupe d'acteurs, une seule paire chiffrée. La pile d'avatars qui se recouvre signale un échange entre plusieurs parties.",
"avoid_when": "Il y a plus d'une ligne de valeur à montrer : au-delà d'une, ce n'est plus cette carte mais une LISTE, qui demande un séparateur et un rythme propres. Et sans acteurs à représenter, la pile d'avatars devient un ornement vide.",
"tags": [
"carte",
"transaction",
"avatars",
"pile",
"flux",
"dashboard",
"blanc",
"ligne-valeur",
"crypto"
],
"vars": [
{
"name": "--vl-surface-soft",
"role": "aplat doux de la ligne de valeur",
"default": "#F1F2EF"
},
{
"name": "--vl-surface-dark",
"role": "fond du badge et de la pastille de devise",
"default": "#141414"
},
{
"name": "--vl-lilac",
"role": "pastille de menu (fin de la pile d'avatars)",
"default": "#B6ABE6"
},
{
"name": "--vl-radius-card",
"role": "rayon de la carte",
"default": "26px"
}
],
"slots": [
"badge",
"title",
"avatars",
"value-row"
],
"geometry": {
"root": ".vl-txn",
"frame": [
748,
208
],
"ratios": {
"pad_over_width": 0.049,
"badge_over_width": 0.08
},
"type_px": {
"title": 18,
"pair": 15,
"sub": 11
},
"pad_ratio": {
"top": 0.125,
"x": 0.049,
"bottom": 0.125
}
},
"benchmarks": [
{
"name": "marges intérieures ≈ 4,9 % de la largeur",
"measure": "num('.vl-txn','paddingLeft') / W",
"expect": 0.049,
"tol": 0.02
},
{
"name": "badge carré (largeur ≈ hauteur)",
"measure": "Math.abs(box('.vl-txn__badge').w - box('.vl-txn__badge').h)",
"max": 1
},
{
"name": "les avatars se RECOUVREENT (le 2e commence avant la fin du 1er)",
"measure": "box('.vl-txn__av--2').left - box('.vl-txn__av--1').right",
"max": -2
},
{
"name": "ligne de valeur collée en bas (son bas touche la marge basse, ± 3 px)",
"measure": "Math.abs((H - num('.vl-txn','paddingBottom')) - box('.vl-txn__row').bottom)",
"max": 3
},
{
"name": "le libellé de paire occupe la largeur restante (flex:1 → > 55 % de la carte)",
"measure": "box('.vl-txn__pair').w / W",
"min": 0.55
},
{
"name": "contraste du titre ≥ 7 (il nomme le flux)",
"measure": "contrast('.vl-txn__title')",
"min": 7
},
{
"name": "contraste de la valeur sur l'aplat doux ≥ 4,5 (petit corps, seuil plein)",
"measure": "contrast('.vl-txn__pair')",
"min": 4.5
},
{
"name": "aucun débordement du contenu hors de la carte",
"measure": "overflow('.vl-txn')",
"max": 0
}
],
"notes": "Le margin-top:auto de la ligne de valeur est ce qui la scelle au bas de la carte quelle que soit la hauteur de l'en-tête : un benchmark vérifie que son bas touche bien la marge basse. Le recouvrement des avatars (marge négative) est mesuré, pas relu à l'œil — c'est lui qui distingue un GROUPE d'une simple file. Les avatars sont des dégradés de tokens (menthe / lilas) à la place des photos de la source : un pattern doit rester rejouable sur n'importe quelle charte, une photo en dur l'en empêcherait.",
"id": "card-07-transactions"
}
À côté
card-02-notched-brief
Carte chanfreinée de second rang
card-03-stat-accent
Vignette statistique sur accent
card-04-stat-barchart
Carte statistique à barres empilées
card-05-balance-gauge
Carte solde à jauge compteur
card-06-forecast-timeline