fix: ajustar contraste e cor das fontes do menu lateral, adicionar alternancia de modo Claro/Escuro (Theme Toggle) e responsividade para PC, Tablet e Celular
Build and Deploy (Gitea Actions) / build-and-deploy (push) Successful in 2m41s Details

This commit is contained in:
Sidney 2026-07-19 21:34:55 -03:00
parent 1876172d78
commit 70c1b8cb19
2 changed files with 180 additions and 10 deletions

View File

@ -1,27 +1,27 @@
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap'); @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap');
:root { :root, [data-theme="dark"] {
--bg-primary: #0a0a0f; --bg-primary: #0a0a0f;
--bg-secondary: #12121a; --bg-secondary: #12121a;
--bg-card: #1a1a2e; --bg-card: #1a1a2e;
--bg-card-hover: #22223a; --bg-card-hover: #22223a;
--bg-elevated: #252540; --bg-elevated: #252540;
--border-color: rgba(255,255,255,0.06); --border-color: rgba(255,255,255,0.09);
--border-active: rgba(108,99,255,0.5); --border-active: rgba(108,99,255,0.5);
--text-primary: #f0f0f5; --text-primary: #f8fafc;
--text-secondary: #8888a0; --text-secondary: #cbd5e1;
--text-muted: #55556a; --text-muted: #94a3b8;
--accent: #6C63FF; --accent: #6C63FF;
--accent-hover: #5a52e0; --accent-hover: #5a52e0;
--accent-glow: rgba(108,99,255,0.25); --accent-glow: rgba(108,99,255,0.25);
--success: #22c55e; --success: #22c55e;
--success-bg: rgba(34,197,94,0.1); --success-bg: rgba(34,197,94,0.12);
--warning: #f59e0b; --warning: #f59e0b;
--warning-bg: rgba(245,158,11,0.1); --warning-bg: rgba(245,158,11,0.12);
--danger: #ef4444; --danger: #ef4444;
--danger-bg: rgba(239,68,68,0.1); --danger-bg: rgba(239,68,68,0.12);
--info: #3b82f6; --info: #3b82f6;
--info-bg: rgba(59,130,246,0.1); --info-bg: rgba(59,130,246,0.12);
--gradient-primary: linear-gradient(135deg, #6C63FF 0%, #a855f7 100%); --gradient-primary: linear-gradient(135deg, #6C63FF 0%, #a855f7 100%);
--gradient-card: linear-gradient(145deg, rgba(26,26,46,0.8), rgba(18,18,26,0.9)); --gradient-card: linear-gradient(145deg, rgba(26,26,46,0.8), rgba(18,18,26,0.9));
--shadow-sm: 0 2px 8px rgba(0,0,0,0.3); --shadow-sm: 0 2px 8px rgba(0,0,0,0.3);
@ -34,6 +34,36 @@
--radius-xl: 24px; --radius-xl: 24px;
} }
[data-theme="light"] {
--bg-primary: #f8fafc;
--bg-secondary: #ffffff;
--bg-card: #ffffff;
--bg-card-hover: #f1f5f9;
--bg-elevated: #f1f5f9;
--border-color: #e2e8f0;
--border-active: #6C63FF;
--text-primary: #0f172a;
--text-secondary: #475569;
--text-muted: #64748b;
--accent: #6C63FF;
--accent-hover: #5a52e0;
--accent-glow: rgba(108,99,255,0.12);
--success: #16a34a;
--success-bg: rgba(22,163,74,0.1);
--warning: #d97706;
--warning-bg: rgba(217,119,6,0.1);
--danger: #dc2626;
--danger-bg: rgba(220,38,38,0.1);
--info: #2563eb;
--info-bg: rgba(37,99,235,0.1);
--gradient-primary: linear-gradient(135deg, #6C63FF 0%, #8b5cf6 100%);
--gradient-card: linear-gradient(145deg, #ffffff, #f8fafc);
--shadow-sm: 0 1px 3px rgba(0,0,0,0.08);
--shadow-md: 0 4px 12px rgba(0,0,0,0.08);
--shadow-lg: 0 10px 25px rgba(0,0,0,0.1);
--shadow-glow: 0 0 20px rgba(108,99,255,0.1);
}
* { margin: 0; padding: 0; box-sizing: border-box; } * { margin: 0; padding: 0; box-sizing: border-box; }
html, body { height: 100%; } html, body { height: 100%; }
@ -1016,3 +1046,119 @@ tr:hover td { background: var(--bg-card-hover); }
font-weight: 600; font-weight: 600;
box-shadow: 0 2px 10px rgba(108, 99, 255, 0.4); box-shadow: 0 2px 10px rgba(108, 99, 255, 0.4);
} }
/* === RESPONSIVE BREAKPOINTS (PC, TABLET, MOBILE) === */
/* Desktop & Laptop (> 1024px) */
@media (min-width: 1025px) {
.mobile-close-btn { display: none !important; }
}
/* Tablet (769px - 1024px) */
@media (max-width: 1024px) and (min-width: 769px) {
.main-content { margin-left: 240px; }
.main-content.collapsed { margin-left: 76px; }
.stats-grid { grid-template-columns: repeat(2, 1fr); }
.page-content { padding: 24px; }
.topbar { padding: 16px 24px; }
}
/* Mobile (<= 768px) */
@media (max-width: 768px) {
.sidebar {
position: fixed;
top: 0;
left: 0;
bottom: 0;
width: 280px !important;
z-index: 1000;
transform: translateX(-100%);
transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1);
box-shadow: 0 0 40px rgba(0,0,0,0.5);
}
.sidebar.open {
transform: translateX(0);
}
.desktop-collapse-btn { display: none !important; }
.mobile-close-btn { display: flex !important; }
.main-content, .main-content.collapsed {
margin-left: 0 !important;
width: 100% !important;
}
.topbar {
padding: 14px 16px;
}
.topbar-left h1 {
font-size: 18px;
}
.search-box {
display: none;
}
.page-content {
padding: 16px;
}
.stats-grid {
grid-template-columns: 1fr;
}
.grid-2, .grid-3 {
grid-template-columns: 1fr;
}
.view-mode-selector {
width: 100%;
justify-content: space-between;
}
.view-mode-btn {
flex: 1;
justify-content: center;
padding: 8px 6px;
font-size: 12px;
}
}
/* === LIGHT THEME OVERRIDES === */
[data-theme="light"] .sidebar {
background: #ffffff;
border-right: 1px solid #e2e8f0;
}
[data-theme="light"] .topbar {
background: rgba(255, 255, 255, 0.9);
border-bottom: 1px solid #e2e8f0;
}
[data-theme="light"] .nav-item {
color: #475569;
}
[data-theme="light"] .nav-item:hover {
background: #f1f5f9;
color: #0f172a;
}
[data-theme="light"] .nav-item.active {
background: rgba(108, 99, 255, 0.12);
color: #6C63FF;
}
[data-theme="light"] .card {
background: #ffffff;
border-color: #e2e8f0;
box-shadow: 0 1px 4px rgba(0,0,0,0.05);
}
[data-theme="light"] .form-input, [data-theme="light"] .form-select {
background: #f8fafc;
border-color: #cbd5e1;
color: #0f172a;
}

View File

@ -1,5 +1,5 @@
import { useState, useEffect, useRef } from 'react'; import { useState, useEffect, useRef } from 'react';
import { Bell, Menu, Search, LogOut, User, CheckCircle, AlertCircle } from 'lucide-react'; import { Bell, Menu, Search, LogOut, User, CheckCircle, AlertCircle, Sun, Moon } from 'lucide-react';
interface TopbarProps { interface TopbarProps {
title: string; title: string;
@ -18,6 +18,7 @@ export default function Topbar({ title, subtitle, onMenuClick, onNavigate }: Top
const [avatarInitials, setAvatarInitials] = useState('AD'); const [avatarInitials, setAvatarInitials] = useState('AD');
const [tenantName, setTenantName] = useState('Administrador'); const [tenantName, setTenantName] = useState('Administrador');
const [email, setEmail] = useState('admin@agendapro.com'); const [email, setEmail] = useState('admin@agendapro.com');
const [theme, setTheme] = useState<'dark' | 'light'>('dark');
const [showNotifications, setShowNotifications] = useState(false); const [showNotifications, setShowNotifications] = useState(false);
const [showProfile, setShowProfile] = useState(false); const [showProfile, setShowProfile] = useState(false);
@ -26,6 +27,19 @@ export default function Topbar({ title, subtitle, onMenuClick, onNavigate }: Top
const notifRef = useRef<HTMLDivElement>(null); const notifRef = useRef<HTMLDivElement>(null);
const profileRef = useRef<HTMLDivElement>(null); const profileRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const savedTheme = (localStorage.getItem('agendapro_theme') as 'dark' | 'light') || 'dark';
setTheme(savedTheme);
document.documentElement.setAttribute('data-theme', savedTheme);
}, []);
const toggleTheme = () => {
const nextTheme = theme === 'dark' ? 'light' : 'dark';
setTheme(nextTheme);
document.documentElement.setAttribute('data-theme', nextTheme);
localStorage.setItem('agendapro_theme', nextTheme);
};
const fetchNotifications = async () => { const fetchNotifications = async () => {
const slug = localStorage.getItem('agendapro_tenant_slug') || 'barbearia-premium'; const slug = localStorage.getItem('agendapro_tenant_slug') || 'barbearia-premium';
try { try {
@ -157,6 +171,16 @@ export default function Topbar({ title, subtitle, onMenuClick, onNavigate }: Top
<Search size={16} /> <Search size={16} />
<input className="form-input" placeholder="Buscar..." style={{ width: '240px', paddingLeft: '36px' }} /> <input className="form-input" placeholder="Buscar..." style={{ width: '240px', paddingLeft: '36px' }} />
</div> </div>
<button
type="button"
className="btn-ghost btn-icon"
onClick={toggleTheme}
title={theme === 'dark' ? "Mudar para Modo Claro" : "Mudar para Modo Escuro"}
style={{ borderRadius: '50%' }}
>
{theme === 'dark' ? <Sun size={20} style={{ color: '#f59e0b' }} /> : <Moon size={20} style={{ color: '#6C63FF' }} />}
</button>
<div style={{ position: 'relative' }} ref={notifRef}> <div style={{ position: 'relative' }} ref={notifRef}>
<button className="btn-ghost btn-icon" style={{ position: 'relative' }} onClick={handleNotificationClick}> <button className="btn-ghost btn-icon" style={{ position: 'relative' }} onClick={handleNotificationClick}>