From 0cbe3af7b5c1ddb48a6d2960545d97db176ea074 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 5 Jul 2026 03:10:21 +0000 Subject: [PATCH] delta-command: precision UI pass Tighten the design system so the interface reads as data-first: Design system (globals.css) - Card is static by default: removed hover motion/blur/shadow shifts. Interactive cards opt in via a new .card-interactive. - Typography scale collapsed to five tiers with one job each: headline, title-lg, title-md, title-sm, body + metric/metric-sm. - Merged duplicate label classes (metric-label, label-md) into .label. - Buttons made a uniform 36px height with keyboard-precise focus rings (ring-2 offset) instead of the shadow-glow effect. - Banners get a solid 3px left stripe (:before) instead of decorative full-opacity fills so scanning severity is instant. - Utilization cells drop rounded-lg + hover scale for a rounded/rounded spreadsheet feel; tabular-nums applied to everything numeric. - Removed the grid-pattern page background; a still page reads faster. Component polish - Sidebar: static brand mark (no glow shadow), thinner nav active bar. - Header: 56px sticky top bar, title + optional inline meta + date only. - KPICard: monochrome inline icon + label, single vertical rhythm, no hover motion, brighter context text. - ActionItemsPanel: divide-y rows with a per-severity 2px left stripe and hover:tint; small severity counter in the header. - ExecutiveBriefingPanel: baseline-aligned AI badge, denser leading, minimum-height empty state. - Milestones + Upcoming Closes: identical row rhythm with divide-y, chip + tabular days-until stack. - PipelineChart & UtilizationChart: tighter margins, 2/3 radius bars, dashed grid (2 4), cursor tint on hover. - Opportunity kanban card converted to card-interactive with tabular amounts and a compact stage-select. - ProjectCard: bulky Update Status select replaced with an inline badge-style status picker (chevron indicator + native select overlay). Verified: next build clean, tsc --noEmit passes. Co-authored-by: Nathan Faggian --- apps/delta-command/src/app/dashboard/page.tsx | 39 ++-- apps/delta-command/src/app/globals.css | 156 ++++++++------- apps/delta-command/src/app/layout.tsx | 2 +- .../components/dashboard/ActionItemsPanel.tsx | 63 +++--- .../dashboard/ExecutiveBriefingPanel.tsx | 52 +++-- .../src/components/dashboard/KPICard.tsx | 76 ++------ .../components/dashboard/MilestonesPanel.tsx | 30 +-- .../components/dashboard/PipelineChart.tsx | 26 ++- .../components/dashboard/UtilizationChart.tsx | 78 ++++---- .../src/components/layout/Header.tsx | 13 +- .../src/components/layout/Sidebar.tsx | 14 +- .../opportunities/OpportunitiesPageClient.tsx | 74 ++++--- .../opportunities/PipelineBoard.tsx | 118 +++++------ .../src/components/projects/ProjectCard.tsx | 184 ++++++++++-------- .../projects/ProjectsPageClient.tsx | 36 ++-- .../src/components/team/TeamFilters.tsx | 10 +- .../src/components/team/TeamPageClient.tsx | 12 +- .../components/team/UtilizationTimeline.tsx | 122 ++++++------ 18 files changed, 552 insertions(+), 553 deletions(-) diff --git a/apps/delta-command/src/app/dashboard/page.tsx b/apps/delta-command/src/app/dashboard/page.tsx index 4c84ad1..6de2478 100644 --- a/apps/delta-command/src/app/dashboard/page.tsx +++ b/apps/delta-command/src/app/dashboard/page.tsx @@ -42,35 +42,31 @@ export default async function DashboardPage() {
-
+
@@ -93,13 +89,13 @@ export default async function DashboardPage() { {atRiskProjects.length > 0 && (
-
-

Projects Needing Attention

+
+

Projects Needing Attention

All projects
-
+
{atRiskProjects.map((project) => (
-

Upcoming Closes

-

- {formatCurrency(closingValue)} in next 30 days -

+

Upcoming Closes

+

{formatCurrency(closingValue)} in next 30 days

View all
-
    +
      {closes.map((opp) => ( -
    • +
    • -

      {opp.title}

      -

      {opp.client}

      -
      +

      {opp.title}

      +

      {opp.client}

      +
      {opp.stage} - {opp.probability}% + + {opp.probability}% probability +
      -

      {formatCurrency(opp.value)}

      -

      +

      {formatCurrency(opp.value)}

      +

      {formatDate(opp.expectedClose)}

      diff --git a/apps/delta-command/src/app/globals.css b/apps/delta-command/src/app/globals.css index 3b4177e..54040ca 100644 --- a/apps/delta-command/src/app/globals.css +++ b/apps/delta-command/src/app/globals.css @@ -14,7 +14,7 @@ body { @apply bg-surface text-surface-on antialiased; - font-feature-settings: "kern" 1, "liga" 1; + font-feature-settings: "kern" 1, "liga" 1, "cv11" 1, "ss01" 1; } h1, h2, h3, h4 { @@ -24,119 +24,131 @@ select option { @apply bg-surface-bright text-surface-on; } + + /* Tabular numbers everywhere data is displayed. */ + .tabular { + font-variant-numeric: tabular-nums; + } } @layer components { + /* + * Cards. + * + * Static by default — precise dashboards don't move under the cursor. + * Use .card-interactive on cards whose click/hover implies a target. + */ .card { - @apply rounded-xl border border-white/[0.06] bg-surface-bright/80 shadow-card - backdrop-blur-sm transition-all duration-300 ease-emphasized - hover:border-white/[0.1] hover:bg-surface-bright hover:shadow-elevated; + @apply rounded-xl border border-white/[0.06] bg-surface-bright/80 shadow-card; + } + + .card-interactive { + @apply card cursor-pointer transition-colors duration-150 ease-standard + hover:border-white/[0.1] hover:bg-surface-bright; } - .card-flat { - @apply rounded-xl border border-white/[0.06] bg-surface-bright/80; + /* Small, uppercase label used for metric captions and section eyebrows. */ + .label { + @apply text-[11px] font-medium uppercase tracking-[0.08em] text-surface-on-variant tabular; } .badge { - @apply inline-flex items-center rounded-md px-2 py-0.5 text-[11px] font-medium leading-4; + @apply inline-flex items-center rounded-md px-2 py-0.5 text-[11px] font-medium leading-4 tabular; } .chip { @apply inline-flex items-center rounded-md bg-surface-container/60 px-2 py-0.5 - text-[11px] font-medium leading-4 text-surface-on-variant ring-1 ring-inset ring-white/[0.06]; + text-[11px] font-medium leading-4 text-surface-on-variant ring-1 ring-inset ring-white/[0.06] tabular; } .btn-primary { - @apply inline-flex items-center justify-center gap-2 rounded-lg bg-accent px-5 py-2 - text-sm font-medium text-white shadow-sm - transition-all duration-200 ease-standard - hover:bg-blue-400 active:scale-[0.98] - focus-visible:outline-none focus-visible:shadow-glow; + @apply inline-flex h-9 items-center justify-center gap-2 rounded-lg bg-accent px-4 + text-sm font-medium text-white + transition-colors duration-150 ease-standard + hover:bg-blue-400 active:bg-blue-500 + focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-surface; } .btn-secondary { - @apply inline-flex items-center justify-center gap-2 rounded-lg border border-white/[0.08] - bg-surface-container px-5 py-2 text-sm font-medium text-surface-on - transition-all duration-200 ease-standard + @apply inline-flex h-9 items-center justify-center gap-2 rounded-lg border border-white/[0.08] + bg-surface-container px-4 text-sm font-medium text-surface-on + transition-colors duration-150 ease-standard hover:bg-surface-container-high - focus-visible:outline-none focus-visible:shadow-glow; + focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-surface; } .btn-tonal { - @apply inline-flex items-center justify-center gap-2 rounded-lg bg-accent-muted px-5 py-2 + @apply inline-flex h-9 items-center justify-center gap-2 rounded-lg bg-accent-muted px-4 text-sm font-medium text-accent-foreground - transition-all duration-200 ease-standard hover:bg-blue-500/20; + transition-colors duration-150 ease-standard hover:bg-blue-500/20 + focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-surface + disabled:opacity-60; } - .icon-btn { - @apply relative flex h-9 w-9 items-center justify-center rounded-lg - text-surface-on-variant transition-all duration-200 ease-standard - hover:bg-white/[0.06] hover:text-surface-on; - } - - .headline-md { - @apply text-2xl font-semibold leading-8 tracking-tight; + /* Typography scale — five tiers, each with one job. */ + .headline { + @apply text-2xl font-semibold leading-8 tracking-tight text-surface-on; } .title-lg { - @apply text-lg font-semibold leading-7 tracking-tight; + @apply text-base font-semibold leading-6 tracking-tight text-surface-on; } .title-md { - @apply text-sm font-semibold leading-5; + @apply text-sm font-semibold leading-5 text-surface-on; } .title-sm { - @apply text-sm font-medium leading-5; + @apply text-sm font-medium leading-5 text-surface-on; } - .body-md { + .body { @apply text-sm font-normal leading-5 text-surface-on-variant; } - .label-md { - @apply text-xs font-medium uppercase tracking-wider text-surface-on-variant/70; - } - - .section-title { - @apply text-base font-semibold tracking-tight text-surface-on; + .metric { + @apply text-3xl font-semibold leading-[1.1] tracking-tight text-surface-on tabular; } - .metric-value { - @apply text-3xl font-semibold leading-none tracking-tight text-surface-on; - } - - .metric-label { - @apply text-xs font-medium uppercase tracking-wider text-surface-on-variant/80; + .metric-sm { + @apply text-xl font-semibold leading-[1.15] tracking-tight text-surface-on tabular; } .nav-item { - @apply relative flex items-center gap-3 rounded-lg px-3 py-2.5 text-sm font-medium - text-sidebar-muted transition-all duration-200 ease-standard + @apply relative flex h-9 items-center gap-3 rounded-md px-3 text-sm font-medium + text-sidebar-muted transition-colors duration-150 ease-standard hover:bg-white/[0.05] hover:text-sidebar-foreground; } .nav-item-active { - @apply bg-white/[0.08] text-sidebar-foreground before:absolute before:left-0 before:top-1/2 - before:h-5 before:w-0.5 before:-translate-y-1/2 before:rounded-full before:bg-accent - before:shadow-[0_0_8px_rgb(59_130_246/0.6)] before:content-['']; + @apply bg-white/[0.06] text-sidebar-foreground + before:absolute before:left-0 before:top-1/2 before:h-4 before:w-[2px] + before:-translate-y-1/2 before:rounded-full before:bg-accent before:content-['']; + } + + .text-field { + @apply h-9 rounded-md border border-white/[0.08] bg-surface-container/80 px-3 text-sm text-surface-on + outline-none transition-colors duration-150 + placeholder:text-surface-on-variant/50 + focus:border-accent/60 focus:ring-1 focus:ring-accent/40; } - .text-field-outlined { - @apply rounded-lg border border-white/[0.08] bg-surface-container/80 text-sm text-surface-on - outline-none transition-all duration-200 - placeholder:text-surface-on-variant/40 - focus:border-accent/60 focus:shadow-glow; + /* Semantic banners — quiet fills + a solid left stripe for scannability. */ + .banner { + @apply relative flex items-center gap-3 rounded-lg border pl-4 pr-4 py-3 text-sm + before:absolute before:left-0 before:top-0 before:h-full before:w-[3px] before:rounded-l-lg before:content-['']; } .banner-error { - @apply flex items-center gap-3 rounded-xl border border-red-500/30 bg-red-500/10 px-5 py-3.5 - text-red-300 backdrop-blur-sm; + @apply banner border-red-500/25 bg-red-500/[0.06] text-red-200 before:bg-red-500; } .banner-warning { - @apply flex items-center gap-3 rounded-xl border border-amber-500/30 bg-amber-500/10 px-5 py-3.5 - text-amber-200 backdrop-blur-sm; + @apply banner border-amber-500/25 bg-amber-500/[0.06] text-amber-100 before:bg-amber-500; + } + + .banner-info { + @apply banner border-blue-500/25 bg-blue-500/[0.06] text-blue-100 before:bg-blue-500; } .progress-track { @@ -144,12 +156,12 @@ } .progress-indicator { - @apply h-full rounded-full bg-accent transition-all duration-500 ease-emphasized; + @apply h-full rounded-full bg-accent transition-[width] duration-500 ease-standard; } .top-app-bar { - @apply sticky top-0 z-20 flex h-[4.25rem] items-center justify-between - border-b border-white/[0.06] bg-surface/80 px-6 backdrop-blur-xl md:px-8; + @apply sticky top-0 z-20 flex h-14 items-center justify-between + border-b border-white/[0.06] bg-surface/80 px-6 backdrop-blur-md md:px-8; } .nav-drawer { @@ -158,17 +170,17 @@ } .segmented-control { - @apply inline-flex rounded-lg bg-surface-container/80 p-1 ring-1 ring-inset ring-white/[0.06]; + @apply inline-flex rounded-md bg-surface-container/60 p-0.5 ring-1 ring-inset ring-white/[0.06]; } .segmented-item { - @apply flex items-center gap-2 rounded-md px-3.5 py-2 text-sm font-medium - text-surface-on-variant transition-all duration-200 ease-standard + @apply flex h-8 items-center gap-1.5 rounded px-3 text-[13px] font-medium + text-surface-on-variant transition-colors duration-150 ease-standard hover:text-surface-on; } .segmented-item-active { - @apply bg-surface-bright text-surface-on shadow-sm ring-1 ring-white/[0.08]; + @apply bg-surface-bright text-surface-on ring-1 ring-inset ring-white/[0.06]; } .link-subtle { @@ -180,22 +192,18 @@ } .stat-icon { - @apply flex h-9 w-9 shrink-0 items-center justify-center rounded-lg; + @apply flex h-8 w-8 shrink-0 items-center justify-center rounded-md; } .kanban-column { - @apply flex w-72 shrink-0 flex-col rounded-xl border border-white/[0.06] - bg-surface-container-low/60 p-3 backdrop-blur-sm; - } - - .page-shell { - @apply bg-radial-glow bg-grid-pattern bg-grid bg-surface; + @apply flex w-72 shrink-0 flex-col rounded-lg border border-white/[0.06] + bg-surface-container-low/60 p-3; } + /* Utilization grid cell — spreadsheet-precise. */ .util-cell { - @apply mx-auto flex h-10 w-[68px] flex-col items-center justify-center rounded-lg - text-sm font-semibold ring-1 ring-inset transition-all duration-200 - hover:scale-[1.02] hover:brightness-110 active:scale-[0.98]; + @apply mx-auto flex h-9 w-16 items-center justify-center rounded + text-[13px] font-semibold tabular ring-1 ring-inset transition-colors duration-100; } } diff --git a/apps/delta-command/src/app/layout.tsx b/apps/delta-command/src/app/layout.tsx index 64680f8..3226d7d 100644 --- a/apps/delta-command/src/app/layout.tsx +++ b/apps/delta-command/src/app/layout.tsx @@ -25,7 +25,7 @@ export default function RootLayout({
      -
      {children}
      +
      {children}
      diff --git a/apps/delta-command/src/components/dashboard/ActionItemsPanel.tsx b/apps/delta-command/src/components/dashboard/ActionItemsPanel.tsx index 3cc7c31..808bcc6 100644 --- a/apps/delta-command/src/components/dashboard/ActionItemsPanel.tsx +++ b/apps/delta-command/src/components/dashboard/ActionItemsPanel.tsx @@ -1,30 +1,26 @@ import Link from "next/link"; +import { AlertCircle, AlertTriangle, ArrowRight, Info } from "lucide-react"; + import type { ActionItem, ActionSeverity } from "@/core/dashboard-analytics"; import { cn } from "@/core/utils"; -import { - AlertCircle, - AlertTriangle, - Info, - ArrowRight, -} from "lucide-react"; -const severityStyles: Record< - ActionSeverity, - { container: string; icon: typeof AlertCircle } -> = { +const SEVERITY = { critical: { - container: "border-red-500/30 bg-red-500/10", icon: AlertCircle, + stripe: "before:bg-red-500", + iconColor: "text-red-400", }, warning: { - container: "border-amber-500/30 bg-amber-500/10", icon: AlertTriangle, + stripe: "before:bg-amber-500", + iconColor: "text-amber-400", }, info: { - container: "border-blue-500/30 bg-blue-500/10", icon: Info, + stripe: "before:bg-blue-500", + iconColor: "text-blue-400", }, -}; +} as const satisfies Record; interface ActionItemsPanelProps { items: ActionItem[]; @@ -38,36 +34,39 @@ export function ActionItemsPanel({ items }: ActionItemsPanelProps) { return (
      -
      -
      -

      Action Required

      -

      - {critical > 0 && `${critical} critical`} - {critical > 0 && warning > 0 && " · "} - {warning > 0 && `${warning} needs attention`} - {critical === 0 && warning === 0 && `${items.length} items`} -

      -
      +
      +

      Action Required

      +

      + {[ + critical > 0 && `${critical} critical`, + warning > 0 && `${warning} warning`, + critical === 0 && warning === 0 && `${items.length} items`, + ] + .filter(Boolean) + .join(" · ")} +

      -
        +
          {items.slice(0, 6).map((item) => { - const style = severityStyles[item.severity]; - const Icon = style.icon; + const config = SEVERITY[item.severity]; + const Icon = config.icon; return (
        • - +

          {item.title}

          -

          {item.detail}

          +

          {item.detail}

          - +
        • ); diff --git a/apps/delta-command/src/components/dashboard/ExecutiveBriefingPanel.tsx b/apps/delta-command/src/components/dashboard/ExecutiveBriefingPanel.tsx index 261a381..fc2ac15 100644 --- a/apps/delta-command/src/components/dashboard/ExecutiveBriefingPanel.tsx +++ b/apps/delta-command/src/components/dashboard/ExecutiveBriefingPanel.tsx @@ -1,7 +1,8 @@ "use client"; import { useState } from "react"; -import { Sparkles, RefreshCw, AlertCircle } from "lucide-react"; +import { AlertCircle, RefreshCw, Sparkles } from "lucide-react"; + import { generateBriefing } from "@/core/api"; import { cn } from "@/core/utils"; @@ -25,53 +26,46 @@ export function ExecutiveBriefingPanel() { return (
          -
          -
          -

          - - AI Executive Briefing -

          -

          - Leadership summary generated from live pipeline, delivery, and capacity data -

          +
          +
          + + + AI + +

          Executive Briefing

          {error && ( -
          +
          {error}
          )} - {briefing ? ( -
          - {briefing} -
          - ) : ( - !error && - !loading && ( -

          - Click Generate to author a - leadership-ready summary. Requires the backend to have{" "} - LLM_API_KEY{" "} - configured (any OpenAI-compatible provider). -

          - ) + {briefing && ( +
          {briefing}
          + )} + + {!briefing && !error && !loading && ( +

          + Composed from live pipeline, capacity, and delivery data. Requires{" "} + LLM_API_KEY on the backend. +

          )} {loading && !briefing && ( -
          - +
          + Composing briefing…
          )} diff --git a/apps/delta-command/src/components/dashboard/KPICard.tsx b/apps/delta-command/src/components/dashboard/KPICard.tsx index 33c2a91..49041fa 100644 --- a/apps/delta-command/src/components/dashboard/KPICard.tsx +++ b/apps/delta-command/src/components/dashboard/KPICard.tsx @@ -1,76 +1,30 @@ -import { cn } from "@/core/utils"; import type { LucideIcon } from "lucide-react"; -import { TrendingDown, TrendingUp, Minus } from "lucide-react"; - -type AccentTone = "blue" | "violet" | "indigo" | "emerald" | "amber" | "red"; - -const ACCENT_STYLES: Record = { - blue: "bg-blue-500/15 text-blue-400", - violet: "bg-violet-500/15 text-violet-400", - indigo: "bg-indigo-500/15 text-indigo-400", - emerald: "bg-emerald-500/15 text-emerald-400", - amber: "bg-amber-500/15 text-amber-400", - red: "bg-red-500/15 text-red-400", -}; interface KPICardProps { label: string; value: string; context?: string; - change?: number; - changeLabel?: string; icon: LucideIcon; - accent?: AccentTone; } -export function KPICard({ - label, - value, - context, - change, - changeLabel, - icon: Icon, - accent = "blue", -}: KPICardProps) { - const TrendIcon = - change === undefined ? null : change > 0 ? TrendingUp : change < 0 ? TrendingDown : Minus; - const trendColor = - change === undefined - ? "" - : change > 0 - ? "text-emerald-400" - : change < 0 - ? "text-red-400" - : "text-surface-on-variant"; - +/** + * Precision KPI card. + * + * - Fixed rhythm: label + value + context, stacked. No hover motion, no + * colored icon backgrounds (the icon is meta, the number is the message). + * - Icon lives inline with the label so the eye reads label -> value -> context + * in a straight vertical line, uninterrupted. + */ +export function KPICard({ label, value, context, icon: Icon }: KPICardProps) { return ( -
          -
          -

          {label}

          -
          - -
          +
          +
          + +

          {label}

          -

          {value}

          +

          {value}

          {context && ( -

          {context}

          - )} - {change !== undefined && TrendIcon && ( -
          - - - {change > 0 ? "+" : ""} - {change}% - - {changeLabel && ( - {changeLabel} - )} -
          +

          {context}

          )}
          ); diff --git a/apps/delta-command/src/components/dashboard/MilestonesPanel.tsx b/apps/delta-command/src/components/dashboard/MilestonesPanel.tsx index 931125d..05d7b93 100644 --- a/apps/delta-command/src/components/dashboard/MilestonesPanel.tsx +++ b/apps/delta-command/src/components/dashboard/MilestonesPanel.tsx @@ -10,33 +10,37 @@ export function MilestonesPanel({ milestones }: MilestonesPanelProps) { return (
          -

          Upcoming Milestones

          +
          +

          Upcoming Milestones

          +

          + {milestones.length} in view + {milestones.filter((m) => m.overdue).length > 0 && + ` · ${milestones.filter((m) => m.overdue).length} overdue`} +

          +
          All projects
          {milestones.length === 0 ? ( -

          No open milestones

          +

          No open milestones

          ) : ( -
            +
              {milestones.slice(0, 5).map((m) => ( -
            • +
            • -

              {m.title}

              -

              {m.projectName}

              +

              {m.title}

              +

              {m.projectName}

              {m.overdue @@ -45,7 +49,7 @@ export function MilestonesPanel({ milestones }: MilestonesPanelProps) { ? "Today" : `${m.daysUntil}d`} -

              +

              {formatShortDate(m.dueDate)}

              diff --git a/apps/delta-command/src/components/dashboard/PipelineChart.tsx b/apps/delta-command/src/components/dashboard/PipelineChart.tsx index ffa7d22..76c3259 100644 --- a/apps/delta-command/src/components/dashboard/PipelineChart.tsx +++ b/apps/delta-command/src/components/dashboard/PipelineChart.tsx @@ -42,33 +42,39 @@ export function PipelineChart({ opportunities }: PipelineChartProps) { return (
              -

              Pipeline by Stage

              -

              - Opportunity count and value across the sales funnel -

              -
              +
              +

              Pipeline by Stage

              +

              + count across the funnel +

              +
              +
              - - + + { if (name === "value") return [formatCurrency(value), "Total Value"]; return [value, "Count"]; }} /> - + {data.map((entry, index) => ( ))} diff --git a/apps/delta-command/src/components/dashboard/UtilizationChart.tsx b/apps/delta-command/src/components/dashboard/UtilizationChart.tsx index 2d4347a..256028c 100644 --- a/apps/delta-command/src/components/dashboard/UtilizationChart.tsx +++ b/apps/delta-command/src/components/dashboard/UtilizationChart.tsx @@ -36,48 +36,54 @@ export function UtilizationChart({ engineers, maxVisible = 30 }: UtilizationChar fill: getBarColor(e.utilization), })); - const chartHeight = Math.min(520, Math.max(256, data.length * 26)); + const chartHeight = Math.min(520, Math.max(224, data.length * 22)); return (
              -

              Team Utilization

              -

              - Current allocation across the delta engineering team - {engineers.length > maxVisible && ( - · top {maxVisible} by utilization - )} -

              +
              +

              Team Utilization

              +

              + {engineers.length > maxVisible ? `top ${maxVisible} by %` : `${engineers.length} engineers`} +

              +
              - - - `${v}%`} - /> - - [`${value}%`, "Utilization"]} - /> - - - {data.map((entry, index) => ( - - ))} - + + + `${v}%`} + /> + + [`${value}%`, "Utilization"]} + /> + + + {data.map((entry, index) => ( + + ))} +
              diff --git a/apps/delta-command/src/components/layout/Header.tsx b/apps/delta-command/src/components/layout/Header.tsx index 0e706b5..b2254a8 100644 --- a/apps/delta-command/src/components/layout/Header.tsx +++ b/apps/delta-command/src/components/layout/Header.tsx @@ -6,20 +6,19 @@ interface HeaderProps { } /** - * The header is deliberately spartan: a page title, an optional meta line - * (used to show a single actionable number), and today's date. Everything - * else lives on the page itself so the chrome never competes with data. + * Two-line header: page title (h2) and today's date. The optional `meta` slot + * carries a single data-bearing summary; anything decorative goes on the page. */ export function Header({ title, meta }: HeaderProps) { const today = format(new Date(), "MMM d, yyyy"); return (
              -
              -

              {title}

              - {meta &&

              {meta}

              } +
              +

              {title}

              + {meta &&

              {meta}

              }
              - {today} + {today}
              ); } diff --git a/apps/delta-command/src/components/layout/Sidebar.tsx b/apps/delta-command/src/components/layout/Sidebar.tsx index 0b2c3d5..e16657c 100644 --- a/apps/delta-command/src/components/layout/Sidebar.tsx +++ b/apps/delta-command/src/components/layout/Sidebar.tsx @@ -17,14 +17,14 @@ export function Sidebar() { return (