Skip to main content
Gremorie

Dashboard

Grid de KPI mais faixa de chart mais table de transações. A superfície de analytics canônica para dashboards SaaS e de storefront.

Visão geral

Uma superfície de dashboard completa: header de página com uma ação de export, um grid de KPI de quatro colunas, um bar chart de receita e uma table de transações recentes. Compõe Card, Badge, Table, BarChart e Button.

Este block é o ponto de partida para qualquer rota de analytics. Substitua o mock data pelos seus hooks do TanStack Query e o layout, o chart e a table continuarão funcionando sem alterações.

Preview

Dashboard

Snapshot of the last 30 days.

Revenue
$48,920

+12.4% from last month

Customers
2,318

+4.1% from last month

Orders
1,204

+18.3% from last month

Refunds
$1,420

-3.2% from last month

Revenue
Monthly recurring revenue
Bar chart of Revenue by month
monthRevenue
Jan4200
Feb5100
Mar4800
Apr6200
May7400
Jun6900
Jul8100
Aug8900
Recent transactions
Latest activity from your storefront.
InvoiceCustomerStatusAmount
INV-001
Olivia Martinolivia@example.com
Paid$1,999
INV-002
Jackson Leejackson@example.com
Paid$39
INV-003
Isabella Nguyenisabella@example.com
Pending$299
INV-004
William Kimwill@example.com
Refunded$99
INV-005
Sofia Davissofia@example.com
Paid$1,499

Anatomia

Dashboard
├─ header                  page title + subtitle + Export Button
├─ KPI grid                four StatCard (Card · CardHeader · CardTitle · trend delta)
├─ Card (Revenue)          BarChart (rx-data) — monthly series
└─ Card (Transactions)     Table — invoice · customer · status Badge · amount

Instalação

npx gremorie@latest add block-dashboard
pnpm dlx gremorie@latest add block-dashboard
yarn dlx gremorie@latest add block-dashboard
bunx --bun gremorie@latest add block-dashboard

Código

'use client';

import {
  Badge,
  Card,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle,
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from '@gremorie/rx-display';
import { BarChart, type ChartConfig, type ChartDatum } from '@gremorie/rx-data';
import { Button } from '@gremorie/rx-forms';
import {
  ArrowDownRight,
  ArrowUpRight,
  CreditCard,
  DollarSign,
  Download,
  ShoppingCart,
  Users,
} from 'lucide-react';

const KPIs = [
  {
    label: 'Revenue',
    value: '$48,920',
    delta: '+12.4%',
    trend: 'up',
    icon: DollarSign,
  },
  {
    label: 'Customers',
    value: '2,318',
    delta: '+4.1%',
    trend: 'up',
    icon: Users,
  },
  {
    label: 'Orders',
    value: '1,204',
    delta: '+18.3%',
    trend: 'up',
    icon: ShoppingCart,
  },
  {
    label: 'Refunds',
    value: '$1,420',
    delta: '-3.2%',
    trend: 'down',
    icon: CreditCard,
  },
] as const;

const REVENUE_DATA: ChartDatum[] = [
  { month: 'Jan', revenue: 4200 },
  { month: 'Feb', revenue: 5100 },
  { month: 'Mar', revenue: 4800 },
  { month: 'Apr', revenue: 6200 },
  { month: 'May', revenue: 7400 },
  { month: 'Jun', revenue: 6900 },
  { month: 'Jul', revenue: 8100 },
  { month: 'Aug', revenue: 8900 },
];

const REVENUE_CONFIG: ChartConfig = {
  revenue: { label: 'Revenue', color: 'var(--chart-1)' },
};

export function Dashboard() {
  return (
    <div className="flex w-full flex-col gap-6">
      <div className="flex items-center justify-between">
        <div className="flex flex-col gap-1">
          <h2 className="text-xl font-semibold">Dashboard</h2>
          <p className="text-sm text-muted-foreground">
            Snapshot of the last 30 days.
          </p>
        </div>
        <Button variant="outline" size="sm">
          <Download aria-hidden="true" />
          Export
        </Button>
      </div>

      <div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
        {KPIs.map(({ label, value, delta, trend, icon: Icon }) => (
          <Card key={label}>
            <CardHeader>
              <CardDescription className="flex items-center justify-between">
                <span>{label}</span>
                <Icon className="size-4 text-muted-foreground" aria-hidden />
              </CardDescription>
              <CardTitle className="text-2xl">{value}</CardTitle>
            </CardHeader>
            <CardContent>
              <p
                className={
                  trend === 'up'
                    ? 'flex items-center gap-1 text-xs text-emerald-600 dark:text-emerald-400'
                    : 'flex items-center gap-1 text-xs text-destructive'
                }
              >
                {trend === 'up' ? (
                  <ArrowUpRight className="size-3" aria-hidden />
                ) : (
                  <ArrowDownRight className="size-3" aria-hidden />
                )}
                {delta} from last month
              </p>
            </CardContent>
          </Card>
        ))}
      </div>

      <Card>
        <CardHeader>
          <CardTitle>Revenue</CardTitle>
          <CardDescription>Monthly recurring revenue</CardDescription>
        </CardHeader>
        <CardContent>
          <BarChart data={REVENUE_DATA} config={REVENUE_CONFIG} xKey="month" />
        </CardContent>
      </Card>

      <Card>
        <CardHeader>
          <CardTitle>Recent transactions</CardTitle>
          <CardDescription>
            Latest activity from your storefront.
          </CardDescription>
        </CardHeader>
        <CardContent>
          <Table>
            <TableHeader>
              <TableRow>
                <TableHead>Invoice</TableHead>
                <TableHead>Customer</TableHead>
                <TableHead>Status</TableHead>
                <TableHead className="text-right">Amount</TableHead>
              </TableRow>
            </TableHeader>
            <TableBody>{/* rows */}</TableBody>
          </Table>
        </CardContent>
      </Card>
    </div>
  );
}

A edição Angular deste componente está planejada; a edição React está production-ready hoje.

Customização

  • Troque o mock data por hooks do TanStack Query / SWR
  • Substitua BarChart por LineChart ou AreaChart de @gremorie/rx-data
  • Adicione filtros (intervalo de datas, segmento) à linha do header
  • Faça a fiação do botão "Export" a um endpoint de download de CSV

Relacionados

On this page