diff --git a/frontend/src/components/layout/Layout.tsx b/frontend/src/components/layout/Layout.tsx
index ca5c22e..db69c6e 100644
--- a/frontend/src/components/layout/Layout.tsx
+++ b/frontend/src/components/layout/Layout.tsx
@@ -1,26 +1,21 @@
import { Outlet } from 'react-router-dom';
import Header from './Header';
+import Footer from './Footer';
import { useAuthContext } from '../../context/AuthContext';
-interface LayoutProps {
- theme: 'dark' | 'light';
- onToggleTheme: () => void;
-}
-
-export default function Layout({ theme, onToggleTheme }: LayoutProps) {
+export default function Layout() {
const { user, loading, setUser } = useAuthContext();
return (
-
+
);
}
diff --git a/frontend/src/pages/LandingPage.tsx b/frontend/src/pages/LandingPage.tsx
new file mode 100644
index 0000000..9230967
--- /dev/null
+++ b/frontend/src/pages/LandingPage.tsx
@@ -0,0 +1,241 @@
+import { Link } from 'react-router-dom';
+
+// ─── Pricing data ─────────────────────────────────────────────────────────────
+
+interface Tier {
+ name: string;
+ price: string;
+ period: string;
+ tagline: string;
+ features: string[];
+ cta: string;
+ highlighted: boolean;
+}
+
+const TIERS: Tier[] = [
+ {
+ name: 'Starter',
+ price: '29€',
+ period: '/mois',
+ tagline: 'Pour démarrer proprement.',
+ features: [
+ '1 projet',
+ 'Domaine custom',
+ 'White-label basique',
+ 'Support communauté',
+ ],
+ cta: 'Commencer',
+ highlighted: false,
+ },
+ {
+ name: 'Studio',
+ price: '99€',
+ period: '/mois',
+ tagline: 'Pour les studios actifs.',
+ features: [
+ '5 projets',
+ 'Analytics intégrés',
+ 'SuperOAuth Tier 3',
+ 'White-label complet',
+ 'Support email',
+ ],
+ cta: 'Choisir Studio',
+ highlighted: true,
+ },
+ {
+ name: 'Pro',
+ price: '249€',
+ period: '/mois',
+ tagline: 'Pour les opérations à fort volume.',
+ features: [
+ 'Projets illimités',
+ 'API access complet',
+ 'Support prioritaire',
+ 'SuperOAuth Tier 3',
+ 'SLA 99.9%',
+ ],
+ cta: 'Choisir Pro',
+ highlighted: false,
+ },
+];
+
+// ─── Component ────────────────────────────────────────────────────────────────
+
+export default function LandingPage() {
+ return (
+
+
+ {/* ── Hero ──────────────────────────────────────────────────────────── */}
+
+
+ {/* Badge */}
+
+
+
+ SuperOAuth Tier 3 — multi-tenant natif
+
+
+
+ {/* Headline */}
+
+ La plateforme des{' '}
+ studios indépendants.
+
+
+ {/* Sous-titre */}
+
+ Lancez votre vitrine de contenu en quelques minutes.
+ Auth multi-tenant, domaine custom, white-label complet —
+ sans compromis sur la qualité.
+
+
+ {/* CTAs */}
+
+
+ {/* Social proof minimal */}
+
+ Intégration SuperOAuth Tier 3 · Auth per-tenant · CNAME custom
+
+
+
+
+ {/* ── Différenciateur ───────────────────────────────────────────────── */}
+
+ {[
+ {
+ label: 'Auth multi-tenant',
+ desc: 'SuperOAuth Tier 3 intégré nativement. Per-tenant providers, isolation complète des données.',
+ },
+ {
+ label: 'White-label total',
+ desc: 'Logo, domaine, emails, couleurs — votre marque, pas la nôtre. CNAME custom inclus dès Starter.',
+ },
+ {
+ label: 'Prévisible',
+ desc: 'Abonnement fixe, pas de commission, pas de per-seat. Votre croissance ne nous rémunère pas.',
+ },
+ ].map(({ label, desc }) => (
+
+ ))}
+
+
+ {/* ── Pricing ───────────────────────────────────────────────────────── */}
+
+
+
+
Tarifs
+
+ Simple. Sans surprise.
+
+
+ Abonnement mensuel sans engagement. Pas de commission sur vos revenus.
+
+
+
+
+ {TIERS.map((tier) => (
+
+ ))}
+
+
+ {/* Enterprise mention */}
+
+
+
+
+
+ );
+}
+
+// ─── PricingCard ──────────────────────────────────────────────────────────────
+
+function PricingCard({ tier }: { tier: Tier }) {
+ const base =
+ 'relative flex flex-col gap-5 rounded border p-6 transition-all duration-150';
+ const highlighted =
+ tier.highlighted
+ ? 'border-od-accent bg-od-surface shadow-accent-glow'
+ : 'border-od-border bg-od-surface hover:border-od-border-hi';
+
+ return (
+
+
+ {tier.highlighted && (
+
+ )}
+
+ {tier.highlighted && (
+
+ Populaire
+
+ )}
+
+ {/* Header */}
+
+
{tier.name}
+
+ {tier.price}
+ {tier.period}
+
+
{tier.tagline}
+
+
+ {/* Separator */}
+
+
+ {/* Features */}
+
+ {tier.features.map((f) => (
+ -
+ —
+ {f}
+
+ ))}
+
+
+ {/* CTA */}
+
+ {tier.cta}
+
+
+
+ );
+}
diff --git a/frontend/src/styles/index.css b/frontend/src/styles/index.css
index 3951b6c..f6f6533 100644
--- a/frontend/src/styles/index.css
+++ b/frontend/src/styles/index.css
@@ -2,39 +2,31 @@
@tailwind components;
@tailwind utilities;
-/* ─── Void Dark (défaut) ─────────────────────────────────────────────────── */
-:root,
-[data-theme="dark"] {
- --od-bg: #0a0a0d; /* fond principal — quasi-noir cool */
- --od-surface: #111115; /* panneaux, cartes */
- --od-surface-hi: #191920; /* survol, éléments élevés */
- --od-border: #222228; /* séparateurs subtils */
- --od-text: #dddde8; /* texte principal */
- --od-muted: #62626e; /* texte secondaire, labels */
- --od-accent: #d4a853; /* or chaud — premium */
- --od-accent-dim: #a07830; /* survol accent */
+/* ─── Void Dark — dark only V1 ──────────────────────────────────────────── */
+:root {
+ --od-bg: #0a0a0a; /* fond principal — validated */
+ --od-surface: #111111; /* panneaux, cartes */
+ --od-surface-hi: #1a1a1a; /* survol, éléments élevés */
+ --od-border: #222222; /* séparateurs subtils */
+ --od-border-hi: #2e2e2e; /* bordures hover */
+ --od-text: #e8e8e8; /* texte principal */
+ --od-muted: #5a5a5a; /* texte secondaire, labels */
+ --od-accent: #c9a84c; /* or mat — validated */
+ --od-accent-dim: #a08038; /* survol accent */
+ --od-accent-glow: rgba(201,168,76,0.12); /* glow subtil */
--od-crit: #d95f5f; /* erreurs */
--od-ok: #5fc875; /* succès */
}
-/* ─── Void Light ─────────────────────────────────────────────────────────── */
-[data-theme="light"] {
- --od-bg: #f2f2f5;
- --od-surface: #ffffff;
- --od-surface-hi: #e8e8ee;
- --od-border: #d0d0da;
- --od-text: #14141a;
- --od-muted: #6a6a78;
- --od-accent: #a07830;
- --od-accent-dim: #7a5c20;
- --od-crit: #c04040;
- --od-ok: #3aa855;
+/* ─── Base ───────────────────────────────────────────────────────────────── */
+html {
+ color-scheme: dark;
}
-/* ─── Base ───────────────────────────────────────────────────────────────── */
body {
background-color: var(--od-bg);
color: var(--od-text);
- font-family: 'Inter', ui-sans-serif, system-ui, sans-serif;
+ font-family: 'Geist', 'Inter', ui-sans-serif, system-ui, sans-serif;
-webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
}
diff --git a/frontend/tailwind.config.ts b/frontend/tailwind.config.ts
index 3635df3..af942ad 100644
--- a/frontend/tailwind.config.ts
+++ b/frontend/tailwind.config.ts
@@ -1,8 +1,8 @@
import type { Config } from 'tailwindcss';
-// Design system "Void" — palette custom OriginsDigital
-// Les couleurs sont définies comme variables CSS dans src/styles/index.css
-// → thème sombre/clair géré via data-theme="dark|light" sur
+// Design system "Void Dark" — OriginsDigital V1
+// Palette validée Step 1 : fond #0a0a0a, surface #111, accent #c9a84c (or mat)
+// Dark only — pas de toggle en V1
export default {
content: ['./index.html', './src/**/*.{ts,tsx}'],
theme: {
@@ -13,17 +13,46 @@ export default {
surface: 'var(--od-surface)',
'surface-hi': 'var(--od-surface-hi)',
border: 'var(--od-border)',
+ 'border-hi': 'var(--od-border-hi)',
text: 'var(--od-text)',
muted: 'var(--od-muted)',
accent: 'var(--od-accent)',
'accent-dim': 'var(--od-accent-dim)',
+ 'accent-glow':'var(--od-accent-glow)',
crit: 'var(--od-crit)',
ok: 'var(--od-ok)',
},
},
fontFamily: {
- sans: ['Inter', 'ui-sans-serif', 'system-ui', 'sans-serif'],
- mono: ['"JetBrains Mono"', '"Fira Code"', 'ui-monospace', 'monospace'],
+ // display : Geist — headlines H1, titres premium
+ display: ['Geist', 'Inter', 'ui-sans-serif', 'system-ui', 'sans-serif'],
+ sans: ['Geist', 'Inter', 'ui-sans-serif', 'system-ui', 'sans-serif'],
+ mono: ['"JetBrains Mono"', '"Fira Code"', 'ui-monospace', 'monospace'],
+ },
+ fontSize: {
+ // Densité élevée — chaque pixel justifié
+ '2xs': ['0.625rem', { lineHeight: '1rem' }],
+ },
+ borderRadius: {
+ sm: '0.25rem',
+ DEFAULT: '0.375rem',
+ md: '0.5rem',
+ lg: '0.75rem',
+ },
+ transitionDuration: {
+ DEFAULT: '150ms',
+ },
+ boxShadow: {
+ 'accent-glow': '0 0 0 1px var(--od-accent-glow), 0 4px 20px var(--od-accent-glow)',
+ },
+ keyframes: {
+ 'fade-in': {
+ from: { opacity: '0', transform: 'translateY(4px)' },
+ to: { opacity: '1', transform: 'translateY(0)' },
+ },
+ },
+ animation: {
+ 'fade-in': 'fade-in 150ms ease-out',
},
},
},