@exxatdesignux/ui 0.2.18 → 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 +15 -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 +21 -6
- package/consumer-extras/cursor-skills/exxat-focused-workflow-page/SKILL.md +57 -0
- package/consumer-extras/cursor-skills/exxat-primary-nav-secondary-panel/SKILL.md +4 -2
- 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 +40 -3
- package/consumer-extras/patterns/focused-workflow-page-pattern.md +84 -0
- package/consumer-extras/patterns/shell-surface-elevation-pattern.md +5 -3
- package/package.json +2 -1
- package/src/components/ui/button-group.tsx +81 -0
- package/src/components/ui/button.tsx +4 -4
- package/src/globals.css +7 -1858
- 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/AGENTS.md +60 -22
- 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)/examples/focused-workflow/page.tsx +5 -0
- package/template/app/(app)/examples/page.tsx +1 -0
- 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/globals.css +7 -1964
- package/template/components/app-route-loading.tsx +14 -0
- package/template/components/app-sidebar.tsx +70 -55
- 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/examples/focused-workflow-showcase.tsx +183 -0
- 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 +3 -2
- 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-table.tsx +143 -485
- 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/table-properties/drawer-button.tsx +13 -0
- package/template/components/table-properties/drawer.tsx +65 -4
- 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 +29 -5
- package/template/components/templates/nested-secondary-panel-shell.tsx +2 -1
- package/template/components/templates/page-loading-shell.tsx +262 -0
- package/template/components/ui/button-group.tsx +1 -0
- package/template/docs/consumer-app-pattern.md +39 -0
- package/template/docs/data-views-pattern.md +40 -3
- package/template/docs/drawer-vs-dialog-pattern.md +3 -1
- package/template/docs/focused-workflow-page-pattern.md +84 -0
- package/template/docs/shell-surface-elevation-pattern.md +5 -3
- package/template/lib/command-menu-search-data.ts +11 -27
- 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 +10 -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/table-state-lifecycle.ts +2 -2
- 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 -612
- 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 -1642
- 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 -382
- 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 -693
- 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,21 @@ 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
|
+
|
|
18
33
|
## [0.2.18] - 2026-05-19
|
|
19
34
|
|
|
20
35
|
### Fixed
|
|
@@ -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
|
|
|
@@ -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
|
|
@@ -12,7 +12,7 @@ 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`**.
|
|
@@ -39,7 +39,9 @@ Custom panel content (anything you register under `PANELS[id]`) should **read `s
|
|
|
39
39
|
## Reference
|
|
40
40
|
|
|
41
41
|
- `components/app-sidebar.tsx` — `openPanel` on same-route primary click.
|
|
42
|
-
- `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.
|
|
43
45
|
- `hooks/use-sidebar-reflow-zoom.ts` — shared zoom / reflow signal.
|
|
44
46
|
- `components/templates/nested-secondary-panel-shell.tsx` — expanded vs `compact` (icon rail) widths; **`bg-[var(--secondary-panel-bg)]`**.
|
|
45
47
|
- `app/globals.css` — `--secondary-panel-bg`, `--sidebar`, product **`theme-one`** / **`theme-prism`** blocks.
|
|
@@ -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`**.
|
|
@@ -38,6 +38,41 @@ Non-table view branches (e.g. **folder** icon grid, **panel** finder, OS-style f
|
|
|
38
38
|
|
|
39
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**).
|
|
40
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
|
+
|
|
41
76
|
## Architecture
|
|
42
77
|
|
|
43
78
|
- **Page shell** — `ListPageTemplate` owns the views toolbar (tabs), optional metrics, and export drawer. Content for the active tab is rendered via `renderContent`.
|
|
@@ -146,11 +181,13 @@ Reference: `components/placements-page-header.tsx`, `components/team-page-header
|
|
|
146
181
|
|
|
147
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.
|
|
148
183
|
|
|
149
|
-
**
|
|
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).
|
|
150
187
|
|
|
151
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.
|
|
152
189
|
|
|
153
|
-
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`**.
|
|
154
191
|
|
|
155
192
|
---
|
|
156
193
|
|
|
@@ -170,7 +207,7 @@ When a route is a **primary** destination in nav (main hub for an entity) **and*
|
|
|
170
207
|
- [ ] **>10 items** → search, filter, sort, properties (per surface type above).
|
|
171
208
|
- [ ] **Has data to export** → **More** menu with **Export** + shared `ExportDrawer` pattern.
|
|
172
209
|
- [ ] **Primary + large / main hub** → `ListPageTemplate`-style shell where applicable.
|
|
173
|
-
- [ ] **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`).
|
|
174
211
|
- [ ] **Primary button** → `Button` default variant (`size="lg"` for parity with Placements), not outline.
|
|
175
212
|
- [ ] **Dashboard view tab** → `KeyMetrics` + shared KPI helpers from **`tableState.rows`**; no duplicate one-off metric cards.
|
|
176
213
|
- [ ] **Data view charts** → `ChartFigure` + `chart-keyboard-selection`; layout persistence via **`data-view-dashboard-storage`** (see `AGENTS.md` §4.3).
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Focused workflow page (dedicated routes)
|
|
2
|
+
|
|
3
|
+
> **Related:** **`AGENTS.md` §6.4** (page vs drawer vs dialog), **§14** (AI checklist), **`docs/drawer-vs-dialog-pattern.md`**, **`.cursor/rules/exxat-page-vs-drawer.mdc`**, **`.cursor/rules/exxat-focused-workflow-page.mdc`**, **`.cursor/skills/exxat-focused-workflow-page/SKILL.md`**.
|
|
4
|
+
|
|
5
|
+
## Intent
|
|
6
|
+
|
|
7
|
+
Use **`FocusedWorkflowPageTemplate`** for **large or multi-step work** on its **own route** — create/edit forms, wizards, and sectioned settings. The shell is **narrower** than list hubs and **does not** use Miller-column / split-panel explorers.
|
|
8
|
+
|
|
9
|
+
| Surface | Use instead |
|
|
10
|
+
| --- | --- |
|
|
11
|
+
| Browsable record hubs (table, board, dashboard tabs) | **`PrimaryPageTemplate`** + **`ListPageTemplate`** |
|
|
12
|
+
| Finder / folder columns / split hub chrome | **`ListPageSplitHubChrome`**, **`ListPageFolderColumnsPanel`** |
|
|
13
|
+
| Quick properties or export beside a grid | **Drawer** (`TablePropertiesDrawer`, `ExportDrawer`) |
|
|
14
|
+
| Blocking confirm on the same route | **Dialog** |
|
|
15
|
+
|
|
16
|
+
## Surface matrix (§6.4)
|
|
17
|
+
|
|
18
|
+
| Need | Drawer | Dialog | **Focused workflow route** |
|
|
19
|
+
| --- | --- | --- | --- |
|
|
20
|
+
| Keep hub visible while acting | Yes | No | No |
|
|
21
|
+
| Own URL / bookmark / history | Rare | No | **Yes** |
|
|
22
|
+
| Multi-step wizard | Cramped | No | **Yes** |
|
|
23
|
+
| Sectioned settings (left nav) | Awkward | No | **Yes** |
|
|
24
|
+
| Short delete confirm | No | **Yes** | Overkill |
|
|
25
|
+
|
|
26
|
+
## Shell
|
|
27
|
+
|
|
28
|
+
**`FocusedWorkflowPageTemplate`** (`components/templates/focused-workflow-page-template.tsx`):
|
|
29
|
+
|
|
30
|
+
- **`SidebarInset`** + **`SiteHeader`** (breadcrumb back link + title).
|
|
31
|
+
- Centered column: **`max-w-3xl` / `max-w-4xl` / `max-w-5xl`** via **`maxWidth`** (`md` | `lg` | `xl`).
|
|
32
|
+
- Default padding: **`FOCUSED_WORKFLOW_CONTENT_PADDING_CLASS`**.
|
|
33
|
+
|
|
34
|
+
Optional **`beforeSiteHeader`** (e.g. **`SidebarAutoCollapse`** on long forms).
|
|
35
|
+
|
|
36
|
+
## Body layouts
|
|
37
|
+
|
|
38
|
+
Import from **`components/templates/focused-workflow-layouts.tsx`**:
|
|
39
|
+
|
|
40
|
+
| Layout | When |
|
|
41
|
+
| --- | --- |
|
|
42
|
+
| **`FocusedWorkflowSingleColumn`** | Default stack — header, form sections, footer actions (e.g. question authoring). |
|
|
43
|
+
| **`FocusedWorkflowStepForm`** + **`FocusedWorkflowWizardFooter`** | Multi-step wizard with progress list and sticky footer (placement-style flows). |
|
|
44
|
+
| **`FocusedWorkflowSidebarSections`** | Sectioned form with **left nav rail** (settings-style); put **`id`** on each `<section>` matching **`sections[].id`**. |
|
|
45
|
+
| **`FocusedWorkflowEmptyState`** | Placeholder / not-yet-configured route body. |
|
|
46
|
+
| **`FocusedWorkflowActionFooter`** | Single-step Cancel (Esc) + primary (Enter) without step chrome. |
|
|
47
|
+
|
|
48
|
+
Keyboard: wizard and action footers pair **`Shortcut`** with inline **`<Kbd variant="bare">`** per **`.cursor/rules/exxat-kbd-shortcuts.mdc`**.
|
|
49
|
+
|
|
50
|
+
## Golden references
|
|
51
|
+
|
|
52
|
+
| Route | Variant |
|
|
53
|
+
| --- | --- |
|
|
54
|
+
| **`/question-bank/new`** | Shell + **`FocusedWorkflowSingleColumn`** + domain composer |
|
|
55
|
+
| **`/settings`** | Shell (`maxWidth="lg"`) + **`FocusedWorkflowSidebarSections`** |
|
|
56
|
+
| **`/examples/focused-workflow`** | Showcase: empty, steps, sidebar (toggle) |
|
|
57
|
+
|
|
58
|
+
## Wiring checklist (implementers)
|
|
59
|
+
|
|
60
|
+
1. **Route** under **`app/(app)/…/page.tsx`** — thin server page; heavy UI in a **client** component.
|
|
61
|
+
2. **`siteHeader`**: **`back`** or **`breadcrumbs`** + **`title`**; avoid duplicating the trail in the body.
|
|
62
|
+
3. Pick **`maxWidth`**: **`md`** for simple forms, **`lg`** for settings / wide fields.
|
|
63
|
+
4. Choose **one** body layout; do **not** nest Miller columns or **`ListPageTemplate`** view tabs inside this shell.
|
|
64
|
+
5. Domain logic stays in **`*-composer.tsx`** / **`*-client.tsx`**; templates stay generic **`FocusedWorkflow*`**.
|
|
65
|
+
6. Run **§14** in **`AGENTS.md`** when reviewing.
|
|
66
|
+
|
|
67
|
+
## AI execution checklist (copy for PRs)
|
|
68
|
+
|
|
69
|
+
- [ ] **`FocusedWorkflowPageTemplate`** on the route — not ad-hoc **`SidebarInset`** / list-hub shell.
|
|
70
|
+
- [ ] Correct body variant: **single column** | **step form** | **sidebar sections** | **empty**.
|
|
71
|
+
- [ ] Wizard/action footers use **`Shortcut`** + bare **`Kbd`** in buttons.
|
|
72
|
+
- [ ] **No** list-hub view tabs, **no** folder-column explorer inside the page.
|
|
73
|
+
- [ ] Template/component names remain **generic** (not tied to one entity).
|
|
74
|
+
- [ ] **§6.5** — no toast for product feedback.
|
|
75
|
+
|
|
76
|
+
## Pair with
|
|
77
|
+
|
|
78
|
+
- **`exxat-page-vs-drawer.mdc`**, **`exxat-drawer-vs-dialog.mdc`**, **`exxat-kbd-shortcuts.mdc`**
|
|
79
|
+
- **`exxat-reuse-before-custom.mdc`** — extend **`focused-workflow-layouts.tsx`** before forking a second shell
|
|
80
|
+
|
|
81
|
+
## See also
|
|
82
|
+
|
|
83
|
+
- **`components/examples/focused-workflow-showcase.tsx`**
|
|
84
|
+
- **`packages/ui/consumer-extras/patterns/focused-workflow-page-pattern.md`** (npm consumers)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Shell surface elevation (sidebar · secondary panel · page)
|
|
2
2
|
|
|
3
3
|
> **Tokens:** `app/globals.css` — `--sidebar`, `--secondary-panel-bg`, `--background`, `--brand-tint*`.
|
|
4
|
-
> **Shell:** `components/templates/nested-secondary-panel-shell.tsx` — `bg-
|
|
4
|
+
> **Shell:** `components/templates/nested-secondary-panel-shell.tsx` — `bg-secondary-panel-bg` + `[data-slot="secondary-panel"]` rule in `globals.css`.
|
|
5
5
|
> **Cursor:** `.cursor/rules/exxat-primary-nav-secondary-panel.mdc` · `.cursor/skills/exxat-primary-nav-secondary-panel/SKILL.md`
|
|
6
6
|
|
|
7
7
|
## Stack (back → front)
|
|
@@ -24,14 +24,16 @@
|
|
|
24
24
|
## OKLCH formulas (dark)
|
|
25
25
|
|
|
26
26
|
```css
|
|
27
|
-
--secondary-panel-bg: color-mix(in oklch, var(--
|
|
27
|
+
--secondary-panel-bg: color-mix(in oklch, var(--background) 32%, var(--sidebar-accent) 68%);
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
+
**Do not** mix with light-mode **`--brand-tint`** in dark — product theme classes keep a light **`--brand-tint`** for logos/KPI glow; the secondary rail must use **`--sidebar-accent`** so the Library panel stays on-hue and dark.
|
|
31
|
+
|
|
30
32
|
Per-product **dark** theme blocks (`.theme-one.dark`, `.theme-prism.dark`, …) set **`--brand-tint-light`** where needed so mixes stay on-hue.
|
|
31
33
|
|
|
32
34
|
## Implementation
|
|
33
35
|
|
|
34
|
-
- **`NestedSecondaryPanelShell`** — `bg-
|
|
36
|
+
- **`NestedSecondaryPanelShell`** — `bg-secondary-panel-bg` (token + `[data-slot="secondary-panel"][data-state="open"]` in `globals.css`), `border-sidebar-border` (not generic `ring-border` alone).
|
|
35
37
|
- **Do not** set secondary panel to `bg-sidebar` (same as level 0 — loses elevation).
|
|
36
38
|
- **Do not** use `color-mix(… var(--sidebar) …)` without brand tokens if it drifts from active product theme.
|
|
37
39
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exxatdesignux/ui",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.19",
|
|
4
4
|
"description": "Exxat shared design system (components, hooks, tokens). Monorepo setup: clone repo then pnpm bootstrap at workspace root — see github.com/ExxatDesign/Exxat-DS-Workspace README.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
},
|
|
28
28
|
"./globals.css": "./src/globals.css",
|
|
29
29
|
"./theme.css": "./src/theme.css",
|
|
30
|
+
"./tokens/*": "./src/tokens/*",
|
|
30
31
|
"./components/*": {
|
|
31
32
|
"types": "./src/components/ui/*.tsx",
|
|
32
33
|
"import": "./src/components/ui/*.tsx",
|