feat(frontend): app shell + login + platform dashboard + billing tarifas

Primeiro commit do frontend Next.js (agente.md secao 161-176): login
split-brand, dashboard "Visão Geral da Plataforma" com instrumentos ao
vivo, e a tela Billing > Tarifas (price books + rate decks) completa —
listagem com busca/ordenacao, criacao com itens/entradas dinamicos via
Server Actions, detalhe — ponta a ponta contra a API real de billing
(fase 22).

Corrige de quebra 2 bugs reais achados construindo Tarifas: a topbar
tinha o titulo fixo "Visao Geral" em toda pagina, e a sidebar fixa de
256px nao tinha nenhuma versao mobile (conteudo espremido em ~130px) —
agora vira drawer via Radix Dialog abaixo de lg, com titulo/descricao da
topbar resolvidos dinamicamente por rota.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EWHKmcVJtstQFErbZ1AanY
This commit is contained in:
2026-08-29 00:54:29 -03:00
parent b27cfaab02
commit 673553975e
55 changed files with 2504 additions and 0 deletions

View File

@@ -0,0 +1,72 @@
import type { Config } from "tailwindcss";
const config: Config = {
darkMode: ["class"],
content: ["./src/**/*.{ts,tsx}"],
theme: {
extend: {
colors: {
border: "hsl(var(--border))",
input: "hsl(var(--input))",
ring: "hsl(var(--ring))",
background: "hsl(var(--background))",
foreground: "hsl(var(--foreground))",
muted: {
DEFAULT: "hsl(var(--muted))",
foreground: "hsl(var(--muted-foreground))",
},
surface: {
DEFAULT: "hsl(var(--surface))",
raised: "hsl(var(--surface-raised))",
},
primary: {
DEFAULT: "hsl(var(--primary))",
foreground: "hsl(var(--primary-foreground))",
},
accent: {
DEFAULT: "hsl(var(--accent))",
foreground: "hsl(var(--accent-foreground))",
},
destructive: {
DEFAULT: "hsl(var(--destructive))",
foreground: "hsl(var(--destructive-foreground))",
},
status: {
gray: "hsl(var(--status-gray))",
blue: "hsl(var(--status-blue))",
green: "hsl(var(--status-green))",
yellow: "hsl(var(--status-yellow))",
orange: "hsl(var(--status-orange))",
red: "hsl(var(--status-red))",
"green-dark": "hsl(var(--status-green-dark))",
},
},
borderRadius: {
lg: "var(--radius)",
md: "calc(var(--radius) - 3px)",
sm: "calc(var(--radius) - 6px)",
xl: "calc(var(--radius) + 4px)",
},
fontFamily: {
sans: ["var(--font-sans)", "IBM Plex Sans", "system-ui", "sans-serif"],
mono: ["var(--font-mono)", "IBM Plex Mono", "ui-monospace", "monospace"],
},
boxShadow: {
panel: "0 1px 2px hsl(var(--shadow-color) / 0.06), 0 8px 24px -8px hsl(var(--shadow-color) / 0.18)",
pop: "0 4px 12px hsl(var(--shadow-color) / 0.12), 0 16px 40px -12px hsl(var(--shadow-color) / 0.28)",
},
keyframes: {
"pulse-live": {
"0%, 100%": { opacity: "1" },
"50%": { opacity: "0.45" },
},
},
animation: {
"pulse-live": "pulse-live 2.4s ease-in-out infinite",
},
},
},
plugins: [],
};
export default config;