feat: design system unificado com template e cores CambioReal

- Cria src/ui-template.js com header, footer e estilos compartilhados
- Atualiza admin-home.js e admin-panel.js para usar template
- Atualiza dashboard.js com logo e cores CambioReal (#7600be)
- Atualiza login.html com novo branding BI-CCC
- Adiciona public/logo.png (CambioReal original)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
root
2026-02-08 13:20:05 -05:00
parent 2bf38c28c9
commit 1321b949e4
6 changed files with 390 additions and 255 deletions

307
src/ui-template.js Normal file
View File

@@ -0,0 +1,307 @@
/**
* UI Template - Design System Unificado BI-CCC
* Header, Footer e estilos compartilhados
*/
// CSS Variables compartilhadas - Cores CambioReal
const cssVariables = `
:root {
--primary: #7600be;
--primary-light: #9B2DE5;
--primary-dark: #5A0091;
--primary-bg: #F5EAFA;
--admin-accent: #2E7D32;
--admin-dark: #1B5E20;
--admin-bg: #E8F5E9;
--bg: #F0F2F5;
--card: #FFFFFF;
--text: #1A1D23;
--text-secondary: #5F6368;
--text-muted: #9AA0A6;
--border: #E8EAED;
--green: #1E8E3E;
--green-bg: #E6F4EA;
--blue: #1A73E8;
--blue-bg: #E8F0FE;
--orange: #E8710A;
--orange-bg: #FEF3E8;
--red: #D93025;
--red-bg: #FDE7E7;
--purple: #7B1FA2;
--purple-bg: #F3E5F5;
}
`;
// CSS do Header unificado
const headerCSS = `
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
background: var(--bg); color: var(--text); line-height: 1.5;
-webkit-font-smoothing: antialiased;
}
/* Header Unificado */
.app-header {
background: linear-gradient(135deg, var(--header-color) 0%, var(--header-dark) 100%);
color: white;
padding: 0 40px;
display: flex;
justify-content: space-between;
align-items: center;
height: 64px;
box-shadow: 0 2px 8px rgba(0,0,0,0.15);
}
.app-header.admin {
--header-color: var(--admin-accent);
--header-dark: var(--admin-dark);
}
.app-header.agent {
--header-color: var(--primary);
--header-dark: var(--primary-dark);
}
.header-brand {
display: flex;
align-items: center;
gap: 16px;
}
.header-brand .logo {
height: 36px;
width: auto;
}
.header-brand .app-name {
display: flex;
align-items: center;
gap: 10px;
}
.header-brand .app-name-badge {
background: rgba(255,255,255,0.2);
padding: 6px 14px;
border-radius: 6px;
font-size: 14px;
font-weight: 800;
letter-spacing: 0.5px;
}
.header-brand .app-subtitle {
font-size: 11px;
opacity: 0.8;
font-weight: 500;
text-transform: uppercase;
letter-spacing: 1px;
}
.header-nav {
display: flex;
align-items: center;
gap: 4px;
}
.header-nav a {
color: white;
text-decoration: none;
padding: 8px 16px;
border-radius: 6px;
font-size: 13px;
font-weight: 600;
transition: all 0.15s;
opacity: 0.85;
}
.header-nav a:hover {
background: rgba(255,255,255,0.15);
opacity: 1;
}
.header-nav a.active {
background: rgba(255,255,255,0.2);
opacity: 1;
}
.header-user {
display: flex;
align-items: center;
gap: 12px;
}
.header-user .user-info {
display: flex;
align-items: center;
gap: 10px;
background: rgba(255,255,255,0.1);
padding: 6px 14px;
border-radius: 20px;
font-size: 13px;
font-weight: 500;
}
.header-user .user-avatar {
width: 28px;
height: 28px;
background: rgba(255,255,255,0.25);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
font-weight: 700;
}
.header-user .user-role {
font-size: 10px;
background: rgba(255,255,255,0.2);
padding: 2px 8px;
border-radius: 10px;
text-transform: uppercase;
font-weight: 700;
letter-spacing: 0.5px;
}
.header-user .btn-logout {
background: rgba(255,255,255,0.15);
color: white;
border: 1px solid rgba(255,255,255,0.3);
padding: 8px 16px;
border-radius: 6px;
font-size: 12px;
font-weight: 600;
cursor: pointer;
text-decoration: none;
font-family: inherit;
transition: all 0.15s;
}
.header-user .btn-logout:hover {
background: rgba(255,255,255,0.25);
}
/* Footer */
.app-footer {
text-align: center;
padding: 20px;
font-size: 12px;
color: var(--text-muted);
border-top: 1px solid var(--border);
background: var(--card);
margin-top: auto;
}
/* Container padrão */
.app-container {
padding: 28px 40px;
max-width: 1600px;
margin: 0 auto;
}
/* Responsive */
@media (max-width: 768px) {
.app-header {
padding: 0 20px;
height: auto;
flex-direction: column;
gap: 12px;
padding: 16px 20px;
}
.header-nav {
width: 100%;
justify-content: center;
}
.header-user {
width: 100%;
justify-content: center;
}
.app-container {
padding: 20px;
}
.header-brand .app-subtitle {
display: none;
}
}
`;
/**
* Gera o header HTML
* @param {Object} options
* @param {string} options.role - 'admin' ou 'agente'
* @param {string} options.userName - Nome do usuário
* @param {string} options.activePage - Página ativa para nav
* @param {boolean} options.showNav - Mostrar navegação
*/
function buildHeader(options = {}) {
const { role = 'agente', userName = '', activePage = '', showNav = true } = options;
const isAdmin = role === 'admin';
const headerClass = isAdmin ? 'admin' : 'agent';
const initials = userName
.split(' ')
.map(n => n[0])
.slice(0, 2)
.join('')
.toUpperCase();
const adminNav = `
<nav class="header-nav">
<a href="/admin" class="${activePage === 'home' ? 'active' : ''}">Home</a>
<a href="/admin/agentes" class="${activePage === 'users' ? 'active' : ''}">Usuarios</a>
<a href="/admin/dashboard" class="${activePage === 'dashboard' ? 'active' : ''}">Dashboard</a>
</nav>
`;
const agentNav = `
<nav class="header-nav">
<a href="/dashboard" class="active">Meu Dashboard</a>
</nav>
`;
return `
<header class="app-header ${headerClass}">
<div class="header-brand">
<img src="/public/logo.png" alt="CambioReal" class="logo">
<div class="app-name">
<span class="app-name-badge">BI - CCC</span>
<span class="app-subtitle">Central Command Center</span>
</div>
</div>
${showNav ? (isAdmin ? adminNav : agentNav) : ''}
<div class="header-user">
<div class="user-info">
<span class="user-avatar">${initials}</span>
<span>${userName}</span>
<span class="user-role">${isAdmin ? 'Admin' : 'Agente'}</span>
</div>
<a href="/logout" class="btn-logout">Sair</a>
</div>
</header>
`;
}
/**
* Gera o footer HTML
*/
function buildFooter() {
const year = new Date().getFullYear();
return `
<footer class="app-footer">
CambioReal &copy; ${year} &mdash; BI - CCC (Central Command Center)
</footer>
`;
}
/**
* Gera o head HTML com estilos base
* @param {string} title - Título da página
* @param {string} additionalCSS - CSS adicional
*/
function buildHead(title, additionalCSS = '') {
return `
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>${title} | BI - CCC</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
<style>
${cssVariables}
${headerCSS}
${additionalCSS}
</style>
`;
}
module.exports = {
buildHeader,
buildFooter,
buildHead,
cssVariables,
headerCSS
};