---
id: glyco-patterns
title: Patterns — Shell, Bento, Copilot Surfaces, Clinical Display, Accessibility
chapter: 04
source-of-truth: src/components/home/, src/components/copilot/, src/components/layout/
---

# 04 — Patterns

How components compose into Glyco's signature surfaces. Use these as blueprints; the
dashboard home (`/dashboard`) is the reference implementation of all of them.

## 1. Dashboard shell

```
┌──────────┬──────────────────────────────────────┐
│ Sidebar  │ Header (glass, breadcrumbs, ⌘K, user)│
│ 220px /  ├──────────────────────────────────────┤
│ 64px     │ Page content (px-6 gutters)          │
│ collapsed│                                      │
└──────────┴──────────────────────────────────────┘
```

- `src/components/layout/dashboard-layout.tsx` composes `sidebar` + `header` + content;
  safe-area insets for notched devices.
- Sidebar: 220px expanded / 64px collapsed, motion-safe transition, active item =
  `--sidebar-active-bg` wash + `--sidebar-active-fg`; nav targets get 44px hit-area
  extenders. Mobile: sidebar becomes `mobile-drawer` (Sheet) under `mobile-header`.
- Header is a glass surface (`--lg-bg-regular`), hidden on mobile.
- Global command palette: `quick-actions-modal.tsx` (cmdk) on **⌘K** — same shortcut
  focuses the composer. Keyboard-first is a product principle.

## 2. Home bento grid

`src/components/home/bento.tsx` — CSS Grid with named areas:

```
"dia dia brief brief"
"dia dia ret   ade"
"comp comp atv  alert"
```

Linha do Dia (2×2) + Glyco Brief (top right) + KPI tiles + composition chart + alerts.
Cards enter with staggered `card-rise` (IntersectionObserver-driven, reduced-motion safe).
The greeting header sits above with the molecule mark + radial primary glow.

## 3. Composer (the AI front door)

`src/components/home/composer.tsx` — hero input at the top of the dashboard:

- `GlassSurface variant="composer"`: clear glass + identity ring + outer glow
  (`--home-glow`), inner gradient `--composer-inner`.
- Animated orb (radial blue gradient, `orb-drift` ambient loop).
- Typing `/` opens the **slash menu** (`slash-menu.tsx`, Linear-style) listing skills:
  `resumo, receita, protocolo, bioimpedancia, comparar`.
- ⌘K focuses it from anywhere; model chip shows the active provider; streaming state
  while the copilot responds.

## 4. Copilot surface routing

Every copilot tool declares `surface: "inline" | "action" | "drawer" | "navigate"` and the
client dispatches accordingly (`copilot-thread.tsx`):

| Surface | Component | Use |
|---------|-----------|-----|
| `inline` | message bubble in thread | read-only answers, summaries |
| `action` | `quick-action.tsx` card | reversible writes — preview + confirm + undo |
| `drawer` | `action-drawer.tsx` (Sheet) | editable artifacts (receita drafts) with dirty-state + draft persistence + undo toast on close |
| `navigate` | router push | "leve-me para…" |

**Risk ladder** (`risk: low | med | high | irreversible`): low/med execute after inline
confirm; high uses `confirm-bar.tsx` (sticky, risk-styled); irreversible requires the
two-step `POST /api/copilot/confirm` flow. Every action is audited (`agent_actions`) and
reversible ones register an undo token surfaced via `undo-toast.tsx`.
The thread region uses `aria-live`; Esc is two-stage (collapse → close).

## 5. Clinical data display

- **KPI tiles** (`kpi-tile.tsx`): state variants ok/attention/risk with glow, animated
  digits, `role="status"`, state spelled out in `aria-label` and as a text/glyph indicator.
- **Reference ranges**: charts shade the clinical target zone
  (`design-system/charts/reference-range.tsx`); values outside it pick up
  `--color-attention`/`--color-risk` plus a textual flag.
- **Trends**: axis-less sparklines (`composicao-chart.tsx`) for in-card context; full
  charts on detail pages.
- **Anonymization in AI surfaces**: patient context renders as
  `[Paciente C.V.] 45 anos · DM2 · objetivo: recomposição` — initials + age + condition;
  never full name/CPF near an LLM boundary.
- **Bioimpedance**: anatomy image + segment overlays (`body-segments.tsx`), donut rings
  for composition, semi-gauges for target progress, `clinical-timeline` for history.

## 6. States: loading, empty, error

| State | Pattern |
|-------|---------|
| Loading | `SkeletonList` matching final layout (`rows/cards/kpi`); buttons flip to `loading` with spinner + label |
| Empty | `EmptyState`: icon + pt-BR title ("Sem medições") + imperative description + CTA |
| Error (card-level) | `Card.Error` / DataLoadError: card explains the failure and offers retry; the rest of the page stays alive — **never** blank the page for one failed query |
| Error (action) | assertive toast with actionable copy |
| Onboarding | `empty-invite.tsx` + driver.js guided tour (`tour-steps.ts`, 6 steps) on first visit |

## 7. Accessibility patterns (WCAG 2.1 AA baseline)

1. **Skip link** "Pular para o conteúdo principal" (2.4.1).
2. **Focus**: visible 2px `--focus-ring` outlines everywhere; offset 2px (0 on inputs,
   3px on switches).
3. **Hit areas**: ≥44×44px; compact controls extend via `::after` insets.
4. **Disabled**: `aria-disabled` + `pointer-events-none` — focusable, announced, inert.
5. **Live regions**: copilot stream and toasts announce via `aria-live` (polite vs
   assertive by severity).
6. **Color independence**: every semantic color pairs with text or a glyph.
7. **Motion**: `prefers-reduced-motion` collapses all animation (global 1ms rule + JS
   gates).
8. **Transparency**: `prefers-reduced-transparency` makes glass opaque (token-level
   fallback).
9. **Contrast modes**: user-toggleable `.high-contrast`; `prefers-contrast: more`
   strengthens glass borders.
10. **Landmarks/roles**: nav/main/section landmarks; `role="status"` on KPIs;
    dialogs trap focus and close on Esc.
11. **Keyboard**: ⌘K palette, slash menu arrows, Esc two-stage close, full Tab coverage.

Print: a dedicated stylesheet strips chrome and glass, forces black-on-white, preserves
clinical content page-breaks, and prints link URLs.

## 8. Page composition checklist (new dashboard page)

1. Server component page in `src/app/dashboard/<area>/page.tsx`; metadata title
   `"<Área> — Glyco"`.
2. Wrap in the dashboard shell (layout already provides sidebar/header).
3. Content cards: `Card variant="glass-regular"` on the canvas; `solid` inside drawers.
4. Provide skeleton, empty, and error states for every data region.
5. pt-BR copy per [01-brand.md §4](01-brand.md); title-case feature names.
6. Entrance: `card-stagger` or `staggerCards()`; nothing animates if reduced motion.
7. Add the page to sidebar nav + command palette registry.
8. Run the accessibility checklist (§7) before review.
