@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,95 +0,0 @@
|
|
|
1
|
-
# Migration 0001 — `brand-deep` alias stabilization
|
|
2
|
-
|
|
3
|
-
> **Released in:** v0.2.18 · **Removed in:** — (no removal — alias is now official) · **Owner:** Exxat DS core
|
|
4
|
-
> **Type:** stabilization (clarifies an existing naming convention)
|
|
5
|
-
|
|
6
|
-
## Why
|
|
7
|
-
|
|
8
|
-
`bg-brand-deep` / `text-brand-deep` Tailwind utilities are used throughout
|
|
9
|
-
`CoachMark` and several skill docs, but the **only** declared primitive is
|
|
10
|
-
`--brand-color-deep`. The bridge `--color-brand-deep: var(--brand-color-deep)`
|
|
11
|
-
in `theme.css @theme inline` made the utilities work — but contributors kept
|
|
12
|
-
asking "is `--brand-deep` a real token or a typo of `--brand-color-deep`?".
|
|
13
|
-
|
|
14
|
-
This migration **does not rename anything**. It documents the alias as
|
|
15
|
-
**official** and codifies the rule for similar future cases:
|
|
16
|
-
|
|
17
|
-
> A Tailwind utility may use a **short, semantic alias** at the L2 bridge,
|
|
18
|
-
> distinct from the L1 primitive name, **only when the alias prevents an
|
|
19
|
-
> awkward utility class** (e.g. `bg-brand-color-deep` is unwieldy; `bg-brand-deep`
|
|
20
|
-
> reads naturally). The alias MUST be listed in `docs/token-taxonomy.md` and
|
|
21
|
-
> in the generated `hooks-index.json`.
|
|
22
|
-
|
|
23
|
-
Without this migration entry, future contributors might "fix" `bg-brand-deep`
|
|
24
|
-
by renaming it to `bg-brand-color-deep`, breaking every coach mark.
|
|
25
|
-
|
|
26
|
-
## Affected surface
|
|
27
|
-
|
|
28
|
-
| Surface | Was | Becomes |
|
|
29
|
-
|---|---|---|
|
|
30
|
-
| Tailwind utility | `bg-brand-deep`, `text-brand-deep` | **unchanged** (stabilized) |
|
|
31
|
-
| CSS custom prop (L2 bridge) | `--color-brand-deep` | **unchanged** (stabilized as alias) |
|
|
32
|
-
| CSS custom prop (L1 primitive) | `--brand-color-deep` | **unchanged** (canonical name) |
|
|
33
|
-
| Doc | _undocumented alias_ | Documented in `docs/token-taxonomy.md` §2.2 |
|
|
34
|
-
|
|
35
|
-
## Before
|
|
36
|
-
|
|
37
|
-
```css
|
|
38
|
-
/* packages/ui/src/theme.css */
|
|
39
|
-
@theme inline {
|
|
40
|
-
--color-brand-deep: var(--brand-color-deep); /* alias — was undocumented */
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
:root {
|
|
44
|
-
--brand-color-deep: oklch(0.28 0.085 286.1); /* L1 primitive */
|
|
45
|
-
}
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
```tsx
|
|
49
|
-
// packages/ui/src/components/ui/coach-mark.tsx — already correct
|
|
50
|
-
<div className="bg-brand-deep text-white">…</div>
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
The risk was that someone would "tidy up" `--color-brand-deep` to
|
|
54
|
-
`--color-brand-color-deep`, breaking `bg-brand-deep`.
|
|
55
|
-
|
|
56
|
-
## After
|
|
57
|
-
|
|
58
|
-
Same code; same tokens; **plus** an authoritative entry in
|
|
59
|
-
[`docs/token-taxonomy.md`](../token-taxonomy.md) §2.2 listing every L1 → L2
|
|
60
|
-
short-alias pair, and a regenerated [`packages/ui/tokens/hooks-index.json`](../../../packages/ui/tokens/hooks-index.json)
|
|
61
|
-
that exposes `--brand-color-deep` with `tailwindUtilities:
|
|
62
|
-
["bg-brand-deep", "text-brand-deep", …]` so tooling can discover the link.
|
|
63
|
-
|
|
64
|
-
## Migration recipe
|
|
65
|
-
|
|
66
|
-
### Automatic
|
|
67
|
-
|
|
68
|
-
None needed — this migration changes documentation only.
|
|
69
|
-
|
|
70
|
-
### Manual
|
|
71
|
-
|
|
72
|
-
For **future** short-alias additions, follow this pattern:
|
|
73
|
-
|
|
74
|
-
1. Declare the L1 primitive: `--brand-<name>: oklch(...)` in `:root` and any
|
|
75
|
-
theme overrides in `.dark` / `.theme-prism` / etc.
|
|
76
|
-
2. Declare the L2 alias in `@theme inline`: `--color-<short>: var(--brand-<name>)`.
|
|
77
|
-
3. Add a row to `docs/token-taxonomy.md` §2.2 listing the alias.
|
|
78
|
-
4. Run `pnpm --filter @exxatdesignux/ui tokens:index` and commit.
|
|
79
|
-
5. Use the alias **only** for the case where the long name is awkward; do
|
|
80
|
-
**not** create aliases for ergonomics alone.
|
|
81
|
-
|
|
82
|
-
## Verification
|
|
83
|
-
|
|
84
|
-
- [x] `pnpm --filter @exxatdesignux/ui tokens:index` runs and emits the alias
|
|
85
|
-
under `tailwindUtilities` for `--brand-color-deep`.
|
|
86
|
-
- [x] `docs/token-taxonomy.md` §2.2 lists `--brand-color-deep` and its alias.
|
|
87
|
-
- [x] `coach-mark.tsx` continues to render the deep-brand background.
|
|
88
|
-
|
|
89
|
-
## References
|
|
90
|
-
|
|
91
|
-
- `packages/ui/src/theme.css` — lines declaring `--brand-color-deep` and the alias
|
|
92
|
-
- `packages/ui/src/components/ui/coach-mark.tsx`
|
|
93
|
-
- `apps/web/docs/token-taxonomy.md` §2.2 (Brand)
|
|
94
|
-
- `apps/web/docs/blueprints/page-header.md` (uses `--brand-color-*` family)
|
|
95
|
-
- `.cursor/rules/exxat-token-discipline.mdc` (codifies the alias rule)
|
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
# Migration 0002 — Exxat L0 canonical token namespace
|
|
2
|
-
|
|
3
|
-
> **Released in:** v0.2.19 (next minor) · **Removed in:** _not planned (additive — L1 stays for shadcn primitives)_ · **Owner:** Design system
|
|
4
|
-
|
|
5
|
-
## Why
|
|
6
|
-
|
|
7
|
-
Until v0.2.18 the token system mixed two conventions:
|
|
8
|
-
|
|
9
|
-
1. **shadcn names** inherited from upstream (`--background`, `--foreground`,
|
|
10
|
-
`--primary`, `--card`, `--popover`, `--ring`, …)
|
|
11
|
-
2. **Exxat extensions** added next to them with assorted prefixes (`--brand-*`,
|
|
12
|
-
`--chip-*`, `--chart-*`, `--dt-*`, `--key-metrics-*`, `--sidebar-*`, …)
|
|
13
|
-
|
|
14
|
-
This was readable but had three pain points:
|
|
15
|
-
|
|
16
|
-
- **Discovery** — `grep -r "--brand"` finds product code but `grep -r "--exxat-"`
|
|
17
|
-
found nothing; there was no single prefix for "this is ours".
|
|
18
|
-
- **Branding** — patterns docs and the SLDS comparison kept asking "where is
|
|
19
|
-
the `--exxat-color-surface-1`?" (the user's framing).
|
|
20
|
-
- **Portability** — future non-React or non-shadcn consumers (Figma sync,
|
|
21
|
-
Penpot, native iOS/Android themes) need a clean namespace they can rename
|
|
22
|
-
without confusing it with upstream shadcn primitives.
|
|
23
|
-
|
|
24
|
-
This migration introduces an **Exxat L0 canonical namespace** that gives every
|
|
25
|
-
product token a single, flat, branded prefix — modeled on SLDS's
|
|
26
|
-
`--slds-g-color-surface-1` style.
|
|
27
|
-
|
|
28
|
-
## Affected surface
|
|
29
|
-
|
|
30
|
-
- `packages/ui/src/globals.css` — L0 block in `:root` (61 aliases). *(Originally landed in `packages/ui/src/theme.css`; that file was retired in [`0003-globals-css-canonical.md`](./0003-globals-css-canonical.md), so the L0 block now lives in `globals.css`.)*
|
|
31
|
-
- `packages/ui/src/globals.css` — added Tailwind bridges in `@theme inline`
|
|
32
|
-
- `apps/web/app/globals.css` — mirror
|
|
33
|
-
- `packages/ui/template/app/globals.css` — mirror
|
|
34
|
-
- `packages/ui/tokens/hooks-index.json` — regenerated (102 → 163 tokens; 24 → 36 namespaces)
|
|
35
|
-
- `apps/web/docs/token-taxonomy.md` — new §2.0 documenting L0
|
|
36
|
-
- `packages/ui/scripts/build-tokens-index.mjs` — `exxat-*` namespace inference
|
|
37
|
-
|
|
38
|
-
**No existing token was renamed.** L1 (shadcn names) and L3 (theme overrides)
|
|
39
|
-
remain canonical OKLCH literals; L0 simply gives every consumer a `var(L1)`
|
|
40
|
-
alias under the Exxat prefix.
|
|
41
|
-
|
|
42
|
-
## Before
|
|
43
|
-
|
|
44
|
-
```tsx
|
|
45
|
-
// Direct CSS variable
|
|
46
|
-
<div style={{ background: "var(--background)", color: "var(--foreground)" }} />
|
|
47
|
-
|
|
48
|
-
// Tailwind utility
|
|
49
|
-
<div className="bg-background text-foreground rounded-md border" />
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
Naming was inconsistent — `--background`, `--brand-color`, `--chip-1`,
|
|
53
|
-
`--dt-row-bg` all live at the top level with no shared "this is Exxat"
|
|
54
|
-
identifier.
|
|
55
|
-
|
|
56
|
-
## After
|
|
57
|
-
|
|
58
|
-
```tsx
|
|
59
|
-
// Direct CSS variable — L0 canonical
|
|
60
|
-
<div style={{ background: "var(--exxat-color-surface-1)", color: "var(--exxat-color-ink-1)" }} />
|
|
61
|
-
|
|
62
|
-
// Tailwind utility — short utility forms backed by L0
|
|
63
|
-
<div className="bg-surface-1 text-ink-1 rounded-2 border-1" />
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
Both forms above continue to work. The L0 forms are **encouraged for new code**
|
|
67
|
-
because they are:
|
|
68
|
-
|
|
69
|
-
- **Grep-able** — `grep --exxat-` finds every product token
|
|
70
|
-
- **Portable** — non-React consumers can map the L0 prefix to their platform
|
|
71
|
-
- **Self-documenting** — `--exxat-color-surface-1` reads as a designed slot,
|
|
72
|
-
not a shadcn implementation detail
|
|
73
|
-
|
|
74
|
-
## Migration recipe
|
|
75
|
-
|
|
76
|
-
> **Non-breaking.** No existing code needs to change. The migration is to use
|
|
77
|
-
> L0 forms in **new** components and **opportunistically** in touched files.
|
|
78
|
-
|
|
79
|
-
### Optional global pass (when you're already in the file)
|
|
80
|
-
|
|
81
|
-
Search and replace inside the file you're editing — do **not** open a
|
|
82
|
-
repo-wide rewrite PR; it adds noise without product value.
|
|
83
|
-
|
|
84
|
-
| shadcn (L1) | Exxat (L0) | Tailwind |
|
|
85
|
-
|---|---|---|
|
|
86
|
-
| `var(--background)` | `var(--exxat-color-surface-1)` | `bg-surface-1` |
|
|
87
|
-
| `var(--card)` | `var(--exxat-color-surface-2)` | `bg-surface-2` |
|
|
88
|
-
| `var(--popover)` | `var(--exxat-color-surface-3)` | `bg-surface-3` |
|
|
89
|
-
| `var(--muted)` | `var(--exxat-color-surface-muted)` | `bg-surface-muted` |
|
|
90
|
-
| `var(--foreground)` | `var(--exxat-color-ink-1)` | `text-ink-1` |
|
|
91
|
-
| `var(--muted-foreground)` | `var(--exxat-color-ink-2)` | `text-ink-2` |
|
|
92
|
-
| `var(--brand-color)` | `var(--exxat-color-brand-1)` | `bg-brand-1` |
|
|
93
|
-
| `var(--brand-color-dark)` | `var(--exxat-color-brand-2)` | `bg-brand-2` |
|
|
94
|
-
| `var(--brand-tint)` | `var(--exxat-color-brand-tint-1)` | `bg-brand-tint-1` |
|
|
95
|
-
| `var(--border)` | `var(--exxat-color-border-1)` | `border-1` |
|
|
96
|
-
| `var(--ring)` | `var(--exxat-color-focus-ring)` | `ring-focus-ring` |
|
|
97
|
-
| `var(--radius)` / `--radius-md` | `var(--exxat-radius-2)` | `rounded-2` |
|
|
98
|
-
| `var(--radius-sm)` | `var(--exxat-radius-1)` | `rounded-1` |
|
|
99
|
-
|
|
100
|
-
### What you SHOULD NOT migrate
|
|
101
|
-
|
|
102
|
-
- **shadcn primitives in `components/ui/*`** still use L1 names (`--background`,
|
|
103
|
-
`--border`, `--ring`, …). They are the upstream contract and stay.
|
|
104
|
-
- **Bridge tokens already aliased at L2** (`--color-brand`, `--color-chip-1`)
|
|
105
|
-
keep their existing utility shape (`bg-brand`, `text-chip-1`).
|
|
106
|
-
|
|
107
|
-
## Verification
|
|
108
|
-
|
|
109
|
-
```bash
|
|
110
|
-
# Regenerate the hooks index, confirm 163 tokens / 36 namespaces.
|
|
111
|
-
pnpm --filter @exxatdesignux/ui tokens:index
|
|
112
|
-
|
|
113
|
-
# Confirm L0 tokens picked up the right namespaces.
|
|
114
|
-
node -e "
|
|
115
|
-
const j = require('./packages/ui/tokens/hooks-index.json');
|
|
116
|
-
const buckets = {};
|
|
117
|
-
for (const [k, v] of Object.entries(j.tokens)) {
|
|
118
|
-
if (!k.startsWith('--exxat-')) continue;
|
|
119
|
-
buckets[v.namespace] = (buckets[v.namespace] || 0) + 1;
|
|
120
|
-
}
|
|
121
|
-
console.table(buckets);
|
|
122
|
-
"
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
Expected counts: `exxat-surface=8`, `exxat-ink=9`, `exxat-brand=7`,
|
|
126
|
-
`exxat-action=3`, `exxat-border=4`, `exxat-focus=1`, `exxat-overlay=1`,
|
|
127
|
-
`exxat-chart=5`, `exxat-chip=6`, `exxat-radius=6`, `exxat-spacing=8`,
|
|
128
|
-
`exxat-control=3`.
|
|
129
|
-
|
|
130
|
-
Sanity check the Tailwind bridge by inspecting any L0 color token —
|
|
131
|
-
`tailwindUtilities` must contain the short forms (`bg-surface-1`,
|
|
132
|
-
`bg-brand-1`, …).
|
|
133
|
-
|
|
134
|
-
## Future direction
|
|
135
|
-
|
|
136
|
-
When all consumers have migrated to L0:
|
|
137
|
-
|
|
138
|
-
1. Flip the canonical direction so **L0 holds the OKLCH literal** and **L1
|
|
139
|
-
becomes a `var(L0)` alias**.
|
|
140
|
-
2. Move per-theme overrides in `.dark` / `.theme-one` / `.theme-prism` /
|
|
141
|
-
`[data-contrast]` to write L0 names.
|
|
142
|
-
3. Mark L1 names `@deprecated` for the components/ui shadcn primitives that
|
|
143
|
-
still consume them, then remove or vendor-rename them inside the DS.
|
|
144
|
-
|
|
145
|
-
That's a much bigger lift and **not** in scope here. This migration just makes
|
|
146
|
-
the eventual flip possible — and gives the rest of the system a clean,
|
|
147
|
-
brandable, portable namespace today.
|
|
148
|
-
|
|
149
|
-
## References
|
|
150
|
-
|
|
151
|
-
- [`token-taxonomy.md`](../token-taxonomy.md) §1 — layering, §2.0 — L0 map
|
|
152
|
-
- [`packages/ui/tokens/hooks-index.json`](../../../packages/ui/tokens/hooks-index.json) — machine-readable index
|
|
153
|
-
- [`.cursor/rules/exxat-token-discipline.mdc`](../../../.cursor/rules/exxat-token-discipline.mdc) — lint rule + ESLint plugin
|
|
154
|
-
- SLDS v1 → v2 uplift skill (inspiration): <https://www.lightningdesignsystem.com/2e1ef9c7e/v/1604/p/9929fa-uplift-skill>
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
# 0003 — `packages/ui/src/globals.css` is now the only CSS source of truth
|
|
2
|
-
|
|
3
|
-
**Status:** Landed
|
|
4
|
-
**Date:** 2026-05-19
|
|
5
|
-
**Author:** Exxat DS hardening sweep
|
|
6
|
-
**Breaking?** Yes for any external consumer of `@exxatdesignux/ui` that
|
|
7
|
-
imported `@exxatdesignux/ui/theme.css` directly. The package is **not yet
|
|
8
|
-
shipped**, so customer impact is zero. Internal consumers updated as part
|
|
9
|
-
of this PR.
|
|
10
|
-
|
|
11
|
-
## Why
|
|
12
|
-
|
|
13
|
-
Until now, the design system kept the same theme tokens duplicated across
|
|
14
|
-
**four** CSS files:
|
|
15
|
-
|
|
16
|
-
| File | Purpose | Status |
|
|
17
|
-
|---|---|---|
|
|
18
|
-
| `packages/ui/src/theme.css` | "thin" package CSS without Tailwind imports | dead — never `@import`-ed by code |
|
|
19
|
-
| `packages/ui/src/globals.css` | "full" package CSS (Tailwind imports + tokens) | drifted (older `--input` value, missing `--header-height`) |
|
|
20
|
-
| `apps/web/app/globals.css` | consumer of the package | up-to-date copy |
|
|
21
|
-
| `packages/ui/template/app/globals.css` | starter template (auto-synced from apps/web) | up-to-date copy |
|
|
22
|
-
|
|
23
|
-
Each token change required up to **three** manual mirror edits, and the
|
|
24
|
-
files had **already silently drifted**: `--input` value differed between
|
|
25
|
-
the package and apps/web (one was `oklch(0.62 0.01 264.52)`, the other
|
|
26
|
-
`oklch(0.6694 0.0063 264.52)`).
|
|
27
|
-
|
|
28
|
-
This is exactly the maintenance trap SLDS deliberately avoids by having
|
|
29
|
-
one source file. Now that the package is not yet shipped, the breaking
|
|
30
|
-
change is free.
|
|
31
|
-
|
|
32
|
-
## What changed
|
|
33
|
-
|
|
34
|
-
1. **`packages/ui/src/globals.css` is now canonical.** It carries
|
|
35
|
-
`@import "tailwindcss"`, `@import "tw-animate-css"`, the
|
|
36
|
-
`@custom-variant` declarations, the full `@theme inline` block (L2),
|
|
37
|
-
every `:root` / `.dark` / `.theme-*` / `[data-contrast="high"]` block
|
|
38
|
-
(L0 + L1 + L3), the `@layer base` rules, and the `@font-face`
|
|
39
|
-
declarations. No `@source` directive — that lives in the consumer.
|
|
40
|
-
|
|
41
|
-
2. **`apps/web/app/globals.css` is now a 20-line shell.** It does:
|
|
42
|
-
```css
|
|
43
|
-
@import "@exxatdesignux/ui/globals.css";
|
|
44
|
-
@source "../../../packages/ui/src";
|
|
45
|
-
```
|
|
46
|
-
Nothing else. All previous content moved into the package.
|
|
47
|
-
|
|
48
|
-
3. **`packages/ui/template/app/globals.css` is the same shell** with the
|
|
49
|
-
`@source` path patched to `../node_modules/@exxatdesignux/ui/src` (the
|
|
50
|
-
`sync-template-from-web.mjs` script already does this rewrite).
|
|
51
|
-
|
|
52
|
-
4. **`packages/ui/src/theme.css` is deleted.** It was a stale, smaller
|
|
53
|
-
copy of `globals.css` that no code `@import`-ed (only docs referenced
|
|
54
|
-
it). The `./theme.css` entry was removed from `package.json` exports.
|
|
55
|
-
|
|
56
|
-
5. **`packages/ui/scripts/build-tokens-index.mjs` now parses
|
|
57
|
-
`globals.css` only** (instead of theme.css + globals.css). Token
|
|
58
|
-
count went from 163 → **195** because the canonical file now captures
|
|
59
|
-
tokens that previously lived only in `apps/web/app/globals.css`
|
|
60
|
-
(`--header-height`, `--theme-color-chrome`, scoped overlays, etc.).
|
|
61
|
-
Namespace count went from 36 → **41**.
|
|
62
|
-
|
|
63
|
-
## Migration recipe
|
|
64
|
-
|
|
65
|
-
### Internal consumers (this monorepo)
|
|
66
|
-
|
|
67
|
-
Nothing to do. The shells already `@import "@exxatdesignux/ui/globals.css"`.
|
|
68
|
-
|
|
69
|
-
### External consumers (post-publish)
|
|
70
|
-
|
|
71
|
-
If you previously had:
|
|
72
|
-
```css
|
|
73
|
-
/* app/globals.css */
|
|
74
|
-
@import "tailwindcss";
|
|
75
|
-
@import "tw-animate-css";
|
|
76
|
-
@import "@exxatdesignux/ui/theme.css"; /* ❌ no longer exported */
|
|
77
|
-
@source "...";
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
Change it to:
|
|
81
|
-
```css
|
|
82
|
-
/* app/globals.css */
|
|
83
|
-
@import "@exxatdesignux/ui/globals.css"; /* brings Tailwind + tw-animate-css + tokens + base layer */
|
|
84
|
-
@source "../node_modules/@exxatdesignux/ui/src";
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
The package globals.css now carries the `@import "tailwindcss"` /
|
|
88
|
-
`@import "tw-animate-css"` for you — your shell only needs `@source`
|
|
89
|
-
plus any app-specific additions.
|
|
90
|
-
|
|
91
|
-
## Verification
|
|
92
|
-
|
|
93
|
-
- `pnpm --filter @exxatdesignux/ui tokens:index` → 195 tokens / 41 namespaces, no errors.
|
|
94
|
-
- `pnpm --filter @exxat-ds/web lint` → no new violations.
|
|
95
|
-
- Grep for stale `theme.css` references → only this migration + the 0002 link.
|
|
96
|
-
|
|
97
|
-
## Follow-ups (optional)
|
|
98
|
-
|
|
99
|
-
- Document the canonical-file rule in `apps/web/AGENTS.md` § token
|
|
100
|
-
taxonomy (already updated).
|
|
101
|
-
- Add a CI check to `tokens:check` that fails when the consumer shell
|
|
102
|
-
contains anything other than `@import` + `@source` + comments, so the
|
|
103
|
-
shell stays thin.
|
|
104
|
-
|
|
105
|
-
## See also
|
|
106
|
-
|
|
107
|
-
- [`docs/token-taxonomy.md`](../token-taxonomy.md) — layered token model.
|
|
108
|
-
- [`0002-exxat-token-namespace.md`](./0002-exxat-token-namespace.md) — the
|
|
109
|
-
L0 namespace introduction (which now lives in `globals.css`, not
|
|
110
|
-
`theme.css`).
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
# Exxat DS — Migrations
|
|
2
|
-
|
|
3
|
-
**Inspired by:** SLDS [v1 → v2 uplift skill](https://www.lightningdesignsystem.com/2e1ef9c7e/v/1604/p/9929fa-uplift-skill).
|
|
4
|
-
|
|
5
|
-
Every breaking change in `@exxatdesignux/ui` (token rename, component prop
|
|
6
|
-
removal, deprecated pattern) lives here as a numbered migration entry. The
|
|
7
|
-
**first entry of any release that breaks API or tokens** must land alongside
|
|
8
|
-
the change.
|
|
9
|
-
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
## How migrations work
|
|
13
|
-
|
|
14
|
-
```
|
|
15
|
-
docs/migrations/
|
|
16
|
-
├── README.md ← this file (active deprecations + index)
|
|
17
|
-
└── NNNN-<slug>.md ← one file per migration
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
| Field | Meaning |
|
|
21
|
-
|---|---|
|
|
22
|
-
| `NNNN` | Zero-padded 4-digit sequence number (`0001`, `0002`, …) |
|
|
23
|
-
| `<slug>` | Short kebab-case identifier — what is changing |
|
|
24
|
-
|
|
25
|
-
**One file per migration.** Two unrelated changes in the same release get two
|
|
26
|
-
files.
|
|
27
|
-
|
|
28
|
-
---
|
|
29
|
-
|
|
30
|
-
## Lifecycle of a deprecation
|
|
31
|
-
|
|
32
|
-
1. **Plan** — Open a migration file even before the release ships. Author the
|
|
33
|
-
`Why` and `Before/After` sections; leave `Released in` blank.
|
|
34
|
-
2. **Announce** — When the change lands, fill `Released in` (e.g. `v0.3.0`),
|
|
35
|
-
add the `@deprecated` comment in `packages/ui/src/globals.css` or the component file:
|
|
36
|
-
```css
|
|
37
|
-
/* @deprecated v0.3.0 — use --brand-color-dark; remove in v0.4.0 */
|
|
38
|
-
```
|
|
39
|
-
Make sure `pnpm --filter @exxatdesignux/ui tokens:index` picks it up
|
|
40
|
-
(`tokens/hooks-index.json` will mark `deprecated: true`).
|
|
41
|
-
3. **Migrate** — Land the migration script (if scriptable) under
|
|
42
|
-
`packages/ui/scripts/migrate-NNNN-<slug>.mjs`; otherwise document the manual
|
|
43
|
-
grep + replace.
|
|
44
|
-
4. **Remove** — When the deprecation window closes (named in the comment),
|
|
45
|
-
delete the deprecated token / component. Set `Removed in` in the migration
|
|
46
|
-
file. The file stays in the repo forever as a record.
|
|
47
|
-
|
|
48
|
-
---
|
|
49
|
-
|
|
50
|
-
## Active deprecations
|
|
51
|
-
|
|
52
|
-
> _None yet._ Update this table when announcing a deprecation.
|
|
53
|
-
|
|
54
|
-
| Migration | Token / Component | Deprecated in | Remove in |
|
|
55
|
-
|---|---|---|---|
|
|
56
|
-
| — | — | — | — |
|
|
57
|
-
|
|
58
|
-
---
|
|
59
|
-
|
|
60
|
-
## Migration template
|
|
61
|
-
|
|
62
|
-
Copy [`_template.md`](./_template.md) when adding a migration:
|
|
63
|
-
|
|
64
|
-
```
|
|
65
|
-
# Migration NNNN — <Title>
|
|
66
|
-
|
|
67
|
-
> **Released in:** vX.Y.Z · **Removed in:** vX.Y.Z (or "planned") · **Owner:** <person/team>
|
|
68
|
-
|
|
69
|
-
## Why
|
|
70
|
-
…
|
|
71
|
-
## Affected surface
|
|
72
|
-
…
|
|
73
|
-
## Before
|
|
74
|
-
…
|
|
75
|
-
## After
|
|
76
|
-
…
|
|
77
|
-
## Migration recipe
|
|
78
|
-
…
|
|
79
|
-
## Verification
|
|
80
|
-
…
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
---
|
|
84
|
-
|
|
85
|
-
## Index
|
|
86
|
-
|
|
87
|
-
| # | Slug | Released | Removed |
|
|
88
|
-
|---|---|---|---|
|
|
89
|
-
| [0001](./0001-brand-deep-alias-stabilization.md) | `brand-deep-alias-stabilization` | v0.2.18 | — (no removal — stabilization) |
|
|
90
|
-
| [0002](./0002-exxat-token-namespace.md) | `exxat-token-namespace` | v0.2.19 | — (additive — L1 stays) |
|
|
91
|
-
| [0003](./0003-globals-css-canonical.md) | `globals-css-canonical` | v0.2.20 | `theme.css` removed |
|
|
92
|
-
|
|
93
|
-
---
|
|
94
|
-
|
|
95
|
-
## See also
|
|
96
|
-
|
|
97
|
-
- [`token-taxonomy.md`](../token-taxonomy.md) — naming + deprecation policy (§5)
|
|
98
|
-
- [`packages/ui/CHANGELOG.md`](../../../packages/ui/CHANGELOG.md) — release notes
|
|
99
|
-
- [`.cursor/rules/exxat-token-discipline.mdc`](../../../.cursor/rules/exxat-token-discipline.mdc) — lint rule for deprecated tokens
|
|
100
|
-
- [`packages/ui/tokens/hooks-index.json`](../../../packages/ui/tokens/hooks-index.json) — machine-readable index (includes `deprecated: true`)
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
# Migration NNNN — <Title>
|
|
2
|
-
|
|
3
|
-
> **Released in:** vX.Y.Z · **Removed in:** vX.Y.Z (or _planned_) · **Owner:** <person / team>
|
|
4
|
-
> **Type:** token rename · component rename · prop removal · pattern deprecation · stabilization
|
|
5
|
-
|
|
6
|
-
## Why
|
|
7
|
-
|
|
8
|
-
One paragraph. Explain the user-visible or developer-visible problem this
|
|
9
|
-
migration addresses.
|
|
10
|
-
|
|
11
|
-
## Affected surface
|
|
12
|
-
|
|
13
|
-
| Surface | Was | Becomes |
|
|
14
|
-
|---|---|---|
|
|
15
|
-
| Tailwind utility | `text-foo` | `text-bar` |
|
|
16
|
-
| CSS custom prop | `--foo` | `--bar` |
|
|
17
|
-
| React component | `<OldName />` | `<NewName />` |
|
|
18
|
-
| Pattern | … | … |
|
|
19
|
-
|
|
20
|
-
## Before
|
|
21
|
-
|
|
22
|
-
```tsx
|
|
23
|
-
// Old usage
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
## After
|
|
27
|
-
|
|
28
|
-
```tsx
|
|
29
|
-
// New usage
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
## Migration recipe
|
|
33
|
-
|
|
34
|
-
### Automatic
|
|
35
|
-
|
|
36
|
-
```bash
|
|
37
|
-
# Run from the monorepo root.
|
|
38
|
-
node packages/ui/scripts/migrate-NNNN-<slug>.mjs
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
(Or note "manual only — no script.")
|
|
42
|
-
|
|
43
|
-
### Manual
|
|
44
|
-
|
|
45
|
-
1. Search for `<pattern>` across `apps/web/`, `packages/ui/src/`, and
|
|
46
|
-
`packages/ui/template/`.
|
|
47
|
-
2. Replace per the table above.
|
|
48
|
-
3. Re-run `pnpm --filter @exxatdesignux/ui tokens:index`.
|
|
49
|
-
4. Re-run `pnpm --filter @exxat-ds/web lint`.
|
|
50
|
-
|
|
51
|
-
## Verification
|
|
52
|
-
|
|
53
|
-
- [ ] `pnpm typecheck` clean across workspace
|
|
54
|
-
- [ ] `pnpm --filter @exxatdesignux/ui tokens:check` passes
|
|
55
|
-
- [ ] No remaining matches for `<old pattern>` in code search (excluding this
|
|
56
|
-
migration file)
|
|
57
|
-
- [ ] Visual regression sweep on affected hubs (Placements / Team /
|
|
58
|
-
Compliance / Library)
|
|
59
|
-
|
|
60
|
-
## References
|
|
61
|
-
|
|
62
|
-
- `packages/ui/CHANGELOG.md` (vX.Y.Z)
|
|
63
|
-
- Related rule: `.cursor/rules/<rule>.mdc`
|
|
64
|
-
- Related blueprint: `apps/web/docs/blueprints/<blueprint>.md`
|
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
# Modern SaaS patterns — the canon Exxat DS works against
|
|
2
|
-
|
|
3
|
-
> **Audience:** humans + AI agents.
|
|
4
|
-
> **Companion to:** [`exxat-senior-ux/SKILL.md`](../../../.cursor/skills/exxat-senior-ux/SKILL.md),
|
|
5
|
-
> [`exxat-ux-principles.mdc`](../../../.cursor/rules/exxat-ux-principles.mdc),
|
|
6
|
-
> [`jobs/`](./jobs/).
|
|
7
|
-
|
|
8
|
-
A senior designer recognizes the work. This doc names the patterns the best
|
|
9
|
-
products converged on in 2024–2026, so the agent can pattern-match instead
|
|
10
|
-
of inventing. **Cite by name + code** when you reference one in a design brief
|
|
11
|
-
(e.g. `Linear issue detail (M1, M4, M7)`).
|
|
12
|
-
|
|
13
|
-
## Canon products — cite by product, not by URL
|
|
14
|
-
|
|
15
|
-
| Product | What to learn from it |
|
|
16
|
-
|---------|-----------------------|
|
|
17
|
-
| **Linear** | Issue detail, command palette spine, density, keyboard-first, presence, "less chrome" |
|
|
18
|
-
| **Notion** | Inline editing, property panels, page-as-database, blocks, slash-commands |
|
|
19
|
-
| **Stripe Dashboard** | Record home, status chips, activity log, money-grade precision |
|
|
20
|
-
| **Figma** | Multiplayer, presence, side panel inspector, infinite-canvas chrome discipline |
|
|
21
|
-
| **Vercel** | Type-first hierarchy, dark-first, minimal chrome, log streams |
|
|
22
|
-
| **Height** | View tabs (table/board/timeline), custom fields, view parity |
|
|
23
|
-
| **Plain / Pylon** | Support detail = identity + timeline + actions; conversation-as-document |
|
|
24
|
-
| **Cron / Amie** | Keyboard-only flows, dense calendar, command surface |
|
|
25
|
-
| **Raycast** | Command palette as full app, extension surface, deep keyboard |
|
|
26
|
-
| **Arc Browser** | Control-stripped, content-first, sidebar as the only chrome |
|
|
27
|
-
|
|
28
|
-
## The 12 patterns that make products feel modern
|
|
29
|
-
|
|
30
|
-
### M1. Content-first chrome
|
|
31
|
-
The data is the star. Sidebars collapse to icons. Headers stay 48–56px. Page
|
|
32
|
-
surfaces are generous. No purple gradient on the top bar.
|
|
33
|
-
|
|
34
|
-
- **In DS:** `SiteHeader` ~h-12; `PrimaryPageTemplate` body has generous
|
|
35
|
-
`max-w-[1440px]`; sidebar collapsible (`SidebarTrigger`).
|
|
36
|
-
|
|
37
|
-
### M2. Command palette as the spine
|
|
38
|
-
`⌘K` opens search + navigation + AI + recent. It is the primary navigation
|
|
39
|
-
for power users. The sidebar exists for orientation, not speed.
|
|
40
|
-
|
|
41
|
-
- **In DS:** `CommandMenu` (⌘K) + Ask Leo split (⌘⌥K).
|
|
42
|
-
Rule: `exxat-command-menu.mdc`.
|
|
43
|
-
|
|
44
|
-
### M3. Side-panel detail over modal dialog
|
|
45
|
-
For non-destructive context-keeping actions (properties, export, invite,
|
|
46
|
-
preview, single-step compose), use a slide-in sheet — never a centered modal.
|
|
47
|
-
|
|
48
|
-
- **In DS:** `Sheet` (no Vaul).
|
|
49
|
-
Rule: `exxat-drawer-vs-dialog.mdc`. Pattern:
|
|
50
|
-
`apps/web/docs/drawer-vs-dialog-pattern.md`.
|
|
51
|
-
|
|
52
|
-
### M4. Status as a first-class citizen
|
|
53
|
-
Colored dots, chips, counts visible everywhere data appears. Status isn't
|
|
54
|
-
hidden in a detail page; it appears on rows, cards, headers, navigation.
|
|
55
|
-
|
|
56
|
-
- **In DS:** `ListHubStatusBadge` + `lib/list-status-badges.ts`. Available per
|
|
57
|
-
row, board card, detail header, breadcrumb count slot.
|
|
58
|
-
|
|
59
|
-
### M5. Inline editing where data is read
|
|
60
|
-
Click the value, edit it. No bounce to forms for single-field changes.
|
|
61
|
-
|
|
62
|
-
- **In DS:** Inline-edit primitive emerging; until then, use a `Sheet` for
|
|
63
|
-
multi-field, popover or contenteditable for single-field. Principle: P15.
|
|
64
|
-
|
|
65
|
-
### M6. Optimistic UI + undo
|
|
66
|
-
Low-risk actions (favorite, archive, status flip) feel instant; reconcile on
|
|
67
|
-
error. Undo via banner or in-place affordance — **never** toast
|
|
68
|
-
(`exxat-no-toast.mdc`).
|
|
69
|
-
|
|
70
|
-
- **In DS:** Optimistic state in `useTableState` selection ops; undo via
|
|
71
|
-
`LocalBanner` with action.
|
|
72
|
-
|
|
73
|
-
### M7. Activity timeline on every record
|
|
74
|
-
Who did what when. The audit log is also a navigation device.
|
|
75
|
-
|
|
76
|
-
- **In DS:** `ActivityTimeline` primitive emerging. Compose from
|
|
77
|
-
`lib/mock/activity` shape until then.
|
|
78
|
-
|
|
79
|
-
### M8. Empty states with one CTA + one sentence
|
|
80
|
-
Illustration optional. One sentence of context. One primary action. Never a
|
|
81
|
-
wall of help text or a tutorial inline.
|
|
82
|
-
|
|
83
|
-
- **In DS:** `EmptyState` primitive; voice from `docs/voice-and-tone.md`.
|
|
84
|
-
|
|
85
|
-
### M9. Skeleton, not spinner
|
|
86
|
-
Loading shapes content. Spinners only for indeterminate < 200ms.
|
|
87
|
-
|
|
88
|
-
- **In DS:** `Skeleton` primitive; suspense boundaries shape the body.
|
|
89
|
-
|
|
90
|
-
### M10. Type-first hierarchy
|
|
91
|
-
Weight, size, color do the heavy lifting before borders, boxes, or tints.
|
|
92
|
-
Ornament is rare and intentional.
|
|
93
|
-
|
|
94
|
-
- **In DS:** Token scale; body in `Inter`; display in `Ivy Presto` (only on
|
|
95
|
-
`PageHeader` H1 by default).
|
|
96
|
-
|
|
97
|
-
### M11. Real-time presence + collaboration as default
|
|
98
|
-
If the product is shared, show who else is here — face rails, cursors,
|
|
99
|
-
status. Inviting others is one click from the page.
|
|
100
|
-
|
|
101
|
-
- **In DS:** `PageHeader variant="collaboration"` face rail +
|
|
102
|
-
`InviteCollaboratorsDrawer`.
|
|
103
|
-
Rule: `exxat-collaboration-access.mdc`.
|
|
104
|
-
|
|
105
|
-
### M12. AI as opt-in sidecar
|
|
106
|
-
Ask Leo style — never the primary path, never auto-runs on a record, always
|
|
107
|
-
discoverable, always cancellable. Deterministic path still exists.
|
|
108
|
-
|
|
109
|
-
- **In DS:** `AskLeoSidebar` + `⌘⌥K` toggle; never a "magic" button on a
|
|
110
|
-
destructive surface.
|
|
111
|
-
|
|
112
|
-
---
|
|
113
|
-
|
|
114
|
-
## The anti-modern signals (what NOT to do)
|
|
115
|
-
|
|
116
|
-
| Signal | Why it's dated |
|
|
117
|
-
|--------|----------------|
|
|
118
|
-
| Toasts everywhere | Modern products use inline + banner + undo. Toasts get missed. |
|
|
119
|
-
| Full-width tab bars stretched edge-to-edge | 2010s pattern. Modern uses `w-fit` segmented controls. |
|
|
120
|
-
| Centered modals for everything | Sheets and routes carry more without breaking flow. |
|
|
121
|
-
| Color-coded sidebar sections | Modern is monochrome chrome + status color on data. |
|
|
122
|
-
| Modal wizards with progress bar | If it has > 3 steps, give it a route. |
|
|
123
|
-
| Spinners on initial load | Skeleton the content shape instead. |
|
|
124
|
-
| Hover-only affordances | Touch + keyboard need parity. |
|
|
125
|
-
| Icons without text labels in primary nav | Recognition fails for new users. |
|
|
126
|
-
| "Beautiful" gradients on chrome | Data should be beautiful; chrome should disappear. |
|
|
127
|
-
| Aggressive empty-state illustrations | One sentence + one action beats illustration + 5 tips. |
|
|
128
|
-
| Edit-takes-you-to-a-form for single fields | Inline edit (M5). |
|
|
129
|
-
| "Back to <parent>" button alongside breadcrumb | P1 — choose one. |
|
|
130
|
-
| Auto-running AI on record open | M12 — opt-in only. |
|
|
131
|
-
|
|
132
|
-
---
|
|
133
|
-
|
|
134
|
-
## Density layers (Linear / Vercel model)
|
|
135
|
-
|
|
136
|
-
| Layer | When |
|
|
137
|
-
|-------|------|
|
|
138
|
-
| **Cozy** (default) | Most surfaces; balances scan + breathing room |
|
|
139
|
-
| **Compact** | Power users on daily workflow; tables, command results |
|
|
140
|
-
| **Comfortable** | Accessibility (low-vision, motor); marketing-adjacent |
|
|
141
|
-
|
|
142
|
-
Provide a user-level setting where audiences differ; default to **cozy**.
|
|
143
|
-
Don't fork stacks per density.
|
|
144
|
-
|
|
145
|
-
---
|
|
146
|
-
|
|
147
|
-
## How to use this doc in a design brief
|
|
148
|
-
|
|
149
|
-
```
|
|
150
|
-
Reference (modern): Linear issue detail (M1, M4, M7),
|
|
151
|
-
Stripe customer record (M4, M11)
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
Cite the **patterns (Mx)** the agent applied, not just the product. Forces
|
|
155
|
-
clear thinking and lets reviewers verify intent.
|
|
156
|
-
|
|
157
|
-
## See also
|
|
158
|
-
|
|
159
|
-
- [`../../../.cursor/skills/exxat-senior-ux/SKILL.md`](../../../.cursor/skills/exxat-senior-ux/SKILL.md) — persona
|
|
160
|
-
- [`../../../.cursor/rules/exxat-ux-discovery-protocol.mdc`](../../../.cursor/rules/exxat-ux-discovery-protocol.mdc) — brief gate
|
|
161
|
-
- [`../../../.cursor/rules/exxat-ux-principles.mdc`](../../../.cursor/rules/exxat-ux-principles.mdc) — principles + breaks
|
|
162
|
-
- [`./jobs/`](./jobs/) — canonical reference per job type
|
|
163
|
-
- [`./component-selection-guide.md`](./component-selection-guide.md) — picking the composition
|
|
164
|
-
- [`./blueprints/`](./blueprints/) — framework-agnostic surface specs
|
|
165
|
-
- [`./voice-and-tone.md`](./voice-and-tone.md) — copy rules
|