Skip to main content

Console org Overview — design spec (de-crowd)

reference · designer · updated 2026-09-05 · source

Design spec for the console org-contextual landing (apps/console/src/app/(console)/org/[org]/overview/page.tsx, data in apps/console/src/lib/module-overview-fixtures.ts). Implements off console-design.md (Aurea Ink matiz) + Grid v2 (grid-system.md). Frontend implements; Designer reviews the rendered result.

Source of the problem (José): the screen stacks 4 full-width module panels, each a 6-column row of equal-weight label+value pairs + a Configurar/Abrir pair + a row of bordered section chips. ~24 numbers, all the same weight, no focal point — a wall of data.

1. The fix in one line

Stop showing every module's full dashboard on the landing. Each module gets one hero metric + 2–3 supporting stats in a card grid (not a full-width stack), the section pills become quiet text links, and one module is the amber protagonist. The 4th–6th metrics live one click away (Abrir → the module). This is a glance surface, not a report.

Principle trade-off named (design-principles.md): Simplicity vs Flexibility — dropping the long-tail metrics + heavy section pills from the card face trades completeness for a focal point. Mitigated by retaining quiet section links + Abrir.

2. Hierarchy — headline vs the rest

Per module, one hero metric (the number the operator watches) renders large; 2–3 secondaries render small and inline; everything else is dropped from the overview (reachable via Abrir). No interactive disclosure/expand — it adds a control that competes with Configurar/Abrir on a surface meant to be read in one glance (Simplicity). Disclosure = Abrir.

ModuleHero (large)Secondaries (small, inline)Dropped from overview
EducaciónAlumnosCursos · Activas (success) · Finalización (success)Inscripciones, Nuevos 30d
FinanzasMRRPor cobrar (warning) · Vencidos (danger) · Conciliado (success)Ingresos mes, Pagos mes
CertificadosEmitidosEste mes · Pendientes (warning) · Revocados (danger)Plantillas
CRMContactosLeads · Oportunidades · ConversiónGanados mes

Rule for picking the 2–3: prefer action-relevant stats (alerts — warning/danger — before vanity counts). This is a data shape, not a token decision; fixtures add a hero: true flag per module and cap displayed secondaries at 3.

3. Layout — two directions

A responsive card grid. Each card: header (icon tile + label + Configurar) / hero metric / a compact secondary-stat strip / a quiet footer (section links + Abrir). The hero metric gives every card a single focal point; the grid breaks the "wall of panels"; only ~4 numbers show per module and only the hero is loud.

┌──────────────────────────────────────────┐
│ ▣ Educación ⚙ │ header: icon tile + label · Configurar (ghost icon)
│ │
│ 128 │ HERO metric — type-metric; amber iff protagonist
│ Alumnos │ hero label — type-small, fg-secondary
│ │
│ 6 Cursos · 96 Activas · 82% Final. │ secondaries — value type-mono + label type-meta
│ ──────────────────────────────────────── │ hairline (border-border-subtle)
│ Alumnos · Cursos · Inscripciones Abrir →│ sections (quiet links) Abrir affordance
└──────────────────────────────────────────┘

Direction B — compact module list/table (alternative)

Each module = one dense row: icon + label | hero | 2 inline secondaries | Abrir. Maximally scannable and calm, scales to 10+ modules. But for 4 modules it reads under-furnished, loses the per-module focal point, and makes the data feel utilitarian (a leaderboard, not a control room).

Recommendation: A. It de-crowds (fewer, ranked numbers; grid not stack; one accent) while keeping each module legible and on-brand with the god-view KPI widget pattern. Revisit B only if the module count grows past ~8.

4. Grid + spacing

  • Container: keep mx-auto w-full max-w-6xl px-6 py-10 (a focused org summary may use a centered reading column; G5 anti-stretch governs the infinite god-view canvas, not this contextual landing).
  • Card grid: grid gap-4 · grid-cols-1 · sm:grid-cols-2. Hold at 2 columns — with 4 modules that's a clean 2×2 and avoids a 1-orphan last row (Grid v2 G13). Only go 2xl:grid-cols-3 once the module count makes the last row ≥2.
  • Card padding: p-6 (24). Internal rhythm (base-8, G2): header → hero mt-5 · hero label is tight under the value (gap-1) · hero → secondaries mt-4 · secondaries → footer mt-5 pt-4 border-t border-border-subtle. Secondary strip: flex flex-wrap gap-x-4 gap-y-2.
  • Icon tile: size-9 rounded-md (R3), bg-elevated, icon 18px stroke 1.5.
  • Mobile→desktop: 1-col stack → 2-col at sm. Cards never side-scroll (G6 overflow-x: clip).

5. The accent moment (exactly one)

Amber appears once on the screen: the protagonist module's hero metric, rendered in text-accent-text (#f0b95a, AA ≥4.5:1 on ink), and that card carries bg-elevated + border-accent-border + a faint bg-accent-soft wash behind the hero block only. Every other card's hero is text-fg-primary on bg-surface / border-border-subtle.

  • The protagonist is data, not an action (this landing has no single primary action — each module is equal). This mirrors the god-view / KPI-widget "one protagonist per band" pattern (kpi.tsx).
  • Status colors are never the accent (color-scope.md, G17): secondary stats use text-success / text-warning / text-danger for their own meaning; these coexist with the one amber moment because they are categories, not the magnet.
  • Actions are never amber — Configurar/Abrir/section links stay neutral. Amber is the data magnet, not navigation.
  • Protagonist is a fixture flag (accent: true, already present — keep at most one). Reviewable as a budget: count surfaces resolving to accent ≤ 1.

6. Per-module actions (so they don't compete with the data)

AffordanceTreatmentTokens / motion
ConfigurarGhost icon button (gear, Settings02Icon 15px) top-right of the header. Tooltip/aria-label "Configurar". Not a labeled button — it's secondary.text-fg-muted → hover text-fg-primary + bg-elevated, rounded-md; press scale(0.97) --duration-press --ease-out
AbrirQuiet text link in the footer right (Abrir + ArrowRight01Icon). The card is not a link (avoids nested-interactive a11y faults).type-small text-fg-secondary → hover text-fg-primary; arrow translateX(2px) on hover, --duration-press --ease-out
Section linksFooter left: middot-separated plain text links (type-small text-fg-muted, underline-offset on hover → text-fg-secondary). Not bordered pills — pills were a top crowding source. Cap at 3.color + underline only, --duration-press --ease-out
Próximamente (module unbuilt, segment: null)Replace Abrir with a muted pill type-meta rounded-pill bg-elevated px-2 py-0.5 text-fg-muted. Configurar may remain.static

Hierarchy: hero metric (loud) > secondaries (quiet, status-toned) > section links + Abrir (quietest, fg-muted/secondary) > Configurar (icon-only, fg-muted). Data wins; actions recede.

7. Tokens (console .console scope — packages/ui/src/admin/console/console-theme.css)

All utilities below resolve through the .console ink scope already on <body>; no new tokens needed. No raw hex in TSX.

ElementToken / utility
Page canvasbg-canvas (#14120f)
Card (default)bg-surface + border border-border-subtle, rounded-xl (R1)
Card (protagonist)bg-elevated + border border-accent-border; hero block wash bg-accent-soft
Icon tilebg-elevated, rounded-md (R3); icon text-fg-secondary (protagonist: text-accent-text)
Module labeltype-h2 text-fg-primary
Hero valuetype-metric (30/600 mono tabular); text-fg-primary / protagonist text-accent-text
Hero labeltype-small text-fg-secondary
Secondary valuetype-mono (13 tabular) · text-fg-primary or status (text-success/-warning/-danger)
Secondary labeltype-meta text-fg-muted
Footer hairlineborder-t border-border-subtle
Section / Abrir linkstype-small; text-fg-muted / text-fg-secondarytext-fg-primary
Configurar hover bgbg-elevated; focus ring --shadow-focus
Radiicard rounded-xl (R1 14) · tile/buttons rounded-md (R3 8) · pills rounded-pill
Spacingbase-8 only: p-6 gap-4 mt-5 mt-4 pt-4 gap-x-4 gap-y-2

Type roles used: type-h2, type-metric, type-mono, type-small, type-meta — all existing (foundation-ui-conventions.md § Typography). No new type tokens.

8. Motion (console tokens, transform/opacity only — console-design.md §6)

InteractionSpec
Card mountopacity 0→1 + translateY(8px→0), staggered --stagger-band (60ms) per card, --duration-enter (220ms) --ease-out. prefers-reduced-motion → instant opacity, no translate.
Card hoverborder-border-subtle → border-border-default + shadow-sm; no transform on the card (too large). box-shadow, border-color ~150ms --ease-out. @media (hover:hover) only.
Configurarhover bg/color; press scale(0.97) --duration-press (120ms) --ease-out.
Abrir arrowtranslateX(2px) on hover, --duration-press --ease-out.
Section linkcolor + underline only, --duration-press --ease-out.

No expand/disclosure animation (no disclosure). Animate only transform/opacity; transition: all banned.

9. States (per module card — each card owns its 4 states)

StateRender
LoadingLayout-matched skeleton: icon-tile shimmer + label bar; hero block wdg-shimmer bg-sunken h-8 w-24; 3 secondary shimmer bars bg-elevated; footer hairline. Same grid (no layout shift). Mirror KpiSkeleton shimmer (apps/admin/src/components/widgets/kpi.tsx). aria-busy, sr-only "Cargando…".
Empty (module enabled, no data yet)Header normal; in place of the hero, one muted line type-small text-fg-muted "Sin datos todavía"; no secondaries; Configurar stays. Not a dashed page-empty box.
Error (this module's summary failed)Header normal; card body = inline error row: AlertCircleIcon + type-small text-danger "No se pudo cargar este módulo" (+ quiet "Reintentar" if a retry exists), role="alert". Per-card only — sibling cards still render (DF4: error is its own state, never a zeroed fallback).
SuccessThe card per §3 Direction A.
Próximamente (unbuilt, segment:null)Success card, Abrir → muted "Próximamente" pill (§6).

Whole-page empty (org not found) keeps the existing centered EmptyState.

10. Paper

No dedicated artboard yet. Visual source of truth for the card anatomy = the god-view KPI widget pattern in console-design.md §4 (one protagonist per band) realized in kpi.tsx. A Paper card mock on the hub file (01KS9HJRSXFAP5FART7R5Y07CM) is optional polish; this token-level spec is sufficient for Frontend. Designer reviews the rendered result against the 8 principles before close.

11. What changes for Frontend (summary)

  1. module-overview-fixtures.ts: add hero: true on one metric per module; keep accent: true on exactly one module; cap displayed secondaries at 3 (drop the long-tail per §2).
  2. overview/page.tsx: replace the full-width space-y-3 panel stack with a grid gap-4 sm:grid-cols-2 of ModuleCards (Direction A anatomy).
  3. Section links: bordered pills → quiet middot text links. Configurar: labeled button → ghost icon button. Abrir: footer text link (card not a link).
  4. Add per-card loading/empty/error states (§9); keep page-level org-not-found EmptyState.
  5. Motion per §8. Extraction: if ModuleCard is reused by another surface, it PROMOTES to the neutral @tedos/ui foundation (never @tedos/ui/admin* — console can't consume that subtree, app-import-boundaries.md #1078) with an inventory row in foundation-ui-conventions.md.