From d5d7b15f16e436533492e7ed91a429c9b5c16967 Mon Sep 17 00:00:00 2001 From: Pierre Ryssen Date: Wed, 11 Mar 2026 16:02:55 +0100 Subject: [PATCH] feat: add a white theme --- app/dashboard/layout.tsx | 37 +---------------- app/dashboard/page.tsx | 6 +-- app/finances/layout.tsx | 28 +------------ app/finances/page.tsx | 7 ++-- app/globals.css | 32 ++++++++++++++- app/instagram/layout.tsx | 28 +------------ app/instagram/page.tsx | 7 ++-- app/layout.tsx | 5 ++- app/page.tsx | 68 +++++++++++++++++++------------- app/tiktok/layout.tsx | 28 +------------ app/tiktok/page.tsx | 17 ++++---- app/twitch/layout.tsx | 28 +------------ app/twitch/page.tsx | 7 ++-- app/youtube/layout.tsx | 28 +------------ app/youtube/page.tsx | 7 ++-- components/AppLayout.tsx | 41 +++++++++++++++++++ components/DragonEye.tsx | 40 ++++++++++++++----- components/Sidebar.tsx | 36 ++++++++++++----- components/StatCard.tsx | 13 ++++-- components/ThemeToggleButton.tsx | 19 +++++++++ lib/theme.tsx | 49 +++++++++++++++++++++++ tailwind.config.js | 7 ++++ 22 files changed, 297 insertions(+), 241 deletions(-) create mode 100644 components/AppLayout.tsx create mode 100644 components/ThemeToggleButton.tsx create mode 100644 lib/theme.tsx diff --git a/app/dashboard/layout.tsx b/app/dashboard/layout.tsx index 7d0779a..fe8d587 100644 --- a/app/dashboard/layout.tsx +++ b/app/dashboard/layout.tsx @@ -1,38 +1,5 @@ -"use client"; - -import { useEffect } from "react"; -import { useRouter } from "next/navigation"; -import { useSession } from "next-auth/react"; -import Sidebar from "@/components/Sidebar"; +import AppLayout from "@/components/AppLayout"; export default function AuthLayout({ children }: { children: React.ReactNode }) { - const { status } = useSession(); - const router = useRouter(); - - useEffect(() => { - if (status === "unauthenticated") { - router.push("/"); - } - }, [status, router]); - - if (status === "loading") { - return ( -
- - CHARGEMENT... - -
- ); - } - - if (status !== "authenticated") return null; - - return ( -
- -
- {children} -
-
- ); + return {children}; } \ No newline at end of file diff --git a/app/dashboard/page.tsx b/app/dashboard/page.tsx index 093ad0e..768781c 100644 --- a/app/dashboard/page.tsx +++ b/app/dashboard/page.tsx @@ -1,9 +1,9 @@ export default function DashboardPage() { return (
-
Vue générale
-

Tableau de bord

-

Données à venir...

+
Vue générale
+

Tableau de bord

+

Données à venir...

); } \ No newline at end of file diff --git a/app/finances/layout.tsx b/app/finances/layout.tsx index fe65f98..fe8d587 100644 --- a/app/finances/layout.tsx +++ b/app/finances/layout.tsx @@ -1,29 +1,5 @@ -"use client"; - -import { useEffect } from "react"; -import { useRouter } from "next/navigation"; -import { useSession } from "next-auth/react"; -import Sidebar from "@/components/Sidebar"; +import AppLayout from "@/components/AppLayout"; export default function AuthLayout({ children }: { children: React.ReactNode }) { - const { status } = useSession(); - const router = useRouter(); - - useEffect(() => { - if (status === "unauthenticated") { - router.push("/"); - } - }, [status, router]); - - if (status === "loading") return null; - if (status !== "authenticated") return null; - - return ( -
- -
- {children} -
-
- ); + return {children}; } \ No newline at end of file diff --git a/app/finances/page.tsx b/app/finances/page.tsx index 075f62f..8319aaa 100644 --- a/app/finances/page.tsx +++ b/app/finances/page.tsx @@ -10,7 +10,7 @@ export default function FinancesPage() {
Revenus
-

Finances

+

Finances

@@ -21,9 +21,10 @@ export default function FinancesPage() { -
+
-

+

AUCUNE DONNÉE FINANCIÈRE DISPONIBLE
POUR LE MOMENT

diff --git a/app/globals.css b/app/globals.css index 26a3738..8563f02 100644 --- a/app/globals.css +++ b/app/globals.css @@ -2,6 +2,36 @@ @tailwind components; @tailwind utilities; +/* ── Dark theme (default) ── */ +:root { + --bg: #0d1117; + --surface: #161b22; + --border: #30363d; + --text-primary: #c9d1d9; + --text-secondary: #8b949e; + --accent: #4aff8c; + --accent-dim: rgba(74,255,140,0.1); + --accent-border: rgba(74,255,140,0.3); +} + +/* ── Light theme ── */ +html.light { + --bg: #f0f6ff; + --surface: #ffffff; + --border: #d0d7de; + --text-primary: #1c2128; + --text-secondary: #57606a; + --accent: #0ea5e9; + --accent-dim: rgba(14,165,233,0.1); + --accent-border: rgba(14,165,233,0.3); +} + +body { + background-color: var(--bg); + color: var(--text-primary); + transition: background-color 0.2s ease, color 0.2s ease; +} + ::-webkit-scrollbar { width: 4px; } ::-webkit-scrollbar-track { background: transparent; } -::-webkit-scrollbar-thumb { background: #30363d; border-radius: 2px; } +::-webkit-scrollbar-thumb { background: var(--border); border-radius: 2px; } diff --git a/app/instagram/layout.tsx b/app/instagram/layout.tsx index fe65f98..fe8d587 100644 --- a/app/instagram/layout.tsx +++ b/app/instagram/layout.tsx @@ -1,29 +1,5 @@ -"use client"; - -import { useEffect } from "react"; -import { useRouter } from "next/navigation"; -import { useSession } from "next-auth/react"; -import Sidebar from "@/components/Sidebar"; +import AppLayout from "@/components/AppLayout"; export default function AuthLayout({ children }: { children: React.ReactNode }) { - const { status } = useSession(); - const router = useRouter(); - - useEffect(() => { - if (status === "unauthenticated") { - router.push("/"); - } - }, [status, router]); - - if (status === "loading") return null; - if (status !== "authenticated") return null; - - return ( -
- -
- {children} -
-
- ); + return {children}; } \ No newline at end of file diff --git a/app/instagram/page.tsx b/app/instagram/page.tsx index 34be773..0047adf 100644 --- a/app/instagram/page.tsx +++ b/app/instagram/page.tsx @@ -10,7 +10,7 @@ export default function InstagramPage() {
Plateforme
-

Instagram

+

Instagram

@@ -21,9 +21,10 @@ export default function InstagramPage() { -
+
-

+

CONNECTEZ VOTRE COMPTE INSTAGRAM
POUR AFFICHER VOS STATISTIQUES

diff --git a/app/layout.tsx b/app/layout.tsx index 39d73e8..cae6fab 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,6 +1,7 @@ import type { Metadata } from "next"; import "./globals.css"; import { SessionProvider } from "next-auth/react"; +import { ThemeProvider } from "@/lib/theme"; export const metadata: Metadata = { title: "WYVIEW", @@ -12,7 +13,9 @@ export default function RootLayout({ children }: { children: React.ReactNode }) - {children} + + {children} + diff --git a/app/page.tsx b/app/page.tsx index 0195857..2ca55e6 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -8,13 +8,11 @@ import DragonEye from "@/components/DragonEye"; export default function AuthPage() { const [tab, setTab] = useState<"login" | "register">("login"); - // Login state const [loginEmail, setLoginEmail] = useState(""); const [loginPassword, setLoginPassword] = useState(""); const [loginError, setLoginError] = useState(""); const [loginLoading, setLoginLoading] = useState(false); - // Register state const [regName, setRegName] = useState(""); const [regEmail, setRegEmail] = useState(""); const [regPassword, setRegPassword] = useState(""); @@ -85,61 +83,64 @@ export default function AuthPage() { } }; + const inputStyle: React.CSSProperties = { + background: "var(--surface)", + color: "var(--text-primary)", + borderColor: "var(--border)", + }; + const inputClass = (hasError: boolean) => - `w-full bg-wy-surface border px-4 py-3 text-sm font-mono text-wy-text-primary placeholder-wy-text-secondary outline-none rounded-md transition-all duration-200 ${ - hasError ? "border-red-500/60" : "border-wy-border focus:border-acid-green/60" + `w-full px-4 py-3 text-sm font-mono outline-none rounded-md transition-all duration-200 border ${ + hasError ? "border-red-500/60" : "focus:border-[color:var(--accent)]" }`; return ( -
+
-
+
- {/* Header */}
-
+
Analytics Dashboard
-

+

WYVIEW

{/* Tabs */} -
+
- - {/* Login Form */} {tab === "login" && (
{ setLoginEmail(e.target.value); setLoginError(""); }} className={inputClass(!!loginError)} + style={inputStyle} /> { setLoginPassword(e.target.value); setLoginError(""); }} className={inputClass(!!loginError)} + style={inputStyle} /> {loginError && (

— {loginError}

@@ -164,14 +167,16 @@ export default function AuthPage() {
)} - {/* Register Form */} {tab === "register" && (
{ setRegName(e.target.value); setRegError(""); }} className={inputClass(false)} + style={inputStyle} /> { setRegEmail(e.target.value); setRegError(""); }} className={inputClass(!!regError)} + style={inputStyle} /> { setRegPassword(e.target.value); setRegError(""); }} className={inputClass(!!regError)} + style={inputStyle} /> { setRegConfirm(e.target.value); setRegError(""); }} className={inputClass(!!regError && regPassword !== regConfirm)} + style={inputStyle} /> {regError && (

— {regError}

)} {regSuccess && ( -

✓ {regSuccess}

+

✓ {regSuccess}

)}
)} -
+
WYVIEW v1.0 /// CROWMATE
diff --git a/app/tiktok/layout.tsx b/app/tiktok/layout.tsx index fe65f98..fe8d587 100644 --- a/app/tiktok/layout.tsx +++ b/app/tiktok/layout.tsx @@ -1,29 +1,5 @@ -"use client"; - -import { useEffect } from "react"; -import { useRouter } from "next/navigation"; -import { useSession } from "next-auth/react"; -import Sidebar from "@/components/Sidebar"; +import AppLayout from "@/components/AppLayout"; export default function AuthLayout({ children }: { children: React.ReactNode }) { - const { status } = useSession(); - const router = useRouter(); - - useEffect(() => { - if (status === "unauthenticated") { - router.push("/"); - } - }, [status, router]); - - if (status === "loading") return null; - if (status !== "authenticated") return null; - - return ( -
- -
- {children} -
-
- ); + return {children}; } \ No newline at end of file diff --git a/app/tiktok/page.tsx b/app/tiktok/page.tsx index 4f79965..2f614d8 100644 --- a/app/tiktok/page.tsx +++ b/app/tiktok/page.tsx @@ -70,7 +70,7 @@ export default function TikTokPage() {
Plateforme
-

TikTok

+

TikTok

@@ -99,7 +99,7 @@ export default function TikTokPage() { {/* Chargement */} {loading && ( -
+
Chargement...
@@ -147,11 +147,11 @@ export default function TikTokPage() { )} - {/* Non connecté */} {!loading && !stats && !error && ( -
+
-

+

Connectez votre compte TikTok
pour afficher vos statistiques

)} - {/* Erreur API */} {!loading && error && ( -
+

{error}

-
diff --git a/app/twitch/layout.tsx b/app/twitch/layout.tsx index fe65f98..fe8d587 100644 --- a/app/twitch/layout.tsx +++ b/app/twitch/layout.tsx @@ -1,29 +1,5 @@ -"use client"; - -import { useEffect } from "react"; -import { useRouter } from "next/navigation"; -import { useSession } from "next-auth/react"; -import Sidebar from "@/components/Sidebar"; +import AppLayout from "@/components/AppLayout"; export default function AuthLayout({ children }: { children: React.ReactNode }) { - const { status } = useSession(); - const router = useRouter(); - - useEffect(() => { - if (status === "unauthenticated") { - router.push("/"); - } - }, [status, router]); - - if (status === "loading") return null; - if (status !== "authenticated") return null; - - return ( -
- -
- {children} -
-
- ); + return {children}; } \ No newline at end of file diff --git a/app/twitch/page.tsx b/app/twitch/page.tsx index 79c31ca..7642d45 100644 --- a/app/twitch/page.tsx +++ b/app/twitch/page.tsx @@ -10,7 +10,7 @@ export default function TwitchPage() {
Plateforme
-

Twitch

+

Twitch

@@ -21,9 +21,10 @@ export default function TwitchPage() {
-
+
-

+

CONNECTEZ VOTRE COMPTE TWITCH
POUR AFFICHER VOS STATISTIQUES

diff --git a/app/youtube/layout.tsx b/app/youtube/layout.tsx index fe65f98..fe8d587 100644 --- a/app/youtube/layout.tsx +++ b/app/youtube/layout.tsx @@ -1,29 +1,5 @@ -"use client"; - -import { useEffect } from "react"; -import { useRouter } from "next/navigation"; -import { useSession } from "next-auth/react"; -import Sidebar from "@/components/Sidebar"; +import AppLayout from "@/components/AppLayout"; export default function AuthLayout({ children }: { children: React.ReactNode }) { - const { status } = useSession(); - const router = useRouter(); - - useEffect(() => { - if (status === "unauthenticated") { - router.push("/"); - } - }, [status, router]); - - if (status === "loading") return null; - if (status !== "authenticated") return null; - - return ( -
- -
- {children} -
-
- ); + return {children}; } \ No newline at end of file diff --git a/app/youtube/page.tsx b/app/youtube/page.tsx index 6e39acd..9c4576e 100644 --- a/app/youtube/page.tsx +++ b/app/youtube/page.tsx @@ -10,7 +10,7 @@ export default function YoutubePage() {
Plateforme
-

YouTube

+

YouTube

@@ -21,9 +21,10 @@ export default function YoutubePage() {
-
+
-

+

CONNECTEZ VOTRE COMPTE YOUTUBE
POUR AFFICHER VOS STATISTIQUES

diff --git a/components/AppLayout.tsx b/components/AppLayout.tsx new file mode 100644 index 0000000..025744f --- /dev/null +++ b/components/AppLayout.tsx @@ -0,0 +1,41 @@ +"use client"; + +import { useEffect } from "react"; +import { useRouter } from "next/navigation"; +import { useSession } from "next-auth/react"; +import Sidebar from "@/components/Sidebar"; +import { useTheme } from "@/lib/theme"; + +export default function AppLayout({ children }: { children: React.ReactNode }) { + const { status } = useSession(); + const router = useRouter(); + const { theme } = useTheme(); + + useEffect(() => { + if (status === "unauthenticated") { + router.push("/"); + } + }, [status, router]); + + if (status === "loading") { + return ( +
+ + CHARGEMENT... + +
+ ); + } + + if (status !== "authenticated") return null; + + return ( +
+ +
+ {children} +
+
+ ); +} + diff --git a/components/DragonEye.tsx b/components/DragonEye.tsx index f67bbb0..1691173 100644 --- a/components/DragonEye.tsx +++ b/components/DragonEye.tsx @@ -1,9 +1,12 @@ "use client"; import { useEffect, useRef } from "react"; +import { useTheme } from "@/lib/theme"; export default function DragonEye({ size = 60 }: { size?: number }) { const irisRef = useRef(null); + const { theme } = useTheme(); + const isLight = theme === "light"; useEffect(() => { const handleMouseMove = (e: MouseEvent) => { @@ -26,6 +29,22 @@ export default function DragonEye({ size = 60 }: { size?: number }) { const h = size; const w = size * 1.6; + // Light theme: sky-blue palette + const glowColor = isLight ? "#38bdf8" : "#4aff8c"; + const eyeBg = isLight + ? "radial-gradient(ellipse at 40% 35%, #e0f7ff, #b8eeff)" + : "radial-gradient(ellipse at 40% 35%, #0a1a0a, #020402)"; + const eyeBorder = isLight ? "rgba(56,189,248,0.4)" : "rgba(74,255,140,0.25)"; + const eyeShadow = isLight + ? "0 0 20px rgba(56,189,248,0.25), inset 0 0 10px rgba(56,189,248,0.1)" + : "0 0 20px rgba(74,255,140,0.1), inset 0 0 20px rgba(0,0,0,0.8)"; + const irisBg = isLight + ? "radial-gradient(ellipse at 40% 35%, #7dd3fc 0%, #0ea5e9 35%, #0369a1 70%)" + : "radial-gradient(ellipse at 40% 35%, #1aff6a 0%, #0a8a3a 35%, #022a12 70%)"; + const irisShadow = isLight ? "0 0 12px rgba(56,189,248,0.6)" : "0 0 12px rgba(74,255,140,0.4)"; + const pupilBg = isLight ? "#001a2e" : "#010801"; + const eyelidBg = isLight ? "#dbeafe" : "#0a0d0f"; + return (
@@ -45,9 +64,9 @@ export default function DragonEye({ size = 60 }: { size?: number }) { className="absolute inset-0 overflow-hidden" style={{ borderRadius: "50%", - background: "radial-gradient(ellipse at 40% 35%, #0a1a0a, #020402)", - border: "1px solid rgba(74,255,140,0.25)", - boxShadow: "0 0 20px rgba(74,255,140,0.1), inset 0 0 20px rgba(0,0,0,0.8)", + background: eyeBg, + border: `1px solid ${eyeBorder}`, + boxShadow: eyeShadow, animation: "blink 9s ease-in-out infinite", }} > @@ -60,8 +79,8 @@ export default function DragonEye({ size = 60 }: { size?: number }) { width: h * 0.65, height: h * 0.65, borderRadius: "50%", - background: "radial-gradient(ellipse at 40% 35%, #1aff6a 0%, #0a8a3a 35%, #022a12 70%)", - boxShadow: "0 0 12px rgba(74,255,140,0.4)", + background: irisBg, + boxShadow: irisShadow, transition: "transform 0.08s ease-out", }} > @@ -72,19 +91,20 @@ export default function DragonEye({ size = 60 }: { size?: number }) { transform: "translate(-50%, -50%)", width: h * 0.1, height: h * 0.55, - background: "#010801", + background: pupilBg, borderRadius: "50%", boxShadow: "0 0 6px rgba(0,0,0,0.9)", animation: "pupilDilate 7s ease-in-out infinite", }} /> + {/* Highlight */}
{ signOut({ callbackUrl: "/" }); }; + const bg = isLight ? "bg-wy-light-surface" : "bg-wy-dark"; + const border = isLight ? "border-wy-light-border" : "border-wy-border"; + const textSec = isLight ? "text-wy-light-text-secondary" : "text-wy-text-secondary"; + const textPri = isLight ? "text-wy-light-text-primary" : "text-wy-text-primary"; + const title = isLight ? "text-wy-light-text-primary" : "text-white"; + return ( -