Compare commits
2
Commits
ab8bf1d9be
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5802575fd7 | ||
|
|
746049ceea |
@@ -13,6 +13,18 @@ Todas as alterações notáveis neste projeto serão documentadas neste ficheiro
|
||||
O formato é baseado em [Keep a Changelog](https://keepachangelog.com/pt/1.1.0/),
|
||||
e este projeto adere ao [Semantic Versioning](https://semver.org/lang/pt-BR/).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Alterado
|
||||
- Alinhado com o sistema de design Descomplicar v1.2.0 (30-10-2026): tokens `--gold-fill #b07a00`,
|
||||
`--on-accent`, `--accent-text`; Roboto no texto e Montserrat nos títulos, carregadas localmente
|
||||
(`next/font/local`, `src/app/fonts/`); gráficos com uma série dourada (`#cc8d00`) e as restantes em
|
||||
`ink`, `line-strong` e laranja; ícones e títulos dourados sobre claro em `gold-fill`/`accent-text`.
|
||||
- `button` e `badge` em pílula; `--color-primary` passa a `gold-fill`.
|
||||
|
||||
### Corrigido
|
||||
- `api/metrics/[siteId]/route.ts`: `error.errors` → `error.issues` (Zod v4); o build falhava.
|
||||
|
||||
## [0.1.1] - 2026-02-14
|
||||
|
||||
### Security - CRÍTICO ⚠️
|
||||
|
||||
@@ -208,7 +208,7 @@ export async function GET(
|
||||
{
|
||||
success: false,
|
||||
error: 'Invalid input',
|
||||
details: error.errors.map(e => `${e.path.join('.')}: ${e.message}`).join(', ')
|
||||
details: error.issues.map(e => `${e.path.join('.')}: ${e.message}`).join(', ')
|
||||
},
|
||||
{ status: 400 }
|
||||
)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
+38
-2
@@ -4,8 +4,26 @@
|
||||
--background: #ffffff;
|
||||
--foreground: #000000;
|
||||
|
||||
/* Descomplicar Design System v1.2.0 */
|
||||
/* Dourado de marca: logótipo, gráficos, destaques decorativos. Nunca como fundo com texto nem em texto/ícones sobre claro. */
|
||||
--gold: #cc8d00;
|
||||
/* Acento de interface: fundos preenchidos (botões, badges) com texto --on-accent por cima; ícones de destaque sobre claro */
|
||||
--gold-fill: #b07a00;
|
||||
--accent-hover: #9a6a00;
|
||||
--on-accent: #ffffff;
|
||||
/* Texto dourado sobre fundo claro */
|
||||
--accent-text: #7a5400;
|
||||
--orange: #dd7500;
|
||||
--ink: #111111;
|
||||
--ink-muted: #5c5750;
|
||||
--line: #e6e0d4;
|
||||
--line-strong: #8f877a;
|
||||
--success: #1d7a4f;
|
||||
--danger: #b3261e;
|
||||
--focus: #7a5400;
|
||||
|
||||
/* Brand Descomplicar */
|
||||
--brand-dourado: #cc8d00;
|
||||
--brand-dourado: var(--gold);
|
||||
--brand-bege: #f2d9a2;
|
||||
--brand-verde: #27a50e;
|
||||
--brand-preto: #000000;
|
||||
@@ -22,8 +40,18 @@
|
||||
--color-brand-verde: var(--brand-verde);
|
||||
--color-brand-preto: var(--brand-preto);
|
||||
|
||||
/* Interface accent (design system v1.2.0) */
|
||||
--color-gold-fill: var(--gold-fill);
|
||||
--color-accent-hover: var(--accent-hover);
|
||||
--color-on-accent: var(--on-accent);
|
||||
--color-accent-text: var(--accent-text);
|
||||
--color-primary: var(--gold-fill);
|
||||
--color-primary-foreground: var(--on-accent);
|
||||
--color-success: var(--success);
|
||||
--color-danger: var(--danger);
|
||||
|
||||
/* Typography */
|
||||
--font-sans: 'Inter', system-ui, -apple-system, sans-serif;
|
||||
--font-sans: 'Roboto', system-ui, -apple-system, 'Segoe UI', sans-serif;
|
||||
--font-display: 'Montserrat', system-ui, -apple-system, sans-serif;
|
||||
--font-mono: 'JetBrains Mono', 'Fira Code', monospace;
|
||||
|
||||
@@ -49,3 +77,11 @@ body {
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4 {
|
||||
font-family: var(--font-display);
|
||||
}
|
||||
|
||||
:focus-visible {
|
||||
outline-color: var(--focus);
|
||||
}
|
||||
|
||||
+9
-7
@@ -1,16 +1,18 @@
|
||||
import type { Metadata } from 'next'
|
||||
import { Inter, Montserrat } from 'next/font/google'
|
||||
import localFont from 'next/font/local'
|
||||
import './globals.css'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const inter = Inter({
|
||||
subsets: ['latin'],
|
||||
const roboto = localFont({
|
||||
src: './fonts/Roboto-latin-wght-normal.woff2',
|
||||
weight: '100 900',
|
||||
variable: '--font-sans',
|
||||
display: 'swap',
|
||||
})
|
||||
|
||||
const montserrat = Montserrat({
|
||||
subsets: ['latin'],
|
||||
const montserrat = localFont({
|
||||
src: './fonts/Montserrat-latin-wght-normal.woff2',
|
||||
weight: '100 900',
|
||||
variable: '--font-display',
|
||||
display: 'swap',
|
||||
})
|
||||
@@ -31,7 +33,7 @@ export default function RootLayout({
|
||||
return (
|
||||
<html lang="pt">
|
||||
<body className={cn(
|
||||
inter.variable,
|
||||
roboto.variable,
|
||||
montserrat.variable,
|
||||
'font-sans antialiased bg-gray-50'
|
||||
)}>
|
||||
@@ -40,7 +42,7 @@ export default function RootLayout({
|
||||
<div className="container mx-auto px-md py-md">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h1 className="text-2xl font-display font-bold text-brand-dourado">
|
||||
<h1 className="text-2xl font-display font-bold text-accent-text">
|
||||
BI Descomplicar®
|
||||
</h1>
|
||||
<p className="text-sm text-gray-600 mt-0.5">
|
||||
|
||||
@@ -27,7 +27,8 @@ interface ChartCardProps {
|
||||
loading?: boolean
|
||||
}
|
||||
|
||||
const COLORS = ['#cc8d00', '#27a50e', '#f2d9a2', '#6e6e6e', '#000000']
|
||||
// Design system: uma série em dourado de marca; restantes em ink, line-strong, laranja
|
||||
const COLORS = ['var(--gold)', 'var(--ink)', 'var(--line-strong)', 'var(--orange)', 'var(--line)']
|
||||
|
||||
export function ChartCard({
|
||||
title,
|
||||
@@ -80,16 +81,16 @@ export function ChartCard({
|
||||
<ResponsiveContainer width="100%" height={300}>
|
||||
{type === 'line' && (
|
||||
<LineChart data={data}>
|
||||
<CartesianGrid strokeDasharray="3 3" stroke="#f2d9a2" opacity={0.5} />
|
||||
<CartesianGrid strokeDasharray="3 3" stroke="var(--line)" />
|
||||
<XAxis
|
||||
dataKey={xAxisKey}
|
||||
stroke="#6e6e6e"
|
||||
stroke="var(--ink-muted)"
|
||||
fontSize={12}
|
||||
tickLine={false}
|
||||
axisLine={false}
|
||||
/>
|
||||
<YAxis
|
||||
stroke="#6e6e6e"
|
||||
stroke="var(--ink-muted)"
|
||||
fontSize={12}
|
||||
tickLine={false}
|
||||
axisLine={false}
|
||||
@@ -98,7 +99,7 @@ export function ChartCard({
|
||||
<Tooltip
|
||||
contentStyle={{
|
||||
backgroundColor: '#fff',
|
||||
border: '1px solid #f2d9a2',
|
||||
border: '1px solid var(--line)',
|
||||
borderRadius: '8px',
|
||||
fontSize: '12px'
|
||||
}}
|
||||
@@ -106,9 +107,9 @@ export function ChartCard({
|
||||
<Line
|
||||
type="monotone"
|
||||
dataKey={dataKey}
|
||||
stroke="#cc8d00"
|
||||
stroke="var(--gold)"
|
||||
strokeWidth={2}
|
||||
dot={{ fill: '#cc8d00', r: 4 }}
|
||||
dot={{ fill: 'var(--gold)', r: 4 }}
|
||||
activeDot={{ r: 6 }}
|
||||
/>
|
||||
</LineChart>
|
||||
@@ -118,20 +119,20 @@ export function ChartCard({
|
||||
<AreaChart data={data}>
|
||||
<defs>
|
||||
<linearGradient id="colorValue" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="5%" stopColor="#cc8d00" stopOpacity={0.8}/>
|
||||
<stop offset="95%" stopColor="#cc8d00" stopOpacity={0}/>
|
||||
<stop offset="5%" stopColor="var(--gold)" stopOpacity={0.8}/>
|
||||
<stop offset="95%" stopColor="var(--gold)" stopOpacity={0}/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<CartesianGrid strokeDasharray="3 3" stroke="#f2d9a2" opacity={0.5} />
|
||||
<CartesianGrid strokeDasharray="3 3" stroke="var(--line)" />
|
||||
<XAxis
|
||||
dataKey={xAxisKey}
|
||||
stroke="#6e6e6e"
|
||||
stroke="var(--ink-muted)"
|
||||
fontSize={12}
|
||||
tickLine={false}
|
||||
axisLine={false}
|
||||
/>
|
||||
<YAxis
|
||||
stroke="#6e6e6e"
|
||||
stroke="var(--ink-muted)"
|
||||
fontSize={12}
|
||||
tickLine={false}
|
||||
axisLine={false}
|
||||
@@ -140,7 +141,7 @@ export function ChartCard({
|
||||
<Tooltip
|
||||
contentStyle={{
|
||||
backgroundColor: '#fff',
|
||||
border: '1px solid #f2d9a2',
|
||||
border: '1px solid var(--line)',
|
||||
borderRadius: '8px',
|
||||
fontSize: '12px'
|
||||
}}
|
||||
@@ -148,7 +149,7 @@ export function ChartCard({
|
||||
<Area
|
||||
type="monotone"
|
||||
dataKey={dataKey}
|
||||
stroke="#cc8d00"
|
||||
stroke="var(--gold)"
|
||||
strokeWidth={2}
|
||||
fillOpacity={1}
|
||||
fill="url(#colorValue)"
|
||||
@@ -165,7 +166,7 @@ export function ChartCard({
|
||||
labelLine={false}
|
||||
label={({ name, percent }) => `${name} (${((percent || 0) * 100).toFixed(0)}%)`}
|
||||
outerRadius={100}
|
||||
fill="#8884d8"
|
||||
fill="var(--gold)"
|
||||
dataKey={dataKey}
|
||||
>
|
||||
{data.map((entry, index) => (
|
||||
@@ -175,7 +176,7 @@ export function ChartCard({
|
||||
<Tooltip
|
||||
contentStyle={{
|
||||
backgroundColor: '#fff',
|
||||
border: '1px solid #f2d9a2',
|
||||
border: '1px solid var(--line)',
|
||||
borderRadius: '8px',
|
||||
fontSize: '12px'
|
||||
}}
|
||||
|
||||
@@ -31,7 +31,7 @@ export function MetricCard({
|
||||
<CardTitle className="text-sm font-medium text-gray-600">
|
||||
{title}
|
||||
</CardTitle>
|
||||
<Icon className="h-4 w-4 text-brand-dourado" />
|
||||
<Icon className="h-4 w-4 text-gold-fill" />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
{loading ? (
|
||||
@@ -47,8 +47,8 @@ export function MetricCard({
|
||||
{change !== undefined && (
|
||||
<p className={cn(
|
||||
"text-xs mt-1 font-medium",
|
||||
detectedTrend === 'up' && "text-brand-verde",
|
||||
detectedTrend === 'down' && "text-red-500",
|
||||
detectedTrend === 'up' && "text-success",
|
||||
detectedTrend === 'down' && "text-danger",
|
||||
detectedTrend === 'neutral' && "text-gray-500"
|
||||
)}>
|
||||
{change > 0 ? '+' : ''}{formatPercent(change / 100, 1)} vs. período anterior
|
||||
|
||||
@@ -4,12 +4,12 @@ import { cva, type VariantProps } from "class-variance-authority"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const badgeVariants = cva(
|
||||
"inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
|
||||
"inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default:
|
||||
"border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80",
|
||||
"border-transparent bg-primary text-primary-foreground shadow hover:bg-accent-hover",
|
||||
secondary:
|
||||
"border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
||||
destructive:
|
||||
|
||||
@@ -5,12 +5,12 @@ import { cva, type VariantProps } from "class-variance-authority"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const buttonVariants = cva(
|
||||
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
||||
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-full text-sm font-display font-bold transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default:
|
||||
"bg-primary text-primary-foreground shadow hover:bg-primary/90",
|
||||
"bg-primary text-primary-foreground shadow hover:bg-accent-hover",
|
||||
destructive:
|
||||
"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
|
||||
outline:
|
||||
@@ -22,8 +22,8 @@ const buttonVariants = cva(
|
||||
},
|
||||
size: {
|
||||
default: "h-9 px-4 py-2",
|
||||
sm: "h-8 rounded-md px-3 text-xs",
|
||||
lg: "h-10 rounded-md px-8",
|
||||
sm: "h-8 rounded-full px-3 text-xs",
|
||||
lg: "h-10 rounded-full px-8",
|
||||
icon: "h-9 w-9",
|
||||
},
|
||||
},
|
||||
|
||||
@@ -35,7 +35,7 @@ const CardTitle = React.forwardRef<
|
||||
>(({ className, ...props }, ref) => (
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn("font-semibold leading-none tracking-tight", className)}
|
||||
className={cn("font-display font-semibold leading-none tracking-tight", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
|
||||
Reference in New Issue
Block a user