@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,130 +0,0 @@
|
|
|
1
|
-
# Blueprint: Page Header
|
|
2
|
-
|
|
3
|
-
> **Status:** Stable. **Owner:** Exxat DS core. **Implements:** WCAG 2.1 AA.
|
|
4
|
-
|
|
5
|
-
## 1. Intent
|
|
6
|
-
|
|
7
|
-
A page header **names the route** the user is on, communicates **freshness**
|
|
8
|
-
of the underlying data, and gives the user the **primary action** for that
|
|
9
|
-
route (and any secondary actions behind a `⋯` overflow). It is the visual
|
|
10
|
-
anchor of every primary hub.
|
|
11
|
-
|
|
12
|
-
**Use when:**
|
|
13
|
-
- The user lands on a primary nav destination (Placements, Team, Question
|
|
14
|
-
bank, Compliance, Settings, Dashboard).
|
|
15
|
-
- The user opens a detail/record view that should advertise its own identity
|
|
16
|
-
(placement record, question detail).
|
|
17
|
-
|
|
18
|
-
**Do NOT use when:**
|
|
19
|
-
- The surface is already inside a hub's view body (sub-sections never get
|
|
20
|
-
their own page header — they get a `DashboardSectionHeading` or similar).
|
|
21
|
-
- The surface is an overlay (drawer / dialog / sheet) — those use their own
|
|
22
|
-
`*Title` slots.
|
|
23
|
-
|
|
24
|
-
## 2. Anatomy
|
|
25
|
-
|
|
26
|
-
```
|
|
27
|
-
┌──────────────────────────────────────────────────────────────────────┐
|
|
28
|
-
│ [icon] Title [face-rail] [primary] [⋯] │ ← title-row (required)
|
|
29
|
-
│ Subtitle · ID · count · freshness │ ← meta (optional)
|
|
30
|
-
└──────────────────────────────────────────────────────────────────────┘
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
| Slot | Required? | What it carries |
|
|
34
|
-
|---|---|---|
|
|
35
|
-
| `icon` | optional | Product mark (`ExxatProductLogo`) or FA glyph |
|
|
36
|
-
| `title` | **required** | One H1 — the route name (e.g. "Placements") |
|
|
37
|
-
| `subtitle` | optional | One line: short context, ID, count, freshness |
|
|
38
|
-
| `face-rail` | optional | `+N collaborators` stack (variant `collaboration`) |
|
|
39
|
-
| `actions/primary` | optional | One filled `Button` (e.g. "New placement") |
|
|
40
|
-
| `actions/overflow` | optional | One outline icon `Button` opening a dropdown menu |
|
|
41
|
-
| `breadcrumb` | optional | Above title; never alongside it |
|
|
42
|
-
|
|
43
|
-
The header **never** carries search, filters, view-tabs, or KPIs — those belong
|
|
44
|
-
to `ListPageTemplate` / `KeyMetrics` / `DataTable`. The header is the route
|
|
45
|
-
identity, nothing more.
|
|
46
|
-
|
|
47
|
-
## 3. States
|
|
48
|
-
|
|
49
|
-
| State | Visual / behavior |
|
|
50
|
-
|---|---|
|
|
51
|
-
| Default | Title + subtitle + actions; primary CTA filled. |
|
|
52
|
-
| Collaboration empty | Outline "Add collaborator" replaces face rail. |
|
|
53
|
-
| Collaboration populated | Face rail with `+N` opens `InviteCollaboratorsDrawer`. |
|
|
54
|
-
| Loading | Title skeleton (60% width), meta skeleton (30% width). |
|
|
55
|
-
| Error | The header still renders; errors land in the body's `LocalBanner`. |
|
|
56
|
-
| RTL | Slots mirror; FA glyphs auto-mirror via Tailwind's `rtl:`. |
|
|
57
|
-
|
|
58
|
-
## 4. Tokens consumed
|
|
59
|
-
|
|
60
|
-
| Token | Used for |
|
|
61
|
-
|---|---|
|
|
62
|
-
| `--background` / `--foreground` | Surface + ink |
|
|
63
|
-
| `--muted-foreground` | Subtitle / meta line |
|
|
64
|
-
| `--brand-color` | Product mark fills (when icon is a product logo) |
|
|
65
|
-
| `--ring` | Focus ring on actions + face rail buttons |
|
|
66
|
-
| `--font-heading` | Title font family (Ivy Presto) — **not** body Inter |
|
|
67
|
-
| `--text-xs` | Meta line at min 11px (SC 1.4.3) |
|
|
68
|
-
| `--radius-md` | Action button corners |
|
|
69
|
-
|
|
70
|
-
For monospace IDs in the subtitle, see
|
|
71
|
-
[`exxat-mono-ids.mdc`](../../../.cursor/rules/exxat-mono-ids.mdc): only the
|
|
72
|
-
ID token gets `font-mono tabular-nums`, the rest of the line stays sans.
|
|
73
|
-
|
|
74
|
-
## 5. Accessibility
|
|
75
|
-
|
|
76
|
-
| WCAG SC | How this blueprint complies |
|
|
77
|
-
|---|---|
|
|
78
|
-
| 1.1.1 Non-text content | Product icon decorative (Case A — title sits beside it). If a header icon must stand alone, follow Case B (label + tooltip). |
|
|
79
|
-
| 1.3.1 Info & relationships | Title is exactly one `<h1>` — every route has one and only one. |
|
|
80
|
-
| 1.4.3 Contrast (text) | `--muted-foreground` is ≥ 5.5:1 on `--background`. |
|
|
81
|
-
| 2.1.1 Keyboard | Tab order: breadcrumb → title link (if any) → face rail → primary → overflow trigger. |
|
|
82
|
-
| 2.4.6 Headings / labels | Title strings match `<title>` (document title) where they describe the same route. |
|
|
83
|
-
| 2.4.11 Focus visible | All interactive slots inherit `:focus-visible` ring from `--ring`. |
|
|
84
|
-
|
|
85
|
-
## 6. Variants
|
|
86
|
-
|
|
87
|
-
| Variant | When to use | Differences |
|
|
88
|
-
|---|---|---|
|
|
89
|
-
| `base` | Default — most routes | Title + actions only |
|
|
90
|
-
| `object-home` | Lists / hubs with optional metrics + tabs **below** the header | Adds a count/freshness slot under the title |
|
|
91
|
-
| `record-home` | Detail / record views | May expose a small detail row (label/value pairs) — keep ≤ 5 pairs |
|
|
92
|
-
| `collaboration` | Shared hubs (Library, future) | Adds face rail + invite entry — see [`exxat-collaboration-access.mdc`](../../../.cursor/rules/exxat-collaboration-access.mdc) |
|
|
93
|
-
|
|
94
|
-
Pick **one** variant per header. Combining `collaboration` with
|
|
95
|
-
`record-home` is allowed only when the record itself is a shareable
|
|
96
|
-
artifact (e.g. a question).
|
|
97
|
-
|
|
98
|
-
## 7. Implementation
|
|
99
|
-
|
|
100
|
-
| Framework | Component(s) | File |
|
|
101
|
-
|---|---|---|
|
|
102
|
-
| **React (this app)** | `PageHeader` (shell) + per-hub headers (composition) | [`apps/web/components/page-header.tsx`](../../components/page-header.tsx), [`apps/web/components/library-page-header.tsx`](../../components/library-page-header.tsx) |
|
|
103
|
-
| Mobile | — | — |
|
|
104
|
-
| Figma | — | — |
|
|
105
|
-
|
|
106
|
-
Reference hub-level compositions:
|
|
107
|
-
|
|
108
|
-
- **Placements** — filled primary CTA `New placement` + `⋯` (Export, Customize…)
|
|
109
|
-
- **Team** — same shape, count + freshness in subtitle
|
|
110
|
-
- **Library** — `variant="collaboration"` + folder-scoped customize entry
|
|
111
|
-
|
|
112
|
-
## 8. Do / Don't
|
|
113
|
-
|
|
114
|
-
| ✅ Do | ❌ Don't |
|
|
115
|
-
|---|---|
|
|
116
|
-
| Render exactly one `<h1>` per route | Render two H1s (e.g. one in header + one in body) |
|
|
117
|
-
| Put the primary CTA inside the header — filled, often `size="lg"` | Use `variant="outline"` for the sole primary action on an exportable page |
|
|
118
|
-
| Put **Export** under `⋯` → `ExportDrawer` | Put Export as a second primary button beside New |
|
|
119
|
-
| Use `ExxatProductLogo` for product marks | Substitute a logo.dev raster for the product mark |
|
|
120
|
-
| Keep subtitle to **one line**; truncate long meta | Stack two meta lines below the title |
|
|
121
|
-
| Show keyboard shortcuts via `Kbd` in tooltips on primary/overflow | Hard-code shortcut hints in the visible button label |
|
|
122
|
-
|
|
123
|
-
## 9. References
|
|
124
|
-
|
|
125
|
-
- [`apps/web/docs/data-views-pattern.md`](../data-views-pattern.md) — `PageHeader` in context of `ListPageTemplate`
|
|
126
|
-
- [`apps/web/docs/collaboration-access-pattern.md`](../collaboration-access-pattern.md) — `variant="collaboration"`
|
|
127
|
-
- [`apps/web/docs/library-hub-header-pattern.md`](../library-hub-header-pattern.md) — folder-scoped header
|
|
128
|
-
- [`.cursor/rules/exxat-collaboration-access.mdc`](../../../.cursor/rules/exxat-collaboration-access.mdc)
|
|
129
|
-
- [`.cursor/rules/exxat-mono-ids.mdc`](../../../.cursor/rules/exxat-mono-ids.mdc)
|
|
130
|
-
- [`apps/web/AGENTS.md`](../../AGENTS.md) §4.7, §6.2, §9
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
# Cards vs table rows vs list rows
|
|
2
|
-
|
|
3
|
-
> **Related:** **`AGENTS.md` §4–§5**, **`.cursor/rules/exxat-data-tables.mdc`**, **`.cursor/rules/exxat-board-cards.mdc`**, **`docs/data-views-pattern.md`**.
|
|
4
|
-
|
|
5
|
-
## When to use **rows** (table or dense list)
|
|
6
|
-
|
|
7
|
-
- **Many similar records** (roughly **10+**) where users **scan**, **sort**, **filter**, and **compare columns**.
|
|
8
|
-
- **Same fields** across entities — columns align; export and **TablePropertiesDrawer** apply.
|
|
9
|
-
- **Primary hub** pattern — **`DataTable`** + **`ListPageTemplate`** per **`exxat-data-tables`**.
|
|
10
|
-
|
|
11
|
-
**Use:** `DataTable`, shared toolbar, row actions, pinned columns.
|
|
12
|
-
|
|
13
|
-
## When to use **cards** (tile / board / marketing)
|
|
14
|
-
|
|
15
|
-
- **Lower cardinality** or **visual-first** browsing — folders, dashboards, “pick a template”, hero metrics beside a chart.
|
|
16
|
-
- **Heterogeneous content** — each card has a different layout (title, badge, avatar, two-line body) where a rigid grid of columns would fight the design.
|
|
17
|
-
- **Kanban** — **`ListPageBoardCard`** + column model; still fed by **`tableState.rows`**.
|
|
18
|
-
|
|
19
|
-
**Use:** `ListPageBoardCard`, `ChartCard`, icon grids under **`ListPageViewFrame`**, dashboard chart tiles.
|
|
20
|
-
|
|
21
|
-
## When to use **list rows** (not full DataTable)
|
|
22
|
-
|
|
23
|
-
- **Medium density** — fewer columns than a grid; reading order is **vertical** (timeline, activity, simple roster without heavy operators).
|
|
24
|
-
- Still wire **search** when the list is the main surface and item count grows.
|
|
25
|
-
|
|
26
|
-
**Prefer** graduating to **`DataTable`** once the hub needs filters, column hide, density, or export parity with other list hubs.
|
|
27
|
-
|
|
28
|
-
## Anti-patterns
|
|
29
|
-
|
|
30
|
-
- **Cards for 50+ homogeneous records** when the product expects sort/filter/compare — that belongs in **`DataTable`**.
|
|
31
|
-
- **A second bespoke “table”** alongside **`DataTable`** for the same dataset — extend the table stack instead (**`exxat-centralized-list-dataset`**).
|
|
32
|
-
- **Raw `<table>`** for product data lists — forbidden (**`exxat-data-tables`**).
|
|
33
|
-
|
|
34
|
-
## See also
|
|
35
|
-
|
|
36
|
-
- **`.cursor/rules/exxat-card-vs-list-rows.mdc`**, **`.cursor/skills/exxat-card-vs-list-rows/SKILL.md`**
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
# Collaboration & access pattern
|
|
2
|
-
|
|
3
|
-
Shared UI for **who can access a hub** (face stack in the header) and **inviting people** (floating sheet). **Reference:** Library — `LibraryPageHeader`, `LibraryClient`, `InviteCollaboratorsDrawer`.
|
|
4
|
-
|
|
5
|
-
**Folder-scoped library:** When the library URL selects a folder (`?scope=folder&folderId=`), the same header **⋯ More** menu also exposes **Customize folder** (name / color / icon) via **`LibraryNewFolderSheet`** mounted on **`LibraryClient`** so it works on every view tab. See **`docs/library-hub-header-pattern.md`** and **`.cursor/rules/exxat-library-hub-header.mdc`**.
|
|
6
|
-
|
|
7
|
-
## When to use
|
|
8
|
-
|
|
9
|
-
- A list hub or library is **shared** across people (not a private directory).
|
|
10
|
-
- Users need to see **who has access**, **invite by email**, and assign **library access** (Owner / Editor / Commenter / Viewer).
|
|
11
|
-
- The hub already uses **`ListPageTemplate`** + **`PageHeader`** (or an entity header built on it).
|
|
12
|
-
|
|
13
|
-
**Do not** use this for org-wide **role** administration (Faculty, Program coordinator, Director) as the only story — those are **directory role tags** on people, not library access.
|
|
14
|
-
|
|
15
|
-
## Vocabulary
|
|
16
|
-
|
|
17
|
-
| Concept | Meaning | Source |
|
|
18
|
-
|--------|---------|--------|
|
|
19
|
-
| **Library access** | What someone can do **in this hub** (Owner, Editor, Commenter, Viewer) | `lib/collaborator-access.ts` |
|
|
20
|
-
| **Directory roles** | Org/job tags on a person (Faculty, Program coordinator, Director) | `PageHeaderCollaborator.roles` |
|
|
21
|
-
| **Face rail** | Overlapping avatars in the header when the roster is non-empty | `PageHeader` `variant="collaboration"` |
|
|
22
|
-
| **Empty roster CTA** | Outline **Add collaborator** in the header when `collaborators` is empty | `PageHeader` + `COLLABORATION_HEADER_ADD_LABEL` |
|
|
23
|
-
| **Invite sheet** | Floating right **`Sheet`** for roster + invite form | `InviteCollaboratorsDrawer` |
|
|
24
|
-
| **Hub wiring** | Roster state + invite sheet in one render-prop shell | `CollaborationAccessFlow` |
|
|
25
|
-
|
|
26
|
-
## Header (`PageHeader`)
|
|
27
|
-
|
|
28
|
-
- Set **`variant="collaboration"`**.
|
|
29
|
-
- Pass **`collaborators`** (`PageHeaderCollaborator[]`) and optional **`accessInfo`**.
|
|
30
|
-
- **Non-empty roster** — overlapping **face rail** only; each face and **`+N`** open the invite sheet via **`onCollaboratorsOpen`**.
|
|
31
|
-
- **Empty roster** — outline **`Add collaborator`** (`addCollaboratorLabel`, default **`COLLABORATION_HEADER_ADD_LABEL`**) opens the same sheet.
|
|
32
|
-
- **Invite** also lives under **⋯ More** on the entity page header (first item when `variant="collaboration"`).
|
|
33
|
-
|
|
34
|
-
```tsx
|
|
35
|
-
<CollaborationAccessFlow
|
|
36
|
-
initialCollaborators={LIBRARY_HEADER_COLLABORATORS}
|
|
37
|
-
resourceLabel={hubHeader.title}
|
|
38
|
-
>
|
|
39
|
-
{({ collaborators, openInvite }) => (
|
|
40
|
-
<LibraryPageHeader
|
|
41
|
-
variant="collaboration"
|
|
42
|
-
title={hubHeader.title}
|
|
43
|
-
questionCount={count}
|
|
44
|
-
collaborators={collaborators}
|
|
45
|
-
onAddCollaborator={openInvite}
|
|
46
|
-
onCollaboratorsOpen={openInvite}
|
|
47
|
-
onExport={() => setExportOpen(true)}
|
|
48
|
-
showMetrics={showMetrics}
|
|
49
|
-
onToggleMetrics={() => setShowMetrics(v => !v)}
|
|
50
|
-
/>
|
|
51
|
-
)}
|
|
52
|
-
</CollaborationAccessFlow>
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
## Hub client state
|
|
56
|
-
|
|
57
|
-
- Prefer **`CollaborationAccessFlow`** — owns **`collaborators`**, **`openInvite`**, and **`InviteCollaboratorsDrawer`**; pass **`openInvite`** to **`onAddCollaborator`** / **`onCollaboratorsOpen`**.
|
|
58
|
-
- Without the flow: **`collaborators`** — `useState` seeded from `lib/mock/<entity>-header-collaborators.ts` (or API later); **`inviteOpen`** — boolean; mount **`InviteCollaboratorsDrawer`** beside **`ListPageTemplate`**.
|
|
59
|
-
- On invite success, append to **`collaborators`** so the **face rail** and sheet roster stay aligned.
|
|
60
|
-
- **Change access** — roster menu updates **`collaborators`** via **`onCollaboratorAccessChange`** ( **`CollaborationAccessFlow`** default).
|
|
61
|
-
- **Remove access** — confirm dialog then **`onCollaboratorRemove`**; blocked for the only **Owner**.
|
|
62
|
-
|
|
63
|
-
## `PageHeaderCollaborator`
|
|
64
|
-
|
|
65
|
-
| Field | Use |
|
|
66
|
-
|-------|-----|
|
|
67
|
-
| `id`, `name`, `imageUrl`, `initials` | Face rail + roster row |
|
|
68
|
-
| `email` | Roster (below name); invite form |
|
|
69
|
-
| `access` | Library access badge (Owner … Viewer) |
|
|
70
|
-
| `roles` | Optional **outline** chips (Faculty, Program coordinator, Director) |
|
|
71
|
-
|
|
72
|
-
## Invite sheet (`InviteCollaboratorsDrawer`)
|
|
73
|
-
|
|
74
|
-
Mirror **`ExportDrawer`** chrome: floating **`Sheet`**, no overlay, **`showCloseButton={false}`**, footer **Cancel** / **Send invite** with inline **`Kbd`** (**Esc** / **⏎**), **`Shortcut`** for Enter on the open surface.
|
|
75
|
-
|
|
76
|
-
**Invite field:** one bordered row — email input + **access** menu on the right.
|
|
77
|
-
|
|
78
|
-
- Use **`Select`** with **`SelectGroup`** for access (invite row in **`InputGroupAddon`**, roster row standalone); **`position="popper"`** inside the sheet; **no** toast on success (**§6.5**).
|
|
79
|
-
|
|
80
|
-
**People with access:** one **`rounded-lg border`** list with **`divide-y`** — **not** one card per person.
|
|
81
|
-
|
|
82
|
-
Row order:
|
|
83
|
-
|
|
84
|
-
1. **Name** (`text-sm font-medium`)
|
|
85
|
-
2. **Email** (`text-xs text-muted-foreground`)
|
|
86
|
-
3. **Role tags** (`Badge variant="outline"`) when `roles` is set
|
|
87
|
-
4. Trailing **library access** **`Select`** when the hub wires **`onCollaboratorAccessChange`**; **Remove access** (trash) opens a confirm **`Dialog`** when **`onCollaboratorRemove`** is set. The sole **Owner** cannot be removed or demoted until another owner exists.
|
|
88
|
-
|
|
89
|
-
## Library access constants
|
|
90
|
-
|
|
91
|
-
- Types and invite options: **`lib/collaborator-access.ts`**
|
|
92
|
-
- **`INVITE_COLLABORATOR_ACCESS_OPTIONS`** — Editor / Commenter / Viewer (no Owner on invite)
|
|
93
|
-
- Customize option **descriptions** per hub; keep **values** stable for forms/API
|
|
94
|
-
|
|
95
|
-
## File map
|
|
96
|
-
|
|
97
|
-
| Piece | Path |
|
|
98
|
-
|-------|------|
|
|
99
|
-
| Access types | `lib/collaborator-access.ts` |
|
|
100
|
-
| Hub flow | `components/collaboration-access-flow.tsx` |
|
|
101
|
-
| Collaborator type | `components/page-header.tsx` (`PageHeaderCollaborator`) |
|
|
102
|
-
| Invite sheet | `components/invite-collaborators-drawer.tsx` |
|
|
103
|
-
| Entity header | `components/library-page-header.tsx` |
|
|
104
|
-
| Hub wiring | `components/library-client.tsx` |
|
|
105
|
-
| Demo roster | `lib/mock/library-header-collaborators.ts` |
|
|
106
|
-
|
|
107
|
-
## Checklist (new hub)
|
|
108
|
-
|
|
109
|
-
- [ ] `PageHeader` / entity header uses **`variant="collaboration"`** when the product is shared.
|
|
110
|
-
- [ ] **Empty roster** shows **Add collaborator**; **non-empty** shows face rail; both open the invite sheet.
|
|
111
|
-
- [ ] **Invite people** under **⋯ More**; **`CollaborationAccessFlow`** (or equivalent) owns roster + sheet.
|
|
112
|
-
- [ ] Roster: single bordered list; **name → email → role tags**; access badge on the right.
|
|
113
|
-
- [ ] Invite row: email + access menu; **`FormDescription`** for format; **no** toast.
|
|
114
|
-
- [ ] Labels from **`collaborator-access.ts`**; mock/API rows extend **`PageHeaderCollaborator`** once.
|
|
115
|
-
|
|
116
|
-
**Handbook:** `AGENTS.md` §4.7 · **Rule:** `.cursor/rules/exxat-collaboration-access.mdc` · **Skill:** `.cursor/skills/exxat-collaboration-access/SKILL.md`
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
# Global command palette (⌘K)
|
|
2
|
-
|
|
3
|
-
**Code:** `components/command-menu.tsx`, config **`buildCommandMenuConfig()`** in **`lib/command-menu-config.ts`**, wired in **`app/(app)/layout.tsx`** via **`CommandMenuProvider`**. Searchable row data is built in **`lib/command-menu-search-data.ts`** (not inside the shell component).
|
|
4
|
-
|
|
5
|
-
## Role
|
|
6
|
-
|
|
7
|
-
The command menu is the app’s **global search and AI entry**—one place to jump to routes, library pages, patterns, and AI starters. It is **not** a duplicate of the left sidebar; it **indexes** product surfaces for fast discovery.
|
|
8
|
-
|
|
9
|
-
## User model
|
|
10
|
-
|
|
11
|
-
| Need | Where it lives |
|
|
12
|
-
|------|----------------|
|
|
13
|
-
| **Find a page, component, or pattern** | Palette — filterable list, **Enter** to navigate. |
|
|
14
|
-
| **Quick AI / natural language** | Prefer **short answers or “research” snippets inside the palette** when the product can return compact, citeable results without leaving the flow. |
|
|
15
|
-
| **Long or complex answers** | **Ask Leo** right sidebar — multi-step reasoning, long-form help, or anything that does not fit a small results surface. |
|
|
16
|
-
|
|
17
|
-
**Design rule:** Treat the palette as **progressive disclosure**—lightweight results first in-menu; **escalate** to Ask Leo when the answer is too large or needs a dedicated conversation surface.
|
|
18
|
-
|
|
19
|
-
## Keyboard
|
|
20
|
-
|
|
21
|
-
- **⌘K / Ctrl+K** — open / toggle the palette (global listener in `CommandMenu`).
|
|
22
|
-
- **Ask Leo** remains **⌘⌥K / Ctrl+Alt+K** (see `.cursor/rules/exxat-kbd-shortcuts.mdc`) so it does not collide with table search where both exist.
|
|
23
|
-
|
|
24
|
-
## Configuration
|
|
25
|
-
|
|
26
|
-
- **Static groups** (AI suggestions, Navigation, Components, Patterns) live in **`lib/command-menu-config.ts`**.
|
|
27
|
-
- Optional **`dataGroups`** are passed to **`buildCommandMenuConfig({ dataGroups })`** from the app shell. **Implementation:** **`getCommandMenuSearchDataGroups()`** in **`lib/command-menu-search-data.ts`** maps mock/API rows (e.g. placements with student names) to **`CommandMenuItem`** rows with **`label`**, **`href`**, and **`keywords`** for cmdk filtering. The layout uses **`buildCommandMenuConfig({ dataGroups: getCommandMenuSearchDataGroups() })`**. Keep domain mapping **outside** `command-menu.tsx` so data sources can change without editing the shell.
|
|
28
|
-
- **`searchOnly` on `CommandMenuGroup`:** cmdk shows **every** mounted item when the search box is empty. For large indexes (hundreds of placements), set **`searchOnly: true`** on that group so **`command-menu.tsx`** does not render it until the user has typed a non-empty query. Static groups (AI, Navigation, …) stay visible on open; the data group appears once the user searches.
|
|
29
|
-
|
|
30
|
-
## Files (quick reference)
|
|
31
|
-
|
|
32
|
-
| Piece | Location |
|
|
33
|
-
|-------|----------|
|
|
34
|
-
| Palette UI | `components/command-menu.tsx` |
|
|
35
|
-
| Static groups + `buildCommandMenuConfig` | `lib/command-menu-config.ts` (`CommandMenuGroup.searchOnly`) |
|
|
36
|
-
| Row → menu items (placements, etc.) | `lib/command-menu-search-data.ts` |
|
|
37
|
-
| Provider + `dataGroups` | `app/(app)/layout.tsx` |
|
|
38
|
-
|
|
39
|
-
## Sidebar
|
|
40
|
-
|
|
41
|
-
**“Search or ask Leo”** in the sidebar opens the same palette; shortcuts and copy should stay aligned with **`AGENTS.md` §7.1**.
|
|
42
|
-
|
|
43
|
-
---
|
|
44
|
-
|
|
45
|
-
Keep this document aligned with **`apps/web/AGENTS.md` §7.1** when behavior or copy changes.
|
|
@@ -1,224 +0,0 @@
|
|
|
1
|
-
# Exxat DS — Component Selection Guide
|
|
2
|
-
|
|
3
|
-
**Audience:** humans + AI agents. **Companion to:** [`token-taxonomy.md`](./token-taxonomy.md), [`blueprints/`](./blueprints/).
|
|
4
|
-
|
|
5
|
-
When you're about to build a UI, **start here**. Follow the decision tree
|
|
6
|
-
to find the right composition before you write any markup. The rule is
|
|
7
|
-
always: **compose existing components first**; only create a new shared
|
|
8
|
-
primitive after asking the user
|
|
9
|
-
([`exxat-reuse-before-custom.mdc`](../../.cursor/rules/exxat-reuse-before-custom.mdc)).
|
|
10
|
-
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
## 0. Quick chart
|
|
14
|
-
|
|
15
|
-
```
|
|
16
|
-
┌─────────────────────────────────────┐
|
|
17
|
-
│ What is the surface? │
|
|
18
|
-
└──┬──────────────────────────────────┘
|
|
19
|
-
│
|
|
20
|
-
┌───────────┴────────────────────────────┐
|
|
21
|
-
│ │
|
|
22
|
-
PRIMARY HUB OVERLAY / SECONDARY
|
|
23
|
-
(route w/ many records, (on top of a hub,
|
|
24
|
-
filters, properties) modal task, side panel)
|
|
25
|
-
│ │
|
|
26
|
-
│ ▼
|
|
27
|
-
│ See § 3
|
|
28
|
-
▼
|
|
29
|
-
See § 1
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
---
|
|
33
|
-
|
|
34
|
-
## 1. Building a primary hub (route with records)
|
|
35
|
-
|
|
36
|
-
```
|
|
37
|
-
Q: Is the data > ~10 comparable records?
|
|
38
|
-
─────────────────────────────────────────
|
|
39
|
-
│ yes ──────────────────────────────► DataTable inside ListPageTemplate (§1.1)
|
|
40
|
-
│ no ──┬─ all rows shown at once?
|
|
41
|
-
│ │ yes ── simple `<dl>` / card list (no Properties / Filters needed)
|
|
42
|
-
│ │ no ── still use DataTable — future growth is expected
|
|
43
|
-
└─────►
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
### 1.1 DataTable hub (canonical)
|
|
47
|
-
|
|
48
|
-
| Need | Use |
|
|
49
|
-
|---|---|
|
|
50
|
-
| Browsable grid | **`DataTable`** + **`useTableState`** ([blueprint](./blueprints/data-table.md)) |
|
|
51
|
-
| View tabs (table/list/board/dashboard) | **`ListPageTemplate`** + connected views ([`exxat-list-page-connected-views.mdc`](../../.cursor/rules/exxat-list-page-connected-views.mdc)) |
|
|
52
|
-
| Column/density/properties | **`TablePropertiesDrawer`** (pass `currentView` + `onViewChange`) |
|
|
53
|
-
| Filters | Shared `FilterFieldDef` chips |
|
|
54
|
-
| Find-in-list | Toolbar search (`⌘K`) |
|
|
55
|
-
| Metrics strip | **`KeyMetrics`** `variant="flat"` ([`kpi-flat-band-pattern.md`](./kpi-flat-band-pattern.md)) — **max 4 tiles** ([`exxat-kpi-max-four.mdc`](../../.cursor/rules/exxat-kpi-max-four.mdc)) |
|
|
56
|
-
| Export | Filled primary CTA + `⋯` → `ExportDrawer` |
|
|
57
|
-
| Kanban view body | **`ListPageBoardCard`** + `ListPageBoardTemplate` ([`exxat-board-cards.mdc`](../../.cursor/rules/exxat-board-cards.mdc)) |
|
|
58
|
-
| Folder / panel view body | **`FolderGridView`** / **`FinderPanelView`** wrapped in **`ListPageViewFrame`** ([`exxat-list-page-view-shells.mdc`](../../.cursor/rules/exxat-list-page-view-shells.mdc)) |
|
|
59
|
-
| Dashboard view body | **`KeyMetrics variant="card"`** + a hub-specific chart section (reference: `library-dashboard-charts.tsx`) |
|
|
60
|
-
| Nested scope nav (All / Mine / tree) | **`secondaryPanel`** + `PANELS` + `useAutoPanel` ([`exxat-primary-nav-secondary-panel.mdc`](../../.cursor/rules/exxat-primary-nav-secondary-panel.mdc)) |
|
|
61
|
-
| Shared hub w/ invite | **`PageHeader` `variant="collaboration"`** + `InviteCollaboratorsDrawer` |
|
|
62
|
-
| Dedicated search (empty `?q=` vs results) | **`DedicatedSearchLandingTemplate`** + **`DedicatedSearchResultsHeaderChrome`** |
|
|
63
|
-
|
|
64
|
-
**Reference:** `PlacementsClient` (Placements) is the most complete example.
|
|
65
|
-
|
|
66
|
-
### 1.2 Visual-browse hub (kanban / gallery)
|
|
67
|
-
|
|
68
|
-
If the product wants a **kanban-first** experience and the table is the
|
|
69
|
-
fallback rather than primary:
|
|
70
|
-
|
|
71
|
-
```
|
|
72
|
-
ListPageTemplate
|
|
73
|
-
├── PageHeader
|
|
74
|
-
├── KeyMetrics (optional, ≤4)
|
|
75
|
-
└── viewType="board" → ListPageBoardTemplate + ListPageBoardCard
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
Even here, **back the board with `useTableState`** so switching to the table
|
|
79
|
-
tab is consistent. Don't fork the data.
|
|
80
|
-
|
|
81
|
-
---
|
|
82
|
-
|
|
83
|
-
## 2. Naming a card / row / list
|
|
84
|
-
|
|
85
|
-
| Pattern | What to reach for |
|
|
86
|
-
|---|---|
|
|
87
|
-
| Dense comparable rows | `DataTable` row (don't card-wall it — see [`card-vs-rows-pattern.md`](./card-vs-rows-pattern.md)) |
|
|
88
|
-
| Kanban column card | `ListPageBoardCard` + `BoardCardTwoLineBlock` + `BoardCardIconRow` |
|
|
89
|
-
| OS-folder grid | `FolderGridView` in `ListPageViewFrame` |
|
|
90
|
-
| Finder split (list + preview) | `FinderPanelView` |
|
|
91
|
-
| Sidebar nav row | `SidebarMenuButton` (do not roll your own) |
|
|
92
|
-
| KPI tile | `KeyMetrics` `MetricItem` — never a custom `Card` w/ number |
|
|
93
|
-
| Coach mark tile | `CoachMark` step — never an ad-hoc onboarding popover |
|
|
94
|
-
|
|
95
|
-
---
|
|
96
|
-
|
|
97
|
-
## 3. Same-route overlay vs new route
|
|
98
|
-
|
|
99
|
-
Always ask: **does the user need the hub visible behind them?**
|
|
100
|
-
|
|
101
|
-
```
|
|
102
|
-
┌────────────────────────────┐
|
|
103
|
-
│ Does the user need the hub │
|
|
104
|
-
│ visible behind them? │
|
|
105
|
-
└─────────────┬──────────────┘
|
|
106
|
-
│
|
|
107
|
-
┌───── YES ─────┴───── NO ─────┐
|
|
108
|
-
▼ ▼
|
|
109
|
-
Same route New route
|
|
110
|
-
(overlay) (own URL)
|
|
111
|
-
│ │
|
|
112
|
-
┌─────┴──────┐ │
|
|
113
|
-
│ Is the task│ │
|
|
114
|
-
│ short + │ │
|
|
115
|
-
│ blocking? │ │
|
|
116
|
-
└─────┬──────┘ │
|
|
117
|
-
│ │
|
|
118
|
-
┌─ YES ┴ NO ──┐ │
|
|
119
|
-
▼ ▼ ▼
|
|
120
|
-
Dialog Sheet panel Page route
|
|
121
|
-
(AlertDialog, (TablePropertiesDrawer, (full create/edit
|
|
122
|
-
delete confirm) ExportDrawer, wizard, deep detail)
|
|
123
|
-
InviteCollaboratorsDrawer)
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
See [`drawer-vs-dialog-pattern.md`](./drawer-vs-dialog-pattern.md) and
|
|
127
|
-
[`exxat-page-vs-drawer.mdc`](../../.cursor/rules/exxat-page-vs-drawer.mdc).
|
|
128
|
-
|
|
129
|
-
---
|
|
130
|
-
|
|
131
|
-
## 4. Search / Find / Command
|
|
132
|
-
|
|
133
|
-
| Need | Use | Shortcut |
|
|
134
|
-
|---|---|---|
|
|
135
|
-
| Find inside a table | `DataTableToolbar` search | `⌘K` / `Ctrl K` (no Alt) |
|
|
136
|
-
| Find inside a hub (across tabs/views) | Same `⌘K` while focus is on the hub | `⌘K` |
|
|
137
|
-
| Global navigation + AI starter | `CommandMenu` ([`command-menu-pattern.md`](./command-menu-pattern.md)) | `⌘K` while no input has focus |
|
|
138
|
-
| Long AI / chat | `AskLeoSidebar` | `⌘⌥K` |
|
|
139
|
-
| Dedicated search page (results view) | `DedicatedSearchLandingTemplate` + `DedicatedSearchResultsHeaderChrome` | — |
|
|
140
|
-
|
|
141
|
-
---
|
|
142
|
-
|
|
143
|
-
## 5. Feedback / messaging
|
|
144
|
-
|
|
145
|
-
| Need | Use |
|
|
146
|
-
|---|---|
|
|
147
|
-
| Persistent banner ("system maintenance") | `SystemBanner` |
|
|
148
|
-
| Per-page contextual info | `LocalBanner` |
|
|
149
|
-
| Per-control success/error | Inline text next to the field |
|
|
150
|
-
| Confirm a destructive action | `AlertDialog` |
|
|
151
|
-
| **Never** | `toast()` / Sonner / snackbars ([`exxat-no-toast.mdc`](../../.cursor/rules/exxat-no-toast.mdc)) |
|
|
152
|
-
|
|
153
|
-
---
|
|
154
|
-
|
|
155
|
-
## 6. Icons
|
|
156
|
-
|
|
157
|
-
| Use case | Pattern |
|
|
158
|
-
|---|---|
|
|
159
|
-
| Icon next to a label | FA glyph + `aria-hidden` (Case A) |
|
|
160
|
-
| Icon standing alone (meaning-bearing) | `<span role="img" aria-label="…" tabIndex={0}>` + `Tooltip` (Case B) |
|
|
161
|
-
| Icon-only button / link | `<button aria-label="…">` wrapped in `Tooltip` (Case C) |
|
|
162
|
-
| Product mark | `ExxatProductLogo` |
|
|
163
|
-
| School / org mark | `logoDevUrl()` |
|
|
164
|
-
|
|
165
|
-
Source: `apps/web/AGENTS.md` §8.6.
|
|
166
|
-
|
|
167
|
-
---
|
|
168
|
-
|
|
169
|
-
## 7. KPIs / metrics
|
|
170
|
-
|
|
171
|
-
| Need | Use |
|
|
172
|
-
|---|---|
|
|
173
|
-
| Hub metric strip on top of `ListPageTemplate` | `KeyMetrics variant="flat"` |
|
|
174
|
-
| Dashboard view tab key-metrics card | `KeyMetrics variant="card"` (1–4 tiles) |
|
|
175
|
-
| Chart + mini-metric next to it | `ChartCard` + chart's own KPI helpers |
|
|
176
|
-
| Trend arrow on a metric | Set `MetricItem.trend` to match delta sign; set `trendPolarity` when "up" is bad |
|
|
177
|
-
|
|
178
|
-
Cap visible KPIs at **4** ([`exxat-kpi-max-four.mdc`](../../.cursor/rules/exxat-kpi-max-four.mdc)).
|
|
179
|
-
|
|
180
|
-
---
|
|
181
|
-
|
|
182
|
-
## 8. Identifiers and typography
|
|
183
|
-
|
|
184
|
-
| Carries | Use |
|
|
185
|
-
|---|---|
|
|
186
|
-
| System ID (`questionId`, record key) | `font-mono tabular-nums` ([`exxat-mono-ids.mdc`](../../.cursor/rules/exxat-mono-ids.mdc)) |
|
|
187
|
-
| Page title | `<h1>` with `font-heading` (Ivy Presto) inside `PageHeader` |
|
|
188
|
-
| Body | Default Inter, ≥ 11px (`text-xs` minimum) |
|
|
189
|
-
| Status label | `ListHubStatusBadge` from `lib/list-status-badges.ts` — never raw text |
|
|
190
|
-
| Currency / counts | `tabular-nums` (no `font-mono`) |
|
|
191
|
-
|
|
192
|
-
---
|
|
193
|
-
|
|
194
|
-
## 9. When NOTHING here fits
|
|
195
|
-
|
|
196
|
-
You are now in the territory covered by
|
|
197
|
-
[`exxat-reuse-before-custom.mdc`](../../.cursor/rules/exxat-reuse-before-custom.mdc):
|
|
198
|
-
|
|
199
|
-
1. Re-scan `apps/web/components/`, `packages/ui/src/components/`, and `apps/web/components/data-views/`.
|
|
200
|
-
2. Check `AGENTS.md` §9 architecture table.
|
|
201
|
-
3. If still no fit, **ask the user** with a short option list:
|
|
202
|
-
- extend an existing primitive (preferred),
|
|
203
|
-
- add a new component under `components/data-views/` or `components/templates/`,
|
|
204
|
-
- or open a packaged shared primitive in `packages/ui`.
|
|
205
|
-
|
|
206
|
-
---
|
|
207
|
-
|
|
208
|
-
## 10. Cheat sheet — one-line rules
|
|
209
|
-
|
|
210
|
-
- **Data list, > 10 rows** → `DataTable` + `ListPageTemplate`.
|
|
211
|
-
- **Visual browse / kanban** → `ListPageBoardCard`.
|
|
212
|
-
- **Folder / panel / OS-folder view** → `data-views/` primitive in `ListPageViewFrame`.
|
|
213
|
-
- **Quick auxiliary task with hub behind** → drawer.
|
|
214
|
-
- **Blocking short confirm** → dialog.
|
|
215
|
-
- **Primary / long / own-URL flow** → new route.
|
|
216
|
-
- **Global ⌘K** → `CommandMenu` (search + quick AI).
|
|
217
|
-
- **Long AI** → Ask Leo (`⌘⌥K`).
|
|
218
|
-
- **Feedback** → banner / inline / dialog — **never** toast.
|
|
219
|
-
- **Icon-only button** → `aria-label` + `Tooltip` (Case C).
|
|
220
|
-
- **System ID** → `font-mono tabular-nums`.
|
|
221
|
-
- **KPI strip** → ≤ 4 tiles, `variant="flat"` on hubs.
|
|
222
|
-
- **Hex color in code** → no. Use a token.
|
|
223
|
-
|
|
224
|
-
See also: [`AGENTS.md` §13 checklist](../AGENTS.md) — run it before shipping a hub.
|