@@ -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'}
+
+
+
+
+ {theme === 'dark' ? (
+
+ ) : (
+
+ )}
+
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%);
}