feat: login provider selection, logout, playlists pages
All checks were successful
CI/CD — Build & Deploy / Build & Deploy (push) Successful in 22s

- LoginPage : sélection Discord/GitHub/Google/Twitch via SuperOAuth
- Header : bouton Connexion → /login, logout ↩ quand connecté, nav Playlists conditionnelle
- useAuth : expose setUser pour logout côté Layout
- PlaylistsPage : liste owned/shared, création inline
- PlaylistPage : détail playlist + liste vidéos ordonnées
- Fix : Video.id number → string (UUID)
- Routes : /login, /playlists, /playlists/:id
This commit is contained in:
2026-03-14 09:32:45 +01:00
parent fcd9867670
commit 4265d21c8b
8 changed files with 331 additions and 28 deletions

View File

@@ -0,0 +1,40 @@
import { Link } from 'react-router-dom';
const PROVIDERS = [
{ id: 'discord', label: 'Discord', icon: '◈' },
{ id: 'github', label: 'GitHub', icon: '◉' },
{ id: 'google', label: 'Google', icon: '◎' },
{ id: 'twitch', label: 'Twitch', icon: '◆' },
] as const;
export default function LoginPage() {
const callbackUrl = encodeURIComponent(`${window.location.origin}/callback`);
const base = import.meta.env.VITE_SUPEROAUTH_URL;
return (
<div className="flex flex-col items-center gap-8 pt-20">
<div className="flex flex-col items-center gap-2">
<span className="font-mono text-xs font-bold tracking-widest text-od-accent">OD</span>
<h1 className="text-xl font-semibold text-od-text">Connexion</h1>
<p className="text-sm text-od-muted">Choisis ton provider pour continuer</p>
</div>
<div className="flex w-full max-w-xs flex-col gap-3">
{PROVIDERS.map(({ id, label, icon }) => (
<a
key={id}
href={`${base}/api/v1/auth/oauth/${id}?redirectUrl=${callbackUrl}`}
className="flex items-center gap-3 rounded border border-od-border bg-od-surface px-4 py-3 text-sm text-od-text transition-colors hover:border-od-accent hover:text-od-accent"
>
<span className="font-mono text-od-muted">{icon}</span>
{label}
</a>
))}
</div>
<Link to="/" className="font-mono text-xs text-od-muted hover:text-od-text transition-colors">
Retour
</Link>
</div>
);
}