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/),
|
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/).
|
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
|
## [0.1.1] - 2026-02-14
|
||||||
|
|
||||||
### Security - CRÍTICO ⚠️
|
### Security - CRÍTICO ⚠️
|
||||||
|
|||||||
@@ -208,7 +208,7 @@ export async function GET(
|
|||||||
{
|
{
|
||||||
success: false,
|
success: false,
|
||||||
error: 'Invalid input',
|
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 }
|
{ status: 400 }
|
||||||
)
|
)
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
+38
-2
@@ -4,8 +4,26 @@
|
|||||||
--background: #ffffff;
|
--background: #ffffff;
|
||||||
--foreground: #000000;
|
--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 Descomplicar */
|
||||||
--brand-dourado: #cc8d00;
|
--brand-dourado: var(--gold);
|
||||||
--brand-bege: #f2d9a2;
|
--brand-bege: #f2d9a2;
|
||||||
--brand-verde: #27a50e;
|
--brand-verde: #27a50e;
|
||||||
--brand-preto: #000000;
|
--brand-preto: #000000;
|
||||||
@@ -22,8 +40,18 @@
|
|||||||
--color-brand-verde: var(--brand-verde);
|
--color-brand-verde: var(--brand-verde);
|
||||||
--color-brand-preto: var(--brand-preto);
|
--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 */
|
/* 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-display: 'Montserrat', system-ui, -apple-system, sans-serif;
|
||||||
--font-mono: 'JetBrains Mono', 'Fira Code', monospace;
|
--font-mono: 'JetBrains Mono', 'Fira Code', monospace;
|
||||||
|
|
||||||
@@ -49,3 +77,11 @@ body {
|
|||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-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 type { Metadata } from 'next'
|
||||||
import { Inter, Montserrat } from 'next/font/google'
|
import localFont from 'next/font/local'
|
||||||
import './globals.css'
|
import './globals.css'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
const inter = Inter({
|
const roboto = localFont({
|
||||||
subsets: ['latin'],
|
src: './fonts/Roboto-latin-wght-normal.woff2',
|
||||||
|
weight: '100 900',
|
||||||
variable: '--font-sans',
|
variable: '--font-sans',
|
||||||
display: 'swap',
|
display: 'swap',
|
||||||
})
|
})
|
||||||
|
|
||||||
const montserrat = Montserrat({
|
const montserrat = localFont({
|
||||||
subsets: ['latin'],
|
src: './fonts/Montserrat-latin-wght-normal.woff2',
|
||||||
|
weight: '100 900',
|
||||||
variable: '--font-display',
|
variable: '--font-display',
|
||||||
display: 'swap',
|
display: 'swap',
|
||||||
})
|
})
|
||||||
@@ -31,7 +33,7 @@ export default function RootLayout({
|
|||||||
return (
|
return (
|
||||||
<html lang="pt">
|
<html lang="pt">
|
||||||
<body className={cn(
|
<body className={cn(
|
||||||
inter.variable,
|
roboto.variable,
|
||||||
montserrat.variable,
|
montserrat.variable,
|
||||||
'font-sans antialiased bg-gray-50'
|
'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="container mx-auto px-md py-md">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div>
|
<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®
|
BI Descomplicar®
|
||||||
</h1>
|
</h1>
|
||||||
<p className="text-sm text-gray-600 mt-0.5">
|
<p className="text-sm text-gray-600 mt-0.5">
|
||||||
|
|||||||
@@ -27,7 +27,8 @@ interface ChartCardProps {
|
|||||||
loading?: boolean
|
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({
|
export function ChartCard({
|
||||||
title,
|
title,
|
||||||
@@ -80,16 +81,16 @@ export function ChartCard({
|
|||||||
<ResponsiveContainer width="100%" height={300}>
|
<ResponsiveContainer width="100%" height={300}>
|
||||||
{type === 'line' && (
|
{type === 'line' && (
|
||||||
<LineChart data={data}>
|
<LineChart data={data}>
|
||||||
<CartesianGrid strokeDasharray="3 3" stroke="#f2d9a2" opacity={0.5} />
|
<CartesianGrid strokeDasharray="3 3" stroke="var(--line)" />
|
||||||
<XAxis
|
<XAxis
|
||||||
dataKey={xAxisKey}
|
dataKey={xAxisKey}
|
||||||
stroke="#6e6e6e"
|
stroke="var(--ink-muted)"
|
||||||
fontSize={12}
|
fontSize={12}
|
||||||
tickLine={false}
|
tickLine={false}
|
||||||
axisLine={false}
|
axisLine={false}
|
||||||
/>
|
/>
|
||||||
<YAxis
|
<YAxis
|
||||||
stroke="#6e6e6e"
|
stroke="var(--ink-muted)"
|
||||||
fontSize={12}
|
fontSize={12}
|
||||||
tickLine={false}
|
tickLine={false}
|
||||||
axisLine={false}
|
axisLine={false}
|
||||||
@@ -98,7 +99,7 @@ export function ChartCard({
|
|||||||
<Tooltip
|
<Tooltip
|
||||||
contentStyle={{
|
contentStyle={{
|
||||||
backgroundColor: '#fff',
|
backgroundColor: '#fff',
|
||||||
border: '1px solid #f2d9a2',
|
border: '1px solid var(--line)',
|
||||||
borderRadius: '8px',
|
borderRadius: '8px',
|
||||||
fontSize: '12px'
|
fontSize: '12px'
|
||||||
}}
|
}}
|
||||||
@@ -106,9 +107,9 @@ export function ChartCard({
|
|||||||
<Line
|
<Line
|
||||||
type="monotone"
|
type="monotone"
|
||||||
dataKey={dataKey}
|
dataKey={dataKey}
|
||||||
stroke="#cc8d00"
|
stroke="var(--gold)"
|
||||||
strokeWidth={2}
|
strokeWidth={2}
|
||||||
dot={{ fill: '#cc8d00', r: 4 }}
|
dot={{ fill: 'var(--gold)', r: 4 }}
|
||||||
activeDot={{ r: 6 }}
|
activeDot={{ r: 6 }}
|
||||||
/>
|
/>
|
||||||
</LineChart>
|
</LineChart>
|
||||||
@@ -118,20 +119,20 @@ export function ChartCard({
|
|||||||
<AreaChart data={data}>
|
<AreaChart data={data}>
|
||||||
<defs>
|
<defs>
|
||||||
<linearGradient id="colorValue" x1="0" y1="0" x2="0" y2="1">
|
<linearGradient id="colorValue" x1="0" y1="0" x2="0" y2="1">
|
||||||
<stop offset="5%" stopColor="#cc8d00" stopOpacity={0.8}/>
|
<stop offset="5%" stopColor="var(--gold)" stopOpacity={0.8}/>
|
||||||
<stop offset="95%" stopColor="#cc8d00" stopOpacity={0}/>
|
<stop offset="95%" stopColor="var(--gold)" stopOpacity={0}/>
|
||||||
</linearGradient>
|
</linearGradient>
|
||||||
</defs>
|
</defs>
|
||||||
<CartesianGrid strokeDasharray="3 3" stroke="#f2d9a2" opacity={0.5} />
|
<CartesianGrid strokeDasharray="3 3" stroke="var(--line)" />
|
||||||
<XAxis
|
<XAxis
|
||||||
dataKey={xAxisKey}
|
dataKey={xAxisKey}
|
||||||
stroke="#6e6e6e"
|
stroke="var(--ink-muted)"
|
||||||
fontSize={12}
|
fontSize={12}
|
||||||
tickLine={false}
|
tickLine={false}
|
||||||
axisLine={false}
|
axisLine={false}
|
||||||
/>
|
/>
|
||||||
<YAxis
|
<YAxis
|
||||||
stroke="#6e6e6e"
|
stroke="var(--ink-muted)"
|
||||||
fontSize={12}
|
fontSize={12}
|
||||||
tickLine={false}
|
tickLine={false}
|
||||||
axisLine={false}
|
axisLine={false}
|
||||||
@@ -140,7 +141,7 @@ export function ChartCard({
|
|||||||
<Tooltip
|
<Tooltip
|
||||||
contentStyle={{
|
contentStyle={{
|
||||||
backgroundColor: '#fff',
|
backgroundColor: '#fff',
|
||||||
border: '1px solid #f2d9a2',
|
border: '1px solid var(--line)',
|
||||||
borderRadius: '8px',
|
borderRadius: '8px',
|
||||||
fontSize: '12px'
|
fontSize: '12px'
|
||||||
}}
|
}}
|
||||||
@@ -148,7 +149,7 @@ export function ChartCard({
|
|||||||
<Area
|
<Area
|
||||||
type="monotone"
|
type="monotone"
|
||||||
dataKey={dataKey}
|
dataKey={dataKey}
|
||||||
stroke="#cc8d00"
|
stroke="var(--gold)"
|
||||||
strokeWidth={2}
|
strokeWidth={2}
|
||||||
fillOpacity={1}
|
fillOpacity={1}
|
||||||
fill="url(#colorValue)"
|
fill="url(#colorValue)"
|
||||||
@@ -165,7 +166,7 @@ export function ChartCard({
|
|||||||
labelLine={false}
|
labelLine={false}
|
||||||
label={({ name, percent }) => `${name} (${((percent || 0) * 100).toFixed(0)}%)`}
|
label={({ name, percent }) => `${name} (${((percent || 0) * 100).toFixed(0)}%)`}
|
||||||
outerRadius={100}
|
outerRadius={100}
|
||||||
fill="#8884d8"
|
fill="var(--gold)"
|
||||||
dataKey={dataKey}
|
dataKey={dataKey}
|
||||||
>
|
>
|
||||||
{data.map((entry, index) => (
|
{data.map((entry, index) => (
|
||||||
@@ -175,7 +176,7 @@ export function ChartCard({
|
|||||||
<Tooltip
|
<Tooltip
|
||||||
contentStyle={{
|
contentStyle={{
|
||||||
backgroundColor: '#fff',
|
backgroundColor: '#fff',
|
||||||
border: '1px solid #f2d9a2',
|
border: '1px solid var(--line)',
|
||||||
borderRadius: '8px',
|
borderRadius: '8px',
|
||||||
fontSize: '12px'
|
fontSize: '12px'
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ export function MetricCard({
|
|||||||
<CardTitle className="text-sm font-medium text-gray-600">
|
<CardTitle className="text-sm font-medium text-gray-600">
|
||||||
{title}
|
{title}
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
<Icon className="h-4 w-4 text-brand-dourado" />
|
<Icon className="h-4 w-4 text-gold-fill" />
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
{loading ? (
|
{loading ? (
|
||||||
@@ -47,8 +47,8 @@ export function MetricCard({
|
|||||||
{change !== undefined && (
|
{change !== undefined && (
|
||||||
<p className={cn(
|
<p className={cn(
|
||||||
"text-xs mt-1 font-medium",
|
"text-xs mt-1 font-medium",
|
||||||
detectedTrend === 'up' && "text-brand-verde",
|
detectedTrend === 'up' && "text-success",
|
||||||
detectedTrend === 'down' && "text-red-500",
|
detectedTrend === 'down' && "text-danger",
|
||||||
detectedTrend === 'neutral' && "text-gray-500"
|
detectedTrend === 'neutral' && "text-gray-500"
|
||||||
)}>
|
)}>
|
||||||
{change > 0 ? '+' : ''}{formatPercent(change / 100, 1)} vs. período anterior
|
{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"
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
const badgeVariants = cva(
|
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: {
|
variants: {
|
||||||
variant: {
|
variant: {
|
||||||
default:
|
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:
|
secondary:
|
||||||
"border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
"border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
||||||
destructive:
|
destructive:
|
||||||
|
|||||||
@@ -5,12 +5,12 @@ import { cva, type VariantProps } from "class-variance-authority"
|
|||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
const buttonVariants = cva(
|
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: {
|
variants: {
|
||||||
variant: {
|
variant: {
|
||||||
default:
|
default:
|
||||||
"bg-primary text-primary-foreground shadow hover:bg-primary/90",
|
"bg-primary text-primary-foreground shadow hover:bg-accent-hover",
|
||||||
destructive:
|
destructive:
|
||||||
"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
|
"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
|
||||||
outline:
|
outline:
|
||||||
@@ -22,8 +22,8 @@ const buttonVariants = cva(
|
|||||||
},
|
},
|
||||||
size: {
|
size: {
|
||||||
default: "h-9 px-4 py-2",
|
default: "h-9 px-4 py-2",
|
||||||
sm: "h-8 rounded-md px-3 text-xs",
|
sm: "h-8 rounded-full px-3 text-xs",
|
||||||
lg: "h-10 rounded-md px-8",
|
lg: "h-10 rounded-full px-8",
|
||||||
icon: "h-9 w-9",
|
icon: "h-9 w-9",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ const CardTitle = React.forwardRef<
|
|||||||
>(({ className, ...props }, ref) => (
|
>(({ className, ...props }, ref) => (
|
||||||
<div
|
<div
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn("font-semibold leading-none tracking-tight", className)}
|
className={cn("font-display font-semibold leading-none tracking-tight", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
))
|
||||||
|
|||||||
Reference in New Issue
Block a user