# Subtitle Preset Grid Redesign - Design Document **Date:** 2026-04-06 **Scope:** Redesign preset preview cards in Caption Settings step to match uploaded video aspect ratio with modern visual refresh --- ## Overview Redesign the subtitle preset selection grid to: 1. Display preset previews with the **same aspect ratio as the uploaded video** 2. Apply a **modern visual refresh** consistent with the app's design language 3. Show **style characteristics** (font, colors) as subtle hints 4. Maintain **responsive layout** across screen sizes --- ## Core Functionality ### Dynamic Aspect Ratio **Data Flow:** 1. Fetch video metadata via `GET /api/media/mediafiles/{media_file_id}/` using `primaryFileId` from WizardContext 2. Extract `width` and `height` from `MediaFileRead` response 3. Calculate aspect ratio: `width / height` 4. Apply as CSS `aspect-ratio` to preset cards via inline style or CSS variable 5. Handle loading state while fetching metadata 6. Fallback to 16:9 if no video is uploaded or API error occurs **Implementation Notes:** - Store aspect ratio in WizardContext alongside other video metadata - Update ratio when `primaryFileId` changes - Cards use container queries for responsive sizing --- ## Visual Design (5 Pillars Applied) ### 1. Typography with Character - Keep existing font system (consistent with app) - Style name: `font-weight: 500`, `font-size: 14px` - Characteristic labels: `font-size: 12px`, muted color (`--gray-10`) ### 2. Committed Color & Theme - Uses **Catppuccin Mocha** palette matching the project: - Canvas: `--bg-canvas: #11111b` - Cards: `--bg-default: #1e1e2e` - Surfaces: `--bg-surface: #313244` - Borders: `--border-default: #45475a`, `--border-subtle: #313244` - Text: `--text-primary: #cdd6f4`, `--text-secondary: #bac2de`, `--text-tertiary: #9399b2` - Selected state: purple accent (`--purple-400: #cba6f7`) with glow shadow - Card hover: border transitions to purple accent - System badge: purple-100 background with purple-400 text - Checkmark indicator on selected card (top-right corner) ### 3. Purposeful Motion - Cards fade in with staggered animation (50ms delay per card) - Smooth border-color transition on hover (150ms ease) - Selection change: immediate border color change - Loading skeleton: shimmer animation ### 4. Brave Spatial Composition - CSS Grid with `auto-fill` and `minmax(200px, 1fr)` - Consistent 16px gap between cards - Cards maintain video aspect ratio without stretching - Responsive: more columns on wide screens, fewer on narrow ### 5. Atmosphere & Depth - Card background: subtle gradient overlay for depth - Selected card: elevated with `box-shadow` + accent glow - Dark preview background (`#0c0a1a`) preserved from existing StylePreview - Rounded corners: `border-radius: 12px` --- ## Component Structure ### PresetCard ``` ┌──────────────────────────────────────┐ │ │ │ [StylePreview Component] │ ← Dynamic aspect-ratio │ "Пример субтитров" │ based on video │ │ ├──────────────────────────────────────┤ │ Style Name [Системный] │ ← Footer │ Lobster · Yellow accent │ ← Characteristics (subtle) └──────────────────────────────────────┘ ``` **Props:** - `preset: CaptionPresetRead` - `isSelected: boolean` - `aspectRatio: number` (width/height, e.g., 1.777 for 16:9) - `onSelect: () => void` - `onEdit: () => void` - `onDelete: () => void` ### StylePreview Updates **New Props:** - `aspectRatio?: number` - overrides default 9/16 **Behavior:** - Uses passed `aspectRatio` for container sizing - Falls back to 9/16 if not provided - Maintains all existing text styling logic ### PresetGrid Updates **New Behavior:** - Fetches video metadata via `useVideoMetadata()` hook - Passes `aspectRatio` to all PresetCard children - Shows skeleton loading state while fetching - Responsive grid layout --- ## Style Characteristics Display Each card footer shows: - **Font family** (e.g., "Lobster", "Inter") - extracted from `preset.style_config.text.font_family` - **Accent color** - small color dot + name if distinct from default - Hidden on cards narrower than 180px (responsive) **Format:** ``` {font_family} · {accent_color_name} ``` Example: `Lobster · Желтый` or `Inter · Неоновый` --- ## Loading State **Skeleton Card:** - Same aspect ratio as target (default 16:9 while loading) - Shimmer animation on preview area - Gray placeholder for text - 4-6 skeleton cards shown while loading --- ## Responsive Behavior | Screen Width | Grid Columns | Card Min Width | |--------------|--------------|----------------| | < 480px | 2 | 140px | | 480-768px | 3 | 160px | | 768-1200px | 4 | 180px | | > 1200px | 5-6 | 200px | --- ## API Integration ### New Hook: `useVideoMetadata` ```typescript function useVideoMetadata(fileId: string | null) { return api.useQuery( "get", "/api/media/mediafiles/{media_file_id}/", { params: { path: { media_file_id: fileId ?? "" } } }, { enabled: !!fileId } ) } ``` ### Aspect Ratio Calculation ```typescript const aspectRatio = useMemo(() => { if (!mediaFile?.width || !mediaFile?.height) return 16 / 9 return mediaFile.width / mediaFile.height }, [mediaFile]) ``` --- ## Edge Cases 1. **No video uploaded:** Fall back to 16:9 aspect ratio 2. **Video metadata unavailable:** Show error toast, fall back to 16:9 3. **Very wide video (>21:9):** Cap max card width to prevent overflow 4. **Very tall video (9:16+):** Limit max height, allow scrolling if needed 5. **No presets:** Show empty state with "Создать пресет" card only --- ## Files Modified 1. `src/features/project/CaptionSettingsStep/PresetGrid.tsx` - Grid logic, aspect ratio distribution 2. `src/features/project/CaptionSettingsStep/PresetGrid.module.scss` - Grid styles, responsive layout 3. `src/features/project/CaptionSettingsStep/StylePreview.tsx` - Accept aspect ratio prop 4. `src/features/project/CaptionSettingsStep/StylePreview.module.scss` - Dynamic sizing 5. `src/features/project/CaptionSettingsStep/useVideoMetadata.ts` - New hook (or inline in PresetGrid) --- ## Acceptance Criteria - [ ] Preset cards display with uploaded video's aspect ratio - [ ] Grid is responsive and works on mobile/desktop - [ ] Loading state shows skeleton cards - [ ] Style characteristics (font, color) visible on cards - [ ] Selected state clearly visible with accent border - [ ] Hover effects smooth and purposeful - [ ] Fallback to 16:9 when no video available - [ ] All existing functionality preserved (select, edit, delete, create)