diff --git a/new-frontend/src/App.tsx b/new-frontend/src/App.tsx index 542319c..6c621e5 100644 --- a/new-frontend/src/App.tsx +++ b/new-frontend/src/App.tsx @@ -1,4 +1,5 @@ import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom' +import { ThemeProvider } from './contexts/ThemeContext' import { AuthProvider } from './contexts/AuthContext' import { TimerProvider } from './contexts/TimerContext' import { LandingPage } from './pages/LandingPage' @@ -18,11 +19,12 @@ import { ProfilePage } from './pages/ProfilePage' export function App() { return ( - - - - {/* Rotas Públicas */} - } /> + + + + + {/* Rotas Públicas */} + } /> } /> } /> @@ -49,8 +51,9 @@ export function App() { {/* Fallback */} } /> - - + + + ) } diff --git a/new-frontend/src/components/landing/Navbar.tsx b/new-frontend/src/components/landing/Navbar.tsx index cfa5fad..d1b4217 100644 --- a/new-frontend/src/components/landing/Navbar.tsx +++ b/new-frontend/src/components/landing/Navbar.tsx @@ -1,8 +1,10 @@ import { Link } from "react-router-dom" import { Button, Chip, ChipLabel } from "@heroui/react" -import { ArrowRight } from "lucide-react" +import { ArrowRight, Sun, Moon } from "lucide-react" +import { useTheme } from "../../contexts/ThemeContext" export const Navbar = () => { + const { theme, toggleTheme } = useTheme() return (
@@ -62,6 +64,20 @@ export const Navbar = () => { {/* Actions */}
+ + void @@ -29,6 +32,7 @@ interface HeaderProps { export const Header = ({ onToggleMobileSidebar }: HeaderProps) => { const { user, activeOrg, setActiveOrg, logout } = useAuth() + const { theme, toggleTheme } = useTheme() const { activeTask, activeSeconds, stopTimer } = useTimer() const [showOrgDropdown, setShowOrgDropdown] = useState(false) const [showUserDropdown, setShowUserDropdown] = useState(false) @@ -206,6 +210,21 @@ export const Header = ({ onToggleMobileSidebar }: HeaderProps) => { Tarefas + {/* Theme Toggle Button */} + + {/* User Profile Menu Dropdown */}
diff --git a/new-frontend/src/components/layout/Sidebar.tsx b/new-frontend/src/components/layout/Sidebar.tsx index 61cd747..005d791 100644 --- a/new-frontend/src/components/layout/Sidebar.tsx +++ b/new-frontend/src/components/layout/Sidebar.tsx @@ -9,9 +9,12 @@ import { Settings, X, Building2, + Sun, + Moon, } from 'lucide-react' import { Chip, ChipLabel } from '@heroui/react' import { useAuth } from '../../contexts/AuthContext' +import { useTheme } from '../../contexts/ThemeContext' interface SidebarProps { isMobileOpen: boolean @@ -20,6 +23,7 @@ interface SidebarProps { export const Sidebar = ({ isMobileOpen, onCloseMobile }: SidebarProps) => { const { activeOrg } = useAuth() + const { theme, toggleTheme } = useTheme() const navItems = [ { @@ -111,18 +115,34 @@ export const Sidebar = ({ isMobileOpen, onCloseMobile }: SidebarProps) => { {/* Bottom Workspace Card Info */}
-
-
- -
-
-

- {activeOrg?.name || 'Workspace Padrão'} -

- - {activeOrg?.roles[0] || 'Ativo'} - +
+
+
+ +
+
+

+ {activeOrg?.name || 'Workspace Padrão'} +

+ + {activeOrg?.roles[0] || 'Ativo'} + +
+ +
diff --git a/new-frontend/src/contexts/ThemeContext.tsx b/new-frontend/src/contexts/ThemeContext.tsx new file mode 100644 index 0000000..4bbb3ff --- /dev/null +++ b/new-frontend/src/contexts/ThemeContext.tsx @@ -0,0 +1,56 @@ +import React, { createContext, useContext, useState, useEffect } from 'react' + +type Theme = 'light' | 'dark' + +interface ThemeContextType { + theme: Theme + toggleTheme: () => void + setTheme: (theme: Theme) => void +} + +const ThemeContext = createContext(undefined) + +export const ThemeProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => { + const [theme, setThemeState] = useState(() => { + const saved = localStorage.getItem('bee_theme') as Theme | null + if (saved === 'light' || saved === 'dark') { + return saved + } + // Default to dark theme for modern developer dashboard experience + return 'dark' + }) + + useEffect(() => { + const root = document.documentElement + if (theme === 'dark') { + root.classList.add('dark') + root.classList.remove('light') + } else { + root.classList.remove('dark') + root.classList.add('light') + } + localStorage.setItem('bee_theme', theme) + }, [theme]) + + const toggleTheme = () => { + setThemeState((prev) => (prev === 'dark' ? 'light' : 'dark')) + } + + const setTheme = (newTheme: Theme) => { + setThemeState(newTheme) + } + + return ( + + {children} + + ) +} + +export const useTheme = (): ThemeContextType => { + const ctx = useContext(ThemeContext) + if (!ctx) { + throw new Error('useTheme must be used within a ThemeProvider') + } + return ctx +} diff --git a/new-frontend/src/index.css b/new-frontend/src/index.css index b8a5e24..d12ec7e 100644 --- a/new-frontend/src/index.css +++ b/new-frontend/src/index.css @@ -1,37 +1,85 @@ @import "tailwindcss"; @config "../tailwind.config.js"; +:root { + --app-bg: #f5f1e8; + --app-bg-strong: #ebe4d7; + --surface: #ffffff; + --surface-muted: #f6efe2; + --surface-raised: #fbf8f1; + --surface-sunken: #ece5d6; + --border: #e2d7c3; + --border-soft: #e7dcc9; + --border-strong: #cdbba0; + --text-main: #1c1917; + --text-muted: #78716c; + --foreground: #1c1917; + --muted: #78716c; + --brand-soft: #ccfbf1; + --accent-soft: #ffedd5; + --shadow-panel: 0 22px 60px rgba(79, 62, 35, 0.08), 0 6px 18px rgba(79, 62, 35, 0.06); + color-scheme: light; +} + +.dark { + --app-bg: #090d16; + --app-bg-strong: #0f141f; + --surface: #111726; + --surface-muted: #171e30; + --surface-raised: #182033; + --surface-sunken: #0c111c; + --border: #1e293b; + --border-soft: #1e293b; + --border-strong: #334155; + --text-main: #f8fafc; + --text-muted: #94a3b8; + --foreground: #f8fafc; + --muted: #94a3b8; + --brand-soft: rgba(15, 118, 110, 0.2); + --accent-soft: rgba(217, 119, 6, 0.2); + --shadow-panel: 0 22px 60px rgba(0, 0, 0, 0.4), 0 6px 18px rgba(0, 0, 0, 0.25); + color-scheme: dark; +} + @theme { --font-sans: 'Plus Jakarta Sans', ui-sans-serif, system-ui, sans-serif; --font-mono: 'JetBrains Mono', ui-monospace, monospace; - --color-app-bg: #f5f1e8; - --color-app-bg-strong: #ebe4d7; - --color-surface: #fffdf8; - --color-surface-muted: #f6efe2; - --color-border-soft: #e7dcc9; - --color-border-strong: #cdbba0; - --color-text-main: #1f2937; - --color-text-muted: #6b7280; + --color-app-bg: var(--app-bg); + --color-app-bg-strong: var(--app-bg-strong); + --color-surface: var(--surface); + --color-surface-muted: var(--surface-muted); + --color-surface-raised: var(--surface-raised); + --color-surface-sunken: var(--surface-sunken); + --color-border: var(--border); + --color-border-soft: var(--border-soft); + --color-border-strong: var(--border-strong); + --color-text-main: var(--text-main); + --color-text-muted: var(--text-muted); + --color-foreground: var(--foreground); + --color-muted: var(--muted); + --color-brand: #0f766e; + --color-brand-hover: #115e59; --color-brand-strong: #115e59; - --color-brand-soft: #ccfbf1; + --color-brand-soft: var(--brand-soft); + --color-accent: #d97706; - --color-accent-soft: #ffedd5; + --color-accent-hover: #b45309; + --color-accent-soft: var(--accent-soft); --color-success: #10b981; - --color-success-soft: #ecfdf5; + --color-success-soft: rgba(16, 185, 129, 0.15); --color-warning: #f59e0b; - --color-warning-soft: #fffbeb; + --color-warning-soft: rgba(245, 158, 11, 0.15); --color-danger: #ef4444; - --color-danger-soft: #fef2f2; + --color-danger-soft: rgba(239, 68, 68, 0.15); - --shadow-panel: - 0 22px 60px rgba(79, 62, 35, 0.08), 0 6px 18px rgba(79, 62, 35, 0.06); + --shadow-panel: var(--shadow-panel); } :root { - color: var(--color-text-main); + color: var(--color-foreground); background-color: var(--color-app-bg); font-family: var(--font-sans); font-synthesis: none; @@ -52,8 +100,19 @@ body, body { margin: 0; - background: - radial-gradient(circle at top left, rgba(217, 119, 6, 0.12), transparent 28%), - radial-gradient(circle at top right, rgba(15, 118, 110, 0.14), transparent 24%), - linear-gradient(180deg, var(--color-app-bg) 0%, #f8f5ef 100%); + transition: background-color 0.2s ease, color 0.2s ease; +} + +html.dark body { + background: + radial-gradient(circle at top left, rgba(217, 119, 6, 0.08), transparent 28%), + radial-gradient(circle at top right, rgba(15, 118, 110, 0.12), transparent 24%), + linear-gradient(180deg, var(--app-bg) 0%, #060910 100%); +} + +html:not(.dark) body { + background: + radial-gradient(circle at top left, rgba(217, 119, 6, 0.08), transparent 28%), + radial-gradient(circle at top right, rgba(15, 118, 110, 0.08), transparent 24%), + linear-gradient(180deg, var(--app-bg) 0%, #faf7f0 100%); }