This directory contains comprehensive design specifications and implementation guides for the Credence Frontend application.
-
State Management ⭐ NEW
- Overview of SettingsContext, WalletContext, and ToastProvider
- State shape, public hooks, and persistence mechanisms
- Provider nesting order (load-bearing dependencies)
- Decision guide: when to add new state vs. local vs. URL params
- Mock patterns for testing
-
- How to run Vitest and generate coverage
- Render helpers, router wrapper, and mock patterns for matchMedia / localStorage / clipboard
- File naming conventions and coverage thresholds
-
Per-route document titles (
useDocumentTitle)src/hooks/useDocumentTitle.tskeepsdocument.titlein sync with the active route- Each page sets a distinct, branded title (e.g.
Bond · Credence); the 404 page usesPage Not Found · Credence - Why it matters: screen readers announce the title on navigation, and tabs, history, and bookmarks become distinguishable per page
- SSR-safe (
typeof documentguard), restores the previous title on unmount, and never double-applies the· Credencebrand suffix
import { useDocumentTitle } from '../hooks/useDocumentTitle' function Bond() { useDocumentTitle('Bond') // document.title === 'Bond · Credence' return <main>…</main> }
-
- Consolidated props, Storybook story paths and variants, accessibility notes, usage snippets, styling ownership, and
--credence-*token references for all public shared UI components - Documents severity/variant vocabularies and cross-links focused component docs
- Consolidated props, Storybook story paths and variants, accessibility notes, usage snippets, styling ownership, and
-
- Complete guide for empty states, error states, and loading patterns
- Microcopy guidelines and tone recommendations
- When and how to use each state type
- Validation checklist
-
Form Inputs & Variants ⭐ NEW
- Standardized states (Default, Error, Disabled, Loading) for all input components
- Usage guidelines and accessibility contracts for
AddressInput,AmountInput, and controls
-
- Canonical
--credence-*CSS variable reference - Color, spacing, radius, typography, and motion scales
- Guidance for replacing one-off hex values in components
- Canonical
-
- Motion token strategy and reduced-motion defaults
- Best practices for animation and transitions
- Implementation examples for UI micro-interactions
-
- Visual design specifications
- Color palette and design tokens
- Layout measurements and spacing
- Animation specifications
- Responsive breakpoints
- Component organization structure
-
- Practical code examples for each page
- Reusable hooks and patterns
- Testing examples
- Accessibility guidelines
- Performance considerations
-
Mobile Navigation Pattern ⭐ NEW
- Hybrid responsive navigation (hamburger mobile + horizontal desktop)
- Complete implementation guide with code examples
- Accessibility requirements (WCAG 2.1 AA)
- Testing guide and troubleshooting
- Decision Matrix | Reconnaissance Report | Figma Rules
-
Architecture Overview ⭐ NEW
- Provider tree and routing architecture
- Context responsibilities
- Theming flow and mock data boundaries
-
Keyboard Interactions Contract ⭐ NEW
- Developer-facing matrix of every interactive component and its expected keyboard behavior
- Covers
ConfirmDialog,TierLadder,Banner,Toggle,AddressInput, skip-link, and navigation - Focus-restore contract and checklist for new interactive components
To implement UI states in your components:
import { EmptyState, ErrorState, LoadingSkeleton } from '../components/states'
function MyComponent() {
const { data, isLoading, error } = useQuery()
if (isLoading) return <LoadingSkeleton variant="card" />
if (error) return <ErrorState type="network" />
if (!data) return <EmptyState title="No data" description="..." />
return <Content data={data} />
}-
State Components:
src/components/states/EmptyState.tsx- Empty state componentErrorState.tsx- Error state componentLoadingSkeleton.tsx- Loading skeleton componentindex.ts- Barrel export
-
Navigation Components:
src/components/navigation/(to be implemented)MobileNav.tsx- Hamburger menu + drawer (mobile)DesktopNav.tsx- Horizontal navigation (desktop)NavigationLinks.tsx- Shared navigation datauseMediaQuery.ts- Breakpoint detection hook
- User-First: Always prioritize user understanding and next actions
- Consistent: Use the same patterns across all views
- Helpful: Provide clear guidance and recovery options
- Accessible: Ensure all states work with assistive technologies
- Performant: Show loading states immediately, optimize transitions
When implementing components, check states in this order:
- Loading - Show immediately when data is being fetched
- Error - Show when something goes wrong
- Empty - Show when there's no data to display
- Content - Show the actual content
When adding new states or modifying existing ones:
- Update the relevant component in
src/components/states/ - Document the change in the appropriate guide
- Add implementation examples if needed
- Update Figma designs to match
- Test accessibility and responsiveness
Before shipping new states:
- Review against UI States Guide principles
- Validate microcopy with product team
- Test on mobile, tablet, and desktop
- Verify accessibility with screen readers
- Check loading state transitions
- Ensure error recovery flows work
- Figma File: [Link to be added]
- Component Storybook: Run
npm run storybooklocally - Accessibility Audit: [Link to be added]
For questions about UI states implementation, contact the design team or refer to the detailed guides in this directory.
- Storage key:
credence:settings— the settings context persists a JSON payload under this key inlocalStorage. - Fallback contract: on load the provider attempts to
JSON.parsethe value; if parsing fails or no key exists the provider falls back to built-in defaults (no exception is thrown).
The Credence frontend now has centralized formatting utilities to ensure consistency across all components.
This module is the single source of truth for all USDC formatting logic across the application.
Exported Functions:
// Format numeric USDC amount with "USDC" suffix
formatUsdc(amount: number): string
// Normalize user-entered string to consistent 2-decimal representation
normalizeUSDC(rawValue: string): string
// Format string for display with thousand separators
formatUSDC(rawValue: string): string
// UI display formatter (identical to formatUSDC)
formatUSDCDisplay(rawValue: string): string
// Sanitize user input while preserving valid decimal input
sanitizeUSDCInput(nextValue: string): stringUsage Examples:
import { formatUsdc, normalizeUSDC, formatUSDC, sanitizeUSDCInput } from '@/lib/format'
// Display formatting
formatUsdc(1234.5) // → "1,234.5 USDC"
// Input normalization
normalizeUSDC('1,234.5') // → "1234.50"
// Display formatting from strings
formatUSDC('1234.5') // → "1,234.50"
// Input sanitization
sanitizeUSDCInput('$1,000.50') // → "1000.50"Behavior Preservation:
- Thousands separators maintained for display
- Decimal precision fixed at 2 places
- Empty values handled gracefully
- Negative values clamped to 0 for normalization
- Invalid input returns empty string or original text for correction
This module is the single source of truth for all Stellar address validation and formatting.
Exported Functions:
// Validate Stellar public key format (56 chars, starts with 'G')
isValidStellarAddress(address: string | undefined | null): boolean
// Truncate address for display (first 12 + ... + last 8 chars)
truncateAddress(address: string | undefined | null): stringUsage Examples:
import { isValidStellarAddress, truncateAddress } from '@/lib/stellar'
// Address validation
isValidStellarAddress('GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWNA') // → true
// Address truncation
truncateAddress('GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWNA')
// → "GAAZI4TCR3TY...CCWNA"Behavior Preservation:
- Exact 56-character validation
- 'G' prefix requirement
- Uppercase alphanumeric characters only
- Short addresses (<20 chars) displayed unchanged
- Whitespace trimmed automatically
- Null/undefined values handled gracefully
All components should now import from these centralized modules instead of maintaining local implementations:
Before:
// In component files
export function normalizeUSDC(rawValue: string) { ... }
export function isValidStellarAddress(address: string) { ... }After:
// Import from centralized modules
import { normalizeUSDC } from '@/lib/format'
import { isValidStellarAddress } from '@/lib/stellar'Both utility modules have comprehensive test suites with ≥95% branch coverage:
src/lib/format.test.ts- USDC formatting testssrc/lib/stellar.test.ts- Stellar address tests
Run tests with:
npm test -- --run src/lib/format.test.ts src/lib/stellar.test.tsThe following components have been refactored to use the centralized utilities:
- AmountInput.tsx - USDC input formatting and sanitization
- AddressInput.tsx - Stellar address validation and truncation
- TrustScore.tsx - Stellar address validation
- useTrustScore.ts - Stellar address validation
- Bond.tsx - USDC display formatting
- Dashboard.tsx - USDC display formatting
- penalty.ts - USDC display formatting
- bondPenalty.ts - USDC display formatting
When adding new formatting or validation logic:
- Check if it belongs in the centralized modules
- Add comprehensive test coverage
- Update this documentation
- Refactor any existing duplicate implementations