// app-flyer.jsx — Renderer de flyers NOMADE (post + story)
// ─────────────────────────────────────────────────────────────────────────
// SYSTÈME DE COULEUR « DÉSERT » — charbon chaud + neutres sable + UN accent
// terracotta employé avec parcimonie (1 trait / 1 pastille / 1 CTA par visuel).
// Aucune valeur dorée. Hiérarchie portée par les neutres, le contraste, la typo.
// ─────────────────────────────────────────────────────────────────────────
const N = {
// — Surfaces (dark mode chaud) —
ink: '#0C0A08', // charbon de base, légèrement chaud
inkDeep: '#070605', // le plus sombre
inkRaise: '#16120D', // surface relevée (cartes / pochettes)
// — Neutres chauds (portent la hiérarchie) —
bone: '#ECE3D4', // blanc cassé / os — texte principal
sand: '#CFBFA4', // sable chaud — emphase secondaire + voix serif
taupe: '#9A8B73', // grège — texte secondaire / labels
stone: '#5E5547', // pierre — bordures / tertiaire
// — Accent terracotta (PONCTUATION uniquement) —
clay: '#C16A43', // terracotta / sienne brûlée — mat, organique
clayDeep: '#8E4527', // brique profonde
claySoft: '#D58A62', // argile claire (dégradés CTA)
// — Alias rétro-compat (mêmes clés que l'ancien système) —
white: '#ECE3D4',
whiteSoft: 'rgba(236,227,212,0.72)',
bronze: '#C16A43', // ⟵ ré-aiguillé sur clay pour compat ; usage restreint
// — Hairlines / voiles réutilisables —
line: 'rgba(236,227,212,0.12)', // filet neutre standard
lineSoft: 'rgba(236,227,212,0.06)', // filet très discret
clayLine: 'rgba(193,106,67,0.38)', // filet accent (rare)
// — Typo —
display: '"Space Grotesk", system-ui, sans-serif',
serif: '"Cormorant Garamond", Georgia, serif',
body: '"Inter", system-ui, sans-serif',
mono: '"JetBrains Mono", ui-monospace, monospace'
};
function Grain() {
return
;
}
// Logo blanc, sans halo doré — une ombre douce et neutre pour le détacher.
function Logo({ height }) {
return ;
}
function BrandRow({ size = 1, pill, accentDot = false }) {
return (
);
}
// Chips neutres — filet fin grège, texte sable. Aucun remplissage coloré.
function Chips({ chips, size = 1 }) {
return (
{chips.filter(Boolean).map((c, i) =>
{c}
)}
);
}
// ── POST 1080×1350 ─────────────────────────────────────────────────────────
function PostFlyer({ data }) {
return (
{data.photoUrl ?
:
— Photo —
}
{data.kicker}
{data.headline}
{data.subtitle}
{data.composer &&
{data.composer}
}
{data.bottomCopy}
nomadeclan.com
);
}
// ── STORY 1080×1920 ────────────────────────────────────────────────────────
function StoryFlyer({ data }) {
return (
{data.photoUrl ?
:
— Photo —
}
{data.kicker}
{data.storyTop}
{data.storyBottom}
{data.composer &&
{data.composer}
}
{/* CTA — l'unique bloc accent terracotta de la story */}
{data.ctaLabel}
{data.ctaUrl}
);
}
window.N = N;
window.PostFlyer = PostFlyer;
window.StoryFlyer = StoryFlyer;
// ═══════════════════════════════════════════════════════════════════════════
// CERTIF LAYOUT — Disque d'Or / Platine / Diamant (visuels SNEP officiels)
// Les disques SNEP ne sont JAMAIS recolorés : ce sont des visuels officiels.
// ═══════════════════════════════════════════════════════════════════════════
const CERTIF_TYPES = {
OR: {
label: "DISQUE D'OR",
singleLabel: "SINGLE D'OR",
file: 'assets/snep-or.png'
},
PLATINE: {
label: 'DISQUE DE PLATINE',
singleLabel: 'SINGLE DE PLATINE',
file: 'assets/snep-platine.png'
},
'2PLATINE': {
label: 'DOUBLE DISQUE DE PLATINE',
singleLabel: null,
file: 'assets/snep-2platine.png'
},
'3PLATINE': {
label: 'TRIPLE DISQUE DE PLATINE',
singleLabel: null,
file: 'assets/snep-3platine.png'
},
DIAMANT: {
label: 'DISQUE DE DIAMANT',
singleLabel: 'SINGLE DE DIAMANT',
file: 'assets/snep-diamant.png'
},
'2DIAMANT': {
label: 'DOUBLE DISQUE DE DIAMANT',
singleLabel: 'DOUBLE DIAMANT',
file: 'assets/snep-2diamant.png'
}
};
// Ombre neutre + halo très discret : le disque garde ses couleurs officielles.
function CertifSeal({ type = 'OR', size = 300 }) {
const cfg = CERTIF_TYPES[type] || CERTIF_TYPES.OR;
return (
);
}
// ── CERTIF POST 1080×1350 ───────────────────────────────────────────────────
function CertifPost({ data }) {
return (
{/* Top brand row */}
{data.pill || 'CERTIFIÉ'}
{/* Kicker */}
{data.kicker || '/ CERTIFICATION'}
{/* Artist name */}
12 ? 84 : 110,
lineHeight: 0.95, letterSpacing: '-0.03em',
textTransform: 'uppercase', color: N.bone
}}>{data.artistName || 'ARTISTE'}
{/* Album name */}
{data.albumName || 'Titre'}
{/* Cert info */}
{(() => {
const cfg = CERTIF_TYPES[data.certifType] || CERTIF_TYPES.OR;
const isSingle = data.certifFormat === 'single';
const label = isSingle ? cfg.singleLabel || cfg.label : cfg.label || cfg.singleLabel;
const unit = isSingle ? 'streams' : 'ventes';
return (
{label}{data.salesNumber ? ` · +${data.salesNumber} ${unit}` : ''}
);
})()}
{/* Hero cover */}
{data.photoUrl ?
:
— Pochette —
}
{/* Foil seal */}
{(() => {
const isWide = ['2PLATINE', '3PLATINE', '2DIAMANT'].includes(data.certifType);
return (
);
})()}
{/* Bottom signature */}
{data.bottomCopy || "Encore une trace qui passe la barre.\nMerci à l'équipe + l'artiste."}
nomadeclan.com
);
}
// ── CERTIF STORY 1080×1920 ──────────────────────────────────────────────────
function CertifStory({ data }) {
return (
{data.pill || 'CERTIFIÉ'}
{data.kicker || '/ CERTIFICATION'}
10 ? 120 : 150,
lineHeight: 0.95, letterSpacing: '-0.03em',
textTransform: 'uppercase', color: N.bone
}}>{data.artistName || 'ARTISTE'}
{data.albumName || 'Titre'}
{(() => {
const cfg = CERTIF_TYPES[data.certifType] || CERTIF_TYPES.OR;
const isSingle = data.certifFormat === 'single';
const label = isSingle ? cfg.singleLabel || cfg.label : cfg.label || cfg.singleLabel;
const unit = isSingle ? 'streams' : 'ventes';
return (
{label}{data.salesNumber ? ` · +${data.salesNumber} ${unit}` : ''}
);
})()}
{data.photoUrl ?
:
— Pochette —
}
{(() => {
const isWide = ['2PLATINE', '3PLATINE', '2DIAMANT'].includes(data.certifType);
return (
);
})()}
{/* CTA — bloc accent terracotta unique */}
{data.ctaLabel || '/ Vos projets chez NOMADE'}
{data.ctaUrl || 'nomadeclan.com'}
);
}
window.CertifPost = CertifPost;
window.CertifStory = CertifStory;
window.CertifSeal = CertifSeal;
// ═══════════════════════════════════════════════════════════════════════════
// SESSION layout — "EN STUDIO / live rec"
// ═══════════════════════════════════════════════════════════════════════════
function SessionPost({ data }) {
return (
{data.photoUrl ?
:
}
{/* Filet accent fin en haut (le seul trait coloré) */}
{/* Pastille live REC — pastille accent unique */}
{data.pill || 'EN STUDIO'}
{data.kicker || '/ SESSION · 01'}
REC ● {data.sessionDate || "AUJOURD'HUI"}
EN SESSION
{data.artistName || data.headline || 'ARTISTE'}
{data.subtitle || 'au studio cette nuit.'}
{(data.chips || []).filter(Boolean).map((c, i) =>
{c}
)}
{data.bottomCopy || 'Une nuit, un son, la trace.'}
nomadeclan.com
);
}
function SessionStory({ data }) {
return (
{data.photoUrl ?
:
}
{data.pill || 'EN STUDIO'}
{data.kicker || '/ SESSION · 01'}
REC ● {data.sessionDate || 'NOW'}
EN SESSION
{data.kicker || '/ LIVE NOW'}
{data.artistName || data.headline || 'ARTISTE'}
{data.subtitle || 'au studio cette nuit.'}
{(data.chips || []).filter(Boolean).map((c, i) =>
{c}
)}
);
}
window.SessionPost = SessionPost;
window.SessionStory = SessionStory;
// ═══════════════════════════════════════════════════════════════════════════
// PROMO layout — carte typographique (offre). Fond charbon, accent terracotta.
// ═══════════════════════════════════════════════════════════════════════════
function PromoPost({ data }) {
return (
{data.kicker || '/ OFFRE LIMITÉE'}
{data.headline || '-30%'}
{data.subtitle || 'sur toutes les sessions studio'}
{data.promoDate || 'Jusqu\'au 30.06.2026'}
{(data.chips || []).filter(Boolean).map((c, i) =>
{c}
)}
{/* Code promo — bloc accent terracotta unique */}
— Code promo
{data.promoCode || 'NOMADE-30'}
Réserver →
{data.bottomCopy || 'Premier arrivé, premier servi.\nPlaces limitées.'}
nomadeclan.com
);
}
function PromoStory({ data }) {
return (
{data.kicker || '/ OFFRE LIMITÉE'}
{data.headline || '-30%'}
{data.subtitle || 'sur toutes les sessions studio'}
{data.promoDate || 'Jusqu\'au 30.06.2026'}
{(data.chips || []).filter(Boolean).map((c, i) =>
{c}
)}
— Code promo
{data.promoCode || 'NOMADE-30'}
Réserver une session →
nomadeclan.com
);
}
window.PromoPost = PromoPost;
window.PromoStory = PromoStory;
window.CERTIF_TYPES = CERTIF_TYPES;
// CertifBackdrop — fond utilisé par CertifPost / CertifStory.
// Charbon chaud + sillons de vinyle en neutre discret + halo sable très léger.
function CertifBackdrop({ children }) {
const Disc = ({ cx, cy, r, opacity = 1 }) => {
const grooves = [];
for (let gr = 30; gr <= r; gr += 8) grooves.push(gr);
return (
{grooves.map((gr, i) =>
)}
);
};
return (
<>
{children}
>);
}