Collabz Design System · Nocturne Éditorial · Spec v1.0

Un seul langage,
onze tokens qui portent tout.

Mise à niveau complète de v0.8.0 → v1.0 dans le schéma exact du codebase actuel. Mêmes clés, mêmes noms de composants, mêmes props — valeurs visuelles remplacées. Tu peux swapper tokens.ts et design/*.tsx sans toucher aux imports.

Deux décisions avant les mockups.

Les blocs 1–4 qui suivent sont cohérents seulement si ces deux réglages sont pris. Je donne ma reco mais j'attends ton feu vert pour figer.

Q1 — Où met-on Fraunces italic ?

Spécimen 390×844 · droit vs italic · même copy

display · 56
Autour de toi.
Autour de toi.
h1 · 36
Soirée de lancement
Soirée de lancement
h2 · 30
Tes mémoires
Tes mémoires
h3 · 24
Qui vient samedi ?
Qui vient samedi ?
body · 16
Loft moderne à Paris 11, ambiance chaleureuse pour créateurs.
Loft moderne à Paris 11, ambiance chaleureuse pour créateurs.
Ma reco — italic réservé au display uniquement, plus une syllabe optionnelle en italic dans h1 pour l'accentuation (ex. Autour de toi.). h2/h3 restent droits. Body reste Inter — Fraunces italic en body fatigue et casse le rythme de scan. Ça garde la signature, ça garde la lisibilité.

Q2 — Accent cuivre unique vs. teinte dominante extraite

Option B · le système discipline, le contenu colore

Plan A · système pur

Cuivre partout, zéro extraction

Primary, focused border, selected chip, loading, link — tout est #E8764A. Simple, prévisible, cohérent écran à écran. Risque : monotonie sur 50+ écrans.

PARIS · IL Y A 3H
Projection néons & studio.
Plan B · recommandé

Cuivre système, teinte contenu

Le cuivre reste la couleur d'affordance (bouton primary, focused, selected, link). Sur les photos plein-écran uniquement, un dominantColor extrait teinte le gradient d'overlay bottom à ~15% d'opacité. Le système reste discipliné, l'énergie vient du créateur.

PARIS · IL Y A 3H
Projection néons & studio.
DOMINANT · WARM SIENNA
Ma reco — on prend Plan B, sous trois gardes-fous : (1) extraction seulement sur Post + Memory + Moment + Event hero — jamais sur les surfaces chrome (tab bar, cards feed list). (2) Intensité capée à 0.15 sur le gradient bottom, zéro influence sur le texte ou les boutons. (3) Le focused border d'inputs reste toujours cuivre — l'affordance ne bouge jamais.

Le reste du document suppose Q1=display-only et Q2=plan-B. Si tu veux changer, un seul token à bouger (typography.display.fontStyle) et un seul nouveau token à retirer (gradients.dominantOverlay).

Bloc 1 — Tokens v1.0

Pour chaque clé existante : ancienne valeur, nouvelle valeur Nocturne, usage. Les clés marquées NEW sont les seuls ajouts.

colors.light · ColorPalette

Tokenv0.8.0v1.0 NocturneUsage
background#f8f9fa#f7f4edPapier éditorial, plus chaud et moins stérile que #f8f9fa.
backgroundSecondary#ffffff#ffffffInchangé — surfaces pures.
backgroundTertiary#f1f3f4#efebe0Warm-neutral aligné au papier.
backgroundElevated#ffffff#ffffffInchangé.
backgroundOverlayrgba(0,0,0,0.5)rgba(20,16,10,0.55)Overlay teinté ink, pas neutre pur.
text#1a1a1a#141210Encre typographique, légère chaleur.
textSecondary#495057#4a453bWarm 500.
textTertiary#6c757d#7a7264Warm 400 · captions + timestamps.
textInverse#ffffff#ffffffInchangé.
border#e9ecef#e5dfd2Ligne hairline papier.
separator#f1f3f4#eee7d8Séparateur intra-liste.
card#ffffff#ffffffInchangé.
cardShadow#000000#000000Inchangé.
headerBackground#f8f9fa#f7f4ed= background, suppression du step inutile.
tabBarBackgroundrgba(245,245,245,0.82)rgba(247,244,237,0.78)Papier translucide, blur renforcé.
tabBarActive#1a1a1a#141210= text. Cohérence.
tabBarInactivergba(0,0,0,0.35)rgba(20,18,16,0.4)Warm inactive.
inputBackground#f1f2f6#efebe0= bgTertiary, réduction palette.
inputText#1a1a1a#141210= text.
inputPlaceholder#adb5bd#b0a890Warm 300.
inputBorder#e9ecef#e5dfd2= border.
icon#6c757d#7a7264= textTertiary.
iconActive#333333#141210= text.
skeletonBase#e9ecef#ebe4d2Warm skeleton.
skeletonHighlight#f8f9fa#f7f1e2Shimmer warm.
statusBar'dark-content''dark-content'Inchangé.
primary#00a8ff (blue)#c96442Accent cuivre light. Même token, nouvelle sémantique.
danger#e74c3c#d94836Rouge légèrement plus sourd, harmonisé cuivre.
success#10B981#3a8d6aVert forêt, plus sobre.
warning#F59E0B#d49028Ocre warm.
info#3498db#4a8aa8Bleu-pétrole sourd.
accent#e84393 (hot pink)#c96442Fusion : accent = primary. Une seule couleur d'affordance.
successBgrgba(16,185,129,0.1)rgba(58,141,106,0.1)Dérivé.
dangerBgrgba(231,76,60,0.1)rgba(217,72,54,0.1)Dérivé.
warningBgrgba(245,158,11,0.12)rgba(212,144,40,0.12)Dérivé.
infoBgrgba(52,152,219,0.1)rgba(74,138,168,0.1)Dérivé.
pressedOverlayrgba(0,0,0,0.05)rgba(20,18,16,0.06)Warm press.
focusedBorder#00a8ff#c96442= primary. Affordance immuable.
disabledBg#f1f3f4#efebe0= bgTertiary.

colors.dark · ColorPalette (OLED default)

Tokenv0.8.0v1.0 NocturneUsage
background#000000#000000Inchangé. OLED first-class.
backgroundSecondary#111111#0b0b0bStep +1, plus proche du noir.
backgroundTertiary#1a1a1a#141414Step +2, resserré.
backgroundElevated#111111#141414= bgTertiary. Réduit le nombre de steps.
backgroundOverlayrgba(0,0,0,0.7)rgba(0,0,0,0.75)Overlay dark un cran plus opaque.
text#f0f0f0#f2efe8Papier chaud, moins clinique.
textSecondary#b0b0b0#a39d90Warm 600.
textTertiary#808080#6b6458Warm 500.
textInverse#000000#0a0806Ink warm.
border#1a1a1a#1e1e1e+2, visible sans être franc.
separator#151515#161616Quasi-inchangé.
card#111111#0b0b0b= bgSecondary.
headerBackground#000000#000000Inchangé.
tabBarBackgroundrgba(10,10,10,0.85)rgba(10,10,10,0.75)Plus translucide — blur plus fort.
tabBarActive#ffffff#f2efe8= text.
tabBarInactivergba(255,255,255,0.4)rgba(242,239,232,0.4)Dérivé text.
inputBackground#1a1a1a#0b0b0b= card. Reconsolidation.
inputBorder#222222#1e1e1e= border.
inputPlaceholder#555555#6b6458= textTertiary.
inputText#f0f0f0#f2efe8= text.
icon#808080#6b6458= textTertiary.
iconActive#f0f0f0#f2efe8= text.
skeletonBase#111111#141414Step +2.
skeletonHighlight#1a1a1a#1c1c1cShimmer.
statusBar'light-content''light-content'Inchangé.
primary#00a8ff#e8764aCuivre dark. Version boostée du #c96442 light pour tenir sur OLED.
danger#e74c3c#ff5a4aBoostée pour dark.
success#10B981#58c896Boosté dark.
warning#F59E0B#f7b842Boosté dark.
info#3498db#5ab0d8Boosté dark.
accent#e84393#e8764a= primary. Une seule couleur.
successBgrgba(16,185,129,0.18)rgba(88,200,150,0.18)Dérivé.
dangerBgrgba(231,76,60,0.18)rgba(255,90,74,0.15)Dérivé.
warningBgrgba(245,158,11,0.2)rgba(247,184,66,0.15)Dérivé.
infoBgrgba(52,152,219,0.18)rgba(90,176,216,0.15)Dérivé.
pressedOverlayrgba(255,255,255,0.08)rgba(242,239,232,0.06)Dérivé text.
focusedBorder#00a8ff#e8764a= primary.
disabledBg#1a1a1a#141414= bgTertiary.

brand · identity persistente

Tokenv0.8.0v1.0Usage
premium#f7b42c#e4b76aOr cuivré, harmonisé accent (au lieu du jaune saturé).
pro#1a1a1a#141210= ink. Cohérence.
onLight#1a1a1a#141210= ink.
onDark#ffffff#f2efe8= paper.

gradients

Règle Nocturne — les gradients Memory (white/black/blue/red/orange) restent user-facing créatifs, ils sont la matière que le créateur met dans sa mémoire. Ils ne contaminent jamais le chrome. On réduit les gradients système à 1 primary + 1 premium + 1 dominant (nouveau).

Tokenv0.8.0v1.0Usage
white[#fff, #f8f9fa][#fff, #f7f4ed]Memory. Retombe sur papier.
black[#000, #1a1a1a][#000, #141210]Memory. Retombe sur ink.
blue[#667eea, #764ba2][#667eea, #764ba2]Memory — inchangé (matière créative).
red[#f093fb, #f5576c][#f093fb, #f5576c]Memory — inchangé.
orange[#ff9a56, #ff6a88][#ff9a56, #ff6a88]Memory — inchangé.
primary[#00a8ff, #0081c4][#e8764a, #c96442]Système. Réservé CTA premium.
premium[#f7b42c, #fc575e][#e4b76a, #c96442]Or → cuivre. Un seul gold-to-copper.
success[#10B981, #059669][#58c896, #3a8d6a]Dérivé.
danger[#e74c3c, #c0392b][#ff5a4a, #d94836]Dérivé.
dominantOverlay NEWdyn 15%Ajout justifié par Q2 · la teinte dominante extraite d'une photo plein-écran colore uniquement le gradient bottom d'overlay. Format : [transparent, rgba(dom, 0.15)]. Passe en prop à GradientOverlay via dominant.

spacing · 8-pt grid — UNCHANGED

Aucune valeur ne bouge. none 0, xxs 2, xs 4, sm 8, md 12, lg 16, xl 20, xxl 24, xxxl 32, huge 40, mega 48, giga 64 — la grille 8-pt reste le sol.

radius

Tokenv0.8.0v1.0Usage
none00Inchangé.
sm44Inchangé · badges stencil.
md88Inchangé · inputs default.
lg1212Inchangé · standard Collabz (cards, boutons).
xl1614Très léger resserrement éditorial.
xxl2018Modals petites.
modal2522Bottom sheets + grandes modales. 25 était trop arrondi vs l'éditorial.
pill99999999Inchangé — chips, avatars, FAB.

fontFamilies — MODIFIED

Nocturne enlève Playfair Display (remplacée par Fraunces, meilleure pour la variation opsz) et Oswald (non-utilisée 90% du temps, le besoin "impact UPPER" est absorbé par Fraunces 800). Dancing Script est conservée strictement pour Memory templates user-facing. Poppins devient Inter pour UI — Poppins est daté en 2026.

Clév0.8.0v1.0Usage
poppins → interPoppins 300/400/500/600/800Inter 400/500/600/700/800Clé renommée · tout le body + label + caption UI.
playfair → frauncesPlayfair 400/600/700Fraunces 400/600/700/800 + italic 400/700Display + headings editorial. OpSize variable.
oswaldOswald 400/600/700removedUsage absorbé par Fraunces 800.
dancingDancing 400/700Dancing 400/700Inchangé. User-facing Memory uniquement.
mono NEWJetBrains Mono 400/500/600Ajout justifié · meta éditoriale (timestamps, km, N°, uppercase captions). Signature visuelle forte, lisible à 10px.

Migration mentale : fontFamilies.poppins.regular devient fontFamilies.inter.regular (le shim est trivial : rename + re-map expo-font).

fontSize / lineHeight / letterSpacing — UNCHANGED

L'échelle modulaire 10 → 48 reste. line-heights tight/normal/relaxed = 1.2/1.5/1.7. letter-spacing inchangé. Aucune rupture de layout côté RN.

typography · presets

Les clés gardent exactement les mêmes noms. Seule la fontFamily ré-aiguillée.

Presetv0.8.0v1.0Note
h1poppins.bold 36/1.2/-0.5fraunces.bold 36/1.2/-0.5Serif éditorial.
h2poppins.bold 30/1.2/-0.5fraunces.bold 30/1.2/-0.5Serif.
h3poppins.semibold 24/1.2/0fraunces.semibold 24/1.2/0Serif.
h4poppins.semibold 20/1.2/0fraunces.semibold 20/1.2/0Serif.
bodypoppins.regular 16/1.5inter.regular 16/1.5Sans. Lisibilité prime.
bodyBoldpoppins.semibold 16/1.5inter.semibold 16/1.5Sans.
bodySmallpoppins.regular 14/1.5inter.regular 14/1.5Sans.
captionpoppins.regular 12/1.5/0.5inter.regular 12/1.5/0.5Sans.
labelpoppins.semibold 14/1.2/0.5inter.semibold 14/1.2/0.5Sans.
displayplayfair.bold 48/1.2/-0.5fraunces.bold 48/1.2/-0.5 italicItalic par défaut · signature Nocturne (Q1 plan recommandé).
meta NEWmono.medium 11/1.4/1Ajout · remplace les usages de caption pour timestamps/km/badges uppercase. Évite d'abuser de caption pour deux sémantiques différentes.

shadows · 3 niveaux — MODIFIED

Shadows atténuées. Nocturne mise sur les steps de surface (bg → bgSecondary → bgTertiary) plutôt que sur des drops. En dark, shadows = 0 opacity (steps uniquement). En light, shadows réduites de 50%.

Tokenv0.8.0v1.0 lightv1.0 dark
none000
subtle0,1,.05,2 · elev 10,1,.04,3 · elev 10,0,0,0 · step +1
default0,2,.1,8 · elev 40,2,.06,12 · elev 30,0,0,0 · step +2
prominent0,4,.15,16 · elev 80,8,.08,24 · elev 60,0,0,0 · step +2 + border hairline primary

motion — MINOR

Tokenv0.8.0v1.0Note
duration.fast150140Léger gain de perceived speed.
duration.base250220Idem.
duration.slow400360Éditorial = un peu moins lent.
duration.slower600600Inchangé.
easing.*standard/decelerate/accelerate/sharpinchangéCourbes conservées.
spring.*gentle/default/bouncy/snappyinchangéConfigs conservées.

opacity / zIndex / iconSize / hitSlop / hapticPatterns / breakpoints — UNCHANGED

Aucune modification. Mêmes valeurs, même typage, même export. Ces tokens sont structurels, pas stylistiques.

Bloc 2 — 20 atoms restylés.

Pour chacun : specimen dark (default) — variants & états, tokens consommés, confirmation API inchangée, ce qui change. Le light-mirror suit les mêmes règles d'équivalence de tokens (non répété à chaque atome pour tenir le format digeste).

01 / 20 · atom

Button

primary · secondary · outline · ghost · sm/md/lg · loading · disabled

Tokens consommés
  • colors.primary (bg primary), colors.textInverse (fg primary)
  • colors.backgroundTertiary (bg secondary)
  • colors.text, colors.textSecondary (ghost)
  • radius.lg, spacing.sm/md/lg/xl/xxl
  • fontFamilies.inter.regular/semibold, fontSize.sm/md/lg
  • opacity.disabled (0.4 — pas 0.5 comme code actuel)
  • gradients.primary si gradient prop
API — inchangée
title
Label du bouton
string
onPress
Handler tap
() => void
variant
primary | secondary | outline | ghost
default "primary"
size
sm | md | lg
default "md"
disabled / loading
Idem v0.8
boolean
gradient
GradientName — prioritaire sur primary
tokens.gradients[*]

Change vs v0.8 : couleur primary (bleu → cuivre), fontFamily (poppins → inter), opacity.disabled 0.5 → 0.4 (aligné tokens), radius inchangé.

02 / 20 · atom

Card

default · elevated · outline · gradient · padding none/sm/md/lg

Default

surface + hairline

Elevated

step +1 (dark) / shadow (light)

Outline

1px border, bg transparent

Gradient

primary uniquement

Tokens : colors.card, colors.border, radius.lg, shadows.default, spacing.md/xl/xxl. API : inchangée (variant, padding, radius, gradient). Change : en dark, elevated passe de shadow → step de surface + border hairline. Plus de "glow" parasite.

03 / 20 · atom

AnimatedTouchable

Wrapper press · spring scale 0.96 + opacity 0.7

Rest state
Pressed · .96 / .7
spring.default {damping:15, stiffness:150} → spring.snappy on release

Tokens : motion.spring.default / snappy, opacity.pressed (0.7), hitSlop.*. API : inchangée. Change : aucun — comportement conservé 1:1, seul le token motion.duration.fast (150→140) influence secondairement la perception.

04 / 20 · atom

Toast

success · error · info · warning — top-anchored, 3s auto-hide

Post publié
!Impossible de charger le feed. Reessayer
Ton profil est maintenant en Pro.

Tokens : colors.backgroundElevated, colors.success/danger/info/warning, radius.xl (14), shadows.prominent, spacing.md/lg. API : inchangée. Change : radius resserré (14 au lieu de 16), icônes semantic circulaires (au lieu d'emoji), border-left 3px de la couleur sémantique (langage Banner hérité).

05 / 20 · atom

DiscreteToast

Pill translucide · actions système sobres

LIEN COPIÉ
SAUVEGARDÉ DANS MÉMOIRES
ENVOI EN COURS…

Tokens : colors.backgroundElevated (rgba + blur), colors.border, radius.pill, typography.meta (NEW). API : inchangée. Change : mono UPPER au lieu de body — lecture éditoriale de l'acknowledgment système.

06 / 20 · atom

GradientOverlay

top · bottom · diagonal · dominant (NEW Q2)

BOTTOM · 85%
Legacy
DOMINANT · WARM
Nocturne
dominant NEW
Couleur hex extraite runtime. Si fournie, le gradient bottom utilise rgba(dom, 0.85) au lieu du noir pur. Opt-in.
string | undefined

API : même props existantes conservées. Ajout opt-in de dominant — zéro breaking change.

07 / 20 · atom

Typography

Tous les variants · display · h1-h4 · body · bodySmall · caption · label · meta NEW

Le réseau des créateurs.
Autour de toi.
Tes mémoires de la semaine
Qui vient samedi ?
Paramètres du compte
Body regular — poussée à la lecture. La photo parle, le texte accompagne.
Body bold — emphase courte dans un paragraphe.
Body small — card dense, list subtitle.
Caption — helper input, microcopy.
Label — above inputs, form fields
PARIS · IL Y A 3H · 65 PARTICIPANTS ▼ NEW meta preset

Change : h1-h4 + display passent en Fraunces (v0.8 Playfair). Display italic par défaut (Q1). Ajout meta preset.

08 / 20 · atom

TextInput

default · search · sm/md/lg · label · helper · error · focused

Ton adresse email
quentin@collabz.link
On t'enverra le lien de confirmation.
Mot de passe *
••••••••
Focused — hairline cuivre immuable.
quentin@collab
Email invalide.

Change : focused border cuivre (= primary token). Variant search = pill radius. Label en Inter semibold (v0.8 Poppins). Helper/error en caption preset.

09-10 / 20 · atoms

Modal · BottomSheet

centered · sheet (BottomSheet = wrapper sémantique)

Supprimer ce post ?

Cette action est irréversible. Ton post disparaîtra pour tous les followers.

Trier par
Récents
Populaires
Proches de toi

Change : radius.modal 25 → 22. Handle de sheet plus discret (40×4 au lieu de 50×5). Close-button circulaire (pattern iOS native).

11 / 20 · atom

Badge

default · premium · verified · pro · success · warning · danger · sm/md/lg

Default ★ Premium Pro ✓ Verified Confirmé En attente Épuisé

Change : premium or-cuivré (#e4b76a, + chaud qu'avant). Verified passe de bleu → outline cuivre (cohérent avec fusion primary=accent). Pro inchangé (ink). Uppercase en Inter semibold — plus Poppins.

12 / 20 · atom

Avatar

sm 32 · md 48 · lg 64 · ring none/default/gradient · badge premium/online/verified

QM
AO
BL
LR
NA

Change : fallback gradient Memory-blue conservé (il vit déjà côté user). Ring gradient stories : bleu→red Memory gradient inchangé. Online-dot green passe à #58c896 (dark) / #3a8d6a (light).

13 / 20 · atom

Skeleton

shimmer · pulse

Change : base/highlight warm-tinted (match papier / ink). skeletonBase dark passe de #111 → #141414, highlight → #1c1c1c. Plus doux, plus papier.

14 / 20 · atom

Divider

horizontal · vertical · spacing via token

Contenu au-dessus
Contenu en-dessous
Gauche
Milieu
Droite

Change : color token default = separator (au lieu de border parfois confus dans legacy). Aucune prop changée.

15 / 20 · atom

Switch

on · off · disabled

Change : on-state = primary cuivre (v0.8 bleu). Knob-on passe de blanc → accentInk (contraste + chaud).

16 / 20 · atom

Chip

selected · unselected · icon · trailing · sm/md/lg · disabled

Tous
Photographe
Modèle
MUA ×
+ Ajouter
Disabled

Change majeur : inversion noir/blanc au lieu de solid primary. Selected = bg=text, fg=bg. Unselected = transparent + hairline. Plus de couleur gratuite — zéro chip coloré (adieu le jaune/orange/bleu cohabitant de l'écran Lieux).

17 / 20 · atom

ListItem

default · danger · leading (icon/avatar) · trailing (chevron/switch/badge)

Mon compte
quentin@collabz.link
Notifications push
Supprimer le compte

Change : chevron passe de bleu → textTertiary. Border radius plus. variant="danger" — texte cuivre danger, pas emoji. Icons Feather (via ThemedIcon) inchangés.

18 / 20 · atom

EmptyState

icon · title · description · CTA

Rien encore.

Commence une conversation avec un autre créateur — ils apparaîtront ici.

Change : title en Fraunces italic (signature Nocturne), ton conserve "tu" casual + CTA verbale ("Découvrir" ≠ "Voir les créateurs"). Icon size lg (48). Pas d'emoji.

19 / 20 · atom

Banner

success · info · warning · danger · actionLabel · onClose

Change : left-edge 3px reste (seul endroit du système avec accent-border). Fond muted semantic dérivé des nouvelles couleurs. Liens inline en cuivre (= primary).

20 / 20 · atom

ThemedIcon

Wrapper Feather · color via token · size via iconSize

Change : rien de fonctionnel. Color default reste text. Feather conservé côté RN, Lucide côté web mirror. Ici on retire le fallback "glyphe Collabz swirl" qui traîne dans 3 écrans — remplacé par Feather activity.

Bloc 3 — 3 molecules restylées.

UserRow, NotificationRow, PostCard. Même API, même imports. L'éditorial redescend jusqu'aux petites rangées.

molecule · 01 / 03

UserRow

avatar · nom · subtitle · badge · trailing (ex. Suivre)

AO
Ambre Onpics
PRO
PARIS · 12.4K FOLLOWERS
LR
Léo Ramirez
★ PREMIUM
LYON · VIDÉASTE
MB
Maxime Bertin
PHOTOGRAPHE · 2 KM

Tokens : spacing.lg padding, colors.separator border-bottom, typography.bodyBold name, typography.meta subtitle (NEW). API : inchangée. Change : subtitle passe de caption (Inter 12) → meta (Mono 11 UPPER) — signature Nocturne, lecture éditoriale.

molecule · 02 / 03

NotificationRow

avatar · message · timestamp · trailing · unread

AO
Ambre Onpics a aimé ton post Néons & studio 11e.
IL Y A 3H
LR
Léo a commenté : « La lumière est folle. »
IL Y A 12H
CC
Collabz — Ton event Soirée de lancement est complet 🎉
HIER · 18H27

Tokens : colors.primary pour unread dot (vs bleu v0.8), rgba(primary, 0.04) fond unread ligne. API : inchangée. Change : quotes utilisateur en Fraunces italic — invite éditoriale. Emoji conservés uniquement s'ils viennent du contenu système textuel (pas chrome).

molecule · 03 / 03

PostCard

author header · body · tags · footer (slot actions)

AO
Ambre Onpics
PRO
PARIS · IL Y A 3H
Projection néons & studio 11e.
Sunset shoot hier soir à Saint-Germain, lumière de folie.
#sunset#paris#film
12.4k
284

Tokens : colors.card, radius.xl (14), spacing.lg padding, typography.h3 body bold title, typography.body description, typography.meta timestamps. API : inchangée (author, timestamp, body, tags, footer). Change : le body peut désormais avoir un "titre" de post qui prend Fraunces si c'est une string longue ≥ 40 car, sinon reste en body. Règle auto-dans-le-composant, pas dans la prop.

Bloc 4 — 5 patterns ajoutés.

Ces cinq patterns sont ad hoc aujourd'hui. On les fige dans le DS — même grammaire Nocturne, mêmes tokens. Ils remplacent des dizaines de lignes dupliquées écran par écran.

pattern · 01 / 05 · NEW

BackButton

Bouton retour standalone · chevron · hit 44 · haptic selection

API
variant
floating (sur photo) / inline (header gris) / text (iOS-style label)
'floating' | 'inline' | 'text'
label
Si variant="text" — sinon ignoré
string?
onPress
Défaut : navigation.goBack()
(() => void)?
tint
'dark'/'light' override pour contraste sur hero photo
default auto
Usage
  • floating — sur écran hero photo (Event detail, Profile, Post full)
  • inline — dans HeaderBar sur écrans standard (Settings, Form)
  • text — iOS-pattern natif, rare (uniquement flows legal/paiement)
  • Hit slop md. Haptic selection au press.
pattern · 02 / 05 · NEW

HeaderBar

Back-centered-actions · 44 + safeArea · collapse on scroll

Paramètres
Messages
API
title
Centered string OU ReactNode (display oversize type pour screens Feed/Discover/Messages)
string | ReactNode
titleVariant
centered (17 semibold) / large (Fraunces 30) / floating (transparent sur hero)
default "centered"
leading
Custom — default BackButton si stack has history, sinon none
ReactNode?
actions
Jusqu'à 2 IconButtons à droite
ReactNode[]
translucent
Sur photo hero — bg=transparent, blur auto
boolean, default false
Quand utiliser
  • centered — Settings, Form, flow de création.
  • large — Feed, Discover, Messages, Mémoires (titre Fraunces oversize qui collapse à 17 au scroll).
  • floating — Post full-screen, Event detail (bg=transparent, actions en pill translucide).
  • Safe area top intégré (pas besoin de padder manuellement).
pattern · 03 / 05 · NEW

StickyBottom

Barre d'action ancrée · fade gradient · safeArea bottom

(contenu scrollable)
(contenu scrollable)
API
children
Contenu (souvent Button ou row de boutons)
ReactNode
variant
fade (gradient) / solid (border-top) — default fade
'fade' | 'solid'
padding
Spacing token — default lg (16)
Spacing
Quand utiliser
  • fade — sur écrans scrollables avec contenu qui peut passer derrière (Feed detail, Event detail).
  • solid — sur formulaires (Create post, Memory composer) — besoin de séparation visuelle claire.
  • SafeArea bottom géré — ne pas padder manuellement.
  • Auto-hide si keyboard open (évite le chevauchement iOS).
pattern · 04 / 05 · NEW

ScreenLayout

Template SafeArea + HeaderBar + ScrollContent + StickyBottom

SAFE AREA TOP · 44
HeaderBar
SCROLL CONTENT · flex:1
SAFE AREA BOTTOM · 34
Anatomy
  • SafeArea — top + bottom auto (no manual padding)
  • HeaderBar slot — passe directement un <HeaderBar>
  • ScrollContent — flex:1 auto-scroll, padding = spacing.lg par défaut
  • StickyBottom slot — optionnel, auto-hide quand keyboard
  • backgroundColor = colors.background par défaut, override possible pour écrans hero full-bleed
API
header
<HeaderBar /> slot · omit pour fullscreen hero
ReactNode?
footer
<StickyBottom /> slot
ReactNode?
scroll
true par défaut · false pour écrans fixes (Post full, Memory)
boolean
padding
Padding horizontal du scroll — default lg (16)
Spacing
background
Override token bg
string?

Gain : les 8 écrans scrollables actuels passent de ~40 LOC de boilerplate chacun à ~8. Dette de "SafeAreaView oublié" ou "keyboard qui couvre le CTA" disparait par construction.

pattern · 05 / 05 · NEW

FAB · FloatingActionButton

Bonus · pattern absent du DS v0.8 mais déjà ad hoc dans l'app (Create Post, Chat new)

API : icon, label (optionnel → pill si présent), variant (primary/surface), position (bottom-right default, bottom-center), onPress. Tokens : colors.primary, radius.pill, shadows.prominent (avec teinte accent à 50%), spacing.mega (48) depuis safeArea bottom (= au-dessus StickyBottom).

Résumé opérationnel.

Ce qui migre en 1 commit
  • tokens.ts — 1 fichier, ~60 valeurs changées, 3 clés ajoutées (gradients.dominantOverlay, typography.meta, fontFamilies.mono), 1 clé retirée (fontFamilies.oswald).
  • fontFamilies.poppinsinter : rename + re-map expo-font.
  • 20 composants design/*.tsx : réécritures internes, zéro changement de signature.
  • 3 molecules design/{UserRow,NotificationRow,PostCard}.tsx : idem.
Ce qui s'ajoute · nouveaux fichiers
  • design/BackButton.tsx
  • design/HeaderBar.tsx
  • design/StickyBottom.tsx
  • design/ScreenLayout.tsx
  • design/FAB.tsx
  • design/index.ts — 5 exports à rajouter
  • design/types.ts — 5 interfaces à ajouter
Ce qui ne bouge pas
  • API publique : zéro breaking change.
  • spacing, iconSize, hitSlop, zIndex, opacity, hapticPatterns, breakpoints.
  • Architecture imports app — @/design reste le barrel unique.
  • Web mirror (ds.collabz.link) — régénération auto à partir de tokens.ts.
Prochaine étape — tu valides Q1 (italic display-only) + Q2 (dominant-overlay opt-in), je livre phase 2 : 12 écrans app complets (Feed, Discover, Event, Profile, Messages thread, Settings, onboarding, empty/error states) appliquant ce système. Mécanique à partir de là.