Files
remotion_service/docs/superpowers/specs/2026-04-06-subtitle-preset-grid-redesign.md
T
2026-04-06 01:44:58 +03:00

213 lines
6.9 KiB
Markdown

# 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)