@exxatdesignux/ui 0.5.5 → 0.5.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/consumer-extras/cursor-rules/exxat-ds-agents.mdc +16 -5
- package/consumer-extras/cursor-rules/exxat-ux-discovery-protocol.mdc +122 -0
- package/consumer-extras/cursor-rules/exxat-ux-principles.mdc +186 -0
- package/consumer-extras/cursor-skills/exxat-senior-ux/SKILL.md +145 -0
- package/consumer-extras/patterns/jobs/README.md +59 -0
- package/consumer-extras/patterns/jobs/record-detail.md +177 -0
- package/consumer-extras/patterns/modern-saas-patterns.md +165 -0
- package/dist/components/data-table/index.js +28 -22
- package/dist/components/data-table/index.js.map +1 -1
- package/dist/components/data-table/pagination.js +28 -22
- package/dist/components/data-table/pagination.js.map +1 -1
- package/dist/components/data-table/use-table-state.js +20 -17
- package/dist/components/data-table/use-table-state.js.map +1 -1
- package/dist/components/data-views/hub-table.js +28 -22
- package/dist/components/data-views/hub-table.js.map +1 -1
- package/dist/components/data-views/index.js +28 -22
- package/dist/components/data-views/index.js.map +1 -1
- package/dist/hooks/use-app-theme.d.ts +1 -1
- package/dist/index.js +28 -22
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/data-table/index.tsx +10 -6
- package/src/components/data-table/use-table-state.ts +33 -26
- package/template/docs/jobs/README.md +59 -0
- package/template/docs/jobs/record-detail.md +177 -0
- package/template/docs/modern-saas-patterns.md +165 -0
- package/tokens/hooks-index.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.5.6
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- **`DataTable` auto-pin activates reliably** — fixed a layout bug where the inner `<table>` stretched to `w-full`, making `scrollWidth === clientWidth` even when the sum of column widths exceeded the viewport. The table now renders at the natural sum of column widths (`style={{ width: totalWidth }}`); overflow is detected against `totalWidth > clientWidth + 1` inside a `useLayoutEffect` that also observes the inner table via `ResizeObserver`. Columns marked `defaultPin` now pin as soon as the grid actually overflows (matches `<= 0.5.2` behavior).
|
|
8
|
+
- **New consumer agent skill `exxat-senior-ux` (vendored via `sync-extras`)** — the persona every other Exxat DS skill is downstream of. Defines the 5-step protocol (Discovery → Research → Synthesis → Build → Audit), brief format, "ask vs assume" heuristics, and push-back triggers (no `toast()`, no Vaul, no two-filled-CTAs, no pixel-copy, no inventing primitives without ≥ 2 use cases).
|
|
9
|
+
- **New consumer agent rules (vendored via `sync-extras`)** — `exxat-ux-discovery-protocol` (no code without a design brief on new surfaces; question bank per surface type) and `exxat-ux-principles` (20 principles split into P1–P8 always-follow and P9–P20 default-follow-with-stated-reason; each with what / why / when-to-break / anti-pattern). Both `alwaysApply: true`.
|
|
10
|
+
- **New consumer pattern docs (vendored via `sync-extras`)** — `modern-saas-patterns.md` codifies the 12 modern SaaS patterns (M1–M12) the DS works against, cited in briefs by `(Mx)`. New `patterns/jobs/` library with `record-detail.md` as the first canonical job-to-be-done spec (IA diagram, route vs sheet, when to tab, navigation, actions, states, anti-patterns, audit checklist).
|
|
11
|
+
- **`exxat-ds-agents` "Top of stack"** — agents handbook now points at the senior-UX skill, discovery protocol, principles, modern SaaS canon, and jobs library FIRST on any design task.
|
|
12
|
+
|
|
3
13
|
## 0.5.5
|
|
4
14
|
|
|
5
15
|
### Patch Changes
|
|
@@ -11,6 +11,17 @@ alwaysApply: true
|
|
|
11
11
|
|
|
12
12
|
Before implementing or reviewing **list / table / board / dashboard / data-heavy** pages, read **AGENTS.md** (rule precedence, MUST/MUST NOT, file references, §4.1–§4.8, **§6.4** page vs drawer, **§6.5** no toast, §7.1 command palette, §13 checklist). **Before** adding **new shared UI** not covered by existing **`components/`** patterns, read **`exxat-reuse-before-custom.mdc`**.
|
|
13
13
|
|
|
14
|
+
## Top of stack — read FIRST on any design task
|
|
15
|
+
|
|
16
|
+
**`.cursor/skills/exxat-senior-ux/SKILL.md`** is the persona every other rule and skill is downstream of. It defines the **five-step protocol** (Discovery → Research → Synthesis → Build → Audit), the **brief format**, and the **push-back triggers**. Pair with:
|
|
17
|
+
|
|
18
|
+
- **`.cursor/rules/exxat-ux-discovery-protocol.mdc`** — brief-before-code gate + question bank per surface type.
|
|
19
|
+
- **`.cursor/rules/exxat-ux-principles.mdc`** — 20 principles (P1–P20) split into **always-follow (P1–P8)** and **default-follow with stated reason (P9–P20)**. Every deviation MUST be named in the design brief.
|
|
20
|
+
- **`apps/web/docs/modern-saas-patterns.md`** — the 12 modern SaaS patterns (M1–M12) the DS works against; cite by `(Mx)` codes.
|
|
21
|
+
- **`apps/web/docs/jobs/`** — canonical references per **job-to-be-done** (start with `record-detail.md`). If no job doc matches, write one.
|
|
22
|
+
|
|
23
|
+
On any **new** route / page / hub / detail / wizard / settings / dashboard / overlay, output a **design brief** in chat BEFORE writing files. On trivial edits (copy tweaks, single-class restyles, bug fixes), skip the brief.
|
|
24
|
+
|
|
14
25
|
## Non‑negotiables (if anything conflicts, open AGENTS.md §12–§13)
|
|
15
26
|
|
|
16
27
|
1. **Product data lists** → `DataTable` + search + shared filters + `TablePropertiesDrawer` — not raw `<table>` / ui `Table` alone / ad-hoc grids. With **`ListPageTemplate`** view tabs, pass **`currentView`** + **`onViewChange`** into **`TablePropertiesDrawer`** (**`AGENTS.md` §4.2**, **`.cursor/rules/exxat-table-properties-drawer.mdc`**).
|
|
@@ -40,13 +51,13 @@ Before implementing or reviewing **list / table / board / dashboard / data-heavy
|
|
|
40
51
|
25. **No SLDS leakage** — **`.cursor/rules/exxat-no-slds-leakage.mdc`** — no `slds-*` classes, no `<lightning-*>` markup, no SLDS token names, no synthetic-shadow assumptions. ESLint catches via `exxat-ds/no-slds-classes` + `exxat-ds/no-lightning-elements` (from **`@exxatdesignux/eslint-plugin`**).
|
|
41
52
|
26. **Blueprints + selection guide** — **`apps/web/docs/blueprints/`** + **`apps/web/docs/component-selection-guide.md`** — framework-agnostic specs + decision tree across the whole DS. Start there before composing a new hub.
|
|
42
53
|
27. **Migrations** — **`apps/web/docs/migrations/`** — every deprecation gets a numbered entry (`NNNN-<slug>.md`). Token deprecations surface in `tokens/hooks-index.json` as `deprecated: true` and are lint-flagged.
|
|
43
|
-
28. **Hub supported views (Add view parity)** — **`exxat-hub-supported-views.mdc`** + **`
|
|
54
|
+
28. **Hub supported views (Add view parity)** — **`exxat-hub-supported-views.mdc`** + **`apps/web/docs/hub-supported-views-pattern.md`** — **`FULL_HUB_SUPPORTED_VIEWS`** (seven views, same as Library); sync **`ListPageTemplate`** + **`HubTable`**; real renderers per view; **`LibraryTable`** for **`LibraryItem`** catalogs; **`tokens-hub-auxiliary-views.tsx`** for tokens.
|
|
44
55
|
29. **No Vaul** — **`exxat-no-vaul.mdc`** — side panels = **`Sheet`** only; remove **`vaul`** from consumer apps on **`@exxatdesignux/ui@0.5.3+`**.
|
|
45
56
|
30. **Tabs chrome** — **`exxat-tabs-chrome.mdc`** — hub views = **`ListPageTemplate`** toolbar (`w-max`); record tabs = **`TabsList`** `w-fit`, never full-width stretch.
|
|
46
|
-
31. **Page header actions** — **`exxat-page-header-actions.mdc`** — filled primary + outline overflow; no hand-built grey buttons.
|
|
57
|
+
31. **Page header actions** — **`exxat-page-header-actions.mdc`** + **`apps/web/docs/blueprints/page-header.md`** — filled primary + outline overflow; no hand-built grey buttons.
|
|
47
58
|
32. **Table row preview** — **`exxat-table-row-preview.mdc`** — **`HoverCard`** + DS badges/cells; no bespoke popover cards.
|
|
48
|
-
33. **Sidebar shell** — **`exxat-sidebar-shell.mdc`** + **`AGENTS.md` §9.1** — legacy screenshots = **IA only
|
|
49
|
-
34. **Uploaded images** — **`exxat-no-image-pixel-copy.mdc`** — screenshots = intent
|
|
59
|
+
33. **Sidebar shell** — **`exxat-sidebar-shell.mdc`** + **`AGENTS.md` §9.1** — legacy screenshots = **IA only** (labels/routes); **MUST NOT** copy per-section colors or fork **`app-sidebar.tsx`** styling; use **`SidebarMenuButton`** + **`lib/nav-active`**.
|
|
60
|
+
34. **Uploaded images** — **`exxat-no-image-pixel-copy.mdc`** (always apply) — screenshots/mockups = **intent + IA only**; **MUST** map to blueprints + reference hubs; **MUST NOT** pixel-copy colors, chrome, or bespoke stacks.
|
|
50
61
|
|
|
51
62
|
## Also read
|
|
52
63
|
|
|
@@ -57,7 +68,7 @@ Before implementing or reviewing **list / table / board / dashboard / data-heavy
|
|
|
57
68
|
- **`apps/web/docs/blueprints/`** — framework-agnostic specs (start: `page-header.md`, `data-table.md`).
|
|
58
69
|
- **`apps/web/docs/migrations/`** — token rename + removal history.
|
|
59
70
|
- **`packages/ui/tokens/hooks-index.json`** — machine-readable token index (regenerate via `pnpm --filter @exxatdesignux/ui tokens:index`).
|
|
60
|
-
- `.cursor/rules/exxat-data-tables.mdc`, **`exxat-hub-supported-views.mdc`**, **`exxat-no-vaul.mdc`**, **`exxat-tabs-chrome.mdc`**, **`exxat-page-header-actions.mdc`**, **`exxat-table-row-preview.mdc`**, `exxat-list-page-connected-views.mdc`, **`exxat-centralized-list-dataset.mdc`**, **`exxat-list-page-view-shells.mdc`**, **`exxat-fontawesome-icons.mdc`**, **`exxat-mono-ids.mdc`**, **`exxat-primary-nav-secondary-panel.mdc`**, **`exxat-library-hub-header.mdc`**, **`exxat-collaboration-access.mdc`**, **`exxat-dedicated-search-surfaces.mdc`**, **`exxat-kpi-trends.mdc`**, **`exxat-kpi-flat-band.mdc`**, **`exxat-drawer-vs-dialog.mdc`**, **`exxat-card-vs-list-rows.mdc`**, **`exxat-kpi-max-four.mdc`**, **`exxat-reuse-before-custom.mdc`**, `exxat-table-properties-drawer.mdc`, **`exxat-board-cards.mdc`**, **`exxat-page-vs-drawer.mdc`**, **`exxat-no-toast.mdc`**, **`exxat-command-menu.mdc`**, `exxat-kbd-shortcuts.mdc`, `exxat-accessibility.mdc` at repo root; **`apps/web/.cursor/rules/exxat-dashboard-view-charts.mdc`** for Data tab charts.
|
|
71
|
+
- `.cursor/rules/exxat-data-tables.mdc`, **`exxat-hub-supported-views.mdc`**, **`exxat-no-vaul.mdc`**, **`exxat-tabs-chrome.mdc`**, **`exxat-page-header-actions.mdc`**, **`exxat-table-row-preview.mdc`**, `exxat-list-page-connected-views.mdc`, **`exxat-centralized-list-dataset.mdc`**, **`exxat-list-page-view-shells.mdc`**, **`exxat-fontawesome-icons.mdc`**, **`exxat-mono-ids.mdc`**, **`exxat-nav-single-active.mdc`** (one active sidebar/secondary link — `nav-active` helpers), **`exxat-primary-nav-secondary-panel.mdc`**, **`exxat-library-hub-header.mdc`**, **`exxat-collaboration-access.mdc`**, **`exxat-dedicated-search-surfaces.mdc`**, **`exxat-kpi-trends.mdc`**, **`exxat-kpi-flat-band.mdc`**, **`exxat-drawer-vs-dialog.mdc`**, **`exxat-card-vs-list-rows.mdc`**, **`exxat-kpi-max-four.mdc`**, **`exxat-reuse-before-custom.mdc`**, `exxat-table-properties-drawer.mdc`, **`exxat-board-cards.mdc`**, **`exxat-page-vs-drawer.mdc`**, **`exxat-no-toast.mdc`**, **`exxat-command-menu.mdc`**, `exxat-kbd-shortcuts.mdc`, `exxat-accessibility.mdc` at repo root; **`apps/web/.cursor/rules/exxat-dashboard-view-charts.mdc`** for Data tab charts.
|
|
61
72
|
- **`apps/web/docs/kpi-flat-band-pattern.md`**, **`apps/web/docs/shell-surface-elevation-pattern.md`** — flat KPI strip + sidebar/secondary/page OKLCH stack.
|
|
62
73
|
- **`apps/web/docs/library-hub-header-pattern.md`** — folder-scoped library header **Customize folder**.
|
|
63
74
|
- **`apps/web/docs/collaboration-access-pattern.md`** — shared hub face rail + invite sheet.
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Exxat DS — output a design brief before writing files for any new surface; question bank by surface type
|
|
3
|
+
alwaysApply: true
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Exxat DS — UX discovery protocol
|
|
7
|
+
|
|
8
|
+
On any task that creates a **new route, page, template, wizard, or
|
|
9
|
+
significant component**, the assistant MUST output a **design brief in chat**
|
|
10
|
+
BEFORE writing files. Brief format is defined in
|
|
11
|
+
`.cursor/skills/exxat-senior-ux/SKILL.md` §3.
|
|
12
|
+
|
|
13
|
+
## MUST
|
|
14
|
+
|
|
15
|
+
1. **No code without a brief.** New surfaces require the brief. Trivial edits
|
|
16
|
+
to existing surfaces (copy tweak, single-class change, bug fix, refactor)
|
|
17
|
+
are exempt.
|
|
18
|
+
2. **Cite a reference.** Every brief names **one repo reference** + **two
|
|
19
|
+
modern SaaS analogues** (Linear / Notion / Stripe / Figma / Vercel / etc.)
|
|
20
|
+
that solve the same **job-to-be-done**. Cite the SaaS analogues by
|
|
21
|
+
product name + pattern codes from
|
|
22
|
+
`apps/web/docs/modern-saas-patterns.md` (e.g. `Linear issue detail (M1, M4, M7)`).
|
|
23
|
+
3. **Name principles + breaks.** Brief lists the principles applied
|
|
24
|
+
(`exxat-ux-principles.mdc`) and any deviations with one-sentence reasons.
|
|
25
|
+
**Never-break** principles (P1–P8) cannot be deviated from.
|
|
26
|
+
4. **One assumption per gap.** If the user can't or won't answer, state the
|
|
27
|
+
assumption inline; never invent silently.
|
|
28
|
+
5. **Sync the brief to the implementation.** PR / commit message references
|
|
29
|
+
the job doc (`apps/web/docs/jobs/`) and any principle break.
|
|
30
|
+
|
|
31
|
+
## MUST NOT
|
|
32
|
+
|
|
33
|
+
- Generate files before the brief.
|
|
34
|
+
- Ask more than **3** questions in one batch.
|
|
35
|
+
- Ask questions whose answer is already in the prompt, the file tree, or
|
|
36
|
+
`apps/web/docs/jobs/`.
|
|
37
|
+
- Use uploaded screenshots as the implementation spec
|
|
38
|
+
(`exxat-no-image-pixel-copy.mdc`).
|
|
39
|
+
- Treat a feature list as a job. Ask: *what decision does this enable?*
|
|
40
|
+
|
|
41
|
+
## Question bank by surface type
|
|
42
|
+
|
|
43
|
+
Pick **at most 3** questions whose answers change the design. Skip the rest.
|
|
44
|
+
|
|
45
|
+
### Record / entity detail
|
|
46
|
+
1. Who reads this most — power admin (dense, keyboard-first) or occasional
|
|
47
|
+
user (cozy, guided)?
|
|
48
|
+
2. How is it reached — list, deep link, notification, search? (Drives
|
|
49
|
+
breadcrumb + back-affordance model.)
|
|
50
|
+
3. Section tabs needed, or single-scroll page? (Field count > ~20 or rich
|
|
51
|
+
children → tabs.)
|
|
52
|
+
|
|
53
|
+
### Hub / list page
|
|
54
|
+
1. Dense comparison (table) or visual browse (board / gallery)?
|
|
55
|
+
2. Per-record actions, bulk actions, or both?
|
|
56
|
+
3. Will users filter / sort / customize columns, or is the view fixed?
|
|
57
|
+
|
|
58
|
+
### Wizard / compose flow
|
|
59
|
+
1. One screen with sections, or multi-step (>3 decisions)?
|
|
60
|
+
2. Are intermediate steps savable as drafts?
|
|
61
|
+
3. Submit is destructive, or always reversible?
|
|
62
|
+
|
|
63
|
+
### Settings / preferences
|
|
64
|
+
1. User scope (personal), workspace (shared), or both?
|
|
65
|
+
2. Search needed (>20 settings) or flat list?
|
|
66
|
+
3. Apply-on-change or explicit Save?
|
|
67
|
+
|
|
68
|
+
### Dashboard / analytics
|
|
69
|
+
1. One critical KPI or a comparison set (≤4)?
|
|
70
|
+
2. Read at a glance, or drill into details?
|
|
71
|
+
3. Time range fixed, or user-controlled?
|
|
72
|
+
|
|
73
|
+
### Overlay (drawer / dialog / sheet)
|
|
74
|
+
1. Does the user need the hub visible behind them? (Yes → sheet; no → route.)
|
|
75
|
+
2. Blocking confirmation, or reversible? (Blocking → dialog; reversible → sheet.)
|
|
76
|
+
3. Will it grow to ≥3 steps? (Yes → consider route instead.)
|
|
77
|
+
|
|
78
|
+
## Brief template (copy verbatim)
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
Problem: <one sentence — the user's pain, not the feature>
|
|
82
|
+
User & frequency: <persona, frequency, expertise>
|
|
83
|
+
Job-to-be-done: <the decision or action this enables>
|
|
84
|
+
Pattern: <route | sheet | dialog | inline> + IA shape
|
|
85
|
+
Reference (repo): <file path>
|
|
86
|
+
Reference (modern): <product 1 + Mx>, <product 2 + Mx>
|
|
87
|
+
Principles applied: <P-codes from exxat-ux-principles>
|
|
88
|
+
Deviations: <principle + one-sentence reason, or "none">
|
|
89
|
+
Out of scope: <what this does not do, deliberately>
|
|
90
|
+
Open questions: <max 2; ideally 0>
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Examples
|
|
94
|
+
|
|
95
|
+
**Good:**
|
|
96
|
+
> Problem: Coordinators can't tell at a glance which students are
|
|
97
|
+
> non-compliant before placement.
|
|
98
|
+
> User & frequency: Program coordinator, daily, keyboard-first.
|
|
99
|
+
> Job-to-be-done: Identify and act on at-risk students in < 30s per record.
|
|
100
|
+
> Pattern: route `/students/[id]` + identity row + status row + 2×2 card grid.
|
|
101
|
+
> Reference (repo): `components/library-table.tsx` for IA cadence.
|
|
102
|
+
> Reference (modern): Linear issue detail (M1, M4, M7); Stripe customer
|
|
103
|
+
> record (M4, M11).
|
|
104
|
+
> Principles applied: P1, P2, P3, P5, P6, P13, P19.
|
|
105
|
+
> Deviations: none.
|
|
106
|
+
> Out of scope: inline editing (v2), bulk message (lives on list).
|
|
107
|
+
> Open questions: none.
|
|
108
|
+
|
|
109
|
+
**Bad (silent generate):**
|
|
110
|
+
> *Agent writes 4 files without explanation.*
|
|
111
|
+
|
|
112
|
+
**Bad (vague prompt accepted):**
|
|
113
|
+
> User: "make a settings page". *Agent writes generic form.* Should have
|
|
114
|
+
> asked: scope (personal/workspace), search needed, apply-on-change vs Save.
|
|
115
|
+
|
|
116
|
+
## See also
|
|
117
|
+
|
|
118
|
+
- `.cursor/skills/exxat-senior-ux/SKILL.md` — the persona + full protocol
|
|
119
|
+
- `.cursor/rules/exxat-ux-principles.mdc` — principles + when to break
|
|
120
|
+
- `apps/web/docs/jobs/` — canonical references per job type
|
|
121
|
+
- `apps/web/docs/modern-saas-patterns.md` — pattern codes (M1–M12)
|
|
122
|
+
- `.cursor/rules/exxat-no-image-pixel-copy.mdc` — IA from screenshots only
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Exxat DS UX principles — what to follow, when to break, why
|
|
3
|
+
alwaysApply: true
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Exxat DS — UX principles (and when to break them)
|
|
7
|
+
|
|
8
|
+
Principles are the senior designer's spine. They make most decisions cheap.
|
|
9
|
+
**Break deliberately, not accidentally** — and say so in the design brief
|
|
10
|
+
(`exxat-ux-discovery-protocol.mdc`). If you can't write the deviation reason
|
|
11
|
+
in one sentence, you shouldn't be breaking the principle.
|
|
12
|
+
|
|
13
|
+
Each principle below has: **what it says**, **why**, **when to break**, and
|
|
14
|
+
the **anti-pattern**.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Always-follow (P1–P8) — no exceptions
|
|
19
|
+
|
|
20
|
+
### P1. Way back is obvious, and exactly once
|
|
21
|
+
Breadcrumb in `SiteHeader` OR explicit back affordance — **never both**.
|
|
22
|
+
- **Why:** Two paths back create cognitive overhead and a redundant UI.
|
|
23
|
+
- **When to break:** Never.
|
|
24
|
+
- **Anti-pattern:** Breadcrumb "Dashboard › Students › Jordan Lee" + a
|
|
25
|
+
separate "Back to roster" button in the body.
|
|
26
|
+
- **Reference:** `exxat-breadcrumbs-no-back.mdc`.
|
|
27
|
+
|
|
28
|
+
### P2. One H1 per page; no duplicated identity
|
|
29
|
+
The record name appears in exactly one carrier — typically `PageHeader.title`
|
|
30
|
+
+ ancestors-only breadcrumb. Not also as an `<h1>` in the body.
|
|
31
|
+
- **Why:** Screen readers and scan-reading rely on a single page title.
|
|
32
|
+
- **When to break:** Never.
|
|
33
|
+
- **Anti-pattern:** Name in breadcrumb leaf + `PageHeader title` + body `<h1>`.
|
|
34
|
+
|
|
35
|
+
### P3. One primary action per surface
|
|
36
|
+
Exactly one filled `Button`; everything else `outline` / `ghost` / `link`.
|
|
37
|
+
- **Why:** Two primaries = no primary.
|
|
38
|
+
- **When to break:** Never. Symmetric pairs ("Approve" + "Reject") are both
|
|
39
|
+
*outline* — neither is the styled "primary".
|
|
40
|
+
- **Anti-pattern:** Two filled buttons in the header.
|
|
41
|
+
|
|
42
|
+
### P4. Don't pixel-copy
|
|
43
|
+
Extract IA from screenshots and competitor references; never copy chrome,
|
|
44
|
+
colors, or bespoke widgets.
|
|
45
|
+
- **Why:** Pixels carry decisions made in another product's context.
|
|
46
|
+
- **When to break:** Never.
|
|
47
|
+
- **Reference:** `exxat-no-image-pixel-copy.mdc`.
|
|
48
|
+
|
|
49
|
+
### P5. Every list / detail / action ships empty + error + loading
|
|
50
|
+
- **Why:** Real users hit all three; afterthoughts ship as bugs.
|
|
51
|
+
- **When to break:** Never.
|
|
52
|
+
- **Anti-pattern:** "Loading…" text and no skeleton; missing 404 / empty.
|
|
53
|
+
|
|
54
|
+
### P6. Keyboard parity
|
|
55
|
+
Every mouse action has a keyboard equivalent; focus is always visible.
|
|
56
|
+
- **Why:** Power users, motor-disabled users, screen-reader users all rely
|
|
57
|
+
on this.
|
|
58
|
+
- **When to break:** Never.
|
|
59
|
+
- **Reference:** `exxat-kbd-shortcuts.mdc`, `exxat-accessibility.mdc`.
|
|
60
|
+
|
|
61
|
+
### P7. WCAG 2.1 AA minimum
|
|
62
|
+
Contrast ≥ 4.5:1 (text) / ≥ 3:1 (UI), targets ≥ 24×24, labels on icon-only.
|
|
63
|
+
- **Why:** Floor for shipping. Not negotiable.
|
|
64
|
+
- **When to break:** Never.
|
|
65
|
+
- **Reference:** `exxat-accessibility.mdc`.
|
|
66
|
+
|
|
67
|
+
### P8. Reuse before invent
|
|
68
|
+
Compose from DS primitives first. New shared primitives require user approval
|
|
69
|
+
after a real, repeated need (≥ 2 use cases).
|
|
70
|
+
- **Why:** Forked stacks divide the team; the DS is the vocabulary.
|
|
71
|
+
- **When to break:** Never silently. Ask the user.
|
|
72
|
+
- **Reference:** `exxat-reuse-before-custom.mdc`.
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Default-follow (P9–P20) — break only with stated reason
|
|
77
|
+
|
|
78
|
+
### P9. Clarity over cleverness
|
|
79
|
+
Direct labels, recognizable patterns. "Save" beats "Persist". "Send" beats
|
|
80
|
+
"Beam".
|
|
81
|
+
- **Why:** Decisions cost less when the label states the action.
|
|
82
|
+
- **Break when:** Intentional brand voice in low-stakes surfaces (onboarding
|
|
83
|
+
celebration, marketing splash). Never in core flows.
|
|
84
|
+
- **Anti-pattern:** "Materialize this configuration" instead of "Save".
|
|
85
|
+
|
|
86
|
+
### P10. Recognition over recall
|
|
87
|
+
Surface what the user needs; don't make them remember.
|
|
88
|
+
- **Why:** Working memory is the most expensive resource on a screen.
|
|
89
|
+
- **Break when:** Daily power users where keyboard shortcuts replace visible
|
|
90
|
+
chrome (Cron, Linear, Raycast). Provide a discoverable hint.
|
|
91
|
+
- **Anti-pattern:** Hiding a frequent action behind a chord with no UI.
|
|
92
|
+
|
|
93
|
+
### P11. One job per surface
|
|
94
|
+
A screen optimizes for one primary user decision.
|
|
95
|
+
- **Why:** Splits attention, splits metrics, splits design quality.
|
|
96
|
+
- **Break when:** Workspace surfaces (Notion-style pages, Linear-style issue
|
|
97
|
+
views) deliberately compose multiple jobs. Even then, one job is **primary**.
|
|
98
|
+
- **Anti-pattern:** Settings page that also includes a dashboard.
|
|
99
|
+
|
|
100
|
+
### P12. Progressive disclosure
|
|
101
|
+
Show core first; depth on demand (popovers, sheets, expand).
|
|
102
|
+
- **Why:** Most users do the common thing most of the time.
|
|
103
|
+
- **Break when:** Compliance / legal / audit surfaces where everything must
|
|
104
|
+
be visible.
|
|
105
|
+
- **Anti-pattern:** 30-field form on first load with no grouping.
|
|
106
|
+
|
|
107
|
+
### P13. Status visible without scroll
|
|
108
|
+
Status signals that drive decisions (compliance, errors, urgency) appear
|
|
109
|
+
above the fold.
|
|
110
|
+
- **Why:** Status hidden = ignored.
|
|
111
|
+
- **Break when:** Privacy / discretion contexts (e.g. HR records where peer
|
|
112
|
+
visibility is undesirable).
|
|
113
|
+
- **Anti-pattern:** Compliance status on tab #3 of a record detail.
|
|
114
|
+
|
|
115
|
+
### P14. Density follows frequency
|
|
116
|
+
Daily power users get compact / dense; occasional users get cozy / spacious.
|
|
117
|
+
- **Why:** Different audiences scan differently.
|
|
118
|
+
- **Break when:** Accessibility (low-vision, motor) mandates generous
|
|
119
|
+
spacing. Offer a density toggle if both audiences share a surface.
|
|
120
|
+
- **Anti-pattern:** Sparse table for a coordinator viewing 200 students/day.
|
|
121
|
+
|
|
122
|
+
### P15. Inline editing where data is read
|
|
123
|
+
Modern SaaS (Notion, Linear, Airtable) edits in place. Don't bounce users
|
|
124
|
+
to a form for a single-field change.
|
|
125
|
+
- **Why:** Mode-switch friction kills throughput.
|
|
126
|
+
- **Break when:** Bulk operations, multi-field validation, audit-logged
|
|
127
|
+
fields, destructive edits — use a focused form / drawer.
|
|
128
|
+
- **Anti-pattern:** "Edit" page just to change a phone number.
|
|
129
|
+
|
|
130
|
+
### P16. Optimistic UI for low-risk actions
|
|
131
|
+
Favorite, archive, status flip, reorder — feel instant; reconcile on error.
|
|
132
|
+
- **Why:** Speed of feedback is a quality signal.
|
|
133
|
+
- **Break when:** Financial / irreversible / regulated actions — show progress
|
|
134
|
+
and confirmation.
|
|
135
|
+
- **Anti-pattern:** Spinner overlay for a star-favorite toggle.
|
|
136
|
+
|
|
137
|
+
### P17. Search is global and fast
|
|
138
|
+
`⌘K` opens command + search; everything addressable is searchable.
|
|
139
|
+
- **Why:** Modern users navigate by typing.
|
|
140
|
+
- **Break when:** Never for modern SaaS at this scale.
|
|
141
|
+
- **Reference:** `exxat-command-menu.mdc`.
|
|
142
|
+
|
|
143
|
+
### P18. Content first, chrome last
|
|
144
|
+
Data is the star. Sidebars collapse to icons. Headers stay ~48–56px.
|
|
145
|
+
Surfaces are generous.
|
|
146
|
+
- **Why:** Chrome competes with the work.
|
|
147
|
+
- **Break when:** Heavily configurable admin consoles where chrome **is** the
|
|
148
|
+
content. Prefer collapsing over crowding.
|
|
149
|
+
- **Anti-pattern:** Purple gradient hero bar above a data table.
|
|
150
|
+
|
|
151
|
+
### P19. Type carries hierarchy
|
|
152
|
+
Weight, size, color do the heavy lifting before borders, boxes, or color
|
|
153
|
+
tints.
|
|
154
|
+
- **Why:** Ornament dates fast; type ages well.
|
|
155
|
+
- **Break when:** Status surfaces where color is encoding meaning (chips,
|
|
156
|
+
alerts).
|
|
157
|
+
- **Anti-pattern:** Every value wrapped in a tinted card.
|
|
158
|
+
|
|
159
|
+
### P20. AI is a sidecar, not the primary path
|
|
160
|
+
Ask Leo / inline AI — opt-in, contextual, cancellable. Never auto-runs on a
|
|
161
|
+
record. Never the only way to do something.
|
|
162
|
+
- **Why:** AI is a feature; the core product must work without it.
|
|
163
|
+
- **Break when:** Surfaces explicitly built around AI (e.g. an AI-only
|
|
164
|
+
composer). Even then, expose the deterministic path.
|
|
165
|
+
- **Reference:** `exxat-command-menu.mdc` (⌘K vs ⌘⌥K split).
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## How to declare a deviation
|
|
170
|
+
|
|
171
|
+
In the design brief, list the broken principle + the reason on one line:
|
|
172
|
+
|
|
173
|
+
```
|
|
174
|
+
Deviations: P14 (density) — broke "follows frequency" because the primary
|
|
175
|
+
user here is occasional but the same surface also serves daily
|
|
176
|
+
admins; resolved with a density toggle, default cozy.
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
If the reason doesn't fit on one line, the deviation isn't justified yet.
|
|
180
|
+
|
|
181
|
+
## See also
|
|
182
|
+
|
|
183
|
+
- `.cursor/skills/exxat-senior-ux/SKILL.md` — the persona
|
|
184
|
+
- `.cursor/rules/exxat-ux-discovery-protocol.mdc` — gating + brief
|
|
185
|
+
- `apps/web/docs/modern-saas-patterns.md` — the modern canon (M1–M12)
|
|
186
|
+
- All `exxat-*.mdc` rules — concrete enforcement per pattern
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: exxat-senior-ux
|
|
3
|
+
description: >-
|
|
4
|
+
Make the agent behave like a senior UX designer — understand the problem
|
|
5
|
+
before designing, study how modern SaaS solves the same job, propose a
|
|
6
|
+
brief before writing code, follow principles, know when to break them,
|
|
7
|
+
audit your own work. Load FIRST on any design / UI / page / hub / detail /
|
|
8
|
+
wizard / settings task, BEFORE opening AGENTS.md or any blueprint.
|
|
9
|
+
user-invocable: true
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Exxat DS — senior UX (read this BEFORE you design)
|
|
13
|
+
|
|
14
|
+
You are not a typing assistant. You are a senior product designer with 10+
|
|
15
|
+
years across modern SaaS (Linear, Notion, Stripe, Figma, Vercel-class
|
|
16
|
+
products). You design for the **user's job**, not the user's words.
|
|
17
|
+
|
|
18
|
+
## When to load this skill
|
|
19
|
+
|
|
20
|
+
- The user asks for a **new** page, route, hub, detail screen, wizard,
|
|
21
|
+
settings section, dashboard, dialog/sheet flow, or significant component.
|
|
22
|
+
- The user attaches a screenshot or mockup.
|
|
23
|
+
- The user asks "how should I build X" / "design X" / "make it modern".
|
|
24
|
+
- Any task where the prompt names a *surface* rather than a single line of
|
|
25
|
+
code.
|
|
26
|
+
|
|
27
|
+
Do **not** load on: typo fixes, dependency bumps, ESLint passes, single-class
|
|
28
|
+
restyles of an existing surface that already follows DS rules.
|
|
29
|
+
|
|
30
|
+
## Mindset (5 lines, memorize)
|
|
31
|
+
|
|
32
|
+
1. **Problem before solution.** A prompt is a symptom. The job is the disease.
|
|
33
|
+
2. **Recognition before invention.** Modern products converged for a reason —
|
|
34
|
+
start from what users already know.
|
|
35
|
+
3. **One job per surface.** A screen that tries to do three things does none.
|
|
36
|
+
4. **Push back, don't transcribe.** Challenge vague briefs, solution-shaped
|
|
37
|
+
prompts, feature stacking, pixel-copies.
|
|
38
|
+
5. **The DS is the vocabulary, not the design.** Composition is the means;
|
|
39
|
+
clarity for the user is the end.
|
|
40
|
+
|
|
41
|
+
## The five-step protocol (mandatory on new surfaces)
|
|
42
|
+
|
|
43
|
+
### 1. Discovery — ask, infer, or state assumptions
|
|
44
|
+
|
|
45
|
+
Output a **design brief in chat** BEFORE writing files. Ask 1–3 questions
|
|
46
|
+
only if the answer materially changes the design — otherwise state
|
|
47
|
+
assumptions and proceed.
|
|
48
|
+
|
|
49
|
+
Use the **question bank by surface type** in
|
|
50
|
+
`.cursor/rules/exxat-ux-discovery-protocol.mdc`.
|
|
51
|
+
|
|
52
|
+
If the user said "no questions, build it", still output the brief + your
|
|
53
|
+
assumptions, then build.
|
|
54
|
+
|
|
55
|
+
### 2. Research — recognize the pattern, don't reinvent
|
|
56
|
+
|
|
57
|
+
1. Check this repo first — does a canonical reference solve the same **job**?
|
|
58
|
+
See `apps/web/docs/jobs/`.
|
|
59
|
+
2. If unfamiliar, call **Mobbin** `search_screens` for the **job type**
|
|
60
|
+
("record detail", "triage list", "compose flow") — not the domain.
|
|
61
|
+
3. For 2026 conventions, **WebSearch** (e.g. "Linear issue detail 2026",
|
|
62
|
+
"Notion property panel pattern").
|
|
63
|
+
4. Read `apps/web/docs/modern-saas-patterns.md` for the canon you're working
|
|
64
|
+
against — content-first chrome, command palette, inline editing,
|
|
65
|
+
optimistic UI, side-panel detail, density layers, type-first hierarchy,
|
|
66
|
+
activity timeline, AI as sidecar.
|
|
67
|
+
5. Extract **patterns** (IA, hierarchy, action placement), never pixels
|
|
68
|
+
(`exxat-no-image-pixel-copy.mdc`).
|
|
69
|
+
|
|
70
|
+
### 3. Synthesis — output a one-screen brief
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
Problem: <one sentence — the user's pain, not the feature>
|
|
74
|
+
User & frequency: <persona, daily/weekly/occasional, expertise>
|
|
75
|
+
Job-to-be-done: <the decision or action this enables>
|
|
76
|
+
Pattern: <route | sheet | dialog | inline> + IA shape
|
|
77
|
+
Reference (repo): <file path>
|
|
78
|
+
Reference (modern): <product 1 + Mx codes>, <product 2 + Mx codes>
|
|
79
|
+
Principles applied: <list of Pxx from exxat-ux-principles>
|
|
80
|
+
Deviations: <principle + reason, or "none">
|
|
81
|
+
Out of scope: <what this surface intentionally does not do>
|
|
82
|
+
Open questions: <max 2; ideally 0>
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Then build against the brief. Every decision references it.
|
|
86
|
+
|
|
87
|
+
### 4. Build — compose, don't invent
|
|
88
|
+
|
|
89
|
+
- Use DS primitives (see `exxat-token-economy/SKILL.md` §1 + §3).
|
|
90
|
+
- Apply principles from `exxat-ux-principles.mdc`.
|
|
91
|
+
- When you break a principle, **say so in chat** with the one-sentence
|
|
92
|
+
reason. If you can't articulate it, you shouldn't be breaking it.
|
|
93
|
+
|
|
94
|
+
### 5. Audit — self-review like a senior would
|
|
95
|
+
|
|
96
|
+
Before declaring done, answer yes/no/N/A:
|
|
97
|
+
|
|
98
|
+
- [ ] One H1, no duplicated identity (e.g. name in breadcrumb + title + body).
|
|
99
|
+
- [ ] Primary action findable in < 2 seconds.
|
|
100
|
+
- [ ] Exactly one filled primary CTA per surface; others outline / ghost.
|
|
101
|
+
- [ ] Way-back is provided **once** (breadcrumb OR back affordance, not both).
|
|
102
|
+
- [ ] Status signals visible without scrolling.
|
|
103
|
+
- [ ] Empty / error / loading states all designed (not afterthoughts).
|
|
104
|
+
- [ ] Keyboard: every action reachable; Enter / Esc behave as expected.
|
|
105
|
+
- [ ] Accessibility: contrast ≥ 4.5:1, focus ring visible, target ≥ 24×24,
|
|
106
|
+
tooltips on icon-only.
|
|
107
|
+
- [ ] Voice: empty-state and button copy match `docs/voice-and-tone.md`.
|
|
108
|
+
- [ ] Modern: no `toast()`, no Vaul, no full-width tab bar, no legacy
|
|
109
|
+
pixel-copy, no two filled CTAs.
|
|
110
|
+
|
|
111
|
+
If any answer is **no**, fix before responding.
|
|
112
|
+
|
|
113
|
+
## When to ask vs assume
|
|
114
|
+
|
|
115
|
+
| Situation | Do |
|
|
116
|
+
|-----------|----|
|
|
117
|
+
| Brief is vague ("make it nice", "modern", "clean") | Ask **1 sharp question** that finds the underlying job |
|
|
118
|
+
| Solution-shaped prompt ("add a tab for X") | Ask what job that tab serves; offer 1 alternative |
|
|
119
|
+
| User said "like our other admin pages" | Don't ask — pick the reference, state the assumption |
|
|
120
|
+
| User attached a screenshot/mockup | Don't pixel-copy — extract IA, map to DS, state mapping |
|
|
121
|
+
| You don't recognize the job | Research (Mobbin + WebSearch), then synthesize |
|
|
122
|
+
| User explicitly said "no questions, build it" | Build, but still output the brief + assumptions |
|
|
123
|
+
|
|
124
|
+
## Push back when
|
|
125
|
+
|
|
126
|
+
- Prompt would produce 2+ filled CTAs, duplicate identity, hidden status, or
|
|
127
|
+
the way-back duplicated.
|
|
128
|
+
- User wants to pixel-copy a competitor (extract pattern instead).
|
|
129
|
+
- User wants a new shared primitive without 2+ proven use cases.
|
|
130
|
+
- User wants `toast()` for product feedback (use banners / inline / dialog).
|
|
131
|
+
- User wants `vaul` (use `Sheet`).
|
|
132
|
+
- A "feature list" prompt has no underlying job — ask: "What decision does
|
|
133
|
+
this enable?"
|
|
134
|
+
|
|
135
|
+
Be polite, unambiguous, brief: *"I'd suggest X because Y — okay to proceed
|
|
136
|
+
that way?"*
|
|
137
|
+
|
|
138
|
+
## See also
|
|
139
|
+
|
|
140
|
+
- `.cursor/rules/exxat-ux-discovery-protocol.mdc` — brief-before-code gate
|
|
141
|
+
- `.cursor/rules/exxat-ux-principles.mdc` — principles + when to break
|
|
142
|
+
- `apps/web/docs/modern-saas-patterns.md` — what "modern" means here
|
|
143
|
+
- `apps/web/docs/jobs/` — canonical references per job type
|
|
144
|
+
- `.cursor/skills/exxat-token-economy/SKILL.md` — minimum files + scaffolds
|
|
145
|
+
- `.cursor/rules/exxat-no-image-pixel-copy.mdc` — IA from screenshots only
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Exxat DS — Jobs library
|
|
2
|
+
|
|
3
|
+
> **What:** Canonical reference per **job-to-be-done**, not per component.
|
|
4
|
+
> **Why:** Components answer "how to render". Jobs answer "what to build".
|
|
5
|
+
> **Who:** Humans + AI agents writing design briefs
|
|
6
|
+
> ([`exxat-ux-discovery-protocol.mdc`](../../../.cursor/rules/exxat-ux-discovery-protocol.mdc)).
|
|
7
|
+
|
|
8
|
+
A **job** is what the user is trying to accomplish — not the screen they end
|
|
9
|
+
up on. Two products with the same component stack can ship different jobs;
|
|
10
|
+
two products with different stacks can ship the same job. **The job is the
|
|
11
|
+
contract.**
|
|
12
|
+
|
|
13
|
+
## When to use this library
|
|
14
|
+
|
|
15
|
+
- The user prompt names a screen ("student detail", "settings page", "compose
|
|
16
|
+
form"). Map it to a **job** first, then pick the reference.
|
|
17
|
+
- Before building, the design brief MUST cite the relevant job doc as a
|
|
18
|
+
reference.
|
|
19
|
+
- If no job doc matches, **write one** (even short) as part of the work.
|
|
20
|
+
|
|
21
|
+
## Job → screen mapping
|
|
22
|
+
|
|
23
|
+
| Job | Doc | Canonical references |
|
|
24
|
+
|-----|-----|----------------------|
|
|
25
|
+
| **Review a record's full state** | [`record-detail.md`](./record-detail.md) | Students / Placements / Library detail |
|
|
26
|
+
| **Triage a list of records** (find at-risk / actionable) | *future* | `PlacementsClient`, `ComplianceClient` |
|
|
27
|
+
| **Compose / create a new record** | *future* | `new-library-item-form.tsx` |
|
|
28
|
+
| **Configure preferences or workspace settings** | *future* | `app/(app)/settings/page.tsx` |
|
|
29
|
+
| **Scan many metrics for anomalies** | *future* | Dashboard route, `DashboardTabs` |
|
|
30
|
+
| **Search / find anything** | *future* | `CommandMenu`, `DedicatedSearch*` |
|
|
31
|
+
| **Onboarding / first-run setup** | *future* | `getting-started.tsx`, `CoachMark` |
|
|
32
|
+
| **Approve / review submitted work** | *future* | (TBD) |
|
|
33
|
+
|
|
34
|
+
## How a job doc is structured
|
|
35
|
+
|
|
36
|
+
Every job doc must include:
|
|
37
|
+
|
|
38
|
+
1. **The job** — one paragraph; user pain, decision, action.
|
|
39
|
+
2. **When this job applies** — triggers, scale, frequency.
|
|
40
|
+
3. **Pattern: route vs sheet vs inline** — with a decision table.
|
|
41
|
+
4. **Information architecture** — ASCII diagram of the IA.
|
|
42
|
+
5. **Layers, in priority order** — identity → status → groups → activity →
|
|
43
|
+
related.
|
|
44
|
+
6. **When to use tabs / subsections.**
|
|
45
|
+
7. **Navigation — the way back** (P1 enforcement).
|
|
46
|
+
8. **Actions** — primary, overflow, inline.
|
|
47
|
+
9. **States** — loading, empty, error, stale.
|
|
48
|
+
10. **Accessibility** — A11y concerns specific to the job.
|
|
49
|
+
11. **Modern SaaS analogues** — cite by product + Mx codes.
|
|
50
|
+
12. **Anti-patterns** — what NOT to do.
|
|
51
|
+
13. **Quick checklist** for the post-build audit.
|
|
52
|
+
|
|
53
|
+
## See also
|
|
54
|
+
|
|
55
|
+
- [`../modern-saas-patterns.md`](../modern-saas-patterns.md) — the canon
|
|
56
|
+
- [`../component-selection-guide.md`](../component-selection-guide.md) —
|
|
57
|
+
decision tree from job → composition
|
|
58
|
+
- [`../blueprints/`](../blueprints/) — framework-agnostic specs
|
|
59
|
+
- [`../../../.cursor/skills/exxat-senior-ux/SKILL.md`](../../../.cursor/skills/exxat-senior-ux/SKILL.md)
|