feat: topbar de navegação como experimento de UI (v1.7.0)

- Substitui header fixo por topbar com backdrop blur e navegação agrupada em 5 seções
- Adiciona FerramentasDropdown consolidando calculadora e modo privacidade
- NotificationBell expandida com orçamentos e pré-lançamentos
- Remove logout-button, header-dashboard e privacy-mode-toggle como componentes separados
- Logo refatorado com variante compact; topbar com links em lowercase
- Adiciona dependência radix-ui ^1.4.3
- Atualiza CHANGELOG para v1.7.0

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Felipe Coutinho
2026-02-24 15:43:14 +00:00
parent af7dd6f737
commit 1b90be6b54
54 changed files with 1492 additions and 787 deletions

View File

@@ -11,7 +11,7 @@ export default function RootLayout({
children: React.ReactNode;
}) {
return (
<section className="space-y-6 px-6">
<section className="space-y-6 pt-4">
<PageDescription
icon={<RiSettings2Line />}
title="Ajustes"

View File

@@ -11,7 +11,7 @@ export default function RootLayout({
children: React.ReactNode;
}) {
return (
<section className="space-y-6 px-6">
<section className="space-y-6 pt-4">
<PageDescription
icon={<RiTodoLine />}
title="Notas"

View File

@@ -11,7 +11,7 @@ export default function RootLayout({
children: React.ReactNode;
}) {
return (
<section className="space-y-6 px-6">
<section className="space-y-6 pt-4">
<PageDescription
icon={<RiCalendarEventLine />}
title="Calendário"

View File

@@ -22,7 +22,7 @@ export default function FaturaLoading() {
{/* Seção de lançamentos */}
<section className="flex flex-col gap-4">
<div className="space-y-6">
<div className="space-y-6 pt-4">
{/* Header */}
<div className="flex items-center justify-between">
<Skeleton className="h-8 w-48 rounded-2xl bg-foreground/10" />

View File

@@ -11,7 +11,7 @@ export default function RootLayout({
children: React.ReactNode;
}) {
return (
<section className="space-y-6 px-6">
<section className="space-y-6 pt-4">
<PageDescription
icon={<RiBankCard2Line />}
title="Cartões"

View File

@@ -3,7 +3,7 @@ import { Skeleton } from "@/components/ui/skeleton";
export default function CartoesLoading() {
return (
<main className="flex flex-col gap-6">
<div className="space-y-6">
<div className="space-y-6 pt-4">
{/* Header */}
<div className="flex items-center justify-between">
<Skeleton className="h-8 w-32 rounded-2xl bg-foreground/10" />

View File

@@ -11,7 +11,7 @@ export default function RootLayout({
children: React.ReactNode;
}) {
return (
<section className="space-y-6 px-6">
<section className="space-y-6 pt-4">
<PageDescription
icon={<RiPriceTag3Line />}
title="Categorias"

View File

@@ -20,7 +20,7 @@ export default function ExtratoLoading() {
{/* Seção de lançamentos */}
<section className="flex flex-col gap-4">
<div className="space-y-6">
<div className="space-y-6 pt-4">
{/* Header */}
<div className="flex items-center justify-between">
<Skeleton className="h-8 w-48 rounded-2xl bg-foreground/10" />

View File

@@ -11,7 +11,7 @@ export default function RootLayout({
children: React.ReactNode;
}) {
return (
<section className="space-y-6 px-6">
<section className="space-y-6 pt-4">
<PageDescription
icon={<RiBankLine />}
title="Contas"

View File

@@ -3,7 +3,7 @@ import { Skeleton } from "@/components/ui/skeleton";
export default function ContasLoading() {
return (
<main className="flex flex-col gap-6">
<div className="space-y-6">
<div className="space-y-6 pt-4">
{/* Header */}
<div className="flex items-center justify-between">
<Skeleton className="h-8 w-32 rounded-2xl bg-foreground/10" />

View File

@@ -11,7 +11,7 @@ export default function RootLayout({
children: React.ReactNode;
}) {
return (
<section className="space-y-6 px-6">
<section className="space-y-6 pt-4">
<PageDescription
icon={<RiSecurePaymentLine />}
title="Análise de Parcelas"

View File

@@ -36,7 +36,7 @@ export default async function Page({ searchParams }: PageProps) {
const { disableMagnetlines, dashboardWidgets } = preferences;
return (
<main className="flex flex-col gap-4 px-6">
<main className="flex flex-col gap-4">
<DashboardWelcome
name={user.name}
disableMagnetlines={disableMagnetlines}

View File

@@ -11,7 +11,7 @@ export default function RootLayout({
children: React.ReactNode;
}) {
return (
<section className="space-y-6 px-6">
<section className="space-y-6 pt-4">
<PageDescription
icon={<RiSparklingLine />}
title="Insights"

View File

@@ -6,7 +6,7 @@ import { Skeleton } from "@/components/ui/skeleton";
export default function InsightsLoading() {
return (
<main className="flex flex-col gap-6">
<div className="space-y-6">
<div className="space-y-6 pt-4">
{/* Header */}
<div className="space-y-2">
<Skeleton className="h-10 w-64 rounded-2xl bg-foreground/10" />

View File

@@ -11,7 +11,7 @@ export default function RootLayout({
children: React.ReactNode;
}) {
return (
<section className="space-y-6 px-6">
<section className="space-y-6 pt-4">
<PageDescription
icon={<RiArrowLeftRightLine />}
title="Lançamentos"

View File

@@ -14,7 +14,7 @@ export default function LancamentosLoading() {
{/* Month Picker placeholder */}
<div className="h-[60px] animate-pulse rounded-2xl bg-foreground/10" />
<div className="space-y-6">
<div className="space-y-6 pt-4">
{/* Header com título e botão */}
<div className="flex items-center justify-between">
<Skeleton className="h-8 w-48 rounded-2xl bg-foreground/10" />

View File

@@ -61,7 +61,7 @@ export default async function DashboardLayout({
/>
<div className="flex flex-1 flex-col pt-14">
<div className="@container/main flex flex-1 flex-col gap-2">
<div className="flex flex-col gap-4 py-4 md:gap-6 w-full max-w-8xl mx-auto px-4">
<div className="flex flex-col gap-4 py-5 md:gap-6 w-full max-w-8xl mx-auto px-4">
{children}
</div>
</div>

View File

@@ -11,7 +11,7 @@ export default function RootLayout({
children: React.ReactNode;
}) {
return (
<section className="space-y-6 px-6">
<section className="space-y-6 pt-4">
<PageDescription
icon={<RiFundsLine />}
title="Orçamentos"

View File

@@ -10,7 +10,7 @@ export default function OrcamentosLoading() {
{/* Month Picker placeholder */}
<div className="h-[60px] animate-pulse rounded-2xl bg-foreground/10" />
<div className="space-y-6">
<div className="space-y-6 pt-4">
{/* Header */}
<div className="flex items-center justify-between">
<div className="space-y-2">

View File

@@ -42,7 +42,7 @@ export default function PagadorDetailsLoading() {
</div>
{/* Tabs */}
<div className="space-y-6">
<div className="space-y-6 pt-4">
<div className="flex gap-2 border-b">
<Skeleton className="h-10 w-32 rounded-t-2xl bg-foreground/10" />
<Skeleton className="h-10 w-32 rounded-t-2xl bg-foreground/10" />

View File

@@ -11,7 +11,7 @@ export default function RootLayout({
children: React.ReactNode;
}) {
return (
<section className="space-y-6 px-6">
<section className="space-y-6 pt-4">
<PageDescription
icon={<RiGroupLine />}
title="Pagadores"

View File

@@ -11,7 +11,7 @@ export default function RootLayout({
children: React.ReactNode;
}) {
return (
<section className="space-y-6 px-6">
<section className="space-y-6 pt-4">
<PageDescription
icon={<RiInboxLine />}
title="Pré-Lançamentos"

View File

@@ -11,7 +11,7 @@ export default function RootLayout({
children: React.ReactNode;
}) {
return (
<section className="space-y-6 px-6">
<section className="space-y-6 pt-4">
<PageDescription
icon={<RiFileChartLine />}
title="Tendências"

View File

@@ -11,7 +11,7 @@ export default function RootLayout({
children: React.ReactNode;
}) {
return (
<section className="space-y-6 px-6">
<section className="space-y-6 pt-4">
<PageDescription
icon={<RiBankCard2Line />}
title="Uso de Cartões"

View File

@@ -11,7 +11,7 @@ export default function RootLayout({
children: React.ReactNode;
}) {
return (
<section className="space-y-6 px-6">
<section className="space-y-6 pt-4">
<PageDescription
icon={<RiStore2Line />}
title="Top Estabelecimentos"

View File

@@ -155,40 +155,38 @@ export default async function Page() {
<div className="flex min-h-screen flex-col">
{/* Navigation */}
<header className="sticky top-0 z-50 bg-background/95 backdrop-blur supports-backdrop-filter:bg-background/60">
<div className="container flex h-16 items-center justify-between">
<div className="flex items-center">
<Logo />
</div>
<div className="max-w-8xl mx-auto px-4 flex h-14 items-center justify-between">
<Logo variant="compact" />
{/* Center Navigation Links */}
<nav className="hidden md:flex items-center gap-6 absolute left-1/2 transform -translate-x-1/2">
<a
href="#telas"
className="text-sm text-muted-foreground hover:text-foreground transition-colors"
className="rounded-full px-3 py-1.5 text-sm font-medium text-muted-foreground hover:text-foreground hover:bg-accent transition-colors"
>
Conheça as telas
</a>
<a
href="#funcionalidades"
className="text-sm text-muted-foreground hover:text-foreground transition-colors"
className="rounded-full px-3 py-1.5 text-sm font-medium text-muted-foreground hover:text-foreground hover:bg-accent transition-colors"
>
Funcionalidades
</a>
<a
href="#companion"
className="text-sm text-muted-foreground hover:text-foreground transition-colors"
className="rounded-full px-3 py-1.5 text-sm font-medium text-muted-foreground hover:text-foreground hover:bg-accent transition-colors"
>
Companion
</a>
<a
href="#stack"
className="text-sm text-muted-foreground hover:text-foreground transition-colors"
className="rounded-full px-3 py-1.5 text-sm font-medium text-muted-foreground hover:text-foreground hover:bg-accent transition-colors"
>
Stack
</a>
<a
href="#como-usar"
className="text-sm text-muted-foreground hover:text-foreground transition-colors"
className="rounded-full px-3 py-1.5 text-sm font-medium text-muted-foreground hover:text-foreground hover:bg-accent transition-colors"
>
Como usar
</a>
@@ -231,7 +229,7 @@ export default async function Page() {
{/* Background gradient */}
<div className="pointer-events-none absolute inset-0 bg-linear-to-b from-primary/5 via-transparent to-transparent" />
<div className="container relative">
<div className="max-w-8xl mx-auto px-4 relative">
<div className="mx-auto flex max-w-5xl flex-col items-center text-center gap-5 md:gap-6">
<Logo variant="small" className="h-12 w-12 mb-1" />
@@ -304,7 +302,7 @@ export default async function Page() {
{/* Metrics Bar */}
<section className="py-8 md:py-12 border-y">
<div className="container">
<div className="max-w-8xl mx-auto px-4">
<div className="mx-auto max-w-4xl">
<div className="grid grid-cols-2 gap-4 md:grid-cols-4 md:gap-8">
<div className="flex flex-col items-center text-center gap-1.5">
@@ -350,7 +348,7 @@ export default async function Page() {
{/* Dashboard Preview Section */}
<section className="py-6 md:py-16">
<div className="container">
<div className="max-w-8xl mx-auto px-4">
<div className="mx-auto max-w-6xl">
<AnimateOnScroll>
<div>
@@ -378,7 +376,7 @@ export default async function Page() {
{/* Screenshots Gallery Section */}
<section id="telas" className="py-12 md:py-24">
<div className="container">
<div className="max-w-8xl mx-auto px-4">
<div className="mx-auto max-w-6xl">
<AnimateOnScroll>
<div className="text-center mb-8 md:mb-12">
@@ -430,7 +428,7 @@ export default async function Page() {
{/* Features Section */}
<section id="funcionalidades" className="py-12 md:py-24">
<div className="container">
<div className="max-w-8xl mx-auto px-4">
<div className="mx-auto max-w-5xl">
<AnimateOnScroll>
<div className="text-center mb-8 md:mb-12">
@@ -512,7 +510,7 @@ export default async function Page() {
{/* Companion Section */}
<section id="companion" className="py-12 md:py-24">
<div className="container">
<div className="max-w-8xl mx-auto px-4">
<div className="mx-auto max-w-5xl">
<AnimateOnScroll>
<div className="grid gap-8 md:gap-12 md:grid-cols-2 items-center">
@@ -625,7 +623,7 @@ export default async function Page() {
{/* Tech Stack Section */}
<section id="stack" className="py-12 md:py-24">
<div className="container">
<div className="max-w-8xl mx-auto px-4">
<div className="mx-auto max-w-5xl">
<AnimateOnScroll>
<div className="text-center mb-8 md:mb-12">
@@ -748,7 +746,7 @@ export default async function Page() {
{/* How to run Section */}
<section id="como-usar" className="py-12 md:py-24">
<div className="container">
<div className="max-w-8xl mx-auto px-4">
<div className="mx-auto max-w-3xl">
<AnimateOnScroll>
<div className="text-center mb-8 md:mb-12">
@@ -783,7 +781,7 @@ export default async function Page() {
{/* Who is this for Section */}
<section className="py-12 md:py-24">
<div className="container">
<div className="max-w-8xl mx-auto px-4">
<div className="mx-auto max-w-3xl">
<AnimateOnScroll>
<div className="text-center mb-8 md:mb-12">
@@ -882,7 +880,7 @@ export default async function Page() {
{/* CTA Section */}
<section className="py-12 md:py-24">
<div className="container">
<div className="max-w-8xl mx-auto px-4">
<AnimateOnScroll>
<div className="mx-auto max-w-3xl text-center px-4 sm:px-0">
<h2 className="text-2xl sm:text-3xl md:text-4xl font-bold tracking-tight mb-3 md:mb-4">
@@ -924,11 +922,11 @@ export default async function Page() {
{/* Footer */}
<footer className="border-t py-8 md:py-12 mt-auto">
<div className="container">
<div className="max-w-8xl mx-auto px-4">
<div className="mx-auto max-w-5xl">
<div className="grid gap-8 sm:grid-cols-2 md:grid-cols-3">
<div className="sm:col-span-2 md:col-span-1">
<Logo />
<Logo variant="compact" />
<p className="text-sm text-muted-foreground mt-3 md:mt-4">
Projeto pessoal de gestão financeira. Open source e
self-hosted.

View File

@@ -25,7 +25,7 @@ export default function RootLayout({
<head>
<meta name="apple-mobile-web-app-title" content="OpenMonetis" />
</head>
<body className="antialiased" suppressHydrationWarning>
<body className="subpixel-antialiased" suppressHydrationWarning>
<ThemeProvider attribute="class" defaultTheme="light">
{children}
<Toaster position="top-right" />