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

6.9 KiB

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

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

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)