[87c7f3ec] Responsive grids: xl/2xl breakpoints + mobile overflow fix across all pages (#158) (#162) (#163)

* [87c7f3ec] feat(responsive): add xl/2xl breakpoint classes to dashboard grid layouts

Adds xl: and 2xl: Tailwind breakpoint classes to all grid layouts in
command-center.tsx, auditor-dashboard.tsx, team-health-cards.tsx,
agent-grid.tsx, and metrics/page.tsx so content can expand denser
beyond the current lg cap at ultrawide (2560px) viewports.

Key changes:
- team-health-cards.tsx: xl:grid-cols-4 2xl:grid-cols-6 (up to 6 teams)
- metrics/page.tsx Team Health: xl:grid-cols-5 2xl:grid-cols-6
- agent-grid.tsx: xl/2xl classes for all 3 column variants
- TokenUsageCostsSection: 2xl:grid-cols-6 added to row 1 (already had xl)
- Fixed-size grids (2-4 items): xl matches lg, 2xl same as xl

* [87c7f3ec] fix(mobile): stack grid-cols-12 layouts on mobile and fix git-browser header overflow

communications/page.tsx: change col-span-3/6 to col-span-12 lg:col-span-3/6 so
the three panels stack vertically on 375px viewports instead of being squished
to 25%/50% widths. Gate the viewport-height constraint (h-[calc(100vh-7rem)]) and
flex-1/min-h-0 to lg: so mobile can scroll naturally. Also fixes the Suspense
fallback skeleton with the same responsive col-spans.

git-browser.tsx: header flex row now goes flex-col on mobile and sm:flex-row on
sm+ (640px), eliminating the overflow from the w-64 SelectTrigger plus Refresh
button (346px combined) at 375px (327px content width). SelectTrigger is
w-full on mobile and sm:w-64 on sm+.

journals/page.tsx and git-browser.tsx grids already use col-span-12 lg:col-span-X
so no grid changes needed there.

---------

Co-authored-by: Frontend Developer 2 <fe-dev-2@agents.roboco.dev>
This commit is contained in:
Renzo F
2026-06-14 20:55:23 +02:00
committed by GitHub
co-authored by Frontend Developer 2
parent ddd9c7a38f
commit bb9d4ff12a
7 changed files with 30 additions and 30 deletions
@@ -297,7 +297,7 @@ function CommunicationsPageContent() {
const selectedChannel = channels?.find(c => c.id === channelId);
return (
<div className="flex flex-col h-[calc(100vh-7rem)]">
<div className="flex flex-col lg:h-[calc(100vh-7rem)]">
{/* Header */}
<div className="flex items-center justify-between mb-4">
<div>
@@ -319,9 +319,9 @@ function CommunicationsPageContent() {
onRetry={() => refetch()}
/>
) : (
<div className="grid grid-cols-12 gap-6 flex-1 min-h-0">
<div className="grid grid-cols-12 gap-4 lg:gap-6 lg:flex-1 lg:min-h-0">
{/* Panel 1: Channels */}
<Card className="col-span-3 flex flex-col overflow-hidden">
<Card className="col-span-12 lg:col-span-3 flex flex-col overflow-hidden">
<CardContent className="p-3 flex flex-col h-full">
<div className="flex items-center gap-2 mb-3 pb-2 border-b">
<Hash className="h-4 w-4 text-muted-foreground" />
@@ -339,7 +339,7 @@ function CommunicationsPageContent() {
</Card>
{/* Panel 2: Groups */}
<Card className="col-span-3 flex flex-col overflow-hidden">
<Card className="col-span-12 lg:col-span-3 flex flex-col overflow-hidden">
<CardContent className="p-3 flex flex-col h-full">
<div className="flex items-center gap-2 mb-3 pb-2 border-b">
<Users className="h-4 w-4 text-muted-foreground" />
@@ -365,7 +365,7 @@ function CommunicationsPageContent() {
</Card>
{/* Panel 3: Sessions */}
<Card className="col-span-6 flex flex-col overflow-hidden">
<Card className="col-span-12 lg:col-span-6 flex flex-col overflow-hidden">
<CardContent className="p-3 flex flex-col h-full">
<div className="flex items-center gap-2 mb-3 pb-2 border-b">
<MessageCircle className="h-4 w-4 text-muted-foreground" />
@@ -393,29 +393,29 @@ function CommunicationsPageContent() {
export default function CommunicationsPage() {
return (
<Suspense fallback={
<div className="flex flex-col h-[calc(100vh-7rem)]">
<div className="flex flex-col lg:h-[calc(100vh-7rem)]">
<div className="flex items-center justify-between mb-4">
<div>
<Skeleton className="h-9 w-48 mb-2" />
<Skeleton className="h-5 w-64" />
</div>
</div>
<div className="grid grid-cols-12 gap-6 flex-1">
<Card className="col-span-3">
<div className="grid grid-cols-12 gap-4 lg:gap-6">
<Card className="col-span-12 lg:col-span-3">
<CardContent className="p-3 space-y-2">
{Array.from({ length: 6 }).map((_, i) => (
<Skeleton key={i} className="h-8 w-full" />
))}
</CardContent>
</Card>
<Card className="col-span-3">
<Card className="col-span-12 lg:col-span-3">
<CardContent className="p-3 space-y-2">
{Array.from({ length: 4 }).map((_, i) => (
<Skeleton key={i} className="h-10 w-full" />
))}
</CardContent>
</Card>
<Card className="col-span-6" />
<Card className="col-span-12 lg:col-span-6" />
</div>
</div>
}>
+8 -8
View File
@@ -210,7 +210,7 @@ export default function MetricsPage() {
{/* Velocity Metrics */}
<div>
<h2 className="text-lg font-semibold mb-3">Velocity</h2>
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4 xl:grid-cols-4 2xl:grid-cols-4">
<MetricCard
title="Completed Today"
value={completedToday}
@@ -241,7 +241,7 @@ export default function MetricsPage() {
{/* Task Status */}
<div>
<h2 className="text-lg font-semibold mb-3">Task Status</h2>
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-5">
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-5 xl:grid-cols-5 2xl:grid-cols-5">
<MetricCard
title="Pending"
value={pending}
@@ -273,7 +273,7 @@ export default function MetricsPage() {
{/* Agent Status */}
<div>
<h2 className="text-lg font-semibold mb-3">Agent Status</h2>
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4 xl:grid-cols-4 2xl:grid-cols-4">
<MetricCard
title="Running"
value={runningAgents}
@@ -304,7 +304,7 @@ export default function MetricsPage() {
{/* Team Health */}
<div>
<h2 className="text-lg font-semibold mb-3">Team Health</h2>
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-5">
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-5 xl:grid-cols-5 2xl:grid-cols-6">
{teamMetrics.map((tm) => (
<TeamHealthCard
key={tm.team}
@@ -346,7 +346,7 @@ function TokenUsageCostsSection() {
<h2 className="text-lg font-semibold">Token Usage &amp; Costs</h2>
{/* Row 1 — Summary cards */}
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-6">
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-6 2xl:grid-cols-6">
<SummaryCard
title="Tokens Input"
value={summary ? fmtTokens(summary.tokens_input) : undefined}
@@ -392,7 +392,7 @@ function TokenUsageCostsSection() {
</div>
{/* Row 2 — Time series + model donut */}
<div className="grid gap-4 lg:grid-cols-3">
<div className="grid gap-4 lg:grid-cols-3 xl:grid-cols-3 2xl:grid-cols-3">
<div className="lg:col-span-2">
<UsageTimeSeriesChart data={timeSeries} isLoading={loadingTS} />
</div>
@@ -400,13 +400,13 @@ function TokenUsageCostsSection() {
</div>
{/* Row 3 — Agent bar + team bar */}
<div className="grid gap-4 lg:grid-cols-2">
<div className="grid gap-4 lg:grid-cols-2 xl:grid-cols-2 2xl:grid-cols-2">
<AgentUsageChart data={agentUsage} isLoading={loadingAgents} />
<TeamUsageChart data={teamUsage} isLoading={loadingTeams} />
</div>
{/* Row 4 — Projection + cache efficiency */}
<div className="grid gap-4 sm:grid-cols-2">
<div className="grid gap-4 sm:grid-cols-2 xl:grid-cols-2 2xl:grid-cols-2">
<ProjectionCard projection={projection} isLoading={loadingProj} />
<CacheEfficiencyCard cacheStats={cacheStats} isLoading={loadingCache} />
</div>