@exxatdesignux/ui 0.2.17 → 0.2.19
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 +30 -0
- package/consumer-extras/AGENTS.md +76 -0
- package/consumer-extras/README.md +5 -1
- package/consumer-extras/cursor-skills/exxat-centralized-list-dataset/SKILL.md +14 -3
- package/consumer-extras/cursor-skills/exxat-consumer-app/SKILL.md +37 -0
- package/consumer-extras/cursor-skills/exxat-ds-skill/SKILL.md +22 -7
- package/consumer-extras/cursor-skills/exxat-focused-workflow-page/SKILL.md +57 -0
- package/consumer-extras/cursor-skills/exxat-kpi-flat-band/SKILL.md +38 -0
- package/consumer-extras/cursor-skills/exxat-primary-nav-secondary-panel/SKILL.md +10 -3
- package/consumer-extras/patterns/consumer-app-pattern.md +39 -0
- package/consumer-extras/patterns/consumer-upgrade-checklist.md +20 -0
- package/consumer-extras/patterns/data-views-pattern.md +42 -3
- package/consumer-extras/patterns/focused-workflow-page-pattern.md +84 -0
- package/consumer-extras/patterns/kpi-flat-band-pattern.md +57 -0
- package/consumer-extras/patterns/shell-surface-elevation-pattern.md +54 -0
- package/package.json +2 -1
- package/src/components/ui/button-group.tsx +81 -0
- package/src/components/ui/button.tsx +4 -4
- package/src/components/ui/sidebar.tsx +2 -2
- package/src/globals.css +7 -1807
- package/src/theme.css +10 -1126
- package/src/tokens/README.md +15 -0
- package/src/tokens/base.css +337 -0
- package/src/tokens/high-contrast.css +1195 -0
- package/src/tokens/layers.css +224 -0
- package/src/tokens/tailwind-bridge.css +118 -0
- package/src/tokens/themes.css +201 -0
- package/template/.cursor/rules/exxat-kbd-shortcuts.mdc +1 -1
- package/template/AGENTS.md +66 -21
- package/template/app/(app)/dashboard/loading.tsx +3 -15
- package/template/app/(app)/dashboard/page.tsx +2 -14
- package/template/app/(app)/data-list/layout.tsx +43 -0
- package/template/app/(app)/data-list/page.tsx +2 -2
- package/template/app/(app)/error.tsx +22 -6
- package/template/app/(app)/examples/focused-workflow/page.tsx +5 -0
- package/template/app/(app)/examples/page.tsx +1 -0
- package/template/app/(app)/layout.tsx +13 -6
- package/template/app/(app)/loading.tsx +1 -18
- package/template/app/(app)/question-bank/find/page.tsx +2 -1
- package/template/app/(app)/question-bank/library/page.tsx +2 -1
- package/template/app/(app)/question-bank/list/page.tsx +2 -1
- package/template/app/(app)/question-bank/new/page.tsx +15 -23
- package/template/app/(app)/question-bank/page.tsx +2 -1
- package/template/app/(app)/settings/page.tsx +4 -5
- package/template/app/global-error.tsx +63 -0
- package/template/app/globals.css +7 -1934
- package/template/app/layout.tsx +2 -0
- package/template/components/app-route-loading.tsx +14 -0
- package/template/components/app-sidebar.tsx +71 -55
- package/template/components/data-table/index.tsx +31 -67
- package/template/components/data-table/use-table-state.ts +33 -6
- package/template/components/data-views/index.ts +37 -9
- package/template/components/data-views/list-page-calendar-view.tsx +593 -0
- package/template/components/data-views/list-page-connected-view-body.tsx +66 -0
- package/template/components/data-views/list-page-folder-columns-panel.tsx +345 -0
- package/template/components/data-views/list-page-split-hub-chrome.tsx +8 -0
- package/template/components/dev-chunk-load-recovery.tsx +41 -0
- package/template/components/examples/focused-workflow-showcase.tsx +183 -0
- package/template/components/exxat-product-logo.tsx +2 -6
- package/template/components/key-metrics.tsx +54 -22
- package/template/components/list-hub-board-view.tsx +68 -0
- package/template/components/list-hub-client.tsx +186 -0
- package/template/components/list-hub-list-view.tsx +36 -0
- package/template/components/list-hub-panel-activator.tsx +8 -0
- package/template/components/list-hub-secondary-nav.tsx +121 -0
- package/template/components/list-hub-table.tsx +336 -0
- package/template/components/new-question-composer.tsx +6 -24
- package/template/components/product-switcher.tsx +5 -5
- package/template/components/product-wordmark.tsx +4 -7
- package/template/components/question-bank-client.tsx +4 -1
- package/template/components/question-bank-folder-columns-panel.tsx +104 -0
- package/template/components/question-bank-hub-client.tsx +2 -5
- package/template/components/question-bank-table.tsx +155 -509
- package/template/components/secondary-panel/nav-link-rows.tsx +83 -0
- package/template/components/secondary-panel.tsx +4 -44
- package/template/components/secondary-panels/list-hub-panel.tsx +39 -0
- package/template/components/secondary-panels/question-bank-panel.tsx +39 -0
- package/template/components/secondary-panels/registry.tsx +15 -0
- package/template/components/settings-appearance-card.tsx +3 -2
- package/template/components/settings-client.tsx +59 -15
- package/template/components/settings-form-row.tsx +9 -4
- package/template/components/sidebar-shell.tsx +2 -1
- package/template/components/table-properties/drawer-button.tsx +51 -20
- package/template/components/table-properties/drawer.tsx +81 -17
- package/template/components/templates/focused-workflow-layouts.tsx +448 -0
- package/template/components/templates/focused-workflow-page-template.tsx +69 -0
- package/template/components/templates/list-page.tsx +40 -13
- package/template/components/templates/nested-secondary-panel-shell.tsx +3 -2
- package/template/components/templates/page-loading-shell.tsx +262 -0
- package/template/components/ui/button-group.tsx +1 -0
- package/template/contexts/product-context.tsx +21 -2
- package/template/docs/consumer-app-pattern.md +39 -0
- package/template/docs/data-views-pattern.md +42 -3
- package/template/docs/drawer-vs-dialog-pattern.md +3 -1
- package/template/docs/focused-workflow-page-pattern.md +84 -0
- package/template/docs/kpi-flat-band-pattern.md +57 -0
- package/template/docs/kpi-strip-max-four-pattern.md +1 -0
- package/template/docs/shell-surface-elevation-pattern.md +54 -0
- package/template/lib/chunk-load-error.ts +13 -0
- package/template/lib/command-menu-search-data.ts +11 -27
- package/template/lib/conditional-rule-match.ts +87 -22
- package/template/lib/data-list-display-options.ts +16 -2
- package/template/lib/data-list-view-registry.ts +104 -0
- package/template/lib/data-list-view-surface.ts +15 -1
- package/template/lib/data-list-view.ts +16 -1
- package/template/lib/data-view-dashboard-storage.ts +38 -35
- package/template/lib/hub-connected-view-renderers.ts +58 -0
- package/template/lib/list-hub-nav.ts +121 -0
- package/template/lib/list-hub-supported-views.ts +10 -0
- package/template/lib/list-page-table-properties.ts +3 -7
- package/template/lib/list-status-badges.ts +4 -97
- package/template/lib/mock/list-hub-directory.ts +27 -0
- package/template/lib/mock/list-hub-kpi.ts +27 -0
- package/template/lib/mock/navigation.tsx +1 -0
- package/template/lib/page-loading-variant.ts +40 -0
- package/template/lib/question-bank-supported-views.ts +13 -0
- package/template/lib/sidebar-state-cookie.ts +9 -0
- package/template/lib/table-state-lifecycle.ts +60 -13
- package/template/app/(app)/data-list/[id]/page.tsx +0 -44
- package/template/app/(app)/data-list/new/page.tsx +0 -34
- package/template/components/compliance-board-view.tsx +0 -142
- package/template/components/compliance-client.tsx +0 -92
- package/template/components/compliance-list-view.tsx +0 -54
- package/template/components/compliance-page-header.tsx +0 -89
- package/template/components/compliance-table.tsx +0 -632
- package/template/components/data-view-dashboard-charts-compliance.tsx +0 -963
- package/template/components/data-view-dashboard-charts-team.tsx +0 -971
- package/template/components/data-view-dashboard-charts.tsx +0 -1503
- package/template/components/new-placement-back-btn.tsx +0 -28
- package/template/components/new-placement-form.tsx +0 -1068
- package/template/components/placement-board-card.tsx +0 -262
- package/template/components/placement-detail.tsx +0 -438
- package/template/components/placements-board-view.tsx +0 -404
- package/template/components/placements-client.tsx +0 -252
- package/template/components/placements-list-view.tsx +0 -171
- package/template/components/placements-page-header.tsx +0 -166
- package/template/components/placements-table-cells.test.tsx +0 -22
- package/template/components/placements-table-cells.tsx +0 -173
- package/template/components/placements-table-columns.tsx +0 -640
- package/template/components/placements-table.tsx +0 -1675
- package/template/components/rotations-empty-state.tsx +0 -50
- package/template/components/rotations-panel-activator.tsx +0 -8
- package/template/components/sites-all-client.tsx +0 -154
- package/template/components/sites-board-view.tsx +0 -67
- package/template/components/sites-list-view.tsx +0 -42
- package/template/components/sites-table.tsx +0 -402
- package/template/components/team-board-view.tsx +0 -122
- package/template/components/team-client.tsx +0 -100
- package/template/components/team-list-view.tsx +0 -59
- package/template/components/team-page-header.tsx +0 -92
- package/template/components/team-table.tsx +0 -714
- package/template/lib/data-view-dashboard-placements-layout.ts +0 -215
- package/template/lib/mock/compliance-kpi.ts +0 -61
- package/template/lib/mock/compliance.ts +0 -146
- package/template/lib/mock/placements-kpi.ts +0 -134
- package/template/lib/mock/placements.ts +0 -183
- package/template/lib/mock/sites-directory.ts +0 -16
- package/template/lib/mock/sites-kpi.ts +0 -25
- package/template/lib/mock/team-kpi.ts +0 -60
- package/template/lib/mock/team.ts +0 -118
- package/template/lib/placement-board-card-layout.ts +0 -79
- package/template/lib/placement-lifecycle.ts +0 -5
package/CHANGELOG.md
CHANGED
|
@@ -15,6 +15,36 @@ After the user bumps `@exxatdesignux/ui`, do this in order:
|
|
|
15
15
|
|
|
16
16
|
---
|
|
17
17
|
|
|
18
|
+
## [0.2.19] - 2026-05-19
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
|
|
22
|
+
- **Design tokens (CSS modules):** Split theme surface into `src/tokens/` (`base.css`, `themes.css`, `high-contrast.css`, `layers.css`, `tailwind-bridge.css`). Entry points `globals.css` / `theme.css` re-export only — **no token value changes**.
|
|
23
|
+
- **Package export:** `@exxatdesignux/ui/tokens/*` for consumers that import token partials alongside Tailwind v4.
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
|
|
27
|
+
- **Starter `template/`** and **consumer extras:** List hub shell, secondary panel registry, route-aware loading skeletons, focused-workflow settings layout, KPI flat band + shell elevation docs/skills — synced from `apps/web`.
|
|
28
|
+
|
|
29
|
+
### Chore (monorepo)
|
|
30
|
+
|
|
31
|
+
- Package **`version`** **0.2.19** — publish with tag **`ui-v0.2.19`**.
|
|
32
|
+
|
|
33
|
+
## [0.2.18] - 2026-05-19
|
|
34
|
+
|
|
35
|
+
### Fixed
|
|
36
|
+
|
|
37
|
+
- **`Sidebar`**: Read `sidebar_state` on the server for `defaultOpen` so the documents **Resources** heading and rail chrome match the first client paint (fixes hydration warnings). Skip redundant cookie restore when state already matches.
|
|
38
|
+
- **`TablePropertiesDrawer`**: Portaled **Add filter / sort / rule** menus use `z-[90]` above the properties sheet (`z-[80]`); `Sheet` and dropdowns use `modal={false}`; filter updates apply synchronously (no `startTransition` deferral). Drawer button routes column/display handlers through refs for the portaled sheet.
|
|
39
|
+
|
|
40
|
+
### Changed
|
|
41
|
+
|
|
42
|
+
- **Starter `template/`** and **consumer extras**: KPI flat band + shell surface elevation patterns/skills; table-properties and hub parity with `apps/web`.
|
|
43
|
+
|
|
44
|
+
### Chore (monorepo)
|
|
45
|
+
|
|
46
|
+
- Package **`version`** set to **0.2.18** for npm publish (tag **`ui-v0.2.18`**).
|
|
47
|
+
|
|
18
48
|
## [0.2.17] - 2026-05-18
|
|
19
49
|
|
|
20
50
|
### Changed
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Exxat DS — consumer app handbook
|
|
2
|
+
|
|
3
|
+
**Purpose:** Guide for **product repositories** that depend on **`@exxatdesignux/ui`** from npm. The monorepo **`apps/web`** app is the full reference implementation; this file is what ships in the package for consumers.
|
|
4
|
+
|
|
5
|
+
**Path after sync:** `docs/exxat-ds/AGENTS-consumer.md` or merge sections into your app handbook via **`exxat-ui sync-extras`**.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. How to use this file (for AI agents)
|
|
10
|
+
|
|
11
|
+
1. **Before** upgrading **`@exxatdesignux/ui`**, read **`consumer-upgrade-checklist.md`** and **`CHANGELOG.md`** in the installed package.
|
|
12
|
+
2. **Before** adding a **list / table / board hub**, read **`data-views-pattern.md`** (view registry + connected bodies), **`consumer-app-pattern.md`**, and skill **`exxat-centralized-list-dataset`**.
|
|
13
|
+
3. **Before** a **dedicated form / wizard / settings route**, read **`focused-workflow-page-pattern.md`** and **`exxat-focused-workflow-page`** skill.
|
|
14
|
+
4. **Before** nested **Library / scope** nav, read **`exxat-primary-nav-secondary-panel`** skill and **`shell-surface-elevation-pattern.md`**.
|
|
15
|
+
5. Run **`exxat-ui sync-extras`** after every DS version bump so **`.cursor/skills/exxat-*`** match the tarball.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## 2. What ships in the package
|
|
20
|
+
|
|
21
|
+
| Artifact | Location in npm | Use |
|
|
22
|
+
|----------|-----------------|-----|
|
|
23
|
+
| Components + tokens | `@exxatdesignux/ui` | Import UI, hooks, CSS |
|
|
24
|
+
| Reference app | `node_modules/@exxatdesignux/ui/template/` | Diff / port routes and hub clients |
|
|
25
|
+
| Cursor skills | `consumer-extras/cursor-skills/` → sync to `.cursor/skills/` | AI checklists |
|
|
26
|
+
| Pattern docs | `consumer-extras/patterns/` → sync to `docs/exxat-ds/` | Human + AI narrative |
|
|
27
|
+
|
|
28
|
+
**`sync-extras` does not** modify your product routes — you port intentionally from **`template/`**.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## 3. List hub stack (centralized)
|
|
33
|
+
|
|
34
|
+
**MUST:**
|
|
35
|
+
|
|
36
|
+
- **`lib/mock/<entity>.ts`** — one row type + seed data.
|
|
37
|
+
- **`lib/<hub>-supported-views.ts`** — allowlist shared by **`ListPageTemplate`** and **`TablePropertiesDrawer`**.
|
|
38
|
+
- **`useTableState`** — **`tableState.rows`** feeds table, list, board, dashboard, folder, panel, tree.
|
|
39
|
+
- **`ListPageConnectedViewBody`** + **`defineHubViewRenderers`** — no silent dashboard fallback.
|
|
40
|
+
- **`ListPageViewFrame`** / **`components/data-views/`** for non-table bodies.
|
|
41
|
+
|
|
42
|
+
**MUST NOT:** Second mock array per view; **`ListPageTemplate`** on a dedicated create/edit URL.
|
|
43
|
+
|
|
44
|
+
**Rule/skill (sync from package):** `exxat-centralized-list-dataset`, `exxat-list-page-connected-views`, `exxat-list-page-view-shells`.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## 4. Shell elevation
|
|
49
|
+
|
|
50
|
+
| Level | Token |
|
|
51
|
+
|-------|--------|
|
|
52
|
+
| Primary sidebar | `--sidebar` |
|
|
53
|
+
| Secondary panel (Library) | `--secondary-panel-bg` |
|
|
54
|
+
| Page | `--background` |
|
|
55
|
+
|
|
56
|
+
Dark mode secondary panel **MUST** use **`color-mix(… var(--sidebar-accent) …)`**, not light **`--brand-tint`**. See **`shell-surface-elevation-pattern.md`**.
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## 5. Consumer app checklist (copy for PRs)
|
|
61
|
+
|
|
62
|
+
- [ ] **`@exxatdesignux/ui`** version recorded; **`exxat-ui sync-extras`** run if skills/docs changed.
|
|
63
|
+
- [ ] Template diff reviewed for new **`template/`** files relevant to this feature.
|
|
64
|
+
- [ ] List hub: **`supportedViewTypes`** aligned; **`ListPageConnectedViewBody`**; **`tableState.rows`** everywhere.
|
|
65
|
+
- [ ] Form/wizard route: **`FocusedWorkflowPageTemplate`** (not list hub shell).
|
|
66
|
+
- [ ] Secondary panel: **`--secondary-panel-bg`** on **`NestedSecondaryPanelShell`**; dark mode spot-checked.
|
|
67
|
+
- [ ] Product switcher: collapsed sidebar opens menu (**`SidebarMenuButton` `tooltip`**, not nested Tooltip + DropdownMenu).
|
|
68
|
+
- [ ] No toast — banners / inline / dialog.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## 6. See also
|
|
73
|
+
|
|
74
|
+
- **`consumer-app-pattern.md`**
|
|
75
|
+
- **`consumer-upgrade-checklist.md`**
|
|
76
|
+
- Monorepo **`apps/web/AGENTS.md`** (full product handbook when you have the design-system repo)
|
|
@@ -8,7 +8,9 @@ touching product routes or pages.
|
|
|
8
8
|
|----------------------|-------------------------------------------|
|
|
9
9
|
| `CHANGELOG.md` (package root) | Stay in `node_modules/…` — read for release notes; **`exxat-ui changelog`** prints it |
|
|
10
10
|
| `cursor-skills/exxat-*` | `.cursor/skills/exxat-*` (replaced) |
|
|
11
|
-
| `patterns/*.md` | `docs/exxat-ds/*.md` (replaced) — includes **`consumer-upgrade-checklist.md
|
|
11
|
+
| `patterns/*.md` | `docs/exxat-ds/*.md` (replaced) — includes **`consumer-upgrade-checklist.md`**, **`consumer-app-pattern.md`**, view-registry + shell docs |
|
|
12
|
+
| `AGENTS.md` (this folder) | Copy or merge into your app handbook as **`AGENTS-consumer.md`** |
|
|
13
|
+
| `cursor-skills/exxat-consumer-app` | Consumer-repo checklist (npm install, template diff) |
|
|
12
14
|
|
|
13
15
|
**Components and hooks** still come only from `node_modules/@exxatdesignux/ui`
|
|
14
16
|
via normal semver installs — `sync-extras` does not copy TS source into your app.
|
|
@@ -20,3 +22,5 @@ pnpm --filter @exxatdesignux/ui vendor:consumer-extras
|
|
|
20
22
|
```
|
|
21
23
|
|
|
22
24
|
…then bump `packages/ui` version and publish so consumers get the new bundle.
|
|
25
|
+
|
|
26
|
+
**List-page stack** (registry, `ListPageConnectedViewBody`, `supportedViewTypes`) lives in **`template/`** inside the tarball — not in `@exxatdesignux/ui` component exports. After changing **`apps/web`** or **`packages/ui/template`**, diff both trees and re-publish so consumer apps that copy from **`node_modules/@exxatdesignux/ui/template/`** stay aligned.
|
|
@@ -60,7 +60,18 @@ Goal: **one row model**, **one filtered bag** (`tableState.rows`), **one place f
|
|
|
60
60
|
|
|
61
61
|
---
|
|
62
62
|
|
|
63
|
-
## 6.
|
|
63
|
+
## 6. View registry + connected body (required)
|
|
64
|
+
|
|
65
|
+
- [ ] **`lib/<hub>-supported-views.ts`** — same array on **`ListPageTemplate`** (`supportedViewTypes`) and **`TablePropertiesDrawerButton`**.
|
|
66
|
+
- [ ] **`ListPageConnectedViewBody`** + **`defineHubViewRenderers(supported, { … })`** — one renderer per **`DataListViewRenderKind`**; missing → **`ListPageViewNotConfigured`** (never silent dashboard).
|
|
67
|
+
- [ ] Branch on **`getDataListViewRenderKind(view)`** via the connected body — not long **`if (view === "table")`** chains in the table file.
|
|
68
|
+
- [ ] **`lib/data-list-view-registry.ts`** — labels/icons/render kinds stay centralized.
|
|
69
|
+
|
|
70
|
+
**Canon:** `docs/data-views-pattern.md` § “View registry and connected bodies”, **`AGENTS.md` §4.1.1**.
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## 7. Implementation checklist (new hub or new view)
|
|
64
75
|
|
|
65
76
|
- [ ] Exactly **one** primary row array shape in **`lib/mock/<entity>.ts`** (or API).
|
|
66
77
|
- [ ] **`useTableState`** seeded from that array; **child views** receive **`tableState.rows`** (or equivalent), **not** a fresh import of the mock list.
|
|
@@ -72,7 +83,7 @@ Goal: **one row model**, **one filtered bag** (`tableState.rows`), **one place f
|
|
|
72
83
|
|
|
73
84
|
---
|
|
74
85
|
|
|
75
|
-
##
|
|
86
|
+
## 8. Reference implementations
|
|
76
87
|
|
|
77
88
|
- **`components/data-list-client.tsx`** + **`data-list-table.tsx`** — Placements pattern.
|
|
78
89
|
- **`components/team-client.tsx`** + **`team-table.tsx`**.
|
|
@@ -80,7 +91,7 @@ Goal: **one row model**, **one filtered bag** (`tableState.rows`), **one place f
|
|
|
80
91
|
|
|
81
92
|
---
|
|
82
93
|
|
|
83
|
-
##
|
|
94
|
+
## 9. Centralized presentation (with the same dataset)
|
|
84
95
|
|
|
85
96
|
**Layout:** Non-table view branches wrap in **`ListPageViewFrame`** (constants in **`list-page-view-frame.tsx`**) — see **`.cursor/rules/exxat-list-page-view-shells.mdc`**.
|
|
86
97
|
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: exxat-consumer-app
|
|
3
|
+
description: Build or upgrade product apps that install @exxatdesignux/ui from npm — sync-extras, diff template/, centralized list hubs, focused workflow routes, shell elevation. Use when working outside the design-system monorepo or after pnpm add @exxatdesignux/ui.
|
|
4
|
+
user-invocable: true
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Exxat DS — consumer app
|
|
8
|
+
|
|
9
|
+
**Pattern:** `consumer-app-pattern.md` (in `docs/exxat-ds/` after sync)
|
|
10
|
+
**Handbook:** `AGENTS-consumer.md` or `consumer-app-pattern.md` parent **`AGENTS.md`** in package extras
|
|
11
|
+
**Upgrade:** `consumer-upgrade-checklist.md`
|
|
12
|
+
|
|
13
|
+
## When this applies
|
|
14
|
+
|
|
15
|
+
- Repo has **`@exxatdesignux/ui`** in **`package.json`**, not the design-system monorepo **`apps/web`**.
|
|
16
|
+
- Task is **porting** a hub, shell, or route from **`node_modules/@exxatdesignux/ui/template/`**.
|
|
17
|
+
|
|
18
|
+
## Checklist
|
|
19
|
+
|
|
20
|
+
- [ ] Read installed **`CHANGELOG.md`**; run **`exxat-ui sync-extras`** after bump.
|
|
21
|
+
- [ ] Diff **`template/`** vs your app for the feature (client, table, mocks, layout).
|
|
22
|
+
- [ ] **List hub:** `lib/<hub>-supported-views.ts` + **`ListPageConnectedViewBody`** + **`defineHubViewRenderers`** + one **`useTableState`** row bag.
|
|
23
|
+
- [ ] **Same** `supportedViewTypes` on **`ListPageTemplate`** and **`TablePropertiesDrawer`**.
|
|
24
|
+
- [ ] **Form/wizard/settings URL:** **`FocusedWorkflowPageTemplate`** — not **`ListPageTemplate`**.
|
|
25
|
+
- [ ] **Secondary panel:** `NestedSecondaryPanelShell` + **`--secondary-panel-bg`**; verify **dark mode** (no light rose panel).
|
|
26
|
+
- [ ] **Product switcher (collapsed):** `DropdownMenuTrigger` → **`SidebarMenuButton`** with **`tooltip=`** — do not nest **`Tooltip`** outside **`DropdownMenuTrigger`**.
|
|
27
|
+
- [ ] CSS: import DS globals; product theme classes on **`<html>`** via **`ProductProvider`** pattern from template.
|
|
28
|
+
|
|
29
|
+
## MUST NOT
|
|
30
|
+
|
|
31
|
+
- Fork **`DataTable`** / view-tab stack when template already has the hub pattern.
|
|
32
|
+
- Import raw **`ENTITY_ROWS`** into folder/board views while the table filters **`useTableState`**.
|
|
33
|
+
- Skip **`exxat-ui sync-extras`** and rely on stale **`.cursor/skills`**.
|
|
34
|
+
|
|
35
|
+
## Pair with
|
|
36
|
+
|
|
37
|
+
- **`exxat-centralized-list-dataset`**, **`exxat-list-page-view-shells`**, **`exxat-focused-workflow-page`**, **`exxat-primary-nav-secondary-panel`**
|
|
@@ -21,7 +21,7 @@ description: >
|
|
|
21
21
|
- **Stack:** Next.js 16 (App Router), React, TypeScript, Tailwind CSS, shadcn/ui primitives, Font Awesome icons
|
|
22
22
|
- **App root:** `exxat-ds/app/(app)/` — route group that wraps all authenticated pages
|
|
23
23
|
- **Single source of truth:** `exxat-ds/AGENTS.md` for full prose explanations; this skill is the actionable summary
|
|
24
|
-
- **Companion skills (narrow topics):** `exxat-fontawesome-icons`, `exxat-mono-ids`, `exxat-primary-nav-secondary-panel`, `exxat-centralized-list-dataset`, `exxat-list-page-view-shells`, `exxat-dedicated-search-surfaces`, `exxat-accessibility`, `exxat-board-cards`, `exxat-collaboration-access` — live under `.cursor/skills/`; vetted copies ship with **`@exxatdesignux/ui`** in `consumer-extras/cursor-skills/` after **`pnpm --filter @exxatdesignux/ui vendor:consumer-extras`**.
|
|
24
|
+
- **Companion skills (narrow topics):** `exxat-fontawesome-icons`, `exxat-mono-ids`, `exxat-primary-nav-secondary-panel`, `exxat-centralized-list-dataset`, `exxat-list-page-view-shells`, `exxat-dedicated-search-surfaces`, `exxat-focused-workflow-page`, `exxat-accessibility`, `exxat-board-cards`, `exxat-collaboration-access` — live under `.cursor/skills/`; vetted copies ship with **`@exxatdesignux/ui`** in `consumer-extras/cursor-skills/` after **`pnpm --filter @exxatdesignux/ui vendor:consumer-extras`**.
|
|
25
25
|
- **Question bank folder-scoped header (rule + doc):** **`.cursor/rules/exxat-question-bank-hub-header.mdc`** and **`docs/question-bank-hub-header-pattern.md`** — pair with **`exxat-primary-nav-secondary-panel`** when URL **`scope=folder`** drives the hub title.
|
|
26
26
|
- **Consumer repos (npm install of `@exxatdesignux/ui`):** After a version bump, read **`node_modules/@exxatdesignux/ui/CHANGELOG.md`**, run **`npx --package=@exxatdesignux/ui@latest exxat-ui sync-extras`** so **`docs/exxat-ds/consumer-upgrade-checklist.md`** and Cursor skills match the tarball, and diff the host app against **`node_modules/@exxatdesignux/ui/template/`** for anything new to port (routes, re-exports, AGENTS). Use **`exxat-ui changelog`**, **`exxat-ui update`**, and **`exxat-ui doctor`** for CLI guidance.
|
|
27
27
|
|
|
@@ -259,8 +259,21 @@ ListPageTemplate
|
|
|
259
259
|
```
|
|
260
260
|
|
|
261
261
|
**Reference implementations:**
|
|
262
|
-
- `components/
|
|
263
|
-
- `
|
|
262
|
+
- **`apps/web`:** `components/list-hub-client.tsx` + `list-hub-table.tsx`, `question-bank-client.tsx` + `question-bank-table.tsx`
|
|
263
|
+
- **`packages/ui/template/`** (ships with npm): `placements-client.tsx` + `placements-table.tsx`, `team-client.tsx` + `team-table.tsx` — diff template on upgrade
|
|
264
|
+
|
|
265
|
+
### 4.1 View registry (do not fork `if (view === …)`)
|
|
266
|
+
|
|
267
|
+
1. **`lib/data-list-view.ts`** — `DATA_LIST_VIEW_TILES` (labels/icons).
|
|
268
|
+
2. **`lib/data-list-view-registry.ts`** — `renderKind`, `showsListPageHubMetricsStrip`, `dataListViewTilesForHub`.
|
|
269
|
+
3. **`lib/foo-supported-views.ts`** — `export const FOO_SUPPORTED_VIEWS = ["table", "list", …] as const`.
|
|
270
|
+
4. **`ListPageTemplate`** — `supportedViewTypes={FOO_SUPPORTED_VIEWS}`.
|
|
271
|
+
5. **`foo-table.tsx`** — `ListPageConnectedViewBody` with renderers per kind; **`TablePropertiesDrawerButton`** gets the same **`supportedViewTypes`**.
|
|
272
|
+
6. Generic bodies under **`components/data-views/`** — calendar, board template, folder grid, etc.
|
|
273
|
+
|
|
274
|
+
**MUST NOT** default unknown views to dashboard KPIs — missing renderers use **`ListPageViewNotConfigured`**.
|
|
275
|
+
|
|
276
|
+
**Narrative:** `docs/data-views-pattern.md` § “View registry and connected bodies”.
|
|
264
277
|
|
|
265
278
|
**Files to create for a new hub page `Foo`:**
|
|
266
279
|
| File | Purpose |
|
|
@@ -268,8 +281,9 @@ ListPageTemplate
|
|
|
268
281
|
| `lib/mock/foo.ts` | Mock data + TypeScript interface (12+ rows) |
|
|
269
282
|
| `lib/mock/foo-kpi.ts` | `fooKpiMetrics()` + `fooKpiInsight()` |
|
|
270
283
|
| `components/foo-page-header.tsx` | `PageHeader` + primary CTA + ⋯ menu |
|
|
271
|
-
| `
|
|
272
|
-
| `components/foo-
|
|
284
|
+
| `lib/foo-supported-views.ts` | Views this hub implements (registry allowlist) |
|
|
285
|
+
| `components/foo-table.tsx` | `ListPageConnectedViewBody` + `DataTable` + `useTableState` + Properties |
|
|
286
|
+
| `components/foo-client.tsx` | `ListPageTemplate` + `supportedViewTypes` |
|
|
273
287
|
| `app/(app)/foo/page.tsx` | Thin server component |
|
|
274
288
|
|
|
275
289
|
**Do not** ship a **nav-linked hub** as an **empty page** or a single “replace this later” paragraph. If the route appears in **`lib/mock/navigation.tsx`**, implement the full hub (mock rows, **`ListPageTemplate`**, connected views per **`exxat-ds/AGENTS.md` §4.1**) unless the product explicitly defines a non-data shell.
|
|
@@ -279,8 +293,9 @@ ListPageTemplate
|
|
|
279
293
|
- **Drawer / sheet** — Use when the user needs **the current page behind them** *and* a **quick view**, **quick actions**, or a **short step** (e.g. properties, export, glance at a row).
|
|
280
294
|
- **Dialog** — **Blocking** confirm/alert/short choice — **`docs/drawer-vs-dialog-pattern.md`**, **`.cursor/rules/exxat-drawer-vs-dialog.mdc`**.
|
|
281
295
|
- **New page** — Use **otherwise**: **primary**, **long-form**, **multi-step**, or flows that need their **own URL** without the hub visible.
|
|
296
|
+
- **Focused workflow route** — **`FocusedWorkflowPageTemplate`** + **`FocusedWorkflowSingleColumn`** | **`FocusedWorkflowStepForm`** | **`FocusedWorkflowSidebarSections`** | **`FocusedWorkflowEmptyState`** — **`docs/focused-workflow-page-pattern.md`**, **`AGENTS.md` §14**, **`exxat-focused-workflow-page`** skill. **Not** list hubs; **not** Miller columns.
|
|
282
297
|
|
|
283
|
-
Align with **`exxat-ds/AGENTS.md` §6.4**, **`docs/data-views-pattern.md`**, **`docs/drawer-vs-dialog-pattern.md`**, **`.cursor/rules/exxat-page-vs-drawer.mdc`**, **`.cursor/rules/exxat-drawer-vs-dialog.mdc`**.
|
|
298
|
+
Align with **`exxat-ds/AGENTS.md` §6.4**, **§14**, **`docs/data-views-pattern.md`**, **`docs/drawer-vs-dialog-pattern.md`**, **`docs/focused-workflow-page-pattern.md`**, **`.cursor/rules/exxat-page-vs-drawer.mdc`**, **`.cursor/rules/exxat-drawer-vs-dialog.mdc`**, **`.cursor/rules/exxat-focused-workflow-page.mdc`**.
|
|
284
299
|
|
|
285
300
|
---
|
|
286
301
|
|
|
@@ -551,7 +566,7 @@ import { DropdownMenuItem, Shortcut } from "@/components/ui/dropdown-menu"
|
|
|
551
566
|
| Duplicate | ⌘/Ctrl + D |
|
|
552
567
|
| Review / Info | ⌘/Ctrl + I |
|
|
553
568
|
| Remove / Delete item | ⌘/Ctrl + ⌫ |
|
|
554
|
-
| Add view (1..n) |
|
|
569
|
+
| Add view (1..n) | **1..9** (plain digit; `dataListViewAddShortcut`) |
|
|
555
570
|
| **Submit a workflow** (Create, Save, Export, Apply) | **Enter** ⏎ — scoped to the open form/drawer/dialog |
|
|
556
571
|
| **Cancel / dismiss** a workflow | **Esc** (Radix Dialog/Sheet/AlertDialog already bind this) |
|
|
557
572
|
| **Advance a multi-step wizard** | ⌘/Ctrl + Enter (plain Enter must not submit mid-flow) |
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: exxat-focused-workflow-page
|
|
3
|
+
description: FocusedWorkflowPageTemplate — dedicated routes for large forms, multi-step wizards, and sectioned settings (single column, steps, sidebar nav). Not list hubs or Miller-column explorers. Use when adding create/edit routes, settings pages, or empty workflow placeholders.
|
|
4
|
+
user-invocable: true
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Exxat DS — focused workflow page
|
|
8
|
+
|
|
9
|
+
**Rule:** `.cursor/rules/exxat-focused-workflow-page.mdc`
|
|
10
|
+
**Doc:** `docs/focused-workflow-page-pattern.md` (app / consumer-extras `patterns/`)
|
|
11
|
+
**Handbook:** `AGENTS.md` §6.4, **§14** checklist
|
|
12
|
+
|
|
13
|
+
## When to use
|
|
14
|
+
|
|
15
|
+
| Use **focused workflow** | Use something else |
|
|
16
|
+
| --- | --- |
|
|
17
|
+
| Own URL; primary create/edit; multi-step wizard; sectioned settings | **List hub** → `ListPageTemplate` + `DataTable` |
|
|
18
|
+
| Large form that should not sit in a drawer | **Quick hub adjunct** → drawer (`ExportDrawer`, `TablePropertiesDrawer`) |
|
|
19
|
+
| | **Blocking confirm** → dialog |
|
|
20
|
+
| | **Finder / folder columns** → `ListPageSplitHubChrome`, `ListPageFolderColumnsPanel` |
|
|
21
|
+
|
|
22
|
+
## Checklist
|
|
23
|
+
|
|
24
|
+
- [ ] Route uses **`FocusedWorkflowPageTemplate`** — not raw `SidebarInset` copy-paste; not **`PrimaryPageTemplate`** / **`ListPageTemplate`**.
|
|
25
|
+
- [ ] **`siteHeader`**: `back` or `breadcrumbs` + `title`; parent trail stays in header, not duplicated in body.
|
|
26
|
+
- [ ] **`maxWidth`**: `md` simple forms · `lg` settings / wide fields · `xl` only when justified.
|
|
27
|
+
- [ ] **One body layout** from `focused-workflow-layouts.tsx`:
|
|
28
|
+
- **`FocusedWorkflowSingleColumn`** — default stack
|
|
29
|
+
- **`FocusedWorkflowStepForm`** + **`FocusedWorkflowWizardFooter`** — wizard
|
|
30
|
+
- **`FocusedWorkflowSidebarSections`** — left section nav (`id` on `<section>` matches `sections[].id`)
|
|
31
|
+
- **`FocusedWorkflowEmptyState`** — not configured / coming soon
|
|
32
|
+
- [ ] **Footers:** **`FocusedWorkflowActionFooter`** or **`FocusedWorkflowWizardFooter`** with **`Shortcut`** + **`<Kbd variant="bare">`** in buttons (**`exxat-kbd-shortcuts.mdc`**).
|
|
33
|
+
- [ ] Domain UI in **`*-composer.tsx`** / **`*-client.tsx`**; keep **`FocusedWorkflow*`** names generic (not product-specific).
|
|
34
|
+
- [ ] Long forms: optional **`beforeSiteHeader={<SidebarAutoCollapse />}`** (see `/question-bank/new`).
|
|
35
|
+
- [ ] **No** **`ListPageTemplate`** view tabs, **no** Miller columns, **no** **`ListPageFolderColumnsPanel`** inside this shell.
|
|
36
|
+
- [ ] **No toast** for outcomes — banners, inline, or dialog (**`exxat-no-toast.mdc`**).
|
|
37
|
+
|
|
38
|
+
## MUST NOT
|
|
39
|
+
|
|
40
|
+
- Ship a **full create/edit wizard** only in a drawer when it needs bookmarkable URL / long focus.
|
|
41
|
+
- Use **`ListPageTemplate`** for a dedicated “new record” route.
|
|
42
|
+
- Name shared templates after one feature (`NewQuestionPageTemplate`, etc.).
|
|
43
|
+
|
|
44
|
+
## Code pointers
|
|
45
|
+
|
|
46
|
+
| Piece | Path |
|
|
47
|
+
| --- | --- |
|
|
48
|
+
| Shell | `components/templates/focused-workflow-page-template.tsx` |
|
|
49
|
+
| Layouts + footers | `components/templates/focused-workflow-layouts.tsx` |
|
|
50
|
+
| Showcase | `components/examples/focused-workflow-showcase.tsx`, `/examples/focused-workflow` |
|
|
51
|
+
| Single column | `app/(app)/question-bank/new/page.tsx` + `new-question-composer.tsx` |
|
|
52
|
+
| Sidebar sections | `app/(app)/settings/page.tsx` + `settings-client.tsx` |
|
|
53
|
+
|
|
54
|
+
## Pair with
|
|
55
|
+
|
|
56
|
+
- **`exxat-page-vs-drawer`**, **`exxat-drawer-vs-dialog`**, **`exxat-kbd-shortcuts`**
|
|
57
|
+
- **`exxat-reuse-before-custom`** — extend layouts before forking shell markup
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: exxat-kpi-flat-band
|
|
3
|
+
description: KeyMetrics variant flat — transparent KPI strip, OKLCH brand glow only, cell-border hairlines (no grid surface). Use when wiring ListPageTemplate metrics, dashboard mix KPIs, or fixing flat band looking like a grey box.
|
|
4
|
+
user-invocable: true
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Exxat DS — KPI flat band
|
|
8
|
+
|
|
9
|
+
**Rule:** `.cursor/rules/exxat-kpi-flat-band.mdc`
|
|
10
|
+
**Doc:** `apps/web/docs/kpi-flat-band-pattern.md`
|
|
11
|
+
|
|
12
|
+
## Checklist
|
|
13
|
+
|
|
14
|
+
- [ ] `variant="flat"` on hub / mix view — not `card` for list-page strip.
|
|
15
|
+
- [ ] `flatBandStyle` = **only** `var(--key-metrics-flat-band-radial)`; shadow **`none`**.
|
|
16
|
+
- [ ] No `--key-metrics-flat-band-linear` in component or hub inline `style`.
|
|
17
|
+
- [ ] Cells **`bg-transparent`**; grid uses **`flatMetricsHairlineClass(count, halfLayout)`** — borders only, **no** `gap-px` fill.
|
|
18
|
+
- [ ] **4 KPIs:** verticals between 1|2|3|4 when wide; 2×2 dividers only below `@[max-width:29.99rem]` container.
|
|
19
|
+
- [ ] Divider + glow tokens stay **OKLCH** (`--key-metrics-flat-divider`, `color-mix(in oklch, var(--brand-color) …)`).
|
|
20
|
+
- [ ] **≤ 4** `MetricItem` — `docs/kpi-strip-max-four-pattern.md`.
|
|
21
|
+
- [ ] KPI helpers use **`tableState.rows`** on connected hubs.
|
|
22
|
+
|
|
23
|
+
## MUST NOT
|
|
24
|
+
|
|
25
|
+
- Grey/lavender **panel** behind metrics (removed linear wash + gap fill).
|
|
26
|
+
- Duplicate KPI **`Card`** wall for same numbers.
|
|
27
|
+
- Mute product suffix to grey in dark (`mutedSuffix` does **not** change `wordmarkColor`).
|
|
28
|
+
|
|
29
|
+
## Code pointers
|
|
30
|
+
|
|
31
|
+
- `apps/web/components/key-metrics.tsx` — `flatMetricsHairlineClass`, `flatBandStyle`
|
|
32
|
+
- `apps/web/app/globals.css` — `--key-metrics-flat-*`
|
|
33
|
+
- `question-bank-client.tsx`, `dashboard-tabs.tsx` — reference usage
|
|
34
|
+
|
|
35
|
+
## Pair with
|
|
36
|
+
|
|
37
|
+
- `exxat-kpi-max-four`, `exxat-kpi-trends`, `exxat-list-page-connected-views`
|
|
38
|
+
- `docs/shell-surface-elevation-pattern.md` — sidebar vs page (not the KPI band)
|
|
@@ -12,17 +12,19 @@ user-invocable: true
|
|
|
12
12
|
## Wiring checklist
|
|
13
13
|
|
|
14
14
|
1. **`lib/mock/navigation.tsx`** — set **`secondaryPanel: "<id>"`** on the primary **`NavLinkItem`**; **`url`** = hub route.
|
|
15
|
-
2. **`components/secondary-
|
|
15
|
+
2. **`components/secondary-panels/registry.tsx`** — add **`SECONDARY_PANELS["<id>"]`** → panel shell (title) + hub-specific nav component (e.g. **`list-hub-panel.tsx`**, **`question-bank-panel.tsx`**). Do not add new hubs inside **`question-bank-*.tsx`**.
|
|
16
16
|
3. **Hub client** — mount **`*PanelActivator`** with **`useAutoPanel("<id>")`** (same id) for the lifetime of the route (e.g. `QuestionBankPanelActivator`).
|
|
17
17
|
4. **Data** — keep **one** **`useTableState`** / **`tableState.rows`**; drive scope from **URL** + small helpers (see **`lib/question-bank-nav.ts`**).
|
|
18
18
|
5. **Folder-scoped hub header (Question bank library)** — When **`scope === "folder"`** in the URL, **`QuestionBankPageHeader`** **⋯ More** includes **Customize folder**; mount **`QuestionBankNewFolderSheet`** on **`QuestionBankClient`** so it works on **all** **`ListPageTemplate`** view tabs — **`.cursor/rules/exxat-question-bank-hub-header.mdc`**, **`docs/question-bank-hub-header-pattern.md`**.
|
|
19
19
|
6. **Collapse control** — the nested rail header uses **`collapseActiveSecondaryPanel()`** (angles-left icon), not “close”, so the panel stays dismissed until **`openPanel`** runs again (nav, scope hook, or hub re-entry). Layout effects that auto-call **`openPanel`** must respect **`secondaryPanelAutoReopenSuppressed`** (see **`app/(app)/question-bank/layout.tsx`** + **`SecondaryPanelProvider`**).
|
|
20
|
+
7. **Surface elevation** — secondary panel = **level 1** (lighter than sidebar, darker than page). Use **`--secondary-panel-bg`** on **`NestedSecondaryPanelShell`**; derive from **`--brand-tint*`** per active product (**One** indigo, **Prism** rose). See **`docs/shell-surface-elevation-pattern.md`**.
|
|
20
21
|
|
|
21
22
|
## MUST NOT
|
|
22
23
|
|
|
23
24
|
- Set **`secondaryPanel`** without **`PANELS[id]`** + **`useAutoPanel`** — broken empty rail.
|
|
24
25
|
- Use this for full product areas that belong as **primary** or **collapsible child** rows.
|
|
25
26
|
- Invent a parallel zoom / reflow hook for the secondary rail — reuse **`useSidebarReflowZoom`** (the provider already wires it; see §"High-zoom auto-collapse" below).
|
|
27
|
+
- Set secondary panel **`bg-sidebar`** or a fixed rose mix for every product — breaks **One** indigo chrome.
|
|
26
28
|
|
|
27
29
|
## High-zoom auto-collapse
|
|
28
30
|
|
|
@@ -37,8 +39,13 @@ Custom panel content (anything you register under `PANELS[id]`) should **read `s
|
|
|
37
39
|
## Reference
|
|
38
40
|
|
|
39
41
|
- `components/app-sidebar.tsx` — `openPanel` on same-route primary click.
|
|
40
|
-
- `components/secondary-panel.tsx` — `SecondaryPanelProvider`,
|
|
42
|
+
- `components/secondary-panel.tsx` — `SecondaryPanelProvider`, **high-zoom auto-collapse**.
|
|
43
|
+
- `components/secondary-panels/registry.tsx` — **`SECONDARY_PANELS`** map (`question-bank`, `list-hub`, …).
|
|
44
|
+
- `lib/list-hub-nav.ts` + `components/list-hub-secondary-nav.tsx` — second hub reference implementation.
|
|
41
45
|
- `hooks/use-sidebar-reflow-zoom.ts` — shared zoom / reflow signal.
|
|
42
|
-
- `components/templates/nested-secondary-panel-shell.tsx` — expanded vs `compact` (icon rail) widths
|
|
46
|
+
- `components/templates/nested-secondary-panel-shell.tsx` — expanded vs `compact` (icon rail) widths; **`bg-[var(--secondary-panel-bg)]`**.
|
|
47
|
+
- `app/globals.css` — `--secondary-panel-bg`, `--sidebar`, product **`theme-one`** / **`theme-prism`** blocks.
|
|
48
|
+
- `contexts/product-context.tsx` — `accentOverrideActive`, theme class on `<html>`.
|
|
49
|
+
- **`docs/shell-surface-elevation-pattern.md`**
|
|
43
50
|
- `components/question-bank-secondary-nav.tsx` + `lib/question-bank-nav.ts`.
|
|
44
51
|
- **Folder-scoped header customize:** `components/question-bank-page-header.tsx`, `components/question-bank-client.tsx` — **`docs/question-bank-hub-header-pattern.md`**, **`.cursor/rules/exxat-question-bank-hub-header.mdc`**.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Consumer app pattern (`@exxatdesignux/ui`)
|
|
2
|
+
|
|
3
|
+
> **Audience:** Product repos that **install** the design system from npm — not the `apps/web` monorepo reference app.
|
|
4
|
+
> **Handbook:** `packages/ui/consumer-extras/AGENTS.md` · **Upgrade:** `consumer-upgrade-checklist.md` · **Skill:** `.cursor/skills/exxat-consumer-app/SKILL.md`
|
|
5
|
+
|
|
6
|
+
## Intent
|
|
7
|
+
|
|
8
|
+
A **consumer app** composes **`@exxatdesignux/ui`** primitives and copies **patterns** from the published **`template/`** tree. It does **not** fork parallel table stacks, view routers, or shell tokens.
|
|
9
|
+
|
|
10
|
+
## MUST
|
|
11
|
+
|
|
12
|
+
1. **Install** — `@exxatdesignux/ui` + peers; import DS CSS once (`@exxatdesignux/ui/globals.css` or documented entry).
|
|
13
|
+
2. **Sync extras** — After version bumps: `npx --package=@exxatdesignux/ui@latest exxat-ui sync-extras` → `.cursor/skills/exxat-*` + `docs/exxat-ds/*.md`.
|
|
14
|
+
3. **Diff template** — Compare `node_modules/@exxatdesignux/ui/template/` for new files (layouts, `ListPageConnectedViewBody`, `FocusedWorkflowPageTemplate`, mocks).
|
|
15
|
+
4. **List hubs** — One **`useTableState`** row bag; **`ListPageConnectedViewBody`** + **`defineHubViewRenderers`**; same **`supportedViewTypes`** on **`ListPageTemplate`** and **`TablePropertiesDrawer`**.
|
|
16
|
+
5. **Shell tokens** — Sidebar / secondary panel / page elevation via **`--sidebar`**, **`--secondary-panel-bg`**, **`--background`** — see **`shell-surface-elevation-pattern.md`**.
|
|
17
|
+
6. **Focused workflows** — Dedicated create/edit/settings routes use **`FocusedWorkflowPageTemplate`** — **`focused-workflow-page-pattern.md`**.
|
|
18
|
+
|
|
19
|
+
## MUST NOT
|
|
20
|
+
|
|
21
|
+
- Copy only components without porting **AGENTS**, **rules**, and **pattern docs** when behavior changes.
|
|
22
|
+
- Ship hub view tabs with long **`if (view === "table")`** chains instead of **`ListPageConnectedViewBody`**.
|
|
23
|
+
- Keep a second mock array per view while the grid uses **`useTableState`**.
|
|
24
|
+
- Set secondary panel to **`bg-sidebar`** or light **`--brand-tint`** mixes in dark mode.
|
|
25
|
+
|
|
26
|
+
## Checklist (new consumer feature)
|
|
27
|
+
|
|
28
|
+
- [ ] Read **`consumer-upgrade-checklist.md`** for the installed UI version.
|
|
29
|
+
- [ ] Run **`exxat-ui sync-extras`** if skills/patterns are stale.
|
|
30
|
+
- [ ] Find the closest **`template/`** hub or page; port file names and imports to your app paths.
|
|
31
|
+
- [ ] **List hub:** `lib/<hub>-supported-views.ts`, `lib/data-list-view-registry.ts`, `ListPageConnectedViewBody`, centralized **`tableState.rows`**.
|
|
32
|
+
- [ ] **Form route:** `FocusedWorkflowPageTemplate` + one body layout from **`focused-workflow-layouts.tsx`**.
|
|
33
|
+
- [ ] **Nav + secondary panel:** `secondaryPanel` on nav item, `PANELS` registry, `useAutoPanel` — **`exxat-primary-nav-secondary-panel`** skill.
|
|
34
|
+
- [ ] Re-run **`fa:subset-audit`** when adding Font Awesome glyphs.
|
|
35
|
+
|
|
36
|
+
## See also
|
|
37
|
+
|
|
38
|
+
- Monorepo reference: `apps/web/` (full product demo)
|
|
39
|
+
- **`.cursor/rules/exxat-consumer-app.mdc`** (when working inside a consumer repo that synced rules)
|
|
@@ -25,6 +25,26 @@ The npm package includes a full Next.js reference under:
|
|
|
25
25
|
|
|
26
26
|
Use it when you need to know **what files exist**, **how shims re-export** `@exxatdesignux/ui`, or **what AGENTS / layout** patterns look like for the current release. Porting is manual: diff template vs your repo and apply intentional changes (imports, new components, CSS entrypoints).
|
|
27
27
|
|
|
28
|
+
### List-page view registry (required for data hubs)
|
|
29
|
+
|
|
30
|
+
After upgrading, confirm each hub table uses **`ListPageConnectedViewBody`** (not long **`if (view === …)`** chains) and that these stay aligned:
|
|
31
|
+
|
|
32
|
+
| File | Purpose |
|
|
33
|
+
|------|---------|
|
|
34
|
+
| `lib/data-list-view-registry.ts` | Render kinds + hub KPI strip rules |
|
|
35
|
+
| `lib/<hub>-supported-views.ts` | What the hub can add/switch to |
|
|
36
|
+
| `components/templates/list-page.tsx` | `supportedViewTypes` on Add view + shortcuts |
|
|
37
|
+
| `components/data-views/list-page-connected-view-body.tsx` | View router |
|
|
38
|
+
| `lib/hub-connected-view-renderers.ts` | **`defineHubViewRenderers(supported, { … })`** — dev warnings when a supported view has no body |
|
|
39
|
+
| `components/data-views/list-page-folder-columns-panel.tsx` | Generic Miller columns for **panel** view (hub wrapper for QB colors/actions) |
|
|
40
|
+
|
|
41
|
+
Pass the **same** `supportedViewTypes` array to **`ListPageTemplate`** and **`TablePropertiesDrawerButton`**. Wrap hub renderers with **`defineHubViewRenderers`**. Import **question-bank-only** tree/folder nav from hub files, not the generic **`data-views`** barrel. See **`docs/exxat-ds/data-views-pattern.md`** § “View registry and connected bodies” and **`consumer-app-pattern.md`** for the full consumer-app checklist.
|
|
42
|
+
|
|
43
|
+
### Shell + sidebar (after DS token changes)
|
|
44
|
+
|
|
45
|
+
- [ ] Dark mode **secondary panel** uses **`--secondary-panel-bg`** from DS globals (sidebar-accent mix) — spot-check Question bank **Library** rail.
|
|
46
|
+
- [ ] Collapsed **product switcher** — **`SidebarMenuButton` `tooltip=`** + **`DropdownMenuTrigger`** only (no outer **`Tooltip`** wrapping the trigger).
|
|
47
|
+
|
|
28
48
|
## 4. Dependency and Node
|
|
29
49
|
|
|
30
50
|
- Keep **`@exxatdesignux/ui`** on the same semver your team tested; prefer explicit **`^x.y.z`** or pinned **`x.y.z`**.
|
|
@@ -18,6 +18,8 @@ This document describes how list pages combine **views**, **toolbar** behavior,
|
|
|
18
18
|
| **Team page (primary template)** | `TeamClient` = `ListPageTemplate` + `KeyMetrics` + `TeamPageHeader` + `TeamTable` (same composition as `DataListClient`) | `components/team-client.tsx`, `lib/mock/team-kpi.ts` |
|
|
19
19
|
| **Team roster** | `TeamTable` — `DataTable` + `useTableState` + `TablePropertiesDrawer`; list/board/dashboard read **`tableState.rows`** | `components/team-table.tsx` |
|
|
20
20
|
| **Dashboard view (list tab)** | **`KeyMetrics`** (`variant="flat"` or `"card"`) — same KPI system as the template metrics strip; **do not** add ad-hoc `Card` grids for entity summaries | `TeamTable` dashboard branch, `lib/mock/team-kpi.ts` |
|
|
21
|
+
| **List hub metrics strip** | **`KeyMetrics variant="flat"`** — transparent cells, OKLCH brand glow only, border hairlines (**no** grey panel) | **`docs/kpi-flat-band-pattern.md`**, Placements / Team / Question bank clients |
|
|
22
|
+
| **Secondary panel chrome** | **`--secondary-panel-bg`** on **`NestedSecondaryPanelShell`** (lighter than sidebar, follows active product) | **`docs/shell-surface-elevation-pattern.md`**, Question bank |
|
|
21
23
|
| **Export** | `ExportDrawer` | `ListPageTemplate` export props; `DataListClient` |
|
|
22
24
|
| **View body layout** (gutter + centered max-width for folder / icon / panel-style content) | **`ListPageViewFrame`** (`components/data-views/list-page-view-frame.tsx`, re-exported from `components/data-views`) | **`FolderGridView`** (uses the frame); **`QuestionBankOsFolderView`** — see **`AGENTS.md` §4.5** |
|
|
23
25
|
|
|
@@ -36,6 +38,41 @@ Non-table view branches (e.g. **folder** icon grid, **panel** finder, OS-style f
|
|
|
36
38
|
|
|
37
39
|
**Handbook:** **`AGENTS.md` §4.5**. **Cursor:** **`.cursor/rules/exxat-list-page-view-shells.mdc`**. **Skill:** **`.cursor/skills/exxat-list-page-view-shells/SKILL.md`**. **Do not** wrap **`DataTable`** in the frame if that stacks padding with the table toolbar (**`AGENTS.md` §5**).
|
|
38
40
|
|
|
41
|
+
## View registry and connected bodies (extensibility)
|
|
42
|
+
|
|
43
|
+
To add a **new view type** without breaking existing hubs:
|
|
44
|
+
|
|
45
|
+
1. **Register once** — Add a tile in `lib/data-list-view.ts` (`DATA_LIST_VIEW_TILES`). Capabilities (hub KPI strip, render kind) derive automatically in `lib/data-list-view-registry.ts`.
|
|
46
|
+
2. **Build the body once** — Add or extend a generic surface under `components/data-views/` (e.g. `ListPageCalendarView`). Entity-specific wiring stays in props (`getEventDate`, board `renderCard`), not a second calendar implementation per hub.
|
|
47
|
+
3. **Declare what each hub supports** — `lib/<hub>-supported-views.ts` exports a `const` array; pass the same array to **`ListPageTemplate`** (`supportedViewTypes`), the hub table (`supportedViewTypes` → `TablePropertiesDrawerButton`), and rely on defaults if omitted. **Add view**, **⌘1–9** shortcuts, and **Properties → View type** tiles all use `dataListViewTilesForHub` / `dataListViewSelectionTilesForHub` so users cannot pick a view the hub never implemented.
|
|
48
|
+
4. **Route in the hub table with `ListPageConnectedViewBody`** — Switch on **`getDataListViewRenderKind(view)`**, not raw `view === "…"` chains. Pass one renderer per kind the hub supports via **`defineHubViewRenderers(MY_HUB_SUPPORTED_VIEWS, { … })`** (`lib/hub-connected-view-renderers.ts`) so dev builds warn when a supported view has no body. **Do not** use a default branch that renders dashboard/KPIs; missing renderers show `ListPageViewNotConfigured`.
|
|
49
|
+
5. **Let the template own hub chrome** — `ListPageTemplate` hides the metrics strip on calendar/dashboard via `showsListPageHubMetricsStrip(activeTab.viewType)`. Hub clients pass `showMetrics` only; they do not reimplement per-tab KPI visibility.
|
|
50
|
+
6. **Panel / Miller columns** — Reuse **`ListPageFolderColumnsPanel`** (`components/data-views/list-page-folder-columns-panel.tsx`) for folder + record columns; hub-specific chrome (folder colors, actions) lives in a thin wrapper (e.g. `QuestionBankFolderColumnsPanel`). **Do not** export question-bank-only tree/folder nav from the generic `data-views` barrel.
|
|
51
|
+
|
|
52
|
+
```tsx
|
|
53
|
+
// lib/my-hub-supported-views.ts
|
|
54
|
+
export const MY_HUB_SUPPORTED_VIEWS = ["table", "list", "calendar"] as const satisfies readonly DataListViewType[]
|
|
55
|
+
|
|
56
|
+
// my-hub-client.tsx
|
|
57
|
+
<ListPageTemplate supportedViewTypes={MY_HUB_SUPPORTED_VIEWS} showMetrics={showMetrics} … />
|
|
58
|
+
|
|
59
|
+
// my-hub-table.tsx
|
|
60
|
+
import { defineHubViewRenderers } from "@/lib/hub-connected-view-renderers"
|
|
61
|
+
|
|
62
|
+
return (
|
|
63
|
+
<ListPageConnectedViewBody
|
|
64
|
+
view={view}
|
|
65
|
+
hubLabel="My hub"
|
|
66
|
+
renderers={defineHubViewRenderers(MY_HUB_SUPPORTED_VIEWS, {
|
|
67
|
+
"data-table": <DataTable … />,
|
|
68
|
+
"calendar-with-toolbar": toolbarShell(<ListPageCalendarView rows={tableState.rows} getEventDate={…} />),
|
|
69
|
+
})}
|
|
70
|
+
/>
|
|
71
|
+
)
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**Checklist for a new view type:** registry tile → `data-views/` component → update each `*-supported-views.ts` that should expose it → add renderer in each `*-table.tsx` (via `defineHubViewRenderers`) → Properties drawer copy in `table-properties/drawer.tsx` if needed → `table-state-lifecycle` picks up types via `DATA_LIST_VIEW_TILES` (no separate allowlist).
|
|
75
|
+
|
|
39
76
|
## Architecture
|
|
40
77
|
|
|
41
78
|
- **Page shell** — `ListPageTemplate` owns the views toolbar (tabs), optional metrics, and export drawer. Content for the active tab is rendered via `renderContent`.
|
|
@@ -144,11 +181,13 @@ Reference: `components/placements-page-header.tsx`, `components/team-page-header
|
|
|
144
181
|
|
|
145
182
|
**When to use a new page (route):** The flow is **primary**, **long-form**, **multi-step**, or should have its **own URL** / bookmark / history **without** the parent page behind it — e.g. full create/edit, wizards, or detail that *is* the task.
|
|
146
183
|
|
|
147
|
-
**
|
|
184
|
+
**Focused workflow shell:** For dedicated create/edit, wizards, and sectioned settings, use **`FocusedWorkflowPageTemplate`** + layouts in **`focused-workflow-layouts.tsx`** — see **`docs/focused-workflow-page-pattern.md`** and **`AGENTS.md` §14**. **Not** for list hubs (**`ListPageTemplate`**) or Miller-column explorers.
|
|
185
|
+
|
|
186
|
+
**Rule of thumb:** **Context + quick** → **drawer**; **blocking short choice** → **dialog**; **primary / long / wizard / settings** → **focused workflow route** (or other dedicated page).
|
|
148
187
|
|
|
149
188
|
**Modal vs side panel (same route):** When the overlay stays on the same URL, prefer **`docs/drawer-vs-dialog-pattern.md`** and **`.cursor/rules/exxat-drawer-vs-dialog.mdc`** — drawers keep the hub visible; dialogs trap focus for confirms.
|
|
150
189
|
|
|
151
|
-
Canonical rules: **`AGENTS.md` §6.4**, root **`.cursor/rules/exxat-page-vs-drawer.mdc`**, **`.cursor/rules/exxat-drawer-vs-dialog.mdc`**.
|
|
190
|
+
Canonical rules: **`AGENTS.md` §6.4**, **§14**, root **`.cursor/rules/exxat-page-vs-drawer.mdc`**, **`.cursor/rules/exxat-drawer-vs-dialog.mdc`**, **`.cursor/rules/exxat-focused-workflow-page.mdc`**.
|
|
152
191
|
|
|
153
192
|
---
|
|
154
193
|
|
|
@@ -168,7 +207,7 @@ When a route is a **primary** destination in nav (main hub for an entity) **and*
|
|
|
168
207
|
- [ ] **>10 items** → search, filter, sort, properties (per surface type above).
|
|
169
208
|
- [ ] **Has data to export** → **More** menu with **Export** + shared `ExportDrawer` pattern.
|
|
170
209
|
- [ ] **Primary + large / main hub** → `ListPageTemplate`-style shell where applicable.
|
|
171
|
-
- [ ] **Page vs drawer vs dialog (§6.4)** — Quick with parent **context** → drawer/sheet; **blocking** confirm → **dialog**; primary or long flows → **
|
|
210
|
+
- [ ] **Page vs drawer vs dialog (§6.4)** — Quick with parent **context** → drawer/sheet; **blocking** confirm → **dialog**; primary or long flows → **focused workflow route** (`docs/focused-workflow-page-pattern.md`, **§14**) or other dedicated page (`docs/drawer-vs-dialog-pattern.md`).
|
|
172
211
|
- [ ] **Primary button** → `Button` default variant (`size="lg"` for parity with Placements), not outline.
|
|
173
212
|
- [ ] **Dashboard view tab** → `KeyMetrics` + shared KPI helpers from **`tableState.rows`**; no duplicate one-off metric cards.
|
|
174
213
|
- [ ] **Data view charts** → `ChartFigure` + `chart-keyboard-selection`; layout persistence via **`data-view-dashboard-storage`** (see `AGENTS.md` §4.3).
|