hensei-web/docs/details-sidebar-segmented-control.md

414 lines
No EOL
12 KiB
Markdown

# DetailsSidebar Segmented Control Implementation
## Overview
Add a segmented control to the DetailsSidebar component that allows users to switch between viewing the canonical (base) item data and the user's customized version with their modifications.
## User Requirements
The sidebar should display two distinct views:
1. **Canonical Data View** - Shows the base item statistics and properties as they exist in the game database
2. **User Version View** - Shows the user's specific customizations and modifications to the item
## Data Structure Analysis
### Current Grid Item Structure
Each grid item (GridCharacter, GridWeapon, GridSummon) contains:
- The base object data (`character`, `weapon`, or `summon`)
- User-specific modifications stored at the grid item level
- Instance-specific properties like position, uncap level, etc.
### User Version Data by Type
#### Weapons (GridWeapon)
- `uncapLevel` - Current uncap level (0-6)
- `transcendenceStep` - Transcendence stage (0-5)
- `awakening` - Object containing:
- `type` - Awakening type with name and slug
- `level` - Awakening level
- `weaponKeys` - Array of weapon keys:
- Opus pendulums (series 2)
- Draconic telumas (series 3, 34)
- Ultima gauph keys (series 17)
- Revans emblems (series 22)
- `ax` - Array of AX skills containing:
- `modifier` - Skill ID
- `strength` - Skill strength value
- `element` - Instance element for null-element weapons
#### Characters (GridCharacter)
- `uncapLevel` - Current uncap level (0-5 or 0-6)
- `transcendenceStep` - Transcendence stage (0-5)
- `awakening` - Awakening type and level
- `rings` - Array of over mastery rings:
- `modifier` - Ring stat type
- `strength` - Ring stat value
- `earring` - Aetherial mastery object:
- `modifier` - Earring stat type
- `strength` - Earring stat value
- `aetherial_mastery` - Alternative property name for earring
- `perpetuity` - Boolean for permanent mastery status
#### Summons (GridSummon)
- `uncapLevel` - Current uncap level (0-5)
- `transcendenceStep` - Transcendence stage (0-5)
- `quick_summon` - Boolean for quick summon status
- `friend` - Boolean for friend summon
## Component Architecture
### Reusable Components to Create
#### 1. `DetailsSidebarSegmentedControl.svelte`
A specialized segmented control for the details sidebar that can be reused across different detail views.
```svelte
<script lang="ts">
interface Props {
hasModifications: boolean
selectedView: 'canonical' | 'user'
onViewChange: (view: 'canonical' | 'user') => void
}
</script>
```
#### 2. `ModificationSection.svelte`
Generic wrapper for modification sections with consistent styling.
```svelte
<script lang="ts">
interface Props {
title: string
visible?: boolean
children: Snippet
}
</script>
{#if visible}
<div class="modification-section">
<h3>{title}</h3>
<div class="modification-content">
{@render children()}
</div>
</div>
{/if}
```
#### 3. `AwakeningDisplay.svelte`
Reusable awakening display component for both weapons and characters.
```svelte
<script lang="ts">
import { getAwakeningImage } from '$lib/utils/modifiers'
interface Props {
awakening?: { type: Awakening; level: number }
size?: 'small' | 'medium' | 'large'
showLevel?: boolean
}
</script>
```
#### 4. `WeaponKeysList.svelte`
Component for displaying weapon keys with proper icons and formatting.
```svelte
<script lang="ts">
import { getWeaponKeyImages } from '$lib/utils/modifiers'
interface Props {
weaponKeys?: WeaponKey[]
weaponData: { element?: number; proficiency?: number; series?: number; name?: LocalizedString }
layout?: 'list' | 'grid'
}
</script>
```
#### 5. `StatModifierItem.svelte`
Generic component for displaying stat modifications (rings, earrings, etc.).
```svelte
<script lang="ts">
interface Props {
label: string
value: string | number
suffix?: string
icon?: string
variant?: 'default' | 'enhanced' | 'max'
}
</script>
<div class="stat-modifier" class:variant>
{#if icon}<img src={icon} alt="" />{/if}
<span class="label">{label}</span>
<span class="value">{value}{suffix}</span>
</div>
```
#### 6. `UncapStatusDisplay.svelte`
Dedicated component for showing current uncap/transcendence status.
```svelte
<script lang="ts">
interface Props {
type: 'character' | 'weapon' | 'summon'
uncapLevel?: number
transcendenceStep?: number
maxUncap: number
showIndicator?: boolean
}
</script>
```
### Data Processing Utilities
#### `modificationDetector.ts`
Utility to detect what modifications exist on a grid item.
```typescript
export interface ModificationStatus {
hasModifications: boolean
hasAwakening: boolean
hasWeaponKeys: boolean
hasAxSkills: boolean
hasRings: boolean
hasEarring: boolean
hasPerpetuity: boolean
hasTranscendence: boolean
}
export function detectModifications(
type: 'character' | 'weapon' | 'summon',
item: GridCharacter | GridWeapon | GridSummon
): ModificationStatus {
// Implementation
}
```
#### `modificationFormatters.ts`
Centralized formatters for modification display.
```typescript
export function formatRingStat(modifier: number, strength: number): string
export function formatEarringStat(modifier: number, strength: number): string
export function formatAxSkill(ax: SimpleAxSkill): string
export function getWeaponKeyTitle(series?: number): string
```
### Component Composition Pattern
The main DetailsSidebar will compose these smaller components:
```svelte
<!-- DetailsSidebar.svelte -->
<DetailsSidebarSegmentedControl {hasModifications} bind:selectedView />
{#if selectedView === 'canonical'}
<!-- Existing canonical view -->
{:else}
<!-- User version composed of reusable components -->
<UncapStatusDisplay {type} {uncapLevel} {transcendenceStep} />
<ModificationSection title="Awakening" visible={item.awakening}>
<AwakeningDisplay awakening={item.awakening} size="medium" showLevel />
</ModificationSection>
{#if type === 'weapon'}
<ModificationSection title={getWeaponKeyTitle(item.weapon?.series)} visible={item.weaponKeys?.length}>
<WeaponKeysList {weaponKeys} weaponData={item.weapon} />
</ModificationSection>
{/if}
<!-- etc... -->
{/if}
```
## Styling Guidelines
### IMPORTANT: Use Existing Theme System
**DO NOT create new style variables or custom styles.** All necessary styling is already defined in the theme files:
- `_colors.scss` - All color variables and element-specific colors
- `_typography.scss` - Font sizes, weights, and text styling
- `_spacing.scss` - Spacing units and gaps
- `_layout.scss` - Border radius, corners, and layout constants
- `_effects.scss` - Shadows, transitions, and visual effects
- `_mixins.scss` - Reusable style mixins
- `_rep.scss` - Representation/aspect ratio utilities
### Component Styling Example
```scss
// Import only what's needed from themes
@use '$src/themes/colors' as colors;
@use '$src/themes/typography' as typography;
@use '$src/themes/spacing' as spacing;
@use '$src/themes/layout' as layout;
@use '$src/themes/effects' as effects;
.modification-section {
// Use existing spacing variables
margin-bottom: spacing.$unit-3x;
padding: spacing.$unit-2x;
h3 {
// Use existing typography
font-size: typography.$font-regular;
font-weight: typography.$medium;
color: var(--text-secondary, colors.$grey-40);
margin-bottom: spacing.$unit-1-5x;
}
}
.stat-modifier {
// Use existing layout patterns
display: flex;
justify-content: space-between;
padding: spacing.$unit;
background: colors.$grey-90;
border-radius: layout.$item-corner-small;
.label {
font-size: typography.$font-small;
color: var(--text-secondary, colors.$grey-50);
}
.value {
font-size: typography.$font-regular;
font-weight: typography.$medium;
color: var(--text-primary, colors.$grey-10);
}
// Use existing effect patterns for enhanced state
&.enhanced {
background: colors.$grey-85;
box-shadow: effects.$hover-shadow;
}
}
.awakening-display {
// Use consistent spacing
display: flex;
gap: spacing.$unit-2x;
align-items: center;
img {
// Use standard sizing
width: spacing.$unit-6x;
height: spacing.$unit-6x;
border-radius: layout.$item-corner-small;
}
}
```
### Theme Variables Reference
#### Colors
- Text: `var(--text-primary)`, `var(--text-secondary)`, `var(--text-tertiary)`
- Backgrounds: `var(--card-bg)`, `colors.$grey-90`, `colors.$grey-85`
- Element colors: `var(--wind-item-detail-bg)`, etc.
- State colors: `var(--color-success)`, `var(--color-error)`
#### Typography
- Sizes: `$font-tiny`, `$font-small`, `$font-regular`, `$font-medium`, `$font-large`
- Weights: `$normal: 400`, `$medium: 500`, `$bold: 600`
#### Spacing
- Base unit: `$unit: 8px`
- Multipliers: `$unit-half`, `$unit-2x`, `$unit-3x`, `$unit-4x`, etc.
- Fractions: `$unit-fourth`, `$unit-third`
#### Layout
- Corners: `$item-corner`, `$item-corner-small`, `$modal-corner`
- Breakpoints: Use mixins from `_mixins.scss`
#### Effects
- Shadows: `$hover-shadow`, `$focus-shadow`
- Transitions: `$duration-zoom`, `$duration-color-fade`
- Transforms: `$scale-wide`, `$scale-tall`
## Benefits of Componentization
### Maintainability
- Each component has a single responsibility
- Changes to display logic are isolated
- Easier to test individual components
- Consistent styling through shared theme system
### Reusability
- `AwakeningDisplay` can be used in hovercards, modals, and sidebars
- `StatModifierItem` works for any stat modification
- `ModificationSection` provides consistent section layout
### Type Safety
- Each component has clearly defined props
- TypeScript interfaces ensure correct data flow
- Compile-time checking prevents runtime errors
### Performance
- Components can be memoized if needed
- Smaller components = smaller re-render boundaries
- Derived states prevent unnecessary recalculation
## Testing Strategy
### Unit Tests for Components
Each reusable component should have tests for:
- Rendering with different prop combinations
- Conditional visibility
- Event handling
- Edge cases (missing data, invalid values)
### Integration Tests
Test the complete DetailsSidebar with:
- View switching
- Data flow between components
- Correct component composition
### Visual Regression Tests
Use Storybook to document and test visual states:
- Different modification combinations
- Various item types
- Empty states
- Loading states
## Implementation Checklist
### Phase 1: Infrastructure
- [ ] Set up modificationDetector utility
- [ ] Set up modificationFormatters utility
- [ ] Create ModificationSection wrapper component
### Phase 2: Display Components
- [ ] Create AwakeningDisplay component
- [ ] Create WeaponKeysList component
- [ ] Create StatModifierItem component
- [ ] Create UncapStatusDisplay component
- [ ] Create DetailsSidebarSegmentedControl
### Phase 3: Integration
- [ ] Update DetailsSidebar to use new components
- [ ] Wire up view switching logic
- [ ] Implement canonical view with existing code
- [ ] Implement user version view with new components
### Phase 4: Polish
- [ ] Add loading states
- [ ] Add empty states
- [ ] Optimize performance
- [ ] Add accessibility attributes
- [ ] Documentation and examples
## Notes
- Components should accept `class` prop for custom styling
- All components should handle missing/null data gracefully
- Consider using slots/snippets for maximum flexibility
- Keep components pure - no direct API calls
- Use consistent prop naming across components
- **Always use existing theme variables - never create custom styles**
- Import only the theme modules you need to minimize bundle size
- Use CSS custom properties (var()) for dynamic theming support