diff --git a/index.html b/index.html index 4aa07c4..7032304 100644 --- a/index.html +++ b/index.html @@ -6,6 +6,14 @@ SalesPilot CRM — 你的業務成長引擎 + diff --git a/src/components/Navbar.jsx b/src/components/Navbar.jsx index 5e205a8..785cabc 100644 --- a/src/components/Navbar.jsx +++ b/src/components/Navbar.jsx @@ -1,8 +1,10 @@ import { useState } from 'react'; import { NAV_LINKS, BRAND } from '../data/navigation'; +import { useTheme } from '../context/ThemeContext'; function Navbar() { const [menuOpen, setMenuOpen] = useState(false); + const { theme, toggleTheme } = useTheme(); return (
@@ -39,6 +41,30 @@ function Navbar() { ))} + 預約 Demo diff --git a/src/context/ThemeContext.jsx b/src/context/ThemeContext.jsx new file mode 100644 index 0000000..bed033e --- /dev/null +++ b/src/context/ThemeContext.jsx @@ -0,0 +1,35 @@ +import { createContext, useContext, useState, useEffect, useCallback } from 'react'; + +const ThemeContext = createContext(null); + +const STORAGE_KEY = 'salespilot-theme'; + +function getInitialTheme() { + if (typeof window === 'undefined') return 'dark'; + return localStorage.getItem(STORAGE_KEY) || 'dark'; +} + +export function ThemeProvider({ children }) { + const [theme, setTheme] = useState(getInitialTheme); + + useEffect(() => { + document.documentElement.dataset.theme = theme; + localStorage.setItem(STORAGE_KEY, theme); + }, [theme]); + + const toggleTheme = useCallback(() => { + setTheme((prev) => (prev === 'dark' ? 'light' : 'dark')); + }, []); + + return ( + + {children} + + ); +} + +export function useTheme() { + const ctx = useContext(ThemeContext); + if (!ctx) throw new Error('useTheme must be used within a ThemeProvider'); + return ctx; +} diff --git a/src/index.css b/src/index.css index 507bc0c..0c8dab9 100644 --- a/src/index.css +++ b/src/index.css @@ -10,6 +10,7 @@ --color-bg-card: #1a2035; --color-bg-card-hover: #1f2847; --color-surface: #252d44; + --color-navbar-bg: rgba(10, 14, 26, 0.8); --color-primary: #6366f1; --color-primary-light: #818cf8; @@ -84,6 +85,34 @@ --navbar-height: 72px; } +/* --- Light Theme --- */ +[data-theme="light"] { + --color-bg: #f8fafc; + --color-bg-elevated: #f1f5f9; + --color-bg-card: #ffffff; + --color-bg-card-hover: #f8fafc; + --color-surface: #e2e8f0; + --color-navbar-bg: rgba(248, 250, 252, 0.85); + + --color-primary-light: #6366f1; + --color-primary-glow: rgba(99, 102, 241, 0.12); + + --color-accent-light: #0891b2; + + --color-text: #0f172a; + --color-text-secondary: #475569; + --color-text-muted: #94a3b8; + --color-text-inverse: #f1f5f9; + + --color-border: rgba(0, 0, 0, 0.08); + --color-border-hover: rgba(0, 0, 0, 0.15); + + --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.06); + --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.08); + --shadow-lg: 0 8px 32px rgba(0, 0, 0, 0.1); + --shadow-glow: 0 0 40px var(--color-primary-glow); +} + /* --- Reset & Base --- */ *, *::before, @@ -256,7 +285,7 @@ button { right: 0; height: var(--navbar-height); z-index: 1000; - background: rgba(10, 14, 26, 0.8); + background: var(--color-navbar-bg); backdrop-filter: blur(16px); border-bottom: 1px solid var(--color-border); } @@ -320,6 +349,23 @@ button { width: 100%; } +.theme-toggle { + display: flex; + align-items: center; + justify-content: center; + width: 36px; + height: 36px; + border-radius: var(--radius-md); + color: var(--color-text-secondary); + transition: all var(--transition-fast); + flex-shrink: 0; +} + +.theme-toggle:hover { + color: var(--color-primary-light); + background: var(--color-primary-glow); +} + .navbar__toggle { display: none; flex-direction: column; @@ -432,7 +478,7 @@ button { font-weight: 800; line-height: 1.15; margin-bottom: var(--space-6); - background: linear-gradient(135deg, #fff 0%, var(--color-primary-light) 50%, var(--color-accent-light) 100%); + background: linear-gradient(135deg, var(--color-text) 0%, var(--color-primary-light) 50%, var(--color-accent-light) 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; diff --git a/src/main.jsx b/src/main.jsx index 644bee6..2c4fa9f 100644 --- a/src/main.jsx +++ b/src/main.jsx @@ -1,10 +1,13 @@ import React from 'react'; import ReactDOM from 'react-dom/client'; +import { ThemeProvider } from './context/ThemeContext'; import App from './App'; import './index.css'; ReactDOM.createRoot(document.getElementById('root')).render( - + + + , );