/** * Squelette commun à tous les templates Rubis : bandeau header avec * logo/brand + container + footer "Émis via Rubis sur l'ongle" (masqué * pour les orgs sur plan Business avec marque blanche activée). * * Tokens visuels passés en prop `tokens` (cf. `#services/brand`). Tous les * styles sont déclarés à l'intérieur de la fonction pour fermer sur la * valeur runtime des tokens — un même `` rend en couleurs * Rubis ou en couleurs Business selon ce qu'on lui passe. * * Approche : styles inline (les `style` props que React Email convertit en * HTML inline). Compatible Gmail, Outlook, Apple Mail. Pas de Tailwind ici. * * Dark mode : forcé en light only (Outlook.com et Gmail mobile auto- * invertissent agressivement, ce qui casse les fonds rubis-deep). Les * sélecteurs `[data-ogsc]` ré-imposent nos couleurs pour ces clients. */ import * as React from 'react' import { Html, Head, Preview, Body, Container, Section, Row, Column, Text, Link, Img, } from '@react-email/components' import type { BrandTokens } from '#services/brand' import { sp } from './_brand.js' type LayoutProps = { /** Tokens résolus pour l'org (cf. resolveBrandTokens). */ tokens: BrandTokens /** Aperçu dans la liste mail (Gmail preview text). */ preview: string /** Sous-titre header (ex: numéro de facture, date). Optionnel. */ brandSubtitle?: string | null /** URL de la landing publique — footer "Rubis sur l'ongle". null = masque le footer (marque blanche). */ landingUrl?: string | null /** Masque le footer Rubis (pour plan Business qui ne veut pas du tout du wordmark). Default false. */ hideRubisFooter?: boolean children: React.ReactNode } export function EmailLayout({ tokens, preview, brandSubtitle, landingUrl, hideRubisFooter = false, children, }: LayoutProps) { const bodyStyle: React.CSSProperties = { backgroundColor: tokens.bodyBg, fontFamily: tokens.fontBody, margin: 0, padding: 0, color: tokens.text, } const containerStyle: React.CSSProperties = { backgroundColor: tokens.cardBg, margin: '0 auto', maxWidth: '560px', overflow: 'hidden', } const headerStyle: React.CSSProperties = { backgroundColor: tokens.banner, padding: `${sp.xl} ${sp.xl}`, } const headerBrandStyle: React.CSSProperties = { color: tokens.white, fontSize: '20px', fontWeight: 800, letterSpacing: '-0.01em', margin: 0, lineHeight: '1.1', } const gemStyle: React.CSSProperties = { display: 'inline-block', marginRight: sp.sm, color: tokens.primaryGlow, fontSize: '18px', verticalAlign: '-1px', } const headerSubtitleStyle: React.CSSProperties = { color: tokens.primaryGlow, fontSize: '12px', margin: `${sp.xs} 0 0 0`, letterSpacing: '0.04em', textTransform: 'uppercase', fontWeight: 600, } const contentStyle: React.CSSProperties = { padding: `${sp.xl} ${sp.xl}`, } const footerStyle: React.CSSProperties = { borderTop: `1px solid ${tokens.border}`, backgroundColor: tokens.bodyBg, padding: `${sp.lg} ${sp.xl}`, } const footerTextStyle: React.CSSProperties = { color: tokens.textVeryMuted, fontSize: '11px', lineHeight: '1.5', margin: 0, textAlign: 'center', } const footerLinkStyle: React.CSSProperties = { color: tokens.primary, fontWeight: 600, textDecoration: 'none', } return ( {/* Force light mode sur les clients qui auto-invertissent. */}