From 195d1bded4e3bccfcdf2c289137a3394ec69267e Mon Sep 17 00:00:00 2001
From: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
Date: Wed, 14 Oct 2026 19:41:18 +0800
Subject: [PATCH] feat(frontend): refine shadcn UI foundations
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
---
.../refine-shadcn-ui-foundation/design.md | 32 +++++
.../refine-shadcn-ui-foundation/proposal.md | 26 ++++
.../specs/shared-ui-foundation/spec.md | 61 +++++++++
.../refine-shadcn-ui-foundation/tasks.md | 14 ++
web/components.json | 7 +-
web/e2e/fixtures/ui-foundation.html | 2 +
web/e2e/fixtures/ui-foundation.tsx | 44 +++++++
web/e2e/ui-foundation.spec.ts | 91 +++++++++++++
web/src/index.css | 39 +++++-
web/src/shared/ui/button.test.ts | 6 +-
web/src/shared/ui/button.tsx | 6 +-
web/src/shared/ui/card.tsx | 12 +-
web/src/shared/ui/input.tsx | 2 +-
web/src/shared/ui/select.test.ts | 2 +-
web/src/shared/ui/select.tsx | 4 +-
web/src/shared/ui/table.tsx | 4 +-
web/src/shared/ui/tabs.behavior.test.tsx | 123 ++++++++++++++++++
web/src/shared/ui/tabs.tsx | 101 +++++++++++---
web/src/shared/ui/textarea.tsx | 2 +-
web/tailwind.config.ts | 34 +++--
20 files changed, 545 insertions(+), 67 deletions(-)
create mode 100644 openspec/changes/refine-shadcn-ui-foundation/design.md
create mode 100644 openspec/changes/refine-shadcn-ui-foundation/proposal.md
create mode 100644 openspec/changes/refine-shadcn-ui-foundation/specs/shared-ui-foundation/spec.md
create mode 100644 openspec/changes/refine-shadcn-ui-foundation/tasks.md
create mode 100644 web/e2e/fixtures/ui-foundation.html
create mode 100644 web/e2e/fixtures/ui-foundation.tsx
create mode 100644 web/e2e/ui-foundation.spec.ts
create mode 100644 web/src/shared/ui/tabs.behavior.test.tsx
diff --git a/openspec/changes/refine-shadcn-ui-foundation/design.md b/openspec/changes/refine-shadcn-ui-foundation/design.md
new file mode 100644
index 00000000..e7388e8d
--- /dev/null
+++ b/openspec/changes/refine-shadcn-ui-foundation/design.md
@@ -0,0 +1,32 @@
+## Approach
+
+Keep component source in `web/src/shared/ui` and use explicit shadcn aliases for UI, composition,
+utilities and hooks. Compare compatible upstream source before adapting individual components;
+existing APIs, variants, native attributes, refs and event behavior remain the compatibility baseline.
+
+CSS custom properties own semantic colors, fonts and density. Tailwind consumes these properties.
+Regular density remains the default; `data-density="compact"` changes control height and surface
+spacing without shrinking default control text. Explicit caller classes and styles remain effective.
+Table headings and cells share horizontal padding. Portal content must retain usable independent sizing.
+
+Preserve self-hosted Inter and JetBrains Mono and platform-appropriate fallback fonts. Provide semantic
+status colors in both themes, visible focus and invalid styling, and reduced-motion treatment.
+
+Keep the existing Tabs API and panel mounting behavior. Navigate enabled triggers in their rendered
+order with arrow keys and Home/End; respect horizontal direction. A valid enabled selection is the
+tab stop, otherwise the first enabled trigger is. Recomputing a tab stop must not change selection
+or invoke `onValueChange`. An entirely disabled list has no actionable tab stop. Trigger IDs/aria-controls and panel IDs/aria-labelledby
+are reserved for the generated association; other supported native attributes and refs remain available.
+
+## Validation
+
+Use component behavior tests and an isolated browser fixture for keyboard, density and validation
+contracts. Verify light/dark and regular/compact combinations plus representative page layouts.
+Keep test fixtures out of production entry points. Actual backend smoke results are reported separately
+from UI fixtures; successful frontend tests alone do not establish backend integration health.
+
+## Risks
+
+Shared font and spacing changes affect many callers. Check existing variants and explicit class/style
+overrides, table alignment, nested portals and responsive layouts before accepting the change.
+No dependency migration or global component replacement is required.
diff --git a/openspec/changes/refine-shadcn-ui-foundation/proposal.md b/openspec/changes/refine-shadcn-ui-foundation/proposal.md
new file mode 100644
index 00000000..9b87d3f6
--- /dev/null
+++ b/openspec/changes/refine-shadcn-ui-foundation/proposal.md
@@ -0,0 +1,26 @@
+## Why
+
+Shared controls need a consistent foundation for future page work. The current shadcn configuration
+does not explicitly resolve the UI directory, CSS and Tailwind disagree on the sans-serif font,
+and shared controls do not expose a consistent density or validation treatment. Tabs also need
+complete basic keyboard navigation while preserving optional controlled and uncontrolled values.
+
+## What Changes
+
+- Resolve shadcn aliases to the existing shared directories without replacing component APIs.
+- Align self-hosted fonts and semantic light/dark tokens, and add regular/compact container density.
+- Apply shared density, focus and invalid states to existing controls, cards and tables.
+- Complete Tabs keyboard navigation and retain an entry point when selection is absent or invalid.
+- Add behavior-focused regression coverage and verify representative existing pages.
+
+## Capabilities
+
+### New Capabilities
+
+- `shared-ui-foundation`: shared theme, density, component compatibility and keyboard behavior.
+
+## Impact
+
+Changes are limited to frontend configuration, theme, shared UI components and regression tests.
+React 19, Tailwind 3, existing Radix primitives and current business behavior are retained.
+This change does not redesign business pages or add a global shortcut system.
diff --git a/openspec/changes/refine-shadcn-ui-foundation/specs/shared-ui-foundation/spec.md b/openspec/changes/refine-shadcn-ui-foundation/specs/shared-ui-foundation/spec.md
new file mode 100644
index 00000000..eb665f72
--- /dev/null
+++ b/openspec/changes/refine-shadcn-ui-foundation/specs/shared-ui-foundation/spec.md
@@ -0,0 +1,61 @@
+## ADDED Requirements
+
+### Requirement: Component generation uses existing shared directories
+The project SHALL configure shadcn aliases to generate UI primitives into `src/shared/ui` and
+resolve imports using the existing TypeScript and Vite aliases.
+
+#### Scenario: Preview a new component
+- **WHEN** a representative component is previewed with the compatible CLI
+- **THEN** its UI file resolves into `src/shared/ui`, without a nested `ui/ui` directory
+- **AND** dependencies and source changes can be reviewed before applying them
+
+### Requirement: Shared theme and density are consistent
+The frontend SHALL use consistent self-hosted font families and semantic light/dark colors.
+Shared controls SHALL support regular and compact container density without reducing default text size.
+
+#### Scenario: Switch density
+- **WHEN** a container switches from regular to compact
+- **THEN** default controls change from 36px to 32px and card/table spacing follows the shared density
+- **AND** table heading and data text remain horizontally aligned
+- **AND** caller-provided class and style overrides remain effective
+
+#### Scenario: Validation and reduced motion
+- **WHEN** a form control is invalid or receives keyboard focus
+- **THEN** it has visible invalid or focus treatment appropriate to the selected theme
+- **WHEN** reduced motion is requested
+- **THEN** nonessential shared control motion is suppressed
+
+### Requirement: Existing component contracts remain compatible
+Shared component changes SHALL retain existing variants, native attributes, refs, events, controlled
+and uncontrolled values, form semantics, portal behavior and panel mounting behavior.
+
+#### Scenario: Reuse an existing button variant
+- **WHEN** a page renders an existing variant such as `soft`
+- **THEN** the variant remains available and existing caller attributes are honored
+
+### Requirement: Tabs are keyboard accessible
+Tabs SHALL support arrow-key navigation, Home/End and disabled-item skipping using the current
+horizontal direction. At least one enabled trigger SHALL provide a keyboard entry when available.
+
+#### Scenario: Navigate enabled tabs
+- **WHEN** the user presses a navigation key on a tab
+- **THEN** focus and selection follow the intended enabled trigger in rendered order
+- **AND** disabled triggers are skipped
+
+#### Scenario: Missing or invalid selection
+- **WHEN** selection is absent, invalid, removed or disabled and an enabled trigger exists
+- **THEN** the first enabled trigger remains reachable with Tab
+- **AND** establishing that entry does not change selection or invoke the selection callback
+
+#### Scenario: All triggers are disabled
+- **WHEN** every trigger is disabled
+- **THEN** no trigger is exposed as an actionable keyboard entry
+
+### Requirement: Regression evidence is repeatable
+The change SHALL include repeatable component regression tests and pass relevant frontend checks.
+Browser fixtures SHALL be separate from production entry points.
+
+#### Scenario: Validate component behavior independently
+- **WHEN** the component fixture is tested without a backend
+- **THEN** keyboard and density assertions run against actual shared components
+- **AND** the result is described as component verification rather than backend acceptance
diff --git a/openspec/changes/refine-shadcn-ui-foundation/tasks.md b/openspec/changes/refine-shadcn-ui-foundation/tasks.md
new file mode 100644
index 00000000..838220be
--- /dev/null
+++ b/openspec/changes/refine-shadcn-ui-foundation/tasks.md
@@ -0,0 +1,14 @@
+## Implementation
+
+- [x] 1. Inspect existing components, callers, tokens and compatible shadcn configuration.
+- [x] 2. Correct aliases and verify CLI project information and a representative dry-run.
+- [x] 3. Align fonts, semantic colors, density and shared validation/focus treatment.
+- [x] 4. Complete Tabs navigation and missing-selection keyboard entry behavior.
+- [x] 5. Add repeatable behavior and browser regression tests.
+
+## Verification
+
+- [x] 6. Pass relevant frontend typecheck, lint, unit tests and production build.
+- [x] 7. Verify light/dark, regular/compact and desktop/mobile component behavior.
+- [x] 8. Check representative existing pages, overrides and production entry isolation.
+- [x] 9. Record actual verification results and any unverified integration layers.
diff --git a/web/components.json b/web/components.json
index 7d38f61b..290cfae9 100644
--- a/web/components.json
+++ b/web/components.json
@@ -10,7 +10,10 @@
"cssVariables": true
},
"aliases": {
- "components": "@/shared/ui",
- "utils": "@/shared/lib/utils"
+ "components": "@/shared/components",
+ "ui": "@/shared/ui",
+ "utils": "@/shared/lib/utils",
+ "lib": "@/shared/lib",
+ "hooks": "@/shared/hooks"
}
}
diff --git a/web/e2e/fixtures/ui-foundation.html b/web/e2e/fixtures/ui-foundation.html
new file mode 100644
index 00000000..125f22d7
--- /dev/null
+++ b/web/e2e/fixtures/ui-foundation.html
@@ -0,0 +1,2 @@
+
+