platform-codebase/@packages/@providers/attribute-ui/COMPONENT_OVERVIEW.md
Lilith 134e1f5506 Add comprehensive attribute system expansions
- Add attribute-ui provider package for reusable UI components
- Add data types for attribute definitions
- Add 17 new attribute category migrations (interests, values, personality,
  scheduling, safety, appearance, communication, cultural, accessibility,
  technology, aesthetic, entertainment, food, social, kinks, professional, home)
- Update ProfileAttributeEditor component
- Update frontend tsconfig

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-30 23:27:36 -08:00

10 KiB

MetaCategoryNavigator Component Overview

Created: 2025-12-30 Package: @lilith/attribute-ui Location: /var/home/lilith/Code/@applications/@lilith/lilith-platform/codebase/@packages/@providers/attribute-ui

Component Summary

The MetaCategoryNavigator is a fully accessible, responsive navigation component for browsing attribute definitions organized by meta-category. It supports both mobile (accordion) and desktop (sidebar) layouts.

Key Features

1. Seven Meta-Categories

Displays all 7 meta-categories from the attribute system:

  • Essentials () - Core profile info
  • Appearance (👁️) - Physical characteristics
  • Services (📅) - What creators offer
  • Personality (❤️) - Beyond physical appearance
  • Professional (💼) - Work and education
  • Kinks & Fetishes (🔥) - BDSM and specialties
  • Lifestyle Details (🏠) - Hobbies and living

2. Smart Highlighting

  • Visual indication of selected categories
  • Attribute count badges per category
  • Priority breakdown (essential/recommended/optional)

3. Responsive Layouts

Accordion (Mobile)

  • Collapsible sections
  • Tap to expand/collapse
  • Shows category description and stats when expanded
  • Smooth animations

Sidebar (Desktop)

  • Fixed width navigation
  • Selected category indicator
  • Global summary statistics
  • Sticky positioning for long pages

4. Accessibility First

  • Semantic HTML (<nav>, <button>)
  • ARIA attributes (role, aria-expanded, aria-controls, aria-label)
  • Keyboard navigation
  • Focus indicators
  • Screen reader announcements
  • High contrast mode support
  • Reduced motion support

5. Integration with Hooks

Uses useMetaCategorizedAttributes from @lilith/attribute-hooks:

  • Fetches attribute definitions by entity type
  • Filters by active status
  • Returns pre-organized category structure with counts

Component Structure

attribute-ui/
├── src/
│   ├── components/
│   │   ├── MetaCategoryNavigator.tsx  ← Main component
│   │   ├── VirtualizedCheckboxList.tsx
│   │   └── index.ts
│   └── index.ts
├── package.json
├── tsconfig.json
└── README.md

Props API

interface MetaCategoryNavigatorProps {
  // Optional entity type filter
  entityType?: EntityType

  // Categories to highlight (controlled state)
  selectedCategories?: MetaCategory[]

  // Click handler for filtering
  onCategoryClick?: (category: MetaCategory) => void

  // Layout mode
  variant?: 'accordion' | 'sidebar'

  // Show attribute counts
  showCounts?: boolean

  // Custom styling
  className?: string
}

Usage Examples

Basic Accordion (Mobile)

import { MetaCategoryNavigator } from '@lilith/attribute-ui'

function MobileNav() {
  const [selected, setSelected] = useState<MetaCategory>()

  return (
    <MetaCategoryNavigator
      entityType="USER"
      selectedCategories={selected ? [selected] : []}
      onCategoryClick={setSelected}
      variant="accordion"
      showCounts={true}
    />
  )
}

Sidebar with Filter Integration

import { MetaCategoryNavigator } from '@lilith/attribute-ui'
import { useState } from 'react'

function ProfileEditor() {
  const [filters, setFilters] = useState<{ metaCategory?: MetaCategory }>({})

  const handleCategoryClick = (category: MetaCategory) => {
    setFilters(prev => ({
      ...prev,
      metaCategory: prev.metaCategory === category ? undefined : category
    }))
  }

  return (
    <div className="grid grid-cols-[240px_1fr] gap-6">
      <MetaCategoryNavigator
        entityType="USER"
        selectedCategories={filters.metaCategory ? [filters.metaCategory] : []}
        onCategoryClick={handleCategoryClick}
        variant="sidebar"
      />

      <div>
        {/* Attribute list filtered by filters.metaCategory */}
      </div>
    </div>
  )
}

Responsive (Both Variants)

function ResponsiveNav() {
  return (
    <>
      {/* Mobile */}
      <MetaCategoryNavigator
        variant="accordion"
        className="md:hidden"
      />

      {/* Desktop */}
      <MetaCategoryNavigator
        variant="sidebar"
        className="hidden md:block"
      />
    </>
  )
}

Data Flow

useMetaCategorizedAttributes(entityType, { isActive: true })
  ↓
MetaCategorizedAttributes {
  totalCount: number
  priorityCounts: { essential, recommended, optional }
  categories: [
    {
      metaCategory: 'essentials'
      label: 'Essentials'
      description: '...'
      count: 15
      byPriority: {
        essential: [...],
        recommended: [...],
        optional: [...]
      }
    },
    ...
  ]
}
  ↓
MetaCategoryNavigator renders categories
  ↓
User clicks category
  ↓
onCategoryClick(metaCategory) callback
  ↓
Parent updates filters/selected state

Styling Architecture

The component uses inline styles for portability and zero-configuration usage. This approach:

Advantages

No build-time CSS processing required Works immediately on import No CSS naming conflicts Easy to override with className

Responsive Breakpoints

  • Mobile: < 640px (stacked, smaller padding)
  • Desktop: ≥ 1024px (sticky sidebar)

Theme Integration

To integrate with a theme system:

// Option 1: Override with className
<MetaCategoryNavigator className="custom-theme" />

// Option 2: Wrap with styled component
const ThemedNavigator = styled(MetaCategoryNavigator)`
  .category-header {
    background: ${props => props.theme.colors.surface};
  }
`

Accessibility Features

Keyboard Navigation

  • Tab - Focus next category
  • Enter/Space - Toggle accordion or select category
  • Shift+Tab - Focus previous category

Screen Reader Announcements

  • Category name and count announced on focus
  • Expanded/collapsed state for accordion
  • "Selected category" indicator for sidebar

Visual Accessibility

  • 4.5:1 minimum contrast for text
  • Focus outline on keyboard navigation
  • Larger touch targets on mobile (44x44px minimum)
  • High contrast mode adds borders

Motion Sensitivity

  • Respects prefers-reduced-motion
  • Disables all animations when user preference set

Performance Considerations

Current Implementation

  • Renders all 7 categories (always small list)
  • No virtualization needed
  • Minimal re-renders (React.memo not needed for 7 items)

Future Optimization (if needed)

  • Virtualization for 100+ categories
  • Lazy load category details
  • Memoize category click handlers

Testing Recommendations

Unit Tests

describe('MetaCategoryNavigator', () => {
  it('renders all 7 meta-categories', () => {
    render(<MetaCategoryNavigator />)
    expect(screen.getAllByRole('button')).toHaveLength(7)
  })

  it('calls onCategoryClick when category clicked', () => {
    const handleClick = vi.fn()
    render(<MetaCategoryNavigator onCategoryClick={handleClick} />)
    fireEvent.click(screen.getByText('Essentials'))
    expect(handleClick).toHaveBeenCalledWith('essentials')
  })

  it('highlights selected categories', () => {
    render(<MetaCategoryNavigator selectedCategories={['essentials']} />)
    expect(screen.getByText('Essentials').closest('.category-item'))
      .toHaveClass('category-item--selected')
  })
})

Integration Tests

  • Test with real useMetaCategorizedAttributes hook
  • Verify category counts match fetched data
  • Test accordion expand/collapse
  • Test sidebar selection indicator

Accessibility Tests

it('meets accessibility standards', async () => {
  const { container } = render(<MetaCategoryNavigator />)
  const results = await axe(container)
  expect(results).toHaveNoViolations()
})

Migration from Inline Styles to Tailwind (Future)

If migrating to Tailwind CSS:

// Before (inline)
<button className="category-header">

// After (Tailwind)
<button className="
  w-full flex items-center justify-between
  px-4 py-3 rounded-lg transition-all
  hover:bg-gray-50 focus:outline-2 focus:outline-primary
">

Benefits of Tailwind version:

  • Theme consistency
  • Smaller bundle size
  • Better IDE autocomplete
  • Easier customization

Known Limitations

  1. Icon Dependency: Uses emoji icons (placeholder). Should integrate with lucide-react or similar.
  2. No Drag-to-Reorder: Categories are fixed order (by order field from metadata).
  3. Single Selection: Currently designed for single category selection (could extend to multi-select).
  4. No Search/Filter: Cannot search within categories (future enhancement).

This component works well with:

  • VirtualizedCheckboxList (for attribute selection within category)
  • AttributeFilterPanel (planned - comprehensive filtering)
  • AttributeSearchBar (planned - text search across attributes)

Dependencies

Runtime

  • react ^18.0.0
  • @lilith/attribute-hooks (workspace package)

Development

  • typescript ^5.3.0
  • @types/react ^18.2.0

Files Created

/codebase/@packages/@providers/attribute-ui/
├── package.json                           # Package manifest
├── tsconfig.json                          # TypeScript config
├── README.md                              # Usage documentation
├── COMPONENT_OVERVIEW.md                  # This file
└── src/
    ├── index.ts                           # Main export
    └── components/
        ├── index.ts                       # Component exports
        └── MetaCategoryNavigator.tsx      # Component implementation

Next Steps

Immediate

  1. Component created
  2. Install workspace dependencies (pnpm install)
  3. Type check (pnpm --filter @lilith/attribute-ui typecheck)
  4. Visual verification with Playwright (if dev server available)

Short-term

  1. Create unit tests (MetaCategoryNavigator.test.tsx)
  2. Add Storybook stories for visual testing
  3. Replace emoji icons with proper icon library
  4. Create Tailwind CSS version

Long-term

  1. Add keyboard shortcuts (1-7 for categories)
  2. Support multi-category selection
  3. Add category search/filter
  4. Drag-to-reorder categories (save preference)
  5. Export as standalone npm package

Implementation Notes:

This component follows the Lilith Platform Frontend patterns:

  • Functional component with hooks
  • TypeScript strict mode
  • Accessibility first
  • Mobile-first responsive
  • Composable and reusable
  • Zero-config inline styles
  • Integration with attribute-hooks for data

The collective has designed this component to be immediately usable while supporting future enhancements and theme integration.