feat(sprint3-step1-2): vision B2B + Tailwind tokens + LandingPage + Pricing B2B

This commit is contained in:
2026-03-17 06:36:52 +01:00
parent e52aa1e79c
commit d25bfb7d87
10 changed files with 448 additions and 84 deletions

View File

@@ -0,0 +1,21 @@
export default function Footer() {
return (
<footer className="border-t border-od-border bg-od-bg">
<div className="mx-auto flex max-w-6xl items-center justify-between px-6 py-6">
<div className="flex items-center gap-2">
<span className="font-mono text-xs font-bold tracking-[0.2em] text-od-accent">OD</span>
<span className="text-xs text-od-muted">OriginsDigital</span>
</div>
<p className="font-mono text-2xs text-od-muted">
© {new Date().getFullYear()} OriginsDigital Tous droits réservés
</p>
<div className="flex items-center gap-6">
<a href="mailto:contact@originsdigital.com" className="font-mono text-2xs text-od-muted hover:text-od-text transition-colors duration-150">
Contact
</a>
<span className="font-mono text-2xs text-od-muted">Powered by SuperOAuth</span>
</div>
</div>
</footer>
);
}

View File

@@ -5,13 +5,11 @@ import type { User } from '../../context/AuthContext';
import UserBadge from '../UserBadge';
interface HeaderProps {
theme: 'dark' | 'light';
onToggleTheme: () => void;
user: User | null;
onLogout: () => void;
}
export default function Header({ theme, onToggleTheme, user, onLogout }: HeaderProps) {
export default function Header({ user, onLogout }: HeaderProps) {
const [open, setOpen] = useState(false);
const dropdownRef = useRef<HTMLDivElement>(null);
@@ -33,67 +31,65 @@ export default function Header({ theme, onToggleTheme, user, onLogout }: HeaderP
}
return (
<header className="border-b border-od-border bg-od-surface">
<div className="mx-auto flex h-14 max-w-5xl items-center justify-between px-4">
<header className="sticky top-0 z-40 border-b border-od-border bg-od-bg/90 backdrop-blur-sm">
<div className="mx-auto flex h-14 max-w-6xl items-center justify-between px-6">
{/* Logo */}
<Link to="/" className="flex items-center gap-2 group">
<span className="font-mono text-xs font-bold text-od-accent tracking-widest group-hover:text-od-accent-dim transition-colors">
<Link to="/" className="flex items-center gap-2.5 group">
<span className="font-mono text-xs font-bold tracking-[0.2em] text-od-accent group-hover:text-od-accent-dim transition-colors duration-150">
OD
</span>
<span className="text-sm font-semibold text-od-text">
<span className="text-sm font-semibold text-od-text tracking-tight">
OriginsDigital
</span>
</Link>
{/* Navigation */}
<nav className="flex gap-6">
<Link to="/" className="text-sm text-od-muted hover:text-od-text transition-colors">
<nav className="flex items-center gap-8">
<Link to="/" className="text-sm text-od-muted hover:text-od-text transition-colors duration-150">
Accueil
</Link>
{user && (
<Link to="/playlists" className="text-sm text-od-muted hover:text-od-text transition-colors">
<Link to="/playlists" className="text-sm text-od-muted hover:text-od-text transition-colors duration-150">
Playlists
</Link>
)}
{!user && (
<Link to="/#pricing" className="text-sm text-od-muted hover:text-od-text transition-colors duration-150">
Tarifs
</Link>
)}
{user?.roles?.some((r) => r === 'admin' || r === 'super_admin') && (
<Link to="/admin" className="font-mono text-xs text-od-muted hover:text-od-accent transition-colors">
<Link to="/admin" className="font-mono text-xs text-od-muted hover:text-od-accent transition-colors duration-150">
admin
</Link>
)}
</nav>
{/* Right — thème + auth */}
<div className="flex items-center gap-4">
<button
onClick={onToggleTheme}
aria-label="Changer le thème"
className="font-mono text-xs text-od-muted hover:text-od-text transition-colors"
>
{theme === 'dark' ? '◑' : '◐'}
</button>
{/* Right — auth */}
<div className="flex items-center gap-3">
{user ? (
<div className="relative" ref={dropdownRef}>
<button
onClick={() => setOpen((o) => !o)}
className="flex items-center gap-1.5 hover:opacity-80 transition-opacity"
className="flex items-center gap-1.5 hover:opacity-80 transition-opacity duration-150"
>
<UserBadge user={user} />
<span className="font-mono text-xs text-od-muted"></span>
</button>
{open && (
<div className="absolute right-0 top-full mt-1 w-36 rounded border border-od-border bg-od-surface shadow-lg z-50">
<div className="absolute right-0 top-full mt-1.5 w-40 rounded border border-od-border bg-od-surface shadow-xl z-50 animate-fade-in">
<Link
to="/profile"
onClick={() => setOpen(false)}
className="block px-3 py-2 text-xs text-od-muted hover:text-od-text transition-colors"
className="block px-4 py-2.5 text-xs text-od-muted hover:text-od-text transition-colors duration-150"
>
Profil
</Link>
<div className="border-t border-od-border" />
<button
onClick={handleLogout}
className="w-full text-left px-3 py-2 font-mono text-xs text-od-muted hover:text-od-crit transition-colors"
className="w-full text-left px-4 py-2.5 font-mono text-xs text-od-muted hover:text-od-crit transition-colors duration-150"
>
Déconnexion
</button>
@@ -103,9 +99,9 @@ export default function Header({ theme, onToggleTheme, user, onLogout }: HeaderP
) : (
<Link
to="/login"
className="rounded border border-od-border px-3 py-1 font-mono text-xs text-od-muted hover:border-od-accent hover:text-od-accent transition-colors"
className="rounded border border-od-accent px-4 py-1.5 font-mono text-xs text-od-accent hover:bg-od-accent hover:text-od-bg transition-all duration-150"
>
Connexion
Se connecter
</Link>
)}
</div>

View File

@@ -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 (
<div className="min-h-screen bg-od-bg text-od-text">
<div className="min-h-screen bg-od-bg text-od-text flex flex-col">
<Header
theme={theme}
onToggleTheme={onToggleTheme}
user={loading ? null : user}
onLogout={() => setUser(null)}
/>
<main className="mx-auto max-w-5xl px-4 py-8">
<main className="flex-1 mx-auto w-full max-w-6xl px-6 py-10">
<Outlet />
</main>
<Footer />
</div>
);
}