From 10fd9cdecb0a164530068a3cd41a95732639d051 Mon Sep 17 00:00:00 2001 From: M1ngdaXie <156019134+M1ngdaXie@users.noreply.github.com> Date: Sun, 8 Feb 2026 16:23:06 -0800 Subject: [PATCH] dark mode --- frontend/.gitignore | 2 + frontend/index.html | 4 +- frontend/public/apple-touch-icon.png | Bin 0 -> 6653 bytes frontend/public/docnest-icon-32.png | Bin 0 -> 744 bytes frontend/public/docnest-icon-64.png | Bin 0 -> 2191 bytes frontend/src/components/Navbar.tsx | 11 ++++- frontend/src/components/ThemeToggle.tsx | 35 +++++++++++++ frontend/src/index.css | 63 ++++++++++++++++++++++++ frontend/src/lib/theme.ts | 37 ++++++++++++++ frontend/src/main.tsx | 3 ++ frontend/src/pages/LandingPage.css | 13 +++++ frontend/src/pages/LandingPage.tsx | 11 ++++- frontend/src/pages/LoginPage.css | 24 ++++++++- frontend/src/pages/LoginPage.tsx | 10 +++- 14 files changed, 207 insertions(+), 6 deletions(-) create mode 100644 frontend/public/apple-touch-icon.png create mode 100644 frontend/public/docnest-icon-32.png create mode 100644 frontend/public/docnest-icon-64.png create mode 100644 frontend/src/components/ThemeToggle.tsx create mode 100644 frontend/src/lib/theme.ts diff --git a/frontend/.gitignore b/frontend/.gitignore index a0f88c9..3b64204 100644 --- a/frontend/.gitignore +++ b/frontend/.gitignore @@ -24,3 +24,5 @@ dist-ssr *.sw? .env .env.local + +/src/assets diff --git a/frontend/index.html b/frontend/index.html index 5af9ea3..6c8b4bd 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -2,7 +2,9 @@ - + + + Realtime Collab diff --git a/frontend/public/apple-touch-icon.png b/frontend/public/apple-touch-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..cc02814d4c97e269119c1aaa217a157d4788f3b1 GIT binary patch literal 6653 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 SoT9FE07`P|vSrfdU;YP#MdJDZ literal 0 HcmV?d00001 diff --git a/frontend/public/docnest-icon-32.png b/frontend/public/docnest-icon-32.png new file mode 100644 index 0000000000000000000000000000000000000000..3d736b0b307ae6e630395a3eabae65ecbeea21b7 GIT binary patch literal 744 zcmVP)8lSXp1%4}mVrWW`szc6(^ns^CPhOhrIz9`I~lKnM=w6?qLt-Hj?hQuGa^YS znrh46$EHb6)A~QD7CpLtl#x`I8R4>=Q~=VGQquh#mt9j9?>I`d!{o?x!0D?G!88uf z!o^vLb_oLmgS?gvUipXDjxc=t@rU91xdRN>?mdH9w%=4+-VuuwQH6U zRAZ3yfnjeeD}#xa93iFC7#J8xa{$axkT1D7P_=@@V8FThH^YS~2tGc*LhUHXcR0(? z)z-|w#c_oC4k)Xt#VbE`$xbj0N(00K7Ge~^f;>CM9VMtiVlX*u(Lyx`a6t_w6a~mp zK~)F9fSY#!1GNDQF^WLJD^*|2@T|EPYcP`={6sqdWO(R5S+FBMbWS8HH&E39AYh=c z%V5Bu%Rs4xNZ=ocU?Dc%K{?>@%a24`c;?z8LQ0rG1i>m3RB?z4^D__wUcUXv08$I0 zk-!1;y5P}^5C1`GOts}135LMT`Kuxg^mUgrkO9n%G#Ri}M92wxW}u6qn~B%ea+=ovr!3w9ugj77Ak1Hu*MKYs zqhWF|c__Q|^woy~a+=l~plTYR4g$9qa5?}KN63bM{r(&70Ccrj@P1@DC_4dJFVq2F zL2M=@!TB(DQ_pM^N9ET}K(=&0o;D)57J|y-tdT%b!N9;!3?fKtI8p&11%0xqw){MJ z2!Ozp#XIKz|Noz6jyiqy;Z_(MWI2dt#N)~trrPqERI(TprztSLiIyA_BO@a?BpC5% z`VWmOiUFuRfB{h9gDl60PvfH(ALL)Y{dkLkfq@N+^lxY)W=0bSl``0h&TLa{c~C=i aZ~*`~ina${L#QhN0000r literal 0 HcmV?d00001 diff --git a/frontend/public/docnest-icon-64.png b/frontend/public/docnest-icon-64.png new file mode 100644 index 0000000000000000000000000000000000000000..59230892bdecbd2fb18cc20c9122b67f5c8ac237 GIT binary patch literal 2191 zcmV;A2ypj_P)}2s7j$zCa5S#p)6XOZUWS#C31+$sB@dNGJJGhPTh6!R07+w-1Ip1$r$_M zJKH2|{3Ofv`|0<2pZEEA-^ajB+{8`%KO<64C0S9w0bmiwGUot%9KZ(vGyoq0@Cg9_ z0B{+=y8v!Wa7^F$m5DjA#%OtHq!8g)W_husT>y~aSf&v`tXR?}IF?Zp95Vu-e6gs3 zZ;Jm%R@8ermN^Tcp;)3WFu7zQe|c!6Fc-j50BPz&5{1p75R z&U|NAZ~4;Yf0wPWzuVKC@~eUR*t~sjnNOx_UYfF^KJ2!n8=S_3IuL7&R(-dpIpur7 z(IW?m=tPWLz1ERL;YGT4cJ=O`mH?6{>_NyFzcS&gJ`n-H8=JT9ZLgu)?^>Ian`A}( z>2w?r+5pY;dS{>T?197j^-{yd`HSyabXZo@`#n~jGdP^5JDJ`UL=h6mmUqIGIbR(t z^U(^COrkxon#_I+$UB%qk5`kvwK++*EdaKLN`R7f343zS)m?w_J&W+zx4)_ne(TPk z;}=hE(}}Wa?UyTMww@(FtTqq_5D^NaW1IM<_<_&}kl+~oqpN{t*o!Ra8=8;g*M5!s zZ@%tp=~z)LX%7Mjj{rj>1*}=SuI~EjO!g`Q&b@P)PK5p!SLwtJ0OUgJ2!#Mk7V^js zpRBvS6L%01mOXqzCju=8pNNJo1YR;*`w5|GfuWH?#p4QE3p}@XdtmKxtbY8aBTxbu8x?3jd#<7d?0&te0o-QP zsk|KlEQMP_+YxG?Oz3y=%3Uf-ZIA?_4!Rp$>?!A1DM5_6Y9xO z*dQ50sWAad-N6oM4>c`Nw}DKbP<^2XIA$0bT0r9 zrx~J|aG4Dvh@*1X+FG74>)GnQV5S{Caxii9$ia4dnJWF6_*=~c2m;23%`@M%ww6bX z9olQ+l9=OXb`htUODLVm9sxjS;v3EMHEY*hltiI27_Z=1=Aoib}h) zwg98)BSk+=yI6t8-Om7IMSXp6IDfB&{oj{Ffvu_qBvJSaQNOdR_h*ICu`l8Vg{-J2 zY=b9!!TQqRR#_4SlD@}^C2c@f)Vh90nMsg;GB})HX&d~QBnod^6Cz$h&0Cw3yNq?a zK@x@EW0uc430U)h#)9`GQMk=sKH{a(&aPgv>JGIwC&}`IL5yQd7V>){k;o)w5VE5F zfPR`X&18px6Gl0fN%KwdbAEoBijzhd9L|$~4D{eL2)GPf2gfoi_@?-4PI-}9JCYT3 zCxCAOm|YZbj{~?%5`~gmfk?eA%Zl1b$M%?|;8^AsFTeIh{B~3>mm?R8+E?g@$zn+( zTX_Zj09h<) - + DocNest DocNest {/* User Section */}
+ {user.avatar_url && ( (() => getPreferredTheme()); + + useEffect(() => { + applyTheme(theme); + }, [theme]); + + const nextTheme: ThemeMode = theme === "dark" ? "light" : "dark"; + + return ( + + ); +} + +export default ThemeToggle; diff --git a/frontend/src/index.css b/frontend/src/index.css index 8c5fa47..4180645 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -27,6 +27,28 @@ --ring: 214 89% 52%; --radius: 0.75rem; } + + .dark { + --background: 215 26% 7%; + --foreground: 0 0% 98%; + --card: 215 21% 11%; + --card-foreground: 0 0% 98%; + --popover: 215 21% 11%; + --popover-foreground: 0 0% 98%; + --primary: 213 93% 60%; + --primary-foreground: 0 0% 100%; + --secondary: 173 70% 42%; + --secondary-foreground: 0 0% 100%; + --muted: 215 15% 15%; + --muted-foreground: 215 10% 58%; + --accent: 197 100% 68%; + --accent-foreground: 215 26% 7%; + --destructive: 0 70% 52%; + --destructive-foreground: 0 0% 100%; + --border: 215 12% 21%; + --input: 215 12% 21%; + --ring: 213 93% 60%; + } } * { @@ -81,6 +103,47 @@ --pixel-text-muted: #64748B; } + .dark { + --surface: 215 21% 11%; + --surface-muted: 215 15% 15%; + --text-primary: 0 0% 98%; + --text-secondary: 215 15% 82%; + --text-muted: 215 10% 70%; + --brand: 213 93% 60%; + --brand-dark: 213 90% 52%; + --brand-teal: 173 70% 42%; + --brand-teal-dark: 173 68% 34%; + + --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.45); + --shadow-md: 0 12px 30px rgba(0, 0, 0, 0.55); + --shadow-lg: 0 20px 50px rgba(0, 0, 0, 0.65); + --focus-ring: 0 0 0 3px rgba(88, 166, 255, 0.35); + --gradient-hero: linear-gradient(120deg, #0d1117 0%, #111827 55%, #161b22 100%); + --gradient-accent: linear-gradient(120deg, #2f81f7 0%, #14b8a6 100%); + + --pixel-purple-deep: #0b1f4b; + --pixel-purple-bright: #2f81f7; + --pixel-pink-vibrant: #58a6ff; + --pixel-cyan-bright: #14b8a6; + --pixel-orange-warm: #f59e0b; + --pixel-yellow-gold: #fbbf24; + --pixel-green-lime: #22c55e; + --pixel-green-forest: #16a34a; + + --pixel-bg-dark: #0d1117; + --pixel-bg-medium: #161b22; + --pixel-bg-light: #1f2937; + --pixel-panel: #0f172a; + --pixel-white: #e5e7eb; + + --pixel-shadow-dark: rgba(0, 0, 0, 0.5); + --pixel-outline: #30363d; + + --pixel-text-primary: #e5e7eb; + --pixel-text-secondary: #c9d1d9; + --pixel-text-muted: #8b949e; + } + body { font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; diff --git a/frontend/src/lib/theme.ts b/frontend/src/lib/theme.ts new file mode 100644 index 0000000..c1e2afc --- /dev/null +++ b/frontend/src/lib/theme.ts @@ -0,0 +1,37 @@ +export type ThemeMode = "light" | "dark"; + +export const getStoredTheme = (): ThemeMode | null => { + try { + const value = localStorage.getItem("theme"); + if (value === "light" || value === "dark") { + return value; + } + } catch { + // Ignore storage access errors + } + return null; +}; + +export const getPreferredTheme = (): ThemeMode => { + const stored = getStoredTheme(); + if (stored) return stored; + + if (typeof window !== "undefined" && window.matchMedia) { + return window.matchMedia("(prefers-color-scheme: dark)").matches + ? "dark" + : "light"; + } + + return "light"; +}; + +export const applyTheme = (theme: ThemeMode) => { + if (typeof document === "undefined") return; + document.documentElement.classList.toggle("dark", theme === "dark"); + + try { + localStorage.setItem("theme", theme); + } catch { + // Ignore storage access errors + } +}; diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx index 966f17a..12f2b2d 100644 --- a/frontend/src/main.tsx +++ b/frontend/src/main.tsx @@ -1,8 +1,11 @@ import React from "react"; import ReactDOM from "react-dom/client"; import App from "./App.tsx"; +import { applyTheme, getPreferredTheme } from "./lib/theme"; import "./index.css"; +applyTheme(getPreferredTheme()); + ReactDOM.createRoot(document.getElementById("root")!).render( diff --git a/frontend/src/pages/LandingPage.css b/frontend/src/pages/LandingPage.css index ef76fc9..5d49099 100644 --- a/frontend/src/pages/LandingPage.css +++ b/frontend/src/pages/LandingPage.css @@ -6,6 +6,13 @@ background: hsl(var(--background)); } +.landing-theme-toggle { + position: fixed; + top: 24px; + right: 24px; + z-index: 20; +} + /* ======================================== Hero Section ======================================== */ @@ -50,6 +57,12 @@ margin-bottom: 1.5rem; } +.hero-logo-icon { + width: 28px; + height: 28px; + image-rendering: pixelated; +} + .hero-brand { font-size: 0.95rem; font-weight: 700; diff --git a/frontend/src/pages/LandingPage.tsx b/frontend/src/pages/LandingPage.tsx index ff69c5f..3f7a8ff 100644 --- a/frontend/src/pages/LandingPage.tsx +++ b/frontend/src/pages/LandingPage.tsx @@ -1,5 +1,7 @@ import FloatingGem from '../components/PixelSprites/FloatingGem'; import PixelIcon from '../components/PixelIcon/PixelIcon'; +import DocNestLogo from '../assets/docnest/docnest-icon-128.png'; +import ThemeToggle from '../components/ThemeToggle'; import { API_BASE_URL } from '../config'; import './LandingPage.css'; @@ -14,6 +16,9 @@ function LandingPage() { return (
+
+ +
{/* Hero Section */}
@@ -26,7 +31,11 @@ function LandingPage() {
- + DocNest DocNest
diff --git a/frontend/src/pages/LoginPage.css b/frontend/src/pages/LoginPage.css index f65d818..c239326 100644 --- a/frontend/src/pages/LoginPage.css +++ b/frontend/src/pages/LoginPage.css @@ -5,6 +5,7 @@ justify-content: center; background: var(--gradient-hero); padding: 24px; + position: relative; } .login-container { @@ -18,11 +19,32 @@ text-align: center; } +.login-theme-toggle { + position: fixed; + top: 24px; + right: 24px; + z-index: 20; +} + +.login-brand { + display: flex; + align-items: center; + justify-content: center; + gap: 12px; + margin-bottom: 8px; +} + +.login-logo { + width: 32px; + height: 32px; + image-rendering: pixelated; +} + .login-title { font-size: 32px; font-weight: 700; color: hsl(var(--text-primary)); - margin: 0 0 8px 0; + margin: 0; } .login-subtitle { diff --git a/frontend/src/pages/LoginPage.tsx b/frontend/src/pages/LoginPage.tsx index 228561b..80225b8 100644 --- a/frontend/src/pages/LoginPage.tsx +++ b/frontend/src/pages/LoginPage.tsx @@ -2,6 +2,8 @@ import { useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; import { useAuth } from '../contexts/AuthContext'; import { API_BASE_URL } from '../config'; +import DocNestLogo from '../assets/docnest/docnest-icon-128.png'; +import ThemeToggle from '../components/ThemeToggle'; import './LoginPage.css'; function LoginPage() { @@ -34,8 +36,14 @@ function LoginPage() { return (
+
+ +
-

DocNest

+
+ DocNest +

DocNest

+

Collaborate in real time with your team