# UX Implementation Guide > **Purpose:** Comprehensive guide for UX implementation across ByteLyst products using common platform UI packages, design tokens, and Cipher design system integration. > **Target Audience:** Product teams implementing UX improvements and testing infrastructure. > **Product:** ChronoMind - AI-powered contextual clock & timer --- ## Overview This guide documents the complete UX implementation approach for ChronoMind, replicating the patterns established in the trading dashboard. The approach covers: - **Common Platform UI Integration** - Leveraging `@bytelyst/ui` shared primitives - **Design Token Usage** - Using `@bytelyst/design-tokens` for consistent styling - **Component Normalization** - Replacing one-off components with shared primitives - **Accessibility Improvements** - Keyboard navigation, ARIA labels, focus management - **Responsive Design** - Viewport matrix testing, shell breakpoints - **Testing Infrastructure** - Playwright E2E tests, Storybook, AI-friendly reports - **Cipher Design System** - Visual hierarchy, spacing, typography principles --- ## Part 1: Common Platform UI Integration ### Local Package Resolution **Critical:** Use local common platform packages by default, not Gitea registry. **File:** `.pnpmfile.cjs` ```javascript // .pnpmfile.cjs // Default to local common platform packages function readPackage(pkg, context) { if (!context.workspace) return pkg; // Default to common-plat (local packages) const packageSource = process.env.BYTELYST_PACKAGE_SOURCE || 'common-plat'; if (packageSource === 'common-plat') { // Resolve @bytelyst/* packages from local common platform if (pkg.name.startsWith('@bytelyst/')) { pkg.dependencies = pkg.dependencies || {}; pkg.dependencies[pkg.name] = 'workspace:*'; } } return pkg; } module.exports = { name: 'bytelyst-package-source', hooks: { readPackage, }, }; ``` **File:** `.npmrc` ```ini # Remove repo-level GITEA_NPM_TOKEN interpolation # Gitea registry auth should live in user-level ~/.npmrc or CI secrets # Only when BYTELYST_PACKAGE_SOURCE=gitea is explicitly used ``` ### Environment Variables ```bash # Default: Use local common platform packages BYTELYST_PACKAGE_SOURCE=common-plat # Optional: Use Gitea registry (requires auth) BYTELYST_PACKAGE_SOURCE=gitea # GITEA_NPM_TOKEN should be in ~/.npmrc or CI secrets ``` ### Verification Commands ```bash # Verify local package resolution pnpm install @bytelyst/ui @bytelyst/design-tokens # Verify packages resolve from local common platform pnpm list @bytelyst/ui # Should show: @bytelyst/ui -> link:../learning_ai_common_plat/packages/ui ``` ### Product Adapter Pattern Create a product adapter to normalize imports and extend shared primitives with product-specific variants: **File:** `web/src/components/ui/Primitives.tsx` ```typescript import * as React from 'react'; import { Badge as CommonBadge, Button as CommonButton, Input as CommonInput, Select as CommonSelect, type BadgeProps as CommonBadgeProps, type ButtonProps as CommonButtonProps, type InputProps as CommonInputProps, type SelectProps as CommonSelectProps, } from '@bytelyst/ui'; // Re-export all shared primitives export { ActionMenu, AlertBanner, DataList, DataTable, Drawer, EmptyState, Modal, PageHeader, Panel, Skeleton, Timeline, Toolbar, // ... all other @bytelyst/ui components } from '@bytelyst/ui'; // Define product-specific variants for ChronoMind type ProductButtonVariant = NonNullable | 'link'; type ProductButtonSize = NonNullable | 'icon'; type ProductFieldVariant = 'surface' | 'muted'; type ProductFieldSize = 'sm' | 'md'; type ProductBadgeVariant = NonNullable | 'danger'; type ProductStatusTone = 'success' | 'warning' | 'error' | 'info' | 'neutral'; // Extend interfaces with product-specific props export interface ButtonProps extends Omit { variant?: ProductButtonVariant; size?: ProductButtonSize; } export interface IconButtonProps extends Omit { icon: React.ReactNode; label: string; } export interface InputProps extends CommonInputProps { controlSize?: ProductFieldSize; variant?: ProductFieldVariant; } // ChronoMind-specific status mapping for badges export type ChronoMindStatus = | 'running' | 'paused' | 'stopped' | 'completed' | 'alarm' | 'snoozed' | 'overdue' | 'upcoming' | 'recurring' | 'one-time' | 'focus' | 'break' | 'pomodoro' | 'routine' | 'error' | 'success'; const chronomindStatusTone: Record = { running: 'success', paused: 'warning', stopped: 'neutral', completed: 'success', alarm: 'error', snoozed: 'warning', overdue: 'error', upcoming: 'info', recurring: 'info', 'one-time': 'neutral', focus: 'success', break: 'info', pomodoro: 'success', routine: 'info', error: 'error', success: 'success', }; // Helper function to map timer status to tone export function statusToneFor(status: ChronoMindStatus | string | null | undefined): ProductStatusTone { if (!status) return 'neutral'; const normalized = status.trim().toLowerCase().replace(/[\s_]+/g, '-') as ChronoMindStatus; return chronomindStatusTone[normalized] ?? 'neutral'; } // Product-specific component implementations export const Button = React.forwardRef( ({ variant = 'primary', size = 'md', className, ...props }, ref) => ( ), ); export const IconButton = React.forwardRef( ({ icon, label, variant = 'ghost', size = 'icon', className, ...props }, ref) => ( ), ); export const Input = React.forwardRef( ({ controlSize = 'md', variant = 'surface', className, ...props }, ref) => ( ), ); export function ChronoMindStatusBadge({ status, children, }: { status: ChronoMindStatus | string | null | undefined; children?: React.ReactNode; }) { return ( {children ?? status ?? 'Unknown'} ); } ``` **Benefits of Product Adapter Pattern:** - Centralized import point for all UI components - Product-specific variants without modifying common platform - Consistent styling across the application - Easy to migrate to new common platform versions - Type-safe extensions with TypeScript --- ## Part 2: Design Token Usage ### CSS Variable Integration Use design tokens from `@bytelyst/design-tokens` via CSS custom properties with ChronoMind-specific prefixes: ```css /* Surface colors */ background: var(--cm-surface-card); background: var(--cm-surface-muted); background: var(--cm-surface-overlay); /* Text colors */ color: var(--cm-text-primary); color: var(--cm-text-secondary); color: var(--cm-text-muted); /* Border colors */ border-color: var(--cm-border); border-color: var(--cm-border-muted); /* Input styling */ background: var(--cm-input); color: var(--cm-text-primary); border-color: var(--cm-border); /* Focus states */ border-color: var(--cm-focus-ring); box-shadow: 0 0 0 2px var(--cm-focus-ring-muted); /* Semantic colors */ color: var(--cm-accent); background: var(--cm-success); background: var(--cm-warning); background: var(--cm-error); /* Spacing */ padding: var(--cm-spacing-sm); padding: var(--cm-spacing-md); padding: var(--cm-spacing-lg); padding: var(--cm-spacing-xl); /* Border radius */ border-radius: var(--cm-radius-control); border-radius: var(--cm-radius-md); border-radius: var(--cm-radius-lg); /* Typography */ font-size: var(--cm-text-sm); font-size: var(--cm-text-base); font-size: var(--cm-text-lg); font-weight: var(--cm-font-medium); font-weight: var(--cm-font-semibold); ``` ### Component Token Patterns **Example: Badge Component for ChronoMind** ```typescript // Using design tokens for badge styling const badgeStyles = { success: { background: 'var(--cm-success-light)', color: 'var(--cm-success-dark)', borderColor: 'var(--cm-success)', }, warning: { background: 'var(--cm-warning-light)', color: 'var(--cm-warning-dark)', borderColor: 'var(--cm-warning)', }, error: { background: 'var(--cm-error-light)', color: 'var(--cm-error-dark)', borderColor: 'var(--cm-error)', }, }; ``` --- ## Part 3: Component Normalization ### Badge Normalization **Before:** One-off CSS classes for different badge styles ```css /* Old approach - one-off classes */ .timer-chip { background: #f0f0f0; padding: 4px 8px; border-radius: 4px; font-size: 12px; } .category-tag { background: #e0e0e0; padding: 6px 12px; border-radius: 6px; } .status-pill { background: #d0d0d0; padding: 5px 10px; border-radius: 20px; } ``` **After:** Shared Badge component from product adapter ```typescript import { Badge, ChronoMindStatusBadge } from '../components/ui/Primitives'; // Replace .timer-chip with Badge Running // Replace .category-tag with Badge Work // Replace .status-pill with ChronoMindStatusBadge ``` ### Alert Banner Unification **Before:** Different alert implementations across components ```typescript // TimerCard.tsx - custom alert
⚠️ Warning message
// RoutineEditor.tsx - different alert
!
Warning text
``` **After:** Shared AlertBanner component ```typescript import { AlertBanner } from '../components/ui/Primitives'; // Both components now use shared AlertBanner Warning message Error message ``` ### Table Controls Standardization **Before:** Custom table controls with inconsistent styling ```typescript // Different button styles across tables ``` **After:** Standardized Button component ```typescript import { Button, IconButton } from '../components/ui/Primitives'; // Consistent button styles } label="Complete" /> ``` --- ## Part 4: Accessibility Improvements ### Keyboard Navigation **Focus Management** ```typescript // Ensure interactive elements are focusable ``` **Keyboard Toggles** ```typescript
{ if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); toggle(); } }} aria-pressed={isActive} > Toggle Option
``` ### ARIA Labels **Button Labels** ```typescript // Icon buttons need explicit labels } label="Start timer" aria-label="Start timer" /> ``` **Status Indicators** ```typescript // Status badges need descriptive labels Running ``` **Form Labels** ```typescript // All inputs need associated labels ``` ### Focus Indicators **Visible Focus States** ```css /* Ensure focus is visible */ *:focus-visible { outline: 2px solid var(--cm-focus-ring); outline-offset: 2px; } /* Or use design token */ *:focus-visible { outline: 2px solid var(--cm-focus-ring); box-shadow: 0 0 0 2px var(--cm-focus-ring-muted); } ``` --- ## Part 5: Responsive Design ### Shell Breakpoints **Responsive Shell Testing** ```typescript const breakpoints = { mobile: 'max-width: 560px', tablet: 'max-width: 768px', desktop: 'min-width: 769px', }; // Shell adapts at these breakpoints @media (max-width: 560px) { .timer-main { margin-left: 0; } .timer-right-panel { display: none; } .timer-sidebar { position: fixed; bottom: 0; width: 100%; height: 60px; } } ``` ### Viewport Matrix Testing **Test all routes across viewports** ```typescript const routes = ['/dashboard', '/focus', '/history', '/routines', '/settings']; const viewports = [ { name: 'Desktop', width: 1200, height: 800 }, { name: 'Tablet', width: 768, height: 1024 }, { name: 'Mobile', width: 375, height: 667 }, ]; routes.forEach((route) => { viewports.forEach((viewport) => { test(`${route} - ${viewport.name} viewport`, async ({ page }) => { await page.setViewportSize({ width: viewport.width, height: viewport.height }); await page.goto(route); // Check for horizontal overflow const bodyWidth = await page.evaluate(() => document.body.scrollWidth); expect(bodyWidth).toBeLessThanOrEqual(viewport.width + 10); // Check main content visibility const mainContent = page.locator('main'); await expect(mainContent).toBeVisible(); }); }); }); ``` --- ## Part 6: Testing Infrastructure ### Playwright Setup **Install Dependencies** ```bash cd web pnpm add -D @playwright/test pnpm exec playwright install chromium ``` **Create Playwright Config** Create `web/playwright.config.ts`: ```typescript import { defineConfig, devices } from '@playwright/test'; export default defineConfig({ testDir: './e2e', fullyParallel: true, forbidOnly: !!process.env.CI, retries: process.env.CI ? 2 : 0, workers: process.env.CI ? 1 : undefined, reporter: 'html', use: { baseURL: 'http://localhost:3030', trace: 'on-first-retry', screenshot: 'only-on-failure', }, projects: [ { name: 'chromium', use: { ...devices['Desktop Chrome'] } }, { name: 'firefox', use: { ...devices['Desktop Firefox'] } }, { name: 'webkit', use: { ...devices['Desktop Safari'] } }, { name: 'Mobile Chrome', use: { ...devices['Pixel 5'] } }, { name: 'Mobile Safari', use: { ...devices['iPhone 12'] } }, ], }); ``` ### Test Suite Structure Create tests in `web/e2e/` directory: ``` web/e2e/ ├── viewport-matrix.spec.ts # Viewport compliance ├── horizontal-overflow.spec.ts # Overflow detection ├── alert-positioning.spec.ts # Critical alerts positioning ├── timer-flows.spec.ts # Timer start/pause/stop flows ├── page-states.spec.ts # Loading/empty/error/success states ├── form-validation.spec.ts # Form validation └── keyboard-navigation.spec.ts # Keyboard navigation ``` --- ## Part 7: Cipher Design System Integration ### Design Principles Follow Cipher design system principles for consistent UX across ChronoMind: #### 1. Visual Hierarchy **Size and Weight** ```typescript // Use design tokens for consistent hierarchy

Timer Title

Section Header

Timer content

``` #### 2. Spacing System **Consistent Spacing** ```typescript // Use design token spacing
Content
``` #### 3. Typography **Font Scales** ```typescript // Use design token font sizes const textStyles = { xs: 'var(--cm-text-xs)', sm: 'var(--cm-text-sm)', base: 'var(--cm-text-base)', lg: 'var(--cm-text-lg)', xl: 'var(--cm-text-xl)', '2xl': 'var(--cm-text-2xl)', };

Body text

``` #### 4. Color System **Semantic Colors** ```typescript // Use semantic color tokens, not literal colors const statusColors = { success: 'var(--cm-success)', warning: 'var(--cm-warning)', error: 'var(--cm-error)', info: 'var(--cm-info)', };
Success message
``` --- ## Part 8: Implementation Roadmap ### Phase 1: Foundation Setup **Week 1-2** - [ ] Set up local package resolution (.pnpmfile.cjs) - [ ] Remove repo-level GITEA_NPM_TOKEN from .npmrc - [ ] Install common platform packages from local source - [ ] Create product adapter (`Primitives.tsx`) - [ ] Set up design token integration - [ ] Configure Playwright ### Phase 2: Component Normalization **Week 3-4** - [ ] Replace one-off badges with Badge component - [ ] Replace custom buttons with Button component - [ ] Replace custom alerts with AlertBanner component - [ ] Replace custom inputs with Input component - [ ] Remove old CSS classes ### Phase 3: Design Token Migration **Week 5-6** - [ ] Identify hardcoded colors - [ ] Map to semantic tokens - [ ] Replace with CSS variables - [ ] Test across themes - [ ] Audit for missed tokens ### Phase 4: Accessibility Improvements **Week 7** - [ ] Add keyboard navigation - [ ] Add ARIA labels - [ ] Improve focus indicators - [ ] Test with screen readers ### Phase 5: Responsive Design **Week 8** - [ ] Test viewport matrix - [ ] Fix horizontal overflow - [ ] Optimize mobile layout - [ ] Test breakpoints ### Phase 6: Testing Infrastructure **Week 9-10** - [ ] Create E2E test suite - [ ] Set up test runner script - [ ] Configure AI-friendly reports - [ ] Integrate with CI --- ## Part 9: Verification Commands ### Type Checking ```bash # Verify TypeScript types pnpm run typecheck ``` ### Build Verification ```bash # Ensure build succeeds pnpm run build ``` ### Test Execution ```bash # Run all E2E tests cd web pnpm test:e2e # Run specific test suites pnpm test:e2e:viewport pnpm test:e2e:overflow pnpm test:e2e:timer-flows ``` --- ## Summary This guide provides a comprehensive approach to implementing UX improvements for ChronoMind using the ByteLyst common platform UI packages, design tokens, and Cipher design system. By following these patterns, ChronoMind will achieve: - Consistent UI with other ByteLyst products - Improved accessibility and keyboard navigation - Responsive design across all viewports - Comprehensive testing infrastructure - Maintainable and scalable codebase The implementation is organized in phases to allow for incremental adoption and verification at each stage.