Files
2026-01-29 21:05:41 -03:00

5.4 KiB

Data Model: YouTube Design Preview Replica

Date: 2026-01-29

Entities

PreviewMode (Enum)

type PreviewMode = 'desktop' | 'sidebar' | 'mobile';
Value Description Thumbnail Size
desktop YouTube homepage/search grid layout 360x202px
sidebar YouTube related videos sidebar 168x94px
mobile YouTube mobile app full-width layout 100% width

ThemeMode (Enum)

type ThemeMode = 'light' | 'dark';

VideoMetadata

User-customizable metadata for preview display.

interface VideoMetadata {
  title: string;           // Video title (max 100 chars for display)
  channelName: string;     // Channel name
  channelAvatarUrl?: string; // Optional channel avatar image URL
  duration: string;        // Format: "MM:SS" or "H:MM:SS"
  viewCount: number;       // Raw number, formatted for display
  publishedAt: Date;       // Used for "X days ago" calculation
}

Validation Rules:

  • title: Required, 1-100 characters
  • channelName: Required, 1-50 characters
  • duration: Required, format /^\d{1,2}:\d{2}(:\d{2})?$/
  • viewCount: Required, non-negative integer
  • publishedAt: Required, valid Date, not in future

UploadedThumbnail

Represents a user-uploaded thumbnail image.

interface UploadedThumbnail {
  id: string;              // UUID
  dataUrl: string;         // Base64 data URL of the image
  originalName: string;    // Original filename
  fileSize: number;        // Size in bytes (max 5MB)
  mimeType: string;        // 'image/jpeg' | 'image/png' | 'image/webp'
  width: number;           // Original image width
  height: number;          // Original image height
  uploadedAt: Date;        // Timestamp
}

Validation Rules:

  • fileSize: Max 5,242,880 bytes (5MB)
  • mimeType: Only 'image/jpeg', 'image/png', 'image/webp'
  • width, height: Positive integers

PreviewState

Complete state for the preview tool, persisted to localStorage.

interface PreviewState {
  // Active preview configuration
  currentThumbnail: UploadedThumbnail | null;
  previewMode: PreviewMode;
  themeMode: ThemeMode;
  metadata: VideoMetadata;

  // History for quick switching
  recentThumbnails: UploadedThumbnail[];  // Max 10 items

  // UI state
  showMetadataEditor: boolean;

  // Persistence metadata
  lastSaved: Date;
  version: number;  // Schema version for migrations
}

VisualTestResult

Result of Playwright visual comparison test.

interface VisualTestResult {
  testId: string;
  previewMode: PreviewMode;
  themeMode: ThemeMode;
  capturedAt: Date;

  // Comparison metrics
  matchPercentage: number;     // 0-100
  passed: boolean;             // matchPercentage >= threshold (98%)

  // File references
  actualScreenshotPath: string;
  expectedScreenshotPath: string;
  diffImagePath?: string;      // Only if failed

  // Error info
  errorMessage?: string;
}

ReferenceScreenshot

Stored YouTube reference for visual comparison.

interface ReferenceScreenshot {
  id: string;
  previewMode: PreviewMode;
  themeMode: ThemeMode;
  capturedAt: Date;
  capturedFrom: string;        // YouTube URL
  filePath: string;

  // Metadata
  viewportWidth: number;
  viewportHeight: number;
  browserType: string;         // 'chromium' | 'firefox' | 'webkit'

  // Version tracking
  isActive: boolean;           // Current baseline
  replacedBy?: string;         // ID of newer version
}

Local Storage Schema

Key: thumbpreview_state

interface LocalStorageSchema {
  version: 1;
  state: PreviewState;
}

Storage Limits:

  • Total localStorage budget: ~5MB
  • Each thumbnail (base64): ~1-2MB typical
  • Keep max 10 recent thumbnails
  • Automatic cleanup of oldest when limit reached

State Transitions

Thumbnail Upload Flow

[No Thumbnail]
    |
    v (user uploads file)
[Validating]
    |
    +-- (invalid) --> [Error: show message] --> [No Thumbnail]
    |
    v (valid)
[Processing]
    |
    v (resize/optimize if needed)
[Preview Ready]
    |
    v (auto-save to localStorage)
[Persisted]

Preview Mode Switch

[Current Mode]
    |
    v (user selects new mode)
[Transitioning]
    |
    v (re-render with new layout)
[New Mode Active]
    |
    v (persist preference)
[Saved]

Theme Mode Switch

[Current Theme]
    |
    v (user clicks toggle)
[Apply Theme Class]
    |
    v (CSS variables update)
[New Theme Active]
    |
    v (persist preference)
[Saved]

Relationships

PreviewState
    |
    +-- 1:1 --> currentThumbnail (UploadedThumbnail)
    |
    +-- 1:N --> recentThumbnails (UploadedThumbnail[])
    |
    +-- 1:1 --> metadata (VideoMetadata)
    |
    +-- enum --> previewMode (PreviewMode)
    |
    +-- enum --> themeMode (ThemeMode)

VisualTestResult
    |
    +-- ref --> ReferenceScreenshot (expectedScreenshotPath)
    |
    +-- enum --> previewMode
    |
    +-- enum --> themeMode

Default Values

const DEFAULT_METADATA: VideoMetadata = {
  title: 'Your Video Title Here',
  channelName: 'Your Channel',
  channelAvatarUrl: undefined,
  duration: '10:30',
  viewCount: 125000,
  publishedAt: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000) // 1 week ago
};

const DEFAULT_STATE: PreviewState = {
  currentThumbnail: null,
  previewMode: 'desktop',
  themeMode: 'light',
  metadata: DEFAULT_METADATA,
  recentThumbnails: [],
  showMetadataEditor: false,
  lastSaved: new Date(),
  version: 1
};