@exxatdesignux/ui 0.5.11 → 0.5.13
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 +45 -0
- package/bin/cli.mjs +70 -1
- package/bin/init.mjs +18 -4
- package/bin/sync-extras.mjs +28 -4
- package/consumer-extras/README.md +41 -5
- package/consumer-extras/cursor-rules/exxat-accessibility.mdc +2 -1
- package/consumer-extras/cursor-rules/exxat-board-cards.mdc +5 -3
- package/consumer-extras/cursor-rules/exxat-breadcrumbs-no-back.mdc +1 -0
- package/consumer-extras/cursor-rules/exxat-card-vs-list-rows.mdc +1 -0
- package/consumer-extras/cursor-rules/exxat-centralized-list-dataset.mdc +4 -2
- package/consumer-extras/cursor-rules/exxat-collaboration-access.mdc +1 -0
- package/consumer-extras/cursor-rules/exxat-command-menu.mdc +3 -2
- package/consumer-extras/cursor-rules/exxat-data-tables.mdc +5 -3
- package/consumer-extras/cursor-rules/exxat-dedicated-search-surfaces.mdc +7 -0
- package/consumer-extras/cursor-rules/exxat-drawer-vs-dialog.mdc +2 -1
- package/consumer-extras/cursor-rules/exxat-ds-agents.mdc +1 -0
- package/consumer-extras/cursor-rules/exxat-fontawesome-icons.mdc +1 -0
- package/consumer-extras/cursor-rules/exxat-hub-supported-views.mdc +6 -4
- package/consumer-extras/cursor-rules/exxat-kbd-shortcuts.mdc +6 -5
- package/consumer-extras/cursor-rules/exxat-kpi-flat-band.mdc +1 -0
- package/consumer-extras/cursor-rules/exxat-kpi-max-four.mdc +1 -0
- package/consumer-extras/cursor-rules/exxat-kpi-trends.mdc +1 -0
- package/consumer-extras/cursor-rules/exxat-library-hub-header.mdc +2 -1
- package/consumer-extras/cursor-rules/exxat-list-page-connected-views.mdc +6 -2
- package/consumer-extras/cursor-rules/exxat-list-page-view-shells.mdc +2 -1
- package/consumer-extras/cursor-rules/exxat-mono-ids.mdc +2 -1
- package/consumer-extras/cursor-rules/exxat-nav-single-active.mdc +4 -3
- package/consumer-extras/cursor-rules/exxat-no-image-pixel-copy.mdc +25 -14
- package/consumer-extras/cursor-rules/exxat-no-slds-leakage.mdc +8 -2
- package/consumer-extras/cursor-rules/exxat-no-toast.mdc +1 -0
- package/consumer-extras/cursor-rules/exxat-no-vaul.mdc +2 -1
- package/consumer-extras/cursor-rules/exxat-page-header-actions.mdc +6 -4
- package/consumer-extras/cursor-rules/exxat-page-vs-drawer.mdc +2 -1
- package/consumer-extras/cursor-rules/exxat-person-identity-display.mdc +1 -0
- package/consumer-extras/cursor-rules/exxat-primary-nav-secondary-panel.mdc +2 -1
- package/consumer-extras/cursor-rules/exxat-reuse-before-custom.mdc +1 -0
- package/consumer-extras/cursor-rules/exxat-sidebar-shell.mdc +13 -7
- package/consumer-extras/cursor-rules/exxat-table-properties-drawer.mdc +5 -3
- package/consumer-extras/cursor-rules/exxat-table-row-preview.mdc +1 -0
- package/consumer-extras/cursor-rules/exxat-tabs-chrome.mdc +6 -4
- package/consumer-extras/cursor-rules/exxat-token-discipline.mdc +6 -0
- package/consumer-extras/cursor-rules/exxat-ux-discovery-protocol.mdc +28 -0
- package/consumer-extras/cursor-rules/exxat-ux-principles.mdc +1 -0
- package/consumer-extras/cursor-skills/exxat-ds-skill/SKILL.md +1 -1
- package/consumer-extras/cursor-skills/exxat-kpi-trends/SKILL.md +5 -3
- package/consumer-extras/patterns/command-menu-pattern.md +2 -2
- package/consumer-extras/patterns/consumer-upgrade-checklist.md +1 -1
- package/consumer-extras/patterns/jobs/README.md +1 -1
- package/consumer-extras/patterns/perf-memory-pattern.md +115 -150
- package/consumer-extras/scripts/dev-guard.mjs +156 -0
- package/consumer-extras/templates/README.md +23 -0
- package/consumer-extras/templates/handoff.md +190 -0
- package/package.json +2 -3
- package/{template → template-vite}/.claude/skills/exxat-ds-skill/SKILL.md +184 -23
- package/template-vite/.cursor/rules/exxat-accessibility.mdc +40 -0
- package/template-vite/.cursor/rules/exxat-board-cards.mdc +28 -0
- package/template-vite/.cursor/rules/exxat-breadcrumbs-no-back.mdc +22 -0
- package/template-vite/.cursor/rules/exxat-card-vs-list-rows.mdc +22 -0
- package/template-vite/.cursor/rules/exxat-centralized-list-dataset.mdc +46 -0
- package/template-vite/.cursor/rules/exxat-collaboration-access.mdc +33 -0
- package/{template → template-vite}/.cursor/rules/exxat-command-menu.mdc +5 -5
- package/template-vite/.cursor/rules/exxat-data-tables.mdc +47 -0
- package/template-vite/.cursor/rules/exxat-dedicated-search-surfaces.mdc +32 -0
- package/template-vite/.cursor/rules/exxat-drawer-vs-dialog.mdc +23 -0
- package/template-vite/.cursor/rules/exxat-ds-agents.mdc +87 -0
- package/template-vite/.cursor/rules/exxat-fontawesome-icons.mdc +32 -0
- package/template-vite/.cursor/rules/exxat-hub-supported-views.mdc +56 -0
- package/{template → template-vite}/.cursor/rules/exxat-kbd-shortcuts.mdc +1 -0
- package/template-vite/.cursor/rules/exxat-kpi-flat-band.mdc +29 -0
- package/template-vite/.cursor/rules/exxat-kpi-max-four.mdc +22 -0
- package/template-vite/.cursor/rules/exxat-kpi-trends.mdc +32 -0
- package/template-vite/.cursor/rules/exxat-library-hub-header.mdc +29 -0
- package/template-vite/.cursor/rules/exxat-list-page-connected-views.mdc +28 -0
- package/template-vite/.cursor/rules/exxat-list-page-view-shells.mdc +32 -0
- package/{template → template-vite}/.cursor/rules/exxat-mono-ids.mdc +1 -0
- package/template-vite/.cursor/rules/exxat-nav-single-active.mdc +32 -0
- package/template-vite/.cursor/rules/exxat-no-image-pixel-copy.mdc +46 -0
- package/template-vite/.cursor/rules/exxat-no-slds-leakage.mdc +84 -0
- package/{template → template-vite}/.cursor/rules/exxat-no-toast.mdc +2 -2
- package/template-vite/.cursor/rules/exxat-no-vaul.mdc +26 -0
- package/template-vite/.cursor/rules/exxat-page-header-actions.mdc +33 -0
- package/{template → template-vite}/.cursor/rules/exxat-page-vs-drawer.mdc +5 -3
- package/template-vite/.cursor/rules/exxat-person-identity-display.mdc +48 -0
- package/template-vite/.cursor/rules/exxat-primary-nav-secondary-panel.mdc +53 -0
- package/template-vite/.cursor/rules/exxat-reuse-before-custom.mdc +37 -0
- package/template-vite/.cursor/rules/exxat-sidebar-shell.mdc +41 -0
- package/template-vite/.cursor/rules/exxat-table-properties-drawer.mdc +79 -0
- package/template-vite/.cursor/rules/exxat-table-row-preview.mdc +25 -0
- package/template-vite/.cursor/rules/exxat-tabs-chrome.mdc +33 -0
- package/template-vite/.cursor/rules/exxat-token-discipline.mdc +109 -0
- package/template-vite/.cursor/rules/exxat-ux-discovery-protocol.mdc +202 -0
- package/template-vite/.cursor/rules/exxat-ux-principles.mdc +187 -0
- package/template-vite/.cursor/skills/exxat-accessibility/SKILL.md +282 -0
- package/template-vite/.cursor/skills/exxat-board-cards/SKILL.md +68 -0
- package/template-vite/.cursor/skills/exxat-card-vs-list-rows/SKILL.md +20 -0
- package/template-vite/.cursor/skills/exxat-centralized-list-dataset/SKILL.md +99 -0
- package/template-vite/.cursor/skills/exxat-collaboration-access/SKILL.md +35 -0
- package/template-vite/.cursor/skills/exxat-dedicated-search-surfaces/SKILL.md +45 -0
- package/template-vite/.cursor/skills/exxat-drawer-vs-dialog/SKILL.md +20 -0
- package/template-vite/.cursor/skills/exxat-ds-skill/SKILL.md +893 -0
- package/template-vite/.cursor/skills/exxat-ds-skill/references/accessibility.md +142 -0
- package/template-vite/.cursor/skills/exxat-ds-skill/references/coach-marks.md +169 -0
- package/template-vite/.cursor/skills/exxat-ds-skill/references/data-table-pattern.md +392 -0
- package/template-vite/.cursor/skills/exxat-fontawesome-icons/SKILL.md +31 -0
- package/template-vite/.cursor/skills/exxat-kpi-flat-band/SKILL.md +38 -0
- package/template-vite/.cursor/skills/exxat-kpi-max-four/SKILL.md +19 -0
- package/template-vite/.cursor/skills/exxat-kpi-trends/SKILL.md +29 -0
- package/template-vite/.cursor/skills/exxat-list-page-view-shells/SKILL.md +36 -0
- package/template-vite/.cursor/skills/exxat-mono-ids/SKILL.md +56 -0
- package/template-vite/.cursor/skills/exxat-primary-nav-secondary-panel/SKILL.md +49 -0
- package/template-vite/.cursor/skills/exxat-senior-ux/SKILL.md +198 -0
- package/template-vite/.cursor/skills/exxat-token-economy/SKILL.md +287 -0
- package/template-vite/.cursor/skills/exxat-ux-audit/SKILL.md +303 -0
- package/{template → template-vite}/components/ask-leo-sidebar.tsx +10 -8
- package/{template → template-vite}/components/command-menu.tsx +1 -1
- package/{template → template-vite}/components/data-views/library-folder-tree-branch.tsx +1 -1
- package/{template → template-vite}/components/dedicated-search-recents.tsx +1 -1
- package/{template → template-vite}/components/dedicated-search-url-composer.tsx +1 -1
- package/{template → template-vite}/components/exxat-product-logo.tsx +3 -3
- package/{template → template-vite}/components/library-client.tsx +1 -1
- package/{template → template-vite}/components/library-hub-client.tsx +2 -2
- package/{template → template-vite}/components/library-secondary-nav.tsx +2 -2
- package/{template → template-vite}/components/library-table.tsx +35 -27
- package/{template → template-vite}/components/new-library-item-form.tsx +1 -1
- package/{template → template-vite}/components/page-breadcrumb-trail.tsx +1 -1
- package/{template → template-vite}/components/settings-client.tsx +1 -1
- package/{template → template-vite}/components/sidebar/app-sidebar.tsx +2 -2
- package/{template → template-vite}/components/sidebar/nav-main.tsx +1 -1
- package/{template → template-vite}/components/sidebar/nav-user.tsx +1 -1
- package/{template → template-vite}/components/sidebar/secondary-nav.tsx +1 -1
- package/{template → template-vite}/components/system-banner-slot.tsx +1 -1
- package/{template → template-vite}/components/templates/discovery-hub-template.tsx +2 -2
- package/{template → template-vite}/components/templates/new-focus-template.tsx +1 -1
- package/{template → template-vite}/components/tokens-secondary-nav.tsx +2 -2
- package/{template → template-vite}/components/tokens-themes-client.tsx +1 -1
- package/{template → template-vite}/hooks/use-secondary-panel-hub-nav.ts +1 -1
- package/template-vite/index.html +49 -0
- package/template-vite/lib/next-compat.tsx +98 -0
- package/{template → template-vite}/package.json +15 -27
- package/template-vite/scripts/port-next-imports.mjs +70 -0
- package/template-vite/src/App.tsx +103 -0
- package/template-vite/src/main.tsx +50 -0
- package/{template/app/(app)/error.tsx → template-vite/src/pages/_error.tsx} +12 -24
- package/{template/app/(app)/loading.tsx → template-vite/src/pages/_loading.tsx} +4 -2
- package/template-vite/src/pages/_not-found.tsx +17 -0
- package/template-vite/src/pages/dashboard.tsx +48 -0
- package/{template/app/(app)/help/page.tsx → template-vite/src/pages/help.tsx} +3 -2
- package/{template/app/(app)/library/layout.tsx → template-vite/src/pages/library/_layout.tsx} +18 -16
- package/{template/app/(app)/library/all/page.tsx → template-vite/src/pages/library/all.tsx} +1 -1
- package/{template/app/(app)/library/new/page.tsx → template-vite/src/pages/library/new.tsx} +12 -18
- package/template-vite/src/routes.tsx +72 -0
- package/template-vite/src/styles/globals.css +25 -0
- package/{template → template-vite}/tsconfig.json +5 -14
- package/template-vite/vite.config.ts +52 -0
- package/consumer-extras/cursor-rules/exxat-dashboard-view-charts.mdc +0 -53
- package/template/.agents/skills/shadcn/SKILL.md +0 -242
- package/template/.agents/skills/shadcn/agents/openai.yml +0 -5
- package/template/.agents/skills/shadcn/assets/shadcn-small.png +0 -0
- package/template/.agents/skills/shadcn/assets/shadcn.png +0 -0
- package/template/.agents/skills/shadcn/cli.md +0 -257
- package/template/.agents/skills/shadcn/customization.md +0 -202
- package/template/.agents/skills/shadcn/evals/evals.json +0 -47
- package/template/.agents/skills/shadcn/mcp.md +0 -94
- package/template/.agents/skills/shadcn/rules/base-vs-radix.md +0 -306
- package/template/.agents/skills/shadcn/rules/composition.md +0 -195
- package/template/.agents/skills/shadcn/rules/forms.md +0 -192
- package/template/.agents/skills/shadcn/rules/icons.md +0 -101
- package/template/.agents/skills/shadcn/rules/styling.md +0 -162
- package/template/.cursor/rules/exxat-accessibility.mdc +0 -33
- package/template/.cursor/rules/exxat-data-tables.mdc +0 -32
- package/template/.cursor/rules/exxat-ds-agents.mdc +0 -26
- package/template/.cursor/rules/exxat-list-page-connected-views.mdc +0 -16
- package/template/.cursor/rules/exxat-table-properties-drawer.mdc +0 -40
- package/template/.nvmrc +0 -1
- package/template/.prettierignore +0 -7
- package/template/Logo/Exxat_Prism.svg +0 -39
- package/template/Logo/Exxat_one.svg +0 -36
- package/template/app/(app)/dashboard/loading.tsx +0 -18
- package/template/app/(app)/dashboard/page.tsx +0 -36
- package/template/app/(app)/layout.tsx +0 -77
- package/template/app/global-error.tsx +0 -63
- package/template/app/globals.css +0 -20
- package/template/app/layout.tsx +0 -133
- package/template/app/page.tsx +0 -9
- package/template/docs/HANDBOOK.md +0 -187
- package/template/docs/blueprints/README.md +0 -86
- package/template/docs/blueprints/_template.md +0 -91
- package/template/docs/blueprints/board-card.md +0 -123
- package/template/docs/blueprints/data-table.md +0 -139
- package/template/docs/blueprints/key-metrics.md +0 -128
- package/template/docs/blueprints/list-page-template.md +0 -123
- package/template/docs/blueprints/page-header.md +0 -130
- package/template/docs/card-vs-rows-pattern.md +0 -36
- package/template/docs/collaboration-access-pattern.md +0 -116
- package/template/docs/command-menu-pattern.md +0 -45
- package/template/docs/component-selection-guide.md +0 -224
- package/template/docs/components-audit-2026-05.md +0 -158
- package/template/docs/consumer-upgrade-checklist.md +0 -52
- package/template/docs/data-views-pattern.md +0 -185
- package/template/docs/drawer-vs-dialog-pattern.md +0 -50
- package/template/docs/glossary.md +0 -59
- package/template/docs/hub-supported-views-pattern.md +0 -53
- package/template/docs/jobs/README.md +0 -59
- package/template/docs/jobs/record-detail.md +0 -177
- package/template/docs/kpi-flat-band-pattern.md +0 -57
- package/template/docs/kpi-strip-max-four-pattern.md +0 -30
- package/template/docs/kpi-trend-pattern.md +0 -58
- package/template/docs/large-dataset-strategy.md +0 -155
- package/template/docs/library-hub-header-pattern.md +0 -25
- package/template/docs/migrations/0001-brand-deep-alias-stabilization.md +0 -95
- package/template/docs/migrations/0002-exxat-token-namespace.md +0 -154
- package/template/docs/migrations/0003-globals-css-canonical.md +0 -110
- package/template/docs/migrations/README.md +0 -100
- package/template/docs/migrations/_template.md +0 -64
- package/template/docs/modern-saas-patterns.md +0 -165
- package/template/docs/perf-memory-pattern.md +0 -206
- package/template/docs/reference-implementations.md +0 -153
- package/template/docs/shell-surface-elevation-pattern.md +0 -52
- package/template/docs/token-taxonomy.md +0 -416
- package/template/docs/voice-and-tone.md +0 -262
- package/template/ecosystem.config.cjs +0 -32
- package/template/next.config.mjs +0 -216
- package/template/postcss.config.mjs +0 -8
- package/template/public/favicon/favicon.ico +0 -0
- package/template/tests/setup.ts +0 -26
- package/template/vitest.config.ts +0 -18
- /package/{template → template-vite}/.cursor/rules/exxat-dashboard-view-charts.mdc +0 -0
- /package/{template → template-vite}/.prettierrc +0 -0
- /package/{template → template-vite}/AGENTS.md +0 -0
- /package/{template → template-vite}/README.md +0 -0
- /package/{template → template-vite}/components/.gitkeep +0 -0
- /package/{template → template-vite}/components/ask-leo-composer.tsx +0 -0
- /package/{template → template-vite}/components/brand-color-picker.tsx +0 -0
- /package/{template → template-vite}/components/chart-area-interactive.tsx +0 -0
- /package/{template → template-vite}/components/charts-overview.tsx +0 -0
- /package/{template → template-vite}/components/collaboration-access-flow.tsx +0 -0
- /package/{template → template-vite}/components/columns-client.tsx +0 -0
- /package/{template → template-vite}/components/columns-showcase.tsx +0 -0
- /package/{template → template-vite}/components/dashboard-promo-banner.tsx +0 -0
- /package/{template → template-vite}/components/dashboard-quota-progress-card.tsx +0 -0
- /package/{template → template-vite}/components/dashboard-report-charts.tsx +0 -0
- /package/{template → template-vite}/components/dashboard-section-heading.tsx +0 -0
- /package/{template → template-vite}/components/dashboard-tabs.tsx +0 -0
- /package/{template → template-vite}/components/data-table/filter-date-calendar.tsx +0 -0
- /package/{template → template-vite}/components/data-table/filter-text-value-input.tsx +0 -0
- /package/{template → template-vite}/components/data-table/index.tsx +0 -0
- /package/{template → template-vite}/components/data-table/pagination.tsx +0 -0
- /package/{template → template-vite}/components/data-table/types.ts +0 -0
- /package/{template → template-vite}/components/data-table/use-table-state.test.ts +0 -0
- /package/{template → template-vite}/components/data-table/use-table-state.ts +0 -0
- /package/{template → template-vite}/components/data-views/board-card-primitives.tsx +0 -0
- /package/{template → template-vite}/components/data-views/data-row-list.tsx +0 -0
- /package/{template → template-vite}/components/data-views/finder-panel-view.tsx +0 -0
- /package/{template → template-vite}/components/data-views/folder-grid-view.tsx +0 -0
- /package/{template → template-vite}/components/data-views/hub-table.tsx +0 -0
- /package/{template → template-vite}/components/data-views/index.ts +0 -0
- /package/{template → template-vite}/components/data-views/list-page-board-card.tsx +0 -0
- /package/{template → template-vite}/components/data-views/list-page-board-template.tsx +0 -0
- /package/{template → template-vite}/components/data-views/list-page-connected-view-body.tsx +0 -0
- /package/{template → template-vite}/components/data-views/list-page-split-details-placeholder.tsx +0 -0
- /package/{template → template-vite}/components/data-views/list-page-split-hub-chrome.tsx +0 -0
- /package/{template → template-vite}/components/data-views/list-page-split-hub-tokens.ts +0 -0
- /package/{template → template-vite}/components/data-views/list-page-tree-column-header.tsx +0 -0
- /package/{template → template-vite}/components/data-views/list-page-tree-panel-shell.tsx +0 -0
- /package/{template → template-vite}/components/data-views/list-page-view-frame.tsx +0 -0
- /package/{template → template-vite}/components/data-views/os-folder-glyph.tsx +0 -0
- /package/{template → template-vite}/components/data-views/outline-tree-menu.tsx +0 -0
- /package/{template → template-vite}/components/data-views/table-cells.tsx +0 -0
- /package/{template → template-vite}/components/dev-chunk-load-recovery.tsx +0 -0
- /package/{template → template-vite}/components/export-drawer.test.tsx +0 -0
- /package/{template → template-vite}/components/export-drawer.tsx +0 -0
- /package/{template → template-vite}/components/folder-details-shell.tsx +0 -0
- /package/{template → template-vite}/components/form-layout-01.tsx +0 -0
- /package/{template → template-vite}/components/hub-tree-panel-view.tsx +0 -0
- /package/{template → template-vite}/components/invite-collaborators-drawer.tsx +0 -0
- /package/{template → template-vite}/components/key-metrics-ask-leo-bridge.tsx +0 -0
- /package/{template → template-vite}/components/key-metrics.tsx +0 -0
- /package/{template → template-vite}/components/leo-insight-indicator.tsx +0 -0
- /package/{template → template-vite}/components/leo-typing-dots.tsx +0 -0
- /package/{template → template-vite}/components/library-board-view.tsx +0 -0
- /package/{template → template-vite}/components/library-dashboard-charts.tsx +0 -0
- /package/{template → template-vite}/components/library-favorite-button.tsx +0 -0
- /package/{template → template-vite}/components/library-new-folder-sheet.tsx +0 -0
- /package/{template → template-vite}/components/library-os-folder-view.tsx +0 -0
- /package/{template → template-vite}/components/library-page-header.tsx +0 -0
- /package/{template → template-vite}/components/library-panel-activator.tsx +0 -0
- /package/{template → template-vite}/components/list-hub-status-badge.tsx +0 -0
- /package/{template → template-vite}/components/list-page-dashboard-charts.tsx +0 -0
- /package/{template → template-vite}/components/onboarding/getting-started.tsx +0 -0
- /package/{template → template-vite}/components/onboarding/index.ts +0 -0
- /package/{template → template-vite}/components/onboarding/onboarding-01.tsx +0 -0
- /package/{template → template-vite}/components/onboarding/onboarding-02.tsx +0 -0
- /package/{template → template-vite}/components/onboarding/onboarding-03.tsx +0 -0
- /package/{template → template-vite}/components/onboarding/onboarding-04.tsx +0 -0
- /package/{template → template-vite}/components/page-header.tsx +0 -0
- /package/{template → template-vite}/components/product-switcher.tsx +0 -0
- /package/{template → template-vite}/components/product-wordmark.tsx +0 -0
- /package/{template → template-vite}/components/settings-appearance-card.tsx +0 -0
- /package/{template → template-vite}/components/settings-form-row.tsx +0 -0
- /package/{template → template-vite}/components/sidebar/app-sidebar-dynamic.tsx +0 -0
- /package/{template → template-vite}/components/sidebar/index.ts +0 -0
- /package/{template → template-vite}/components/sidebar/nav-documents.tsx +0 -0
- /package/{template → template-vite}/components/sidebar/nav-secondary.tsx +0 -0
- /package/{template → template-vite}/components/sidebar/secondary-panel.tsx +0 -0
- /package/{template → template-vite}/components/sidebar/sidebar-auto-collapse.tsx +0 -0
- /package/{template → template-vite}/components/sidebar/sidebar-auto-open.tsx +0 -0
- /package/{template → template-vite}/components/sidebar/sidebar-shell.tsx +0 -0
- /package/{template → template-vite}/components/site-header.tsx +0 -0
- /package/{template → template-vite}/components/table-properties/column-row.tsx +0 -0
- /package/{template → template-vite}/components/table-properties/draggable-list.ts +0 -0
- /package/{template → template-vite}/components/table-properties/drawer-button.tsx +0 -0
- /package/{template → template-vite}/components/table-properties/drawer.tsx +0 -0
- /package/{template → template-vite}/components/table-properties/filter-card.tsx +0 -0
- /package/{template → template-vite}/components/table-properties/index.ts +0 -0
- /package/{template → template-vite}/components/table-properties/sort-card.tsx +0 -0
- /package/{template → template-vite}/components/table-properties/types.ts +0 -0
- /package/{template → template-vite}/components/task-list-panel.tsx +0 -0
- /package/{template → template-vite}/components/task-priority-badge.tsx +0 -0
- /package/{template → template-vite}/components/templates/dedicated-search-landing-template.tsx +0 -0
- /package/{template → template-vite}/components/templates/dedicated-search-results-template.tsx +0 -0
- /package/{template → template-vite}/components/templates/list-page.tsx +0 -0
- /package/{template → template-vite}/components/templates/nested-secondary-panel-shell.tsx +0 -0
- /package/{template → template-vite}/components/templates/primary-page-template.tsx +0 -0
- /package/{template → template-vite}/components/templates/secondary-panel-hub-template.tsx +0 -0
- /package/{template → template-vite}/components/theme-color-sync.tsx +0 -0
- /package/{template → template-vite}/components/theme-provider.tsx +0 -0
- /package/{template → template-vite}/components/tinted-icon-disc.tsx +0 -0
- /package/{template → template-vite}/components/tokens-hub-auxiliary-views.tsx +0 -0
- /package/{template → template-vite}/components/tokens-themes-section.tsx +0 -0
- /package/{template → template-vite}/components/ui/accordion.tsx +0 -0
- /package/{template → template-vite}/components/ui/ai-thinking-surface.tsx +0 -0
- /package/{template → template-vite}/components/ui/alert-dialog.tsx +0 -0
- /package/{template → template-vite}/components/ui/avatar.tsx +0 -0
- /package/{template → template-vite}/components/ui/badge.tsx +0 -0
- /package/{template → template-vite}/components/ui/banner.tsx +0 -0
- /package/{template → template-vite}/components/ui/breadcrumb.tsx +0 -0
- /package/{template → template-vite}/components/ui/button.tsx +0 -0
- /package/{template → template-vite}/components/ui/calendar.tsx +0 -0
- /package/{template → template-vite}/components/ui/card.tsx +0 -0
- /package/{template → template-vite}/components/ui/chart.tsx +0 -0
- /package/{template → template-vite}/components/ui/checkbox.tsx +0 -0
- /package/{template → template-vite}/components/ui/coach-mark.tsx +0 -0
- /package/{template → template-vite}/components/ui/collapsible.tsx +0 -0
- /package/{template → template-vite}/components/ui/command.tsx +0 -0
- /package/{template → template-vite}/components/ui/context-menu.tsx +0 -0
- /package/{template → template-vite}/components/ui/date-picker-field.tsx +0 -0
- /package/{template → template-vite}/components/ui/dialog.tsx +0 -0
- /package/{template → template-vite}/components/ui/dot-pattern.tsx +0 -0
- /package/{template → template-vite}/components/ui/drag-handle-grip.tsx +0 -0
- /package/{template → template-vite}/components/ui/dropdown-menu.tsx +0 -0
- /package/{template → template-vite}/components/ui/field.tsx +0 -0
- /package/{template → template-vite}/components/ui/form.tsx +0 -0
- /package/{template → template-vite}/components/ui/hover-card.tsx +0 -0
- /package/{template → template-vite}/components/ui/input-group.tsx +0 -0
- /package/{template → template-vite}/components/ui/input-mask.tsx +0 -0
- /package/{template → template-vite}/components/ui/input.tsx +0 -0
- /package/{template → template-vite}/components/ui/kbd.tsx +0 -0
- /package/{template → template-vite}/components/ui/label.tsx +0 -0
- /package/{template → template-vite}/components/ui/leo-icon.tsx +0 -0
- /package/{template → template-vite}/components/ui/payment-card-fields.tsx +0 -0
- /package/{template → template-vite}/components/ui/popover.tsx +0 -0
- /package/{template → template-vite}/components/ui/radio-group.tsx +0 -0
- /package/{template → template-vite}/components/ui/resizable.tsx +0 -0
- /package/{template → template-vite}/components/ui/scroll-area.tsx +0 -0
- /package/{template → template-vite}/components/ui/select.tsx +0 -0
- /package/{template → template-vite}/components/ui/selection-tile-grid.tsx +0 -0
- /package/{template → template-vite}/components/ui/separator.tsx +0 -0
- /package/{template → template-vite}/components/ui/sheet.tsx +0 -0
- /package/{template → template-vite}/components/ui/sidebar.tsx +0 -0
- /package/{template → template-vite}/components/ui/skeleton.tsx +0 -0
- /package/{template → template-vite}/components/ui/slider.tsx +0 -0
- /package/{template → template-vite}/components/ui/sonner.tsx +0 -0
- /package/{template → template-vite}/components/ui/status-badge.tsx +0 -0
- /package/{template → template-vite}/components/ui/table.tsx +0 -0
- /package/{template → template-vite}/components/ui/tabs.tsx +0 -0
- /package/{template → template-vite}/components/ui/textarea.tsx +0 -0
- /package/{template → template-vite}/components/ui/tip.tsx +0 -0
- /package/{template → template-vite}/components/ui/toggle-group.tsx +0 -0
- /package/{template → template-vite}/components/ui/toggle-switch.tsx +0 -0
- /package/{template → template-vite}/components/ui/toggle.tsx +0 -0
- /package/{template → template-vite}/components/ui/tooltip.tsx +0 -0
- /package/{template → template-vite}/components/ui/view-segmented-control.tsx +0 -0
- /package/{template → template-vite}/components.json +0 -0
- /package/{template → template-vite}/contexts/chart-variant-context.tsx +0 -0
- /package/{template → template-vite}/contexts/command-menu-context.tsx +0 -0
- /package/{template → template-vite}/contexts/dashboard-view-context.tsx +0 -0
- /package/{template → template-vite}/contexts/product-context.tsx +0 -0
- /package/{template → template-vite}/contexts/system-banner-context.tsx +0 -0
- /package/{template → template-vite}/eslint.config.mjs +0 -0
- /package/{template → template-vite}/fontawesome-subset.manifest.json +0 -0
- /package/{template → template-vite}/hooks/.gitkeep +0 -0
- /package/{template → template-vite}/hooks/use-app-theme.ts +0 -0
- /package/{template → template-vite}/hooks/use-coach-mark.ts +0 -0
- /package/{template → template-vite}/hooks/use-location-hash.ts +0 -0
- /package/{template → template-vite}/hooks/use-mobile.ts +0 -0
- /package/{template → template-vite}/hooks/use-mod-key-label.ts +0 -0
- /package/{template → template-vite}/hooks/use-sidebar-reflow-zoom.ts +0 -0
- /package/{template → template-vite}/lib/.gitkeep +0 -0
- /package/{template → template-vite}/lib/ask-leo-route-context.ts +0 -0
- /package/{template → template-vite}/lib/chart-keyboard-selection.test.ts +0 -0
- /package/{template → template-vite}/lib/chart-keyboard-selection.ts +0 -0
- /package/{template → template-vite}/lib/chart-line-dash.ts +0 -0
- /package/{template → template-vite}/lib/chunk-load-error.ts +0 -0
- /package/{template → template-vite}/lib/coach-mark-registry.ts +0 -0
- /package/{template → template-vite}/lib/collaborator-access.ts +0 -0
- /package/{template → template-vite}/lib/command-menu-config.ts +0 -0
- /package/{template → template-vite}/lib/command-menu-search-data.ts +0 -0
- /package/{template → template-vite}/lib/conditional-rule-match.ts +0 -0
- /package/{template → template-vite}/lib/dashboard-customize-coach-mark.ts +0 -0
- /package/{template → template-vite}/lib/dashboard-layout-merge.ts +0 -0
- /package/{template → template-vite}/lib/data-list-display-options.ts +0 -0
- /package/{template → template-vite}/lib/data-list-persistence.ts +0 -0
- /package/{template → template-vite}/lib/data-list-view-registry.ts +0 -0
- /package/{template → template-vite}/lib/data-list-view-surface.ts +0 -0
- /package/{template → template-vite}/lib/data-list-view.ts +0 -0
- /package/{template → template-vite}/lib/data-view-dashboard-storage.ts +0 -0
- /package/{template → template-vite}/lib/date-filter.ts +0 -0
- /package/{template → template-vite}/lib/dedicated-search-recents.ts +0 -0
- /package/{template → template-vite}/lib/dedicated-search-url.ts +0 -0
- /package/{template → template-vite}/lib/dev-log.test.ts +0 -0
- /package/{template → template-vite}/lib/dev-log.ts +0 -0
- /package/{template → template-vite}/lib/discovery-hub.ts +0 -0
- /package/{template → template-vite}/lib/editable-target.ts +0 -0
- /package/{template → template-vite}/lib/exxat-palette.json +0 -0
- /package/{template → template-vite}/lib/exxat-palette.ts +0 -0
- /package/{template → template-vite}/lib/floating-sheet-panel.ts +0 -0
- /package/{template → template-vite}/lib/full-hub-supported-views.ts +0 -0
- /package/{template → template-vite}/lib/hub-connected-view-renderers.ts +0 -0
- /package/{template → template-vite}/lib/initials-from-name.ts +0 -0
- /package/{template → template-vite}/lib/library-authoring.ts +0 -0
- /package/{template → template-vite}/lib/library-dedicated-search.ts +0 -0
- /package/{template → template-vite}/lib/library-hub-search.ts +0 -0
- /package/{template → template-vite}/lib/library-nav.ts +0 -0
- /package/{template → template-vite}/lib/library-recent-searches.ts +0 -0
- /package/{template → template-vite}/lib/library-supported-views.ts +0 -0
- /package/{template → template-vite}/lib/list-hub-supported-views.ts +0 -0
- /package/{template → template-vite}/lib/list-page-table-properties.ts +0 -0
- /package/{template → template-vite}/lib/list-status-badges.ts +0 -0
- /package/{template → template-vite}/lib/logo-dev.ts +0 -0
- /package/{template → template-vite}/lib/mailto.ts +0 -0
- /package/{template → template-vite}/lib/mock/dashboard.ts +0 -0
- /package/{template → template-vite}/lib/mock/library-folders.ts +0 -0
- /package/{template → template-vite}/lib/mock/library-header-collaborators.ts +0 -0
- /package/{template → template-vite}/lib/mock/library-inspector.ts +0 -0
- /package/{template → template-vite}/lib/mock/library-kpi.ts +0 -0
- /package/{template → template-vite}/lib/mock/library.ts +0 -0
- /package/{template → template-vite}/lib/mock/navigation.tsx +0 -0
- /package/{template → template-vite}/lib/motion-ui.ts +0 -0
- /package/{template → template-vite}/lib/product-brand.ts +0 -0
- /package/{template → template-vite}/lib/raf-throttle.ts +0 -0
- /package/{template → template-vite}/lib/row-height.ts +0 -0
- /package/{template → template-vite}/lib/sidebar-state-cookie.ts +0 -0
- /package/{template → template-vite}/lib/stock-portrait.ts +0 -0
- /package/{template → template-vite}/lib/table-state-lifecycle.ts +0 -0
- /package/{template → template-vite}/lib/utils.test.ts +0 -0
- /package/{template → template-vite}/lib/utils.ts +0 -0
- /package/{template → template-vite}/public/.gitkeep +0 -0
- /package/{template → template-vite}/public/Illustration/Rotation.svg +0 -0
- /package/{template → template-vite}/public/avatars/user.svg +0 -0
- /package/{template/public → template-vite/public/favicon}/favicon.ico +0 -0
- /package/{template/app → template-vite/public}/favicon.ico +0 -0
- /package/{template → template-vite}/public/folders/icons8-folder-windows-11.svg +0 -0
- /package/{template → template-vite}/public/logos/exxat-one.svg +0 -0
- /package/{template → template-vite}/public/logos/exxat-prism.svg +0 -0
- /package/{template → template-vite}/public/mock-schools/emory.svg +0 -0
- /package/{template → template-vite}/public/mock-schools/rush.svg +0 -0
- /package/{template → template-vite}/scripts/fontawesome-subset-audit.mjs +0 -0
- /package/{template → template-vite}/scripts/pm2-startup-macos.sh +0 -0
- /package/{template → template-vite}/skills-lock.json +0 -0
- /package/{template/app/(app)/columns/page.tsx → template-vite/src/pages/columns.tsx} +0 -0
- /package/{template/app/(app)/library/find/page.tsx → template-vite/src/pages/library/find.tsx} +0 -0
- /package/{template/app/(app)/library/page.tsx → template-vite/src/pages/library/index.tsx} +0 -0
- /package/{template/app/(app)/library/list/page.tsx → template-vite/src/pages/library/list.tsx} +0 -0
- /package/{template/app/(app)/settings/page.tsx → template-vite/src/pages/settings.tsx} +0 -0
- /package/{template/app/(app)/tokens-themes/page.tsx → template-vite/src/pages/tokens-themes.tsx} +0 -0
- /package/{template → template-vite}/stores/app-store.ts +0 -0
- /package/{template → template-vite}/types/react-payment-inputs.d.ts +0 -0
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
# `apps/web/components/` audit — 2026-05
|
|
2
|
-
|
|
3
|
-
**Author:** Exxat DS hardening sweep · **Scope:** observation only — no code moved.
|
|
4
|
-
|
|
5
|
-
This audit was triggered by formalizing the design system (token taxonomy +
|
|
6
|
-
blueprints + selection guide + ESLint guardrails) so that any future
|
|
7
|
-
component refactor has a clear target structure. **No file is moved or
|
|
8
|
-
deleted by this audit itself.** Treat each finding as a follow-up PR
|
|
9
|
-
candidate; bundle them as you like.
|
|
10
|
-
|
|
11
|
-
## 1. Sizes & shape
|
|
12
|
-
|
|
13
|
-
| Bucket | Count | Notes |
|
|
14
|
-
|---|---|---|
|
|
15
|
-
| Top-level `components/*.tsx` | **99** | Mix of hub clients, hub tables, hub views, page headers, dashboard charts, sidebar bits, leaf primitives |
|
|
16
|
-
| `components/data-table/` | 5 | Correct — base table stack |
|
|
17
|
-
| `components/data-views/` | 14 | Correct — generic view primitives + board card |
|
|
18
|
-
| `components/onboarding/` | 5 (4 demos + index) | Demo variants of `GettingStarted` |
|
|
19
|
-
| `components/table-properties/` | (drawer + parts) | Correct |
|
|
20
|
-
| `components/templates/` | 7 | Correct — page-level templates |
|
|
21
|
-
| `components/ui/` | 40+ | Reserved for shadcn primitives bridged from `packages/ui` |
|
|
22
|
-
|
|
23
|
-
## 2. Findings
|
|
24
|
-
|
|
25
|
-
### 2.1 Dead components (zero importers found)
|
|
26
|
-
|
|
27
|
-
> **Resolved 2026-05-19.** A re-verification scan confirmed that
|
|
28
|
-
> `form-layout-01.tsx` and `section-cards.tsx` are **not present** in either
|
|
29
|
-
> `apps/web/components/` or `packages/ui/template/components/` — the audit's
|
|
30
|
-
> initial finding was based on a stale snapshot. No action needed.
|
|
31
|
-
|
|
32
|
-
### 2.2 Onboarding components split between two locations
|
|
33
|
-
|
|
34
|
-
> **Resolved 2026-05-19.** Option A landed:
|
|
35
|
-
> - `getting-started.tsx` moved into `components/onboarding/getting-started.tsx`
|
|
36
|
-
> (both `apps/web/` and `packages/ui/template/`).
|
|
37
|
-
> - Deprecated shims `dashboard-onboarding.tsx` and
|
|
38
|
-
> `dashboard-onboarding-gallery.tsx` deleted in both locations
|
|
39
|
-
> (no consumers outside themselves).
|
|
40
|
-
> - `components/onboarding/index.ts` now re-exports `GettingStarted`,
|
|
41
|
-
> `GettingStartedProgressCard`, `GettingStartedVariantView`,
|
|
42
|
-
> `renderGettingStartedVariant`, `GETTING_STARTED_STORAGE_KEY`, and
|
|
43
|
-
> the `Onboarding01`–`Onboarding04` variant cards.
|
|
44
|
-
> - Dashboard consumers (`dashboard-tabs.tsx`, `dashboard-report-charts.tsx`)
|
|
45
|
-
> import via `@/components/onboarding/getting-started`; intra-folder
|
|
46
|
-
> variants use the relative `./getting-started` path.
|
|
47
|
-
|
|
48
|
-
### 2.3 Sidebar shell — high top-level density
|
|
49
|
-
|
|
50
|
-
> **Resolved 2026-05-19.** All 11 sidebar files relocated into
|
|
51
|
-
> `components/sidebar/` (both `apps/web/` and `packages/ui/template/`):
|
|
52
|
-
>
|
|
53
|
-
> ```
|
|
54
|
-
> components/sidebar/
|
|
55
|
-
> ├── index.ts ← barrel re-export
|
|
56
|
-
> ├── app-sidebar.tsx
|
|
57
|
-
> ├── app-sidebar-dynamic.tsx
|
|
58
|
-
> ├── sidebar-shell.tsx
|
|
59
|
-
> ├── sidebar-auto-collapse.tsx
|
|
60
|
-
> ├── sidebar-auto-open.tsx
|
|
61
|
-
> ├── nav-main.tsx
|
|
62
|
-
> ├── nav-secondary.tsx
|
|
63
|
-
> ├── nav-documents.tsx
|
|
64
|
-
> ├── nav-user.tsx
|
|
65
|
-
> ├── secondary-nav.tsx
|
|
66
|
-
> └── secondary-panel.tsx
|
|
67
|
-
> ```
|
|
68
|
-
>
|
|
69
|
-
> **External consumers** now import via the barrel:
|
|
70
|
-
> `import { AppSidebar, SidebarShell, useSecondaryPanel } from "@/components/sidebar"`.
|
|
71
|
-
> Per-file paths still resolve (escape hatch), e.g.
|
|
72
|
-
> `@/components/sidebar/secondary-panel`.
|
|
73
|
-
>
|
|
74
|
-
> **Intra-folder** imports use relative paths (`./nav-user`, `./secondary-panel`)
|
|
75
|
-
> so internal restructure does not ripple out.
|
|
76
|
-
>
|
|
77
|
-
> Dead-import audit at completion: zero references to `@/components/<sidebar-file>"`
|
|
78
|
-
> remain outside the new folder.
|
|
79
|
-
>
|
|
80
|
-
> `nav-main`, `nav-secondary`, `nav-documents`, `sidebar-auto-open` are
|
|
81
|
-
> currently zero-import (only mentioned in docs/skills). They were moved for
|
|
82
|
-
> directory consistency; pruning truly dead files is a separate concern.
|
|
83
|
-
|
|
84
|
-
### 2.4 Dedicated-search files — naming consistent
|
|
85
|
-
|
|
86
|
-
`dedicated-search-recents.tsx`, `dedicated-search-url-composer.tsx`,
|
|
87
|
-
`components/templates/dedicated-search-{landing,results}-template.tsx` —
|
|
88
|
-
generic family already lives across `templates/` + top-level. **No action.**
|
|
89
|
-
|
|
90
|
-
### 2.5 Entity-bound views — correctly at top level
|
|
91
|
-
|
|
92
|
-
`*-list-view.tsx`, `*-board-view.tsx`, `*-page-header.tsx`, `*-client.tsx`,
|
|
93
|
-
`*-table.tsx`, `*-dashboard-charts*.tsx`, `*-os-folder-view.tsx`,
|
|
94
|
-
`*-panel-activator.tsx` — these are entity-specific compositions that
|
|
95
|
-
**must** stay co-located with the hub they serve. **No action.**
|
|
96
|
-
|
|
97
|
-
### 2.6 Possibly generic — re-evaluate during reuse work
|
|
98
|
-
|
|
99
|
-
- `tinted-icon-disc.tsx` — used in KPI/empty states. If the API has stabilized,
|
|
100
|
-
consider moving to `components/data-views/` or `packages/ui/src/components/ui/`.
|
|
101
|
-
- `task-list-panel.tsx`, `task-priority-badge.tsx` — generic-sounding but
|
|
102
|
-
bound to a Task entity. Confirm scope before any move.
|
|
103
|
-
- `tree-panel-view.tsx`-style: `hub-tree-panel-view.tsx`,
|
|
104
|
-
`folder-details-shell.tsx` — already generic-sounding. If imported by
|
|
105
|
-
≥ 2 hubs, move under `data-views/`.
|
|
106
|
-
|
|
107
|
-
A quick rule of thumb:
|
|
108
|
-
|
|
109
|
-
> If a component is imported by **only one** hub, it stays at the top level
|
|
110
|
-
> next to that hub.
|
|
111
|
-
> If it is (or could be) imported by **≥ 2** hubs, promote it into
|
|
112
|
-
> `components/data-views/` (record-bearing) or `components/templates/`
|
|
113
|
-
> (page chrome).
|
|
114
|
-
|
|
115
|
-
### 2.7 `packages/ui/template/` parity
|
|
116
|
-
|
|
117
|
-
Most top-level files are mirrored under `packages/ui/template/components/`
|
|
118
|
-
(starter scaffold for `create-exxat-app`). When a file moves in
|
|
119
|
-
`apps/web/components/`, `pnpm --filter @exxatdesignux/ui sync-template`
|
|
120
|
-
will also move it under `template/`. **Always run `sync-template` after any
|
|
121
|
-
refactor under §2.3 / §2.6** so the published starter stays buildable.
|
|
122
|
-
|
|
123
|
-
## 3. Non-findings — what's already healthy
|
|
124
|
-
|
|
125
|
-
- **`components/ui/`** is reserved for shadcn-aligned primitives; no
|
|
126
|
-
duplicates appear at the top level (e.g. no rogue `button.tsx` next to the
|
|
127
|
-
one in `ui/`).
|
|
128
|
-
- **`components/data-views/`** is the right home for generic record-bearing
|
|
129
|
-
surfaces (`FolderGridView`, `FinderPanelView`, `ListPageBoardCard`).
|
|
130
|
-
Entity-specific board cards (`placement-board-card.tsx`) correctly stay
|
|
131
|
-
at top level.
|
|
132
|
-
- **`components/templates/`** is the right home for page-level wrappers
|
|
133
|
-
(`ListPageTemplate`, `DedicatedSearch*Template`,
|
|
134
|
-
`SecondaryPanelHubTemplate`, `DiscoveryHubTemplate`). No drift.
|
|
135
|
-
- **No `components/lightning/`** folder anywhere — `exxat-no-slds-leakage`
|
|
136
|
-
rule already passes.
|
|
137
|
-
- **No second toast surface** — only `components/ui/sonner.tsx` exists, and
|
|
138
|
-
it's gated by `exxat-no-toast` + the new `exxat-ds/no-sonner-toast` lint.
|
|
139
|
-
|
|
140
|
-
## 4. Suggested follow-up PRs
|
|
141
|
-
|
|
142
|
-
| # | Title | Scope | Risk |
|
|
143
|
-
|---|---|---|---|
|
|
144
|
-
| 1 | Remove dead `form-layout-01.tsx` + `section-cards.tsx` from `apps/web/` and `packages/ui/template/` | Trivial | Low |
|
|
145
|
-
| 2 | Consolidate `getting-started.tsx` + `dashboard-onboarding*.tsx` under `components/onboarding/` | Small | Low (import rename) |
|
|
146
|
-
| 3 | ~~Move sidebar files into `components/sidebar/`~~ — **done 2026-05-19** (§2.3) | Medium | — |
|
|
147
|
-
| 4 | Promote `tinted-icon-disc.tsx`, `hub-tree-panel-view.tsx`, `folder-details-shell.tsx` to `data-views/` if used by ≥ 2 hubs | Small per file | Low |
|
|
148
|
-
| 5 | Run `sync-template` after each of 1–4 to keep `packages/ui/template/` aligned | Single command | Low |
|
|
149
|
-
|
|
150
|
-
None of these is urgent. They become valuable when the top-level file count
|
|
151
|
-
exceeds ~110 or when a new hub joins the codebase.
|
|
152
|
-
|
|
153
|
-
## 5. References
|
|
154
|
-
|
|
155
|
-
- [`apps/web/AGENTS.md`](../AGENTS.md) §9 — architecture pointers
|
|
156
|
-
- [`apps/web/docs/component-selection-guide.md`](./component-selection-guide.md)
|
|
157
|
-
- [`.cursor/rules/exxat-reuse-before-custom.mdc`](../../.cursor/rules/exxat-reuse-before-custom.mdc) — ask before adding new primitives
|
|
158
|
-
- [`.cursor/rules/exxat-list-page-view-shells.mdc`](../../.cursor/rules/exxat-list-page-view-shells.mdc) — when to extract to `data-views/`
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
# Upgrading `@exxatdesignux/ui` (human + AI checklist)
|
|
2
|
-
|
|
3
|
-
Use this after **`npm install @exxatdesignux/ui@…`** / **`pnpm add @exxatdesignux/ui@…`**. It is copied into **`docs/exxat-ds/`** when you run **`exxat-ui sync-extras`**, so Cursor and other tools can find it beside other DS pattern docs.
|
|
4
|
-
|
|
5
|
-
## 1. See what changed
|
|
6
|
-
|
|
7
|
-
| Source | Purpose |
|
|
8
|
-
|--------|---------|
|
|
9
|
-
| **`node_modules/@exxatdesignux/ui/CHANGELOG.md`** | Release notes for the installed version (and peers). |
|
|
10
|
-
| **`npx --package=@exxatdesignux/ui@latest exxat-ui changelog`** | Print the changelog from the package on disk / npx extract. |
|
|
11
|
-
|
|
12
|
-
## 2. Refresh AI / pattern docs (optional but recommended)
|
|
13
|
-
|
|
14
|
-
```bash
|
|
15
|
-
npx --package=@exxatdesignux/ui@latest exxat-ui sync-extras
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
Overwrites only **`.cursor/skills/exxat-*`** and **`docs/exxat-ds/*.md`** (including this file). Does **not** change your app routes or product code.
|
|
19
|
-
|
|
20
|
-
## 3. Align app code with the reference template
|
|
21
|
-
|
|
22
|
-
The npm package includes a full Next.js reference under:
|
|
23
|
-
|
|
24
|
-
**`node_modules/@exxatdesignux/ui/template/`**
|
|
25
|
-
|
|
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
|
-
|
|
28
|
-
## 4. Dependency and Node
|
|
29
|
-
|
|
30
|
-
- Keep **`@exxatdesignux/ui`** on the same semver your team tested; prefer explicit **`^x.y.z`** or pinned **`x.y.z`**.
|
|
31
|
-
- Match **`engines.node`** in your app to the value declared in **`node_modules/@exxatdesignux/ui/package.json`** (see CHANGELOG if it changed).
|
|
32
|
-
- **≥ 0.5.3:** Remove **`vaul`** from your app `package.json` and delete any `components/ui/drawer.tsx` shim — side panels use **`Sheet`** only (**`.cursor/rules/exxat-no-vaul.mdc`**).
|
|
33
|
-
|
|
34
|
-
## 5. Consumer UI audit (after sync-extras)
|
|
35
|
-
|
|
36
|
-
If the app was built before current agent rules, verify:
|
|
37
|
-
|
|
38
|
-
| Symptom | Fix |
|
|
39
|
-
|---------|-----|
|
|
40
|
-
| Full-width tab bar on list hub | Use **`ListPageTemplate`** view toolbar — **`exxat-tabs-chrome.mdc`** |
|
|
41
|
-
| Full-width Overview / Academics tabs | **`TabsList`** must stay **`w-fit`** — no `w-full` / `flex-1` stretch |
|
|
42
|
-
| Grey custom header buttons | **`PageHeader`** + **`Button`** variants — **`exxat-page-header-actions.mdc`** |
|
|
43
|
-
| Bespoke student popover in table | **`HoverCard`** + shared cells/badges — **`exxat-table-row-preview.mdc`** |
|
|
44
|
-
| Custom hub table / trimmed Add view | **`HubTable`** + **`FULL_HUB_SUPPORTED_VIEWS`** — **`exxat-hub-supported-views.mdc`** |
|
|
45
|
-
| Agent copied uploaded screenshots pixel-for-pixel | **`exxat-no-image-pixel-copy.mdc`** — images = IA only; map to blueprints + reference hubs |
|
|
46
|
-
|
|
47
|
-
## 6. Still stuck?
|
|
48
|
-
|
|
49
|
-
- **`npx --package=@exxatdesignux/ui@latest exxat-ui doctor`** — compares local CLI version vs npm **`latest`**.
|
|
50
|
-
- **`npx --package=@exxatdesignux/ui@latest exxat-ui update`** — install commands and reminders.
|
|
51
|
-
|
|
52
|
-
Maintainers publish from the design-system monorepo with git tags **`ui-v<version>`**; registry **`latest`** follows those tags.
|
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
# Data views pattern (table, list, board)
|
|
2
|
-
|
|
3
|
-
> **Canonical rules for agents (MUST/MUST NOT, checklists):** [`AGENTS.md`](../AGENTS.md) in this package (including **§8 Accessibility**). This file is the long-form narrative; keep both aligned when patterns change.
|
|
4
|
-
|
|
5
|
-
> **Scaling past ~2K rows:** see [`large-dataset-strategy.md`](./large-dataset-strategy.md) for pagination, server-mode upgrade path, and the virtualization follow-up.
|
|
6
|
-
|
|
7
|
-
This document describes how list pages combine **views**, **toolbar** behavior, **filters**, **properties**, and **persistence** in this codebase.
|
|
8
|
-
|
|
9
|
-
## Add view parity (seven views)
|
|
10
|
-
|
|
11
|
-
**Binding:** `.cursor/rules/exxat-hub-supported-views.mdc`. **Detail:** `docs/hub-supported-views-pattern.md`.
|
|
12
|
-
|
|
13
|
-
Every list hub **should** use **`FULL_HUB_SUPPORTED_VIEWS`** (table, list, board, dashboard, folder, panel, tree-panel) on both **`ListPageTemplate`** and **`HubTable`**, with a working renderer per view. **Library** (`library-table.tsx`) is the reference. Do not ship table-only or four-view allowlists on showcase/catalog hubs unless product documents an exception.
|
|
14
|
-
|
|
15
|
-
## Reuse existing components (required)
|
|
16
|
-
|
|
17
|
-
**Prefer composing what already exists** over rebuilding one-off tabs, search, filters, or property panels. The **Placements** flow is the reference implementation; new list/table/board pages should wire the same building blocks with new data and column definitions.
|
|
18
|
-
|
|
19
|
-
| Need | Reuse | Where Placements uses it |
|
|
20
|
-
| --- | --- | --- |
|
|
21
|
-
| **View tabs** (table / list / board, lifecycle filters) | `ListPageTemplate` (`ViewTab`, `renderContent`, optional metrics + export) | `components/library-hub-client.tsx` + `components/templates/list-page.tsx` |
|
|
22
|
-
| **Table shell** (search, filter bar, sort, grouping, columns, pagination) | `HubTable` → `DataTable`, `DataTableToolbar`, `useTableState` | `components/data-table/`, `components/data-views/hub-table.tsx`, `components/columns-showcase.tsx` |
|
|
23
|
-
| **Properties drawer** (display, columns, filters, sort, view type tiles) | `TablePropertiesDrawer` from `@/components/table-properties` (auto-wired by `HubTable`) | `DrawerToolbar` / list–board shells in `library-table.tsx` |
|
|
24
|
-
| **Board / list** | `PlacementsBoardView`, `PlacementListRowContent` (wrapped by `HubTable.renderListRow` → `DataRowList`) + same `useTableState` | `PlacementsTable` |
|
|
25
|
-
| **Page header** (primary CTA + More ⋯ + export) | Per-hub page header composing `PageHeader` + `ExportDrawer` button | `components/library-page-header.tsx` |
|
|
26
|
-
| **Primary hub composition** | `*Client` = `ListPageTemplate` + `KeyMetrics` + `*PageHeader` + `*Table`. Reference: `LibraryHubClient`. | `components/library-hub-client.tsx`, `components/columns-client.tsx`, `components/tokens-themes-client.tsx` |
|
|
27
|
-
| **Hub table body** | `HubTable` — wraps `DataTable` + `useTableState` + `TablePropertiesDrawer`; list / board / dashboard read **`tableState.rows`**. Pagination chrome is auto-mounted when the hub passes `pagination` + `onPaginationChange`. | `components/data-views/hub-table.tsx`, `components/library-table.tsx`, `components/columns-showcase.tsx` |
|
|
28
|
-
| **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. | `LibraryTable` dashboard branch, `components/library-dashboard-charts.tsx` |
|
|
29
|
-
| **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 / Library clients |
|
|
30
|
-
| **Secondary panel chrome** | **`--secondary-panel-bg`** on **`NestedSecondaryPanelShell`** (lighter than sidebar, follows active product) | **`docs/shell-surface-elevation-pattern.md`**, Library |
|
|
31
|
-
| **Export** | `ExportDrawer` | `ListPageTemplate` export props; `PlacementsClient` |
|
|
32
|
-
| **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); **`LibraryOsFolderView`** — see **`AGENTS.md` §4.5** |
|
|
33
|
-
|
|
34
|
-
**Rules:** (1) Import and compose these components; pass **props** and **column defs** for your entity. (2) If something is missing, **extend the shared component** under `components/` (e.g. a new optional slot on `DataTableToolbar`) rather than copying markup into a single page. (3) Card-only or lightweight pages may use a smaller **Properties** sheet only when there is **no** table—otherwise use `TablePropertiesDrawer` with `DataTable` (see Team).
|
|
35
|
-
|
|
36
|
-
### Table pages must use view tabs
|
|
37
|
-
|
|
38
|
-
If the page uses a **`DataTable`** (or equivalent data grid) as the main surface, it **must** sit under **`ListPageTemplate`** so users get the **views toolbar** (tabs, add view, per-tab settings). The default `ViewTab` entries should include at least one tab whose `viewType` is **`table`** when the primary experience is tabular data. **Do not** render a `DataTable` alone under only `PageHeader` + body.
|
|
39
|
-
|
|
40
|
-
- **Reference:** `PlacementsClient` (Placements) and `TeamClient` (Team).
|
|
41
|
-
- **Rationale:** Consistent navigation, saved views, per-tab view type (table / list / board), and export at the template level.
|
|
42
|
-
|
|
43
|
-
## View layout frame (centered, reusable)
|
|
44
|
-
|
|
45
|
-
Non-table view branches (e.g. **folder** icon grid, **panel** finder, OS-style folder explorer) **should** use **`ListPageViewFrame`** for the same horizontal gutter and optional **`max-w-*`** centering as other hubs — **not** hand-copied `mx-4 lg:mx-6` + `mx-auto max-w-6xl` in each `*-table.tsx`. New view types belong in **`components/data-views/`** as **generic** components with render props; hub tables only wire **`tableState.rows`** and callbacks.
|
|
46
|
-
|
|
47
|
-
**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**).
|
|
48
|
-
|
|
49
|
-
## Architecture
|
|
50
|
-
|
|
51
|
-
- **Page shell** — `ListPageTemplate` owns the views toolbar (tabs), optional metrics, and export drawer. Content for the active tab is rendered via `renderContent`.
|
|
52
|
-
- **Per–lifecycle (or category) data** — `PlacementsTable` swaps **columns** and **row sets** based on `lifecycleTabId` (e.g. All / Upcoming / Ongoing / Completed). Each lifecycle tab gets its **own** `PlacementsTable` instance (`key={tab.filterId}`) so `useTableState` resets correctly when columns change.
|
|
53
|
-
- **Shared table state** — `useTableState` holds sort, search, filters, grouping, column order/visibility/pins/widths, row height, gridlines, and pagination flags. **Table**, **list**, **board**, and **dashboard** all read the same state so switching view type keeps behavior aligned.
|
|
54
|
-
|
|
55
|
-
## Mock data and connected views
|
|
56
|
-
|
|
57
|
-
1. **Put entity rows in `lib/mock/<entity>.ts`** — Export a typed array (e.g. `TeamMember[]`, `Placement[]`) and reuse it from the page client and from KPI helpers.
|
|
58
|
-
2. **KPI / summary helpers** — Add `lib/mock/<entity>-kpi.ts` (or next to the mock file) with pure functions **`entityKpiMetrics(rows: T[])`** and **`entityKpiInsight(rows: T[])`** returning `MetricItem[]` and `MetricInsight` from `@/components/key-metrics`. Set **`MetricItem.trendPolarity`** when an increase is **not** favorable (see **`docs/kpi-trend-pattern.md`**). Drive **both** the template **`metrics`** slot and the **dashboard view** from the **same helpers**, passing **`tableState.rows`** in the table component so filters/search apply everywhere.
|
|
59
|
-
3. **Single table component** — One component (e.g. `TeamTable`) receives **`members`** (full mock) + **`view`**. It calls **`useTableState(members, columns, …)`** once. Branch on `view`:
|
|
60
|
-
- **`table`** → `DataTable` with that state.
|
|
61
|
-
- **`list` / `board`** → `DataTableToolbar` + list/board UI with **`tableState.rows`**.
|
|
62
|
-
- **`dashboard`** → `DataTableToolbar` + **`KeyMetrics`** (and/or other **existing** dashboard building blocks — `ChartsOverview` only when charts are product-appropriate) fed by **`teamKpiMetrics(tableState.rows)`** / **`teamKpiInsight(tableState.rows)`** — **not** bespoke `Card` grids duplicating KPIs.
|
|
63
|
-
4. **Client wiring** — `renderContent` always renders the table component with **`view={tab.viewType}`** and **`key={tab.id}`** (not `viewType`) so switching views does not remount state. **Do not** show “not wired” placeholders for list/board/dashboard when the table stack supports those views.
|
|
64
|
-
5. **Full-route dashboards** — The **`/dashboard`** page uses **`DashboardTabs`**, **`KeyMetrics`**, and **`ChartsOverview`** with `lib/mock/dashboard.ts`. List-page **dashboard view** is a **narrower** slice: reuse **`KeyMetrics`** (+ entity KPI helpers) first; add charts only when they match the entity and reuse **`ChartsOverview`** patterns from `components/charts-overview.tsx`.
|
|
65
|
-
|
|
66
|
-
## Table vs list vs board vs dashboard
|
|
67
|
-
|
|
68
|
-
| Concern | Table | List | Board | Dashboard (view tab) |
|
|
69
|
-
| --- | --- | --- | --- | --- |
|
|
70
|
-
| Primary surface | `DataTable` | `DataRowList` + entity row body (e.g. `PlacementListRowContent`) wired via `HubTable.renderListRow` | `PlacementsBoardView` / entity board | **`KeyMetrics`** (+ optional charts via shared dashboard components) |
|
|
71
|
-
| Data source | `useTableState` | **`tableState.rows`** | **`tableState.rows`** | **`tableState.rows`** via KPI helpers |
|
|
72
|
-
| Column headers / labels | `showColumnLabels` | Same source columns, list layout | Phase columns + optional board column menu | N/A (metrics from same columns/filters) |
|
|
73
|
-
| Row click / navigation | From `PlacementsTable` | From list shell | Card `onOpen` | N/A |
|
|
74
|
-
| Pagination | Optional `PaginationBar` + `CountSyncer` | Same pattern | N/A (board uses phase columns) | N/A |
|
|
75
|
-
|
|
76
|
-
## Toolbar and properties
|
|
77
|
-
|
|
78
|
-
- **Search** — Global quick search lives in table state (`search` / `showToolbarSearch` from display options). Board phase columns can add local search in the board column header.
|
|
79
|
-
- **Filters** — Built from `ColumnDef.filter` and `filterFields` passed to `TablePropertiesDrawer`. Connectors between filters (`and` / `or`) are part of table state.
|
|
80
|
-
- **Sort / group** — Sort rules and `groupBy` are in table state; board menu proxies the same actions when `boardColumnMenu` is wired.
|
|
81
|
-
- **Properties drawer** — `TablePropertiesDrawer` is **generic**: supply `filterFields`, `fieldDefinitionsForDrawer`, `resolveColumnLabel`, `activeFilters`, sort/column handlers, `displayOptions`, and optional view-type tiles. Domain-specific defaults (e.g. `FILTER_FIELDS` in `types.ts`) are optional; new pages can pass their own definitions.
|
|
82
|
-
|
|
83
|
-
**Import:** `@/components/table-properties` re-exports the drawer and types.
|
|
84
|
-
|
|
85
|
-
## Dropdown menus (view settings, row actions)
|
|
86
|
-
|
|
87
|
-
**`DropdownMenuContent`** in **`@exxatdesignux/ui`** merges a **default surface** (**`DROPDOWN_MENU_CONTENT_SURFACE_CLASS`**: **`min-w-52 w-max max-w-[min(24rem,calc(100vw-2rem))]`**) so **ListPageTemplate** view settings / Add view, **`DataTable`** filter and column menus, and hub **row ⋯** menus size to their labels (including shortcut hints) without fixed **`w-40` / `w-48`** rails. Sizing is **pure CSS** — do **not** add **`ResizeObserver`** or per-open measurement for standard menus.
|
|
88
|
-
|
|
89
|
-
**Override** when product intent needs a fixed width (e.g. pagination **page size** **`w-20`**, **`NavUser`** trigger-width + **`min-w-60`**, school switcher **`!w-max min-w-72 …`**).
|
|
90
|
-
|
|
91
|
-
## Board UI reuse
|
|
92
|
-
|
|
93
|
-
**Handbook:** **`AGENTS.md` §4.4** — board card shell, badge row, shared status maps, and MUST/MUST NOT. **Cursor:** **`.cursor/rules/exxat-board-cards.mdc`**, skill **`.cursor/skills/exxat-board-cards/SKILL.md`**.
|
|
94
|
-
|
|
95
|
-
- **Card shell** — `components/data-views/list-page-board-card.tsx` — **`ListPageBoardCard`**, **`ListPageBoardCardHeader`**, **`ListPageBoardCardTitleRow`**, **`ListPageBoardCardAvatar`**, **`ListPageBoardCardBadgeRow`**, **`ListPageBoardCardBody`**, **`ListPageBoardCardSecondary`**. All product board cards on list hubs **should** use this shell (same **`Card` `size="sm"`** pattern as Placements).
|
|
96
|
-
- **Primitives** — `components/data-views/board-card-primitives.tsx` — `BoardCardIconRow`, `BoardCardTwoLineBlock` (optional `line2`), `BoardNewCardPlaceholder`, `lineClampClass`.
|
|
97
|
-
- **Status (Team & Compliance)** — `lib/list-status-badges.ts` — single source for label strings + badge `className` tails for **table, list, and board**. Do **not** pair with `uppercase` on the Badge (labels are sentence case, aligned with Placements `BoardStatusBadge`).
|
|
98
|
-
- **Owner initials** — `lib/initials-from-name.ts` when mock rows have a display name but no `initials` field.
|
|
99
|
-
- **Shared column shell** — `components/data-views/list-page-board-template.tsx` — `ListPageBoardTemplate` + `ListPageBoardColumnDef<T>`: define columns with `filter` predicates, `renderCard`, `getRowKey`. Used by **Team** and **Compliance** boards; new hubs should start here before custom chrome.
|
|
100
|
-
- **Library board** — `components/library-board-view.tsx` — composes **`ListPageBoardCard`** parts with `BoardCardTwoLineBlock` for the body and `ListHubStatusBadge` for the status row. Use this as the reference for any new domain board card.
|
|
101
|
-
- New entities should add their own card component that composes **`ListPageBoardCard`** + primitives rather than duplicating column scroll/layout or ad-hoc card chrome.
|
|
102
|
-
|
|
103
|
-
## Dashboard view (list pages)
|
|
104
|
-
|
|
105
|
-
- **Reuse the dashboard chart bundle** — `components/dashboard-report-charts.tsx` — `DashboardReportCharts`: flat `KeyMetrics` + middle chart section + period comparison `KeyMetrics` card. **`ChartsOverview`** is the default middle section for `/dashboard`. Hubs pass **`chartsSection={<MyDashboardChartsSection rows={tableState.rows} />}`** so charts reflect the hub's own row set. Reference: **`LibraryDashboardChartsSection`** in `components/library-dashboard-charts.tsx`. Chart **style** can follow `ChartVariantProvider` when using `ChartsOverview`.
|
|
106
|
-
- **Data tab canvas charts** share **`ChartFigure`**, **`ChartCard`**, and **`ChartDataTable`** with `charts-overview.tsx`. **Layout** is stored in one place: **`lib/data-view-dashboard-storage.ts`** under a per-hub scope (see `AGENTS.md` §4.3). **Keyboard-selected bars/slices** must use **`lib/chart-keyboard-selection.ts`** (`activeBar` / `activeShape`) so behavior matches the gallery — not opacity-only `Cell` dimming.
|
|
107
|
-
|
|
108
|
-
## Persistence
|
|
109
|
-
|
|
110
|
-
- **Page-level** (`lib/data-list-persistence.ts`, key `exxat-ds:data-list:page:v1`): `displayOptions`, `showMetrics`, `tabs`, `activeTabId`. Loaded in `PlacementsClient` with `useLayoutEffect`, saved debounced on change. `ListPageTemplate` runs in **controlled** mode when `tabs` / `onTabsChange` / `activeTabId` / `onActiveTabChange` are passed.
|
|
111
|
-
- **Per–lifecycle tab** (key `exxat-ds:data-list:lifecycle:v1:<filterId>`): sort, search, filters, group by, column order/hidden/widths/pins/wrap, column menu search map, row height, gridlines, filter bar visibility, search popover, conditional rules, pagination toggle and page/size. Hydrated in `PlacementsTable` with `useLayoutEffect`; saved debounced when those fields change.
|
|
112
|
-
|
|
113
|
-
To add a new page: copy the `PlacementsClient` pattern (controlled `ListPageTemplate` + storage key namespace) or call `schedulePageSave` / `scheduleLifecycleSave` with your own keys.
|
|
114
|
-
|
|
115
|
-
## Rules of thumb
|
|
116
|
-
|
|
117
|
-
1. **One `useTableState` per logical table** — Remount with `key` when the column set or entity context changes.
|
|
118
|
-
2. **Don’t fork filter/sort UX** — Reuse `TablePropertiesDrawer` and `DataTableToolbar` patterns so accessibility and behavior stay consistent.
|
|
119
|
-
3. **Boards derive from the same columns** — `boardColumns` / `hiddenColKeys` should reflect table `displayCols` so “hide column” and “properties” stay in sync.
|
|
120
|
-
4. **Persist stable JSON** — Version objects with `v: 1` and keep keys namespaced to allow migrations later.
|
|
121
|
-
|
|
122
|
-
---
|
|
123
|
-
|
|
124
|
-
## Required UX for dense lists (10+ items)
|
|
125
|
-
|
|
126
|
-
When a page shows a **list**, **table**, or **card grid** with **more than 10 items**, it must expose:
|
|
127
|
-
|
|
128
|
-
| Capability | Table / list / board | Card-only pages (no `DataTable`) |
|
|
129
|
-
| --- | --- | --- |
|
|
130
|
-
| **Search** | Toolbar search + column quick-search where applicable | At least one search control filtering the visible set |
|
|
131
|
-
| **Filter** | Filter bar + `TablePropertiesDrawer` filters | Filters in toolbar or in Properties, as appropriate to the content |
|
|
132
|
-
| **Sorting** | Column sort / sort rules in drawer | User-visible sort (e.g. name, date, role) |
|
|
133
|
-
| **Properties** | `TablePropertiesDrawer` (columns, display, filters, sort) | A **Properties** entry point (sheet or drawer) for view options — same *role* as table properties, even if the UI is simpler |
|
|
134
|
-
|
|
135
|
-
Below the threshold, these may be omitted unless the page is a primary data hub (see below).
|
|
136
|
-
|
|
137
|
-
---
|
|
138
|
-
|
|
139
|
-
## Data pages: primary CTA + More + Export
|
|
140
|
-
|
|
141
|
-
If the page **has exportable data** (rows, members, library items, etc.), follow the **Library** header pattern:
|
|
142
|
-
|
|
143
|
-
1. **Primary action** — One default (filled) button for the main task (e.g. **New question**, **Invite collaborator**, **Add token**). Do **not** use `variant="outline"` for that primary action.
|
|
144
|
-
2. **More (⋯)** — An outline **icon** button opening a menu that includes **Export** (and other overflow actions). Wire **Export** to `ExportDrawer` (or equivalent).
|
|
145
|
-
3. **Subtitle** — Prefer a short line with **count + freshness** (e.g. `24 records · Last updated now`), matching `PlacementsPageHeader`.
|
|
146
|
-
|
|
147
|
-
Reference: `components/library-page-header.tsx`, `components/library-hub-client.tsx`.
|
|
148
|
-
|
|
149
|
-
---
|
|
150
|
-
|
|
151
|
-
## Page vs drawer (actions and auxiliary views)
|
|
152
|
-
|
|
153
|
-
**When to use a drawer or sheet:** The user needs **the surrounding page** (list, hub, or parent task) to stay **visible for context** *and* they need a **quick view**, **quick actions**, or a **short auxiliary step** — e.g. table properties, export, a brief row summary, or “change one setting and dismiss.”
|
|
154
|
-
|
|
155
|
-
**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.
|
|
156
|
-
|
|
157
|
-
**Rule of thumb:** **Context + quick** → **drawer**; **blocking short choice** → **dialog**; **otherwise** → **new page**.
|
|
158
|
-
|
|
159
|
-
**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.
|
|
160
|
-
|
|
161
|
-
Canonical rules: **`AGENTS.md` §6.4**, root **`.cursor/rules/exxat-page-vs-drawer.mdc`**, **`.cursor/rules/exxat-drawer-vs-dialog.mdc`**.
|
|
162
|
-
|
|
163
|
-
---
|
|
164
|
-
|
|
165
|
-
## Primary pages with large datasets
|
|
166
|
-
|
|
167
|
-
When a route is a **primary** destination in nav (main hub for an entity) **and** the dataset is **large** or **highly interactive**:
|
|
168
|
-
|
|
169
|
-
- Use the **primary page template**: `ListPageTemplate` (tabs, metrics strip, export drawer at template level) + data client pattern as in **`PlacementsClient`** / **`PlacementsTable`** — not a minimal `PageHeader`-only layout.
|
|
170
|
-
- Smaller satellite pages may use **`PageHeader` + section content**; once the dataset grows past the dense-list threshold, add the toolbar rules above and consider promoting to the full template if the page becomes a main hub.
|
|
171
|
-
|
|
172
|
-
---
|
|
173
|
-
|
|
174
|
-
## Summary checklist
|
|
175
|
-
|
|
176
|
-
- [ ] **Reuse** — Tabs, search, filters, and property UI come from **`ListPageTemplate`**, **`DataTable` / `useTableState`**, **`TablePropertiesDrawer`**, and related Placements modules—not ad-hoc duplicates.
|
|
177
|
-
- [ ] **Table + tabs** — Any **`DataTable`** is wrapped in **`ListPageTemplate`** (view tabs), not only `PageHeader` + body.
|
|
178
|
-
- [ ] **>10 items** → search, filter, sort, properties (per surface type above).
|
|
179
|
-
- [ ] **Has data to export** → **More** menu with **Export** + shared `ExportDrawer` pattern.
|
|
180
|
-
- [ ] **Primary + large / main hub** → `ListPageTemplate`-style shell where applicable.
|
|
181
|
-
- [ ] **Page vs drawer vs dialog (§6.4)** — Quick with parent **context** → drawer/sheet; **blocking** confirm → **dialog**; primary or long flows → **new route** (`docs/drawer-vs-dialog-pattern.md`).
|
|
182
|
-
- [ ] **Primary button** → `Button` default variant (`size="lg"` for parity with Placements), not outline.
|
|
183
|
-
- [ ] **Dashboard view tab** → `KeyMetrics` + shared KPI helpers from **`tableState.rows`**; no duplicate one-off metric cards.
|
|
184
|
-
- [ ] **Data view charts** → `ChartFigure` + `chart-keyboard-selection`; layout persistence via **`data-view-dashboard-storage`** (see `AGENTS.md` §4.3).
|
|
185
|
-
- [ ] **Mock + KPIs** → Entity rows in **`lib/mock/`**; **`entityKpiMetrics` / `entityKpiInsight`** consumed by template metrics and dashboard view.
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
# Sheet panel vs dialog vs route
|
|
2
|
-
|
|
3
|
-
> **Related:** `docs/data-views-pattern.md` (Page vs drawer), **`AGENTS.md` §6.4**, **`.cursor/rules/exxat-page-vs-drawer.mdc`**. **This doc** splits **floating `Sheet` panels** vs **modal dialog** when both stay on the same route.
|
|
4
|
-
|
|
5
|
-
## Sheet (side panel — product “drawers”)
|
|
6
|
-
|
|
7
|
-
**Use when:**
|
|
8
|
-
|
|
9
|
-
- The **list or hub behind the panel** still matters (user compares, copies, or dismisses and continues browsing).
|
|
10
|
-
- The flow is **medium length** — export options, table/column properties, invite collaborators, filters that mirror the grid.
|
|
11
|
-
- **Width** helps — tables of options, multi-field forms that would feel cramped in a narrow dialog.
|
|
12
|
-
|
|
13
|
-
**Implementation:** **`Sheet`** from `@exxatdesignux/ui/components/sheet` with the floating inset pattern (`showOverlay={false}`, `getFloatingSheetInsetProps`) — see `ExportDrawer`, `TablePropertiesDrawer`, `InviteCollaboratorsDrawer`, `LibraryNewFolderSheet`.
|
|
14
|
-
|
|
15
|
-
**Avoid when:** The task is the **only** thing the user should focus on and the parent would distract (prefer **dialog** for a sharp confirm, or **route** for a full wizard).
|
|
16
|
-
|
|
17
|
-
## Dialog (modal)
|
|
18
|
-
|
|
19
|
-
**Use when:**
|
|
20
|
-
|
|
21
|
-
- You need a **hard stop** — user must answer or dismiss before interacting with the page again (confirm delete, acknowledge legal, pick a single blocking choice).
|
|
22
|
-
- The content is **short and focused** — one decision, one form step, or a compact message with primary/secondary actions.
|
|
23
|
-
- **Destructive or irreversible** actions — pair with clear copy; **Esc** / Cancel returns safely.
|
|
24
|
-
|
|
25
|
-
**Examples:** `AlertDialog`, confirm-before-remove, “Save changes?” when navigating away.
|
|
26
|
-
|
|
27
|
-
**Avoid when:** Users need to **reference** the grid or copy values from the page while the panel is open — use a **sheet panel** or **inline** pattern instead.
|
|
28
|
-
|
|
29
|
-
## Route (new page)
|
|
30
|
-
|
|
31
|
-
Use when the work is **primary**, **long**, **multi-step**, or deserves its **own URL** — see **`exxat-page-vs-drawer.mdc`** and **`AGENTS.md` §6.4**.
|
|
32
|
-
|
|
33
|
-
## Quick matrix
|
|
34
|
-
|
|
35
|
-
| Need | Sheet panel | Dialog | Route |
|
|
36
|
-
| --- | --- | --- | --- |
|
|
37
|
-
| Keep hub visible | Yes | No (blocks) | No |
|
|
38
|
-
| Short confirm / alert | Rare | Yes | Overkill |
|
|
39
|
-
| Long form / wizard | Cramped | No | Yes |
|
|
40
|
-
| Properties tied to a table | Yes | Too small | Optional |
|
|
41
|
-
|
|
42
|
-
## Accessibility
|
|
43
|
-
|
|
44
|
-
- **Dialog / sheet:** Must expose a **title** (`DialogTitle`, `SheetTitle`) — use `sr-only` if visually hidden.
|
|
45
|
-
- **Focus trap** is expected in dialogs; sheet panels should still **restore focus** on close to the invoking control.
|
|
46
|
-
|
|
47
|
-
## See also
|
|
48
|
-
|
|
49
|
-
- **`.cursor/rules/exxat-drawer-vs-dialog.mdc`**, **`.cursor/skills/exxat-drawer-vs-dialog/SKILL.md`**
|
|
50
|
-
- **`exxat-no-toast.mdc`** — use dialog/banner/inline, not toasts, for outcomes that need acknowledgment.
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
# Exxat DS — Glossary
|
|
2
|
-
|
|
3
|
-
> Shared vocabulary. When a rule or pattern uses a term in **bold**, it's defined here. Add a term when you find yourself explaining the same word twice in PR review.
|
|
4
|
-
|
|
5
|
-
| Term | Definition | See also |
|
|
6
|
-
|---|---|---|
|
|
7
|
-
| **Active view** | The currently selected view tab on a hub (table, list, board, dashboard, …). Drives which `HubTableRenderers` entry mounts and what the **Properties drawer** shows in its view-type tile grid. | `exxat-table-properties-drawer.mdc` |
|
|
8
|
-
| **Bare Kbd** | The `<Kbd variant="bare">` rendering — no background, no border, inherits `currentColor` at 70 %. Used inline **inside** a button so the chord doesn't look pasted on. The default `tile` variant is reserved for tooltips and menu shortcut slots. | `exxat-kbd-shortcuts.mdc` |
|
|
9
|
-
| **Blueprint** | Framework-agnostic spec for one UI pattern. Says *what* the pattern is and *what* it must do without committing to React. See `docs/blueprints/`. | `docs/blueprints/README.md` |
|
|
10
|
-
| **Board card** | The kanban-style card surface on a board view. Composed of `ListPageBoardCard` (shell), `ListPageBoardCardTitleRow`, optional `ListPageBoardCardAvatar`, optional badge row with `ListHubStatusBadge` (`surface="board"`), and a body using `BoardCardTwoLineBlock` / `BoardCardIconRow`. | `exxat-board-cards.mdc` |
|
|
11
|
-
| **Brand glow** | The OKLCH-mixed brand tint applied as a soft halo behind a surface (KPI flat band, secondary panel). Not a hard background — the tint **adds**, the underlying surface still reads. | `docs/kpi-flat-band-pattern.md`, `docs/shell-surface-elevation-pattern.md` |
|
|
12
|
-
| **Bulk-actions slot** | The floating action bar that appears when one or more rows are selected in a `HubTable`. Wired via `bulkActionsSlot={(selected) => …}`. | `packages/ui/src/components/data-views/hub-table.tsx` |
|
|
13
|
-
| **Cell pattern** | One column's rendering recipe — built by composing existing primitives (`Badge`, `AvatarInitials`, `ListHubStatusBadge`, `ToggleSwitch`, FA glyphs, `Tip`, `Tooltip`, `DropdownMenu`). The canonical catalog of patterns lives in `apps/web/components/columns-showcase.tsx`; the live demo is at `/columns`. | `docs/reference-implementations.md` |
|
|
14
|
-
| **Cell primitive** | One of the named, importable `ColumnDef['cell']` renderers exported from `@/components/data-views` (re-exported from `apps/web/components/data-views/table-cells.tsx`): `ProgressCell`, `CurrencyCell`, `NumericCell`, `RatingCell`, `SignalBarsCell`, `BooleanToggleCell`, `AttachmentCountCell`, `ExternalLinkCell`, `RelativeTimeCell`, `PeopleAvatarRailCell`, `PillCell`, `TagListCell`, `RowActionsCell`. Every cell renderer in the showcase comes from this module; new hubs **must** import these instead of inlining the same JSX. | `.cursor/skills/exxat-token-economy/SKILL.md` §3, `exxat-data-tables.mdc` |
|
|
15
|
-
| **Centralized list dataset** | The rule that **one** `useTableState` row bag drives **every** view (table, list, board, dashboard, panel, tree, …) on a given hub. No parallel mock arrays per view. | `exxat-centralized-list-dataset.mdc` |
|
|
16
|
-
| **Coach mark** | The onboarding overlay that highlights a UI element and explains it. State managed by `useCoachMark`. Dismissals stick per flow id. | `apps/web/lib/coach-mark-registry.ts` |
|
|
17
|
-
| **Collaboration variant** | The `PageHeader` flavor that exposes the face rail + Invite-people overflow item for shared hubs. | `exxat-collaboration-access.mdc` |
|
|
18
|
-
| **Column def (`ColumnDef`)** | The typed column shape consumed by `DataTable` / `HubTable`. Adding `filter:` to a column auto-generates a filter chip and toolbar dropdown entry. | `packages/ui/src/components/data-table/types.ts` |
|
|
19
|
-
| **Conditional rule** | A `ColumnDef`-level rule that applies a background tint to a cell when its value matches an operator + value (e.g. "score < 60 → red"). Authored in the **Properties drawer**. | `packages/ui/src/components/table-properties/` |
|
|
20
|
-
| **Content rail** | The centered, max-width column the `PrimaryPageTemplate` reserves for primary content. Width comes from the template, not the page; don't override per-page. | `apps/web/components/templates/primary-page-template.tsx` |
|
|
21
|
-
| **DataTable** | The low-level table primitive in `packages/ui`. Mount this **only** outside a hub (drawer-body mini-grids, modal sub-tables). Inside `ListPageTemplate`, use `HubTable`. | `exxat-data-tables.mdc` |
|
|
22
|
-
| **`delta`** | The KPI **count** of change (e.g. `"+5"`, `-3`, `"+12 %"`) on a `MetricItem`. Pass `""` or `0` to suppress the trend chip. Never prose. | `exxat-kpi-trends.mdc` |
|
|
23
|
-
| **`description`** | The KPI **caption** beneath the value and trend row on a `MetricItem`. Use this for prose like `"left + right"` or `"vs last week"`. Never a delta count. | `exxat-kpi-trends.mdc` |
|
|
24
|
-
| **Display options** | Per-table preferences (toolbar search visibility, density, gridlines, pagination toggle, …) that flow through `DataListDisplayOptions`. `HubTable` owns the state by default; the hub client can take it over with `displayOptions` + `onDisplayOptionsChange`. | `packages/ui/src/components/table-properties/` |
|
|
25
|
-
| **Empty state** | The text + icon + (optional) action shown when a view body has zero rows after filters. Distinct from "no data ever" (use `EmptyTableState`) vs "no matches" (filter-aware copy). | `docs/voice-and-tone.md` |
|
|
26
|
-
| **Face rail** | The small overlapping-faces row on a `PageHeader` (collaboration variant) showing collaborators. Click to open the invite drawer. | `exxat-collaboration-access.mdc` |
|
|
27
|
-
| **Filter chip** | The dismissible chip rendered above a `HubTable` body for each active filter. Auto-generated from `ColumnDef.filter`. | `exxat-data-tables.mdc` |
|
|
28
|
-
| **Flat band (KPI)** | `KeyMetrics variant="flat"` — transparent cell, brand glow only, hairline cell borders. The shape used on every primary hub metrics strip. | `exxat-kpi-flat-band.mdc` |
|
|
29
|
-
| **Hairline** | A 1 px border at exactly `--border` color used to separate KPI cells, table cells, surface divisions. Never thicker for hierarchy — use spacing or color instead. | `docs/kpi-flat-band-pattern.md` |
|
|
30
|
-
| **HubTable** | The canonical hub view body. Wraps `useTableState`, the toolbar (search + filter chips + filter dropdown + sort), `TablePropertiesDrawerButton`, view-type tiles, bulk-actions, and conditional rules. Always use this inside `ListPageTemplate.renderContent`. | `exxat-data-tables.mdc` |
|
|
31
|
-
| **Hub primitive** | Synonym for `HubTable` — the single primitive that produces a "hub-shaped" view body. | same |
|
|
32
|
-
| **Inspector** | A side-anchored drawer that shows a single record's details without leaving the hub. Resolved against the same `tableState.rows` as the grid. | `exxat-centralized-list-dataset.mdc` |
|
|
33
|
-
| **`KeyMetrics`** | The KPI strip / band component. Accepts `MetricItem[]` (≤ 4) and a single `MetricInsight`. Use `variant="flat"` on hubs; `variant="card"` for embedded analytics cards. | `exxat-kpi-flat-band.mdc`, `exxat-kpi-max-four.mdc` |
|
|
34
|
-
| **KPI strip** | The horizontal KPI row at the top of a hub. ≤ 4 tiles. | `exxat-kpi-max-four.mdc` |
|
|
35
|
-
| **Lifecycle tab label** | The string shown under "Properties" in the drawer header (e.g. "Library", "Tokens & themes", "Columns"). Set on `HubTable.lifecycleTabLabel`. | `packages/ui/src/components/table-properties/drawer-button.tsx` |
|
|
36
|
-
| **List hub status badge** | The shared status chip + icon used everywhere status appears (table rows, board cards, list rows). Colors and icons live in `lib/list-status-badges.ts`. `surface="table"` for grid; `surface="board"` for cards. | `exxat-board-cards.mdc` |
|
|
37
|
-
| **List page template** | The hub frame component. Owns the page header slot, metrics strip slot, view-tabs row, and the `renderContent(tab, updateTab)` body callback. | `packages/ui/src/components/templates/list-page.tsx` |
|
|
38
|
-
| **Mono ID** | A system-generated identifier shown in `font-mono tabular-nums` so digits align and the ID is visibly distinct from prose. Mono **only** the ID token in a mixed line. | `exxat-mono-ids.mdc` |
|
|
39
|
-
| **OKLCH** | The perceptually uniform color space used by the brand-tint mix and the glow tokens. Surfaces stack: page → secondary panel → sidebar. | `docs/shell-surface-elevation-pattern.md` |
|
|
40
|
-
| **Pattern** | Long-form narrative that explains a UI behavior in prose: when to use it, how it composes, anti-patterns, references. Lives in `docs/*-pattern.md`. Complements (but doesn't replace) a blueprint or rule. | `docs/HANDBOOK.md` |
|
|
41
|
-
| **`PrimaryPageTemplate`** | The page chrome: breadcrumbs, site header, content rail with the project's standard max-width. Wrap every primary route in this. | `apps/web/components/templates/primary-page-template.tsx` |
|
|
42
|
-
| **Progressive disclosure** | The principle that complexity is exposed only when the user opts into it. KPIs default visible, filters default folded into the toolbar, conditional rules live in the Properties drawer, etc. | `docs/HANDBOOK.md` §1 |
|
|
43
|
-
| **Properties drawer** | The right-side `Sheet` opened from the table toolbar, hosting view-type tiles, column visibility, density, sort, group-by, filters, conditional rules, and pagination toggle. Mounted automatically by `HubTable`. | `exxat-table-properties-drawer.mdc` |
|
|
44
|
-
| **Reference page** | A canonical full implementation of a hub or pattern in `apps/web/components/*.tsx` (e.g. `columns-showcase.tsx`, `tokens-themes-client.tsx`, `library-table.tsx`). Listed in `docs/reference-implementations.md`. Copy from these before inventing. | `docs/reference-implementations.md` |
|
|
45
|
-
| **Rule (binding)** | A `.cursor/rules/*.mdc` doc with MUST / MUST NOT. Binds the AI agent and the human reviewer. Wins over patterns and narratives. | `docs/HANDBOOK.md` §4 |
|
|
46
|
-
| **Secondary panel** | A scoped navigation rail (e.g. "Library → All / Mine / Tree", "Tokens & themes → Colors / Radius / Motion / …") that sits between the main sidebar and the page. Opening one collapses the main sidebar; closing one restores the previous sidebar state. | `exxat-primary-nav-secondary-panel.mdc` |
|
|
47
|
-
| **Site header** | The top bar on a primary route (org/product switcher + breadcrumbs + actions). Owned by `PrimaryPageTemplate`. | `apps/web/components/templates/primary-page-template.tsx` |
|
|
48
|
-
| **Skill** | A `.cursor/skills/<name>/SKILL.md` (mirrored in `.claude/skills/`) workflow + checklist for a recurring agent task. Use a skill when the same checklist would be repeated across many sessions. | `apps/web/AGENTS.md` |
|
|
49
|
-
| **`supportedViewTypes`** | The allowlist of `DataListViewType` values a hub implements. Default **`FULL_HUB_SUPPORTED_VIEWS`** (seven views, same Add view as Library). Must match on **`ListPageTemplate`** + **`HubTable`**; every entry needs a renderer. | `packages/ui/src/lib/data-list-view-registry.ts`, `docs/hub-supported-views-pattern.md` |
|
|
50
|
-
| **`FULL_HUB_SUPPORTED_VIEWS`** | table · list · board · dashboard · folder · panel · tree-panel — canonical list-hub allowlist. | `data-list-view-registry.ts` |
|
|
51
|
-
| **Trend polarity** | `MetricItem.trendPolarity` says whether "up" is good (`higher_is_better`, default), bad (`lower_is_better`), or value-neutral (`informational`). The arrow's tint follows the polarity, not the sign. | `exxat-kpi-trends.mdc` |
|
|
52
|
-
| **`useTableState`** | The state hook that owns rows, filters, search, sort, pagination, group-by, and column visibility. Always one instance per hub. | `exxat-centralized-list-dataset.mdc` |
|
|
53
|
-
| **View tab** | A tab on `ListPageTemplate` representing one view of the same dataset (table, list, board, dashboard, folder, panel, tree, …). Each tab carries a `viewType` and the `renderContent` callback receives it. | `exxat-list-page-connected-views.mdc` |
|
|
54
|
-
| **View type (`DataListViewType`)** | The enum of view shapes the design system supports — `"table" \| "list" \| "board" \| "dashboard" \| "folder" \| "panel" \| "tree"`. Each tab declares one. | `apps/web/lib/data-list-view.ts` |
|
|
55
|
-
| **Voice & tone** | The microcopy rules for the product: empty states, errors, banners, buttons, validation. See `docs/voice-and-tone.md`. | `docs/voice-and-tone.md` |
|
|
56
|
-
|
|
57
|
-
---
|
|
58
|
-
|
|
59
|
-
*Missing a term? Add it. Glossary entries are short — link to the rule or pattern for depth, don't restate it here.*
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
# Hub supported views pattern (Add view parity)
|
|
2
|
-
|
|
3
|
-
> **Agents:** `.cursor/rules/exxat-hub-supported-views.mdc` (binding). **Reference hub:** Library / All questions (`library-table.tsx`, `library-client.tsx`).
|
|
4
|
-
|
|
5
|
-
## Problem this solves
|
|
6
|
-
|
|
7
|
-
`ListPageTemplate` filters **Add view** and Properties view tiles from `supportedViewTypes`. If Column types passes four views but Library passes seven, users see inconsistent menus. If a hub allows Board but has no `board-with-toolbar` renderer, users see **“does not implement Board view”**.
|
|
8
|
-
|
|
9
|
-
## Canonical allowlist
|
|
10
|
-
|
|
11
|
-
Import from the registry (single source of truth):
|
|
12
|
-
|
|
13
|
-
```ts
|
|
14
|
-
import { FULL_HUB_SUPPORTED_VIEWS } from "@/lib/data-list-view-registry"
|
|
15
|
-
// or
|
|
16
|
-
import { LIBRARY_SUPPORTED_VIEWS } from "@/lib/library-supported-views" // alias of FULL
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
Seven views: **table**, **list**, **board**, **dashboard**, **folder**, **panel**, **tree-panel**.
|
|
20
|
-
|
|
21
|
-
`HubTable` and `ListPageTemplate` use this list when `supportedViewTypes` is omitted.
|
|
22
|
-
|
|
23
|
-
`PRIMARY_HUB_SUPPORTED_VIEWS` (four views) remains for hubs that intentionally omit folder/panel/tree — document that in `lib/<entity>-supported-views.ts`.
|
|
24
|
-
|
|
25
|
-
## Wiring checklist
|
|
26
|
-
|
|
27
|
-
1. **`ListPageTemplate`** — `supportedViewTypes={FULL_HUB_SUPPORTED_VIEWS}` (or entity alias).
|
|
28
|
-
2. **`HubTable`** — same allowlist (or omit on both).
|
|
29
|
-
3. **List** — `renderListRow` returning **`ListPageBoardCard`** `layout="row"` (copy from `library-table.tsx`).
|
|
30
|
-
4. **Board** — `renderBoardCard` + `boardGroups` and/or `renderers["board-with-toolbar"]`.
|
|
31
|
-
5. **Dashboard** — `renderers["dashboard-with-toolbar"]` with **`KeyMetrics`** on filtered rows.
|
|
32
|
-
6. **Folder / panel / tree** — explicit `renderers` entries (Library reference) or **`LibraryTable`** for `LibraryItem` rows.
|
|
33
|
-
|
|
34
|
-
## Special cases in this app
|
|
35
|
-
|
|
36
|
-
| Hub | Pattern |
|
|
37
|
-
|-----|---------|
|
|
38
|
-
| **Library / All questions** | `LibraryTable` + `LIBRARY_SUPPORTED_VIEWS` — reference |
|
|
39
|
-
| **Column types** | `LibraryTable` with `columnDefs` + `hubLabels` + `DEFAULT_LIBRARY_FOLDERS` — custom table, shared other views |
|
|
40
|
-
| **Tokens & themes** | `FULL_HUB_SUPPORTED_VIEWS` + `tokens-hub-auxiliary-views.tsx` |
|
|
41
|
-
| **New entity hub** | Start from `library-table.tsx` or token/columns references; never table-only unless approved |
|
|
42
|
-
|
|
43
|
-
## Anti-patterns
|
|
44
|
-
|
|
45
|
-
- `supportedViewTypes={["table"]}` on a `ListPageTemplate` hub.
|
|
46
|
-
- `COLUMNS_SUPPORTED_VIEWS = PRIMARY_HUB_SUPPORTED_VIEWS` without board/folder/panel/tree renderers.
|
|
47
|
-
- Minimal `renderListRow` with only stem + `questionId` (not product list UI).
|
|
48
|
-
|
|
49
|
-
## See also
|
|
50
|
-
|
|
51
|
-
- `packages/ui/src/lib/data-list-view-registry.ts`
|
|
52
|
-
- `apps/web/docs/data-views-pattern.md`
|
|
53
|
-
- `apps/web/lib/hub-connected-view-renderers.ts` — `defineHubViewRenderers` dev warnings
|