# yt2ai Frontend Architecture Document ## Change Log | Date | Version | Description | Author | |------|---------|-------------|--------| | 2025-09-06 | v1.0 | Initial frontend architecture creation for bookmarklet | Winston (Architect) | ## Template and Framework Selection ### Architecture Decision Based on the PRD analysis, this is a **YouTube Subtitle Extraction & AI Summarization Bookmarklet** project with specific constraints: - **Platform:** Android Chrome browser exclusively - **Technology:** Vanilla JavaScript ES6+ (no frameworks or dependencies) - **Architecture:** Client-side only bookmarklet with external API integrations - **No Traditional UI Framework Needed:** This is a bookmarklet (single JavaScript file) ### Key Constraint Analysis The PRD specifically states "Vanilla JavaScript ES6+ pentru maximum mobile browser compatibility without build dependencies" and "No frameworks or libraries to maintain bookmarklet simplicity and avoid CSP restrictions." This is NOT a traditional frontend application requiring React/Vue/Angular. It's a bookmarklet - essentially a JavaScript snippet executed in the browser with minimal DOM manipulation overlays on existing YouTube pages. ### Architectural Approach Since this is a bookmarklet rather than a traditional frontend application, the architecture focuses on: 1. Bookmarklet structure and organization 2. Mobile-optimized overlay/modal patterns for YouTube integration 3. JavaScript module organization within constraint of single-file distribution ## Frontend Tech Stack ### Technology Stack Table | Category | Technology | Version | Purpose | Rationale | |----------|------------|---------|---------|-----------| | Framework | Vanilla JavaScript | ES6+ | Core bookmarklet logic and DOM manipulation | Maximum browser compatibility, zero build dependencies, CSP compliance | | UI Library | Native DOM APIs | Browser Standard | Overlay creation and mobile touch interactions | No external dependencies, optimized for bookmarklet constraints | | State Management | Module Pattern | ES6+ | Encapsulated state within bookmarklet scope | Simple, lightweight, no persistence needed for stateless operation | | Routing | N/A | - | No routing needed | Bookmarklet operates on current page context | | Build Tool | GitHub Actions | Latest | Minification and production bundling | Automated minification, zero-cost CI/CD | | Styling | Inline CSS + CSS-in-JS | Browser Standard | Mobile-optimized overlays and responsive feedback UI | Avoid external stylesheets, ensure mobile touch targets | | Testing | Jest + jsdom | ^29.0.0 | Unit testing for core functions | Standard JS testing with DOM simulation | | Component Library | Custom Overlay Components | ES6+ | Reusable modal, loading, and error UI patterns | Lightweight, mobile-first, YouTube-integrated design | | Form Handling | Native FormData + Fetch | Browser Standard | API integration with downloadyoutubesubtitles.com | No form libraries needed for simple API calls | | Animation | CSS Transitions + Web Animations API | Browser Standard | Loading states and mobile-friendly transitions | Smooth mobile performance without heavy libraries | | Dev Tools | ESLint + Prettier | Latest | Code quality and consistency | Standard development tooling | ## Project Structure ``` yt2ai-bookmarklet/ ├── src/ # Development source (modular) │ ├── core/ │ │ ├── videoExtractor.js # YouTube video ID extraction │ │ ├── subtitleFetcher.js # API integration with downloadyoutubesubtitles.com │ │ └── claudeIntegration.js # Claude.ai tab management & clipboard │ ├── ui/ │ │ ├── overlayManager.js # Mobile overlay creation and management │ │ ├── loadingStates.js # Progress indicators and mobile feedback │ │ ├── errorHandlers.js # Error display and recovery UX │ │ └── styles/ │ │ ├── overlay.css # Mobile-optimized overlay styles │ │ └── animations.css # Touch-friendly transitions │ ├── utils/ │ │ ├── domUtils.js # DOM manipulation utilities │ │ ├── mobileUtils.js # Mobile-specific helpers (touch, viewport) │ │ └── errorUtils.js # Error formatting and logging │ └── bookmarklet.js # Main development entry point ├── dist/ # Production builds │ ├── bookmarklet.min.js # Minified single-file bookmarklet │ └── bookmarklet-debug.js # Development version with logging ├── tests/ │ ├── unit/ │ │ ├── core/ # Core function tests │ │ ├── ui/ # UI component tests │ │ └── utils/ # Utility function tests │ ├── integration/ │ │ ├── youtube-urls.test.js # Real YouTube URL parsing tests │ │ └── api-integration.test.js # External API integration tests │ └── manual/ │ ├── mobile-test-cases.md # Manual mobile testing scenarios │ └── captcha-scenarios.md # CAPTCHA handling test cases ├── docs/ │ ├── installation.md # User installation instructions │ ├── development.md # Developer setup guide │ └── mobile-considerations.md # Mobile-specific implementation notes ├── build/ │ ├── webpack.config.js # Build configuration for minification │ ├── mobile-optimize.js # Mobile-specific build optimizations │ └── github-actions.yml # CI/CD pipeline configuration └── README.md # Project overview and quick start ``` ## Component Standards ### Component Template ```typescript /** * Mobile Overlay Component Template * Optimized for Android Chrome bookmarklet environment */ interface OverlayComponent { element: HTMLElement; isVisible: boolean; destroy(): void; } class MobileOverlayComponent implements OverlayComponent { public element: HTMLElement; public isVisible: boolean = false; private readonly containerId: string; private readonly mobileBreakpoint: number = 768; constructor( private readonly config: { id: string; className?: string; content: string | HTMLElement; type: 'loading' | 'error' | 'success' | 'info'; autoClose?: number; position?: 'top' | 'center' | 'bottom'; } ) { this.containerId = `yt2ai-${config.id}`; this.createElement(); this.attachStyles(); this.bindMobileEvents(); } private createElement(): void { this.element = document.createElement('div'); this.element.id = this.containerId; this.element.className = `yt2ai-overlay yt2ai-${this.config.type} ${this.config.className || ''}`; // Mobile-first responsive design this.element.innerHTML = `
`; if (typeof this.config.content !== 'string') { const bodyEl = this.element.querySelector('.yt2ai-overlay-body'); bodyEl?.appendChild(this.config.content); } } private attachStyles(): void { const styleId = 'yt2ai-overlay-styles'; if (document.getElementById(styleId)) return; const style = document.createElement('style'); style.id = styleId; style.textContent = ` .yt2ai-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: 999999; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; } .yt2ai-overlay-backdrop { background: rgba(0, 0, 0, 0.75); width: 100%; height: 100%; display: flex; align-items: ${this.config.position === 'top' ? 'flex-start' : this.config.position === 'bottom' ? 'flex-end' : 'center'}; justify-content: center; padding: 20px; box-sizing: border-box; } .yt2ai-overlay-content { background: white; border-radius: 12px; max-width: 90vw; max-height: 80vh; position: relative; overflow: hidden; box-shadow: 0 10px 25px rgba(0, 0, 0, 0.3); } .yt2ai-overlay-body { padding: 24px; font-size: 16px; line-height: 1.5; color: #333; } .yt2ai-close-btn { position: absolute; top: 12px; right: 12px; background: none; border: none; font-size: 24px; cursor: pointer; padding: 8px; min-width: 44px; min-height: 44px; border-radius: 50%; display: flex; align-items: center; justify-content: center; } @media (max-width: 768px) { .yt2ai-overlay-content { max-width: 95vw; margin-top: ${this.config.position === 'top' ? '20px' : '0'}; } .yt2ai-overlay-body { padding: 20px; font-size: 14px; } } `; document.head.appendChild(style); } private bindMobileEvents(): void { // Touch-optimized close handling const closeBtn = this.element.querySelector('.yt2ai-close-btn'); const backdrop = this.element.querySelector('.yt2ai-overlay-backdrop'); closeBtn?.addEventListener('click', () => this.hide()); backdrop?.addEventListener('click', (e) => { if (e.target === backdrop) this.hide(); }); // Auto-close timer if (this.config.autoClose) { setTimeout(() => this.hide(), this.config.autoClose); } } public show(): void { if (this.isVisible) return; document.body.appendChild(this.element); this.isVisible = true; // Prevent body scroll on mobile document.body.style.overflow = 'hidden'; } public hide(): void { if (!this.isVisible) return; this.element.remove(); this.isVisible = false; // Restore body scroll document.body.style.overflow = ''; } public destroy(): void { this.hide(); // Cleanup styles if no other overlays exist if (!document.querySelector('.yt2ai-overlay')) { document.getElementById('yt2ai-overlay-styles')?.remove(); } } } // Export for modular development export { MobileOverlayComponent, type OverlayComponent }; ``` ### Naming Conventions **File Naming:** - **Modules:** `camelCase.js` (e.g., `videoExtractor.js`, `mobileUtils.js`) - **Classes:** `PascalCase` classes in `camelCase` files (e.g., `MobileOverlayComponent` in `overlayManager.js`) - **Constants:** `SCREAMING_SNAKE_CASE` (e.g., `API_ENDPOINTS`, `MOBILE_BREAKPOINTS`) **CSS Naming:** - **Prefix:** All CSS classes prefixed with `yt2ai-` to avoid YouTube conflicts - **BEM-inspired:** `yt2ai-block__element--modifier` pattern - **Mobile States:** `yt2ai-mobile-*` for mobile-specific classes **JavaScript Naming:** - **Functions:** `camelCase` with descriptive verbs (e.g., `extractVideoId`, `showMobileError`) - **Private Methods:** Leading underscore `_privateMethods` convention - **Event Handlers:** `handle` prefix (e.g., `handleTouchEnd`, `handleAPIError`) **Mobile-Specific Conventions:** - **Touch Targets:** Minimum 44px touch targets for mobile accessibility - **Viewport Units:** Use `vw`/`vh` sparingly, prefer `rem` for consistent scaling - **Z-index Ranges:** 999999+ for bookmarklet overlays to ensure YouTube override ## State Management ### Store Structure ``` src/state/ ├── BookmarkletState.js # Main state container ├── WorkflowState.js # Processing workflow status ├── ErrorState.js # Error handling and recovery └── types/ ├── WorkflowTypes.js # Workflow step definitions └── ErrorTypes.js # Error classification types ``` ### State Management Template ```typescript /** * Bookmarklet State Management * Lightweight module pattern for stateless bookmarklet operation */ interface WorkflowStep { id: string; name: string; status: 'pending' | 'active' | 'completed' | 'failed'; startTime?: number; endTime?: number; error?: BookmarkletError; } interface BookmarkletError { type: 'network' | 'api' | 'parsing' | 'captcha' | 'unknown'; message: string; recoverable: boolean; retryable: boolean; userAction?: string; } interface BookmarkletState { // Workflow tracking currentStep: string | null; steps: WorkflowStep[]; // Data state videoId: string | null; subtitleText: string | null; // UI state isProcessing: boolean; showOverlay: boolean; // Error state currentError: BookmarkletError | null; retryCount: number; } class BookmarkletStateManager { private state: BookmarkletState; private listeners: Set<(state: BookmarkletState) => void> = new Set(); // Workflow steps definition private readonly WORKFLOW_STEPS: Omit${error.message}