github-actions
Sync Docker Space
5f3e9f5
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="theme-color" content="#10B981">
<title>Screenshot Studio</title>
<meta name="description" content="Convert text and HTML into beautiful, formatted screenshots using AI">
<link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}?v=5">
</head>
<body>
<!-- Mobile Header -->
<div class="mobile-header">
<button class="hamburger-btn" onclick="toggleSidebar()" aria-label="Toggle menu">
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
</svg>
</button>
<div class="logo">
<h1>
<div class="logo-icon">S</div>
Screenshot Studio
</h1>
</div>
</div>
<!-- Sidebar Overlay (mobile) -->
<div class="sidebar-overlay" id="sidebarOverlay" onclick="closeSidebar()"></div>
<div class="app-container">
<!-- Sidebar -->
<aside class="sidebar" id="sidebar">
<div class="logo">
<h1>
<div class="logo-icon">S</div>
Screenshot Studio
</h1>
</div>
<nav class="nav-menu">
<div class="nav-item active" onclick="switchTool('text-to-image')">
<svg class="nav-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round"
d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
</svg>
Text to Image
</div>
<div class="nav-item" onclick="switchTool('html-to-image')">
<svg class="nav-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round"
d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4" />
</svg>
HTML to Image
</div>
<div class="nav-item" onclick="switchTool('image-to-screenshots')">
<svg class="nav-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
Image to Screenshots
</div>
<div class="nav-item" onclick="switchTool('resources')">
<svg class="nav-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round"
d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z" />
</svg>
Resources
</div>
</nav>
<!-- Cache Clear Button -->
<div class="cache-button-container">
<button onclick="clearCache()" class="cache-clear-btn">
<svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
</svg>
Clear AI Cache
</button>
<div id="cacheStats" class="cache-stats"></div>
</div>
</aside>
<!-- Main Content -->
<main class="main-content">
<!-- ═══ Text to Image ═══ -->
<div id="text-to-image" class="tool-section active">
<div class="header">
<h2>Text to Image</h2>
<p>Convert your text content into beautifully formatted screenshots using AI</p>
</div>
<div class="card">
<div class="form-group mb-16">
<label class="form-label">AI Model</label>
<select id="textModelChoice" class="form-input">
<option value="default">Default Model (122B Qwen ~ High Quality)</option>
<option value="fast">Fast Model (80B Qwen ~ High Speed)</option>
<option value="kimi">Kimi K2.5 (Thinking ~ 16k Tokens)</option>
<option value="deepseek">DeepSeek V3.2 (Thinking ~ 8k Tokens)</option>
<option value="devstral">Mistral Devstral (Fast ~ 8k Tokens)</option>
</select>
</div>
<div class="form-group">
<label class="form-label">Enter your text content</label>
<textarea id="textInput" class="form-textarea"
placeholder="Type or paste your content here...&#10;&#10;Example: Write notes for Class 12 Nepali subject..."></textarea>
</div>
<!-- Advanced Settings -->
<div class="advanced-toggle" onclick="toggleAdvancedText()">
<svg id="advancedIcon" width="18" height="18" fill="none" stroke="currentColor"
viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
</svg>
<span>Advanced Settings</span>
</div>
<div id="advancedSettings" class="advanced-settings hidden">
<div class="form-row">
<div class="form-group flex-1">
<label class="form-label">Zoom Level</label>
<input type="number" id="textZoom" class="form-input" value="2.1" min="1" max="5"
step="0.1">
<p class="form-hint">Default: 2.1× (210%)</p>
</div>
<div class="form-group flex-1">
<label class="form-label">Overlap (px)</label>
<input type="number" id="textOverlap" class="form-input" value="20" min="0" max="200"
step="5">
<p class="form-hint">Default: 15px</p>
</div>
</div>
<div class="form-row">
<div class="form-group flex-1">
<label class="form-label">Width</label>
<input type="number" id="textViewportWidth" class="form-input" value="1920" min="800"
max="3840" step="80">
<p class="form-hint">Output width in px</p>
</div>
<div class="form-group flex-1">
<label class="form-label">Height</label>
<input type="number" id="textViewportHeight" class="form-input" value="1080" min="600"
max="2160" step="60">
<p class="form-hint">Output height in px</p>
</div>
<div class="form-group flex-1">
<label class="form-label">Max Shots</label>
<input type="number" id="textMaxScreenshots" class="form-input" value="50" min="1"
max="100" step="1">
<p class="form-hint">Safety limit</p>
</div>
</div>
<div class="form-row mt-10">
<div class="form-group w-full">
<label class="checkbox-container flex items-center gap-8">
<input type="checkbox" id="textEnableVerification" checked>
<span class="font-medium">Enable AI Content Verification (Recommended)</span>
</label>
<p class="form-hint mt-4">Secondary AI pass to fix missing data and hallucinations</p>
</div>
</div>
<button class="btn btn-secondary mt-4" onclick="resetAdvancedText()">
<svg width="14" height="14" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
</svg>
Reset Defaults
</button>
</div>
<div class="flex gap-12 mt-20">
<button class="btn btn-secondary flex-1" onclick="previewHTML()">
<svg width="18" height="18" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
</svg>
Preview HTML
</button>
<div id="textButtonContainer" class="flex gap-12 flex-2">
<button class="btn btn-primary flex-1" onclick="generateFromText()">
<svg width="18" height="18" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M13 10V3L4 14h7v7l9-11h-7z" />
</svg>
Generate Screenshots
</button>
</div>
</div>
</div>
<!-- HTML Preview Modal -->
<div id="htmlPreviewModal" class="image-modal">
<button class="modal-close" onclick="closePreviewModal()">&times;</button>
<div class="preview-modal-body">
<h3 class="preview-modal-title">HTML Preview</h3>
<div class="preview-modal-actions">
<button class="btn btn-secondary" onclick="copyHTMLToClipboard()">
<svg width="14" height="14" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" />
</svg>
Copy HTML
</button>
<button class="btn btn-primary" onclick="closePreviewModal(); generateFromText();">
Continue to Generate
</button>
</div>
<div class="preview-frame-wrapper">
<iframe id="htmlPreviewFrame" class="preview-frame"></iframe>
</div>
</div>
</div>
<div id="textLoading" class="loading">
<div class="spinner"></div>
<p class="loading-text" id="loadingMessage">Processing your content with AI...</p>
<div class="progress-container mt-14">
<div class="progress-bar">
<div class="progress-fill" id="progressFill"></div>
</div>
<p class="progress-text" id="progressText">0%</p>
<p class="eta-text" id="etaText"></p>
</div>
</div>
<div id="textError" class="alert alert-error hidden"></div>
<div id="textResult" class="result-section">
<div class="alert alert-success">
<svg width="22" height="22" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<div id="textResultMessage"></div>
</div>
<div id="textScreenshotGrid" class="screenshot-grid"></div>
</div>
</div>
<!-- ═══ HTML to Image ═══ -->
<div id="html-to-image" class="tool-section">
<div class="header">
<h2>HTML to Image</h2>
<p>Convert HTML files or code directly into high-quality screenshots</p>
</div>
<div class="card">
<div class="tabs">
<button class="tab active" onclick="switchHtmlTab('paste')">Paste HTML</button>
<button class="tab" onclick="switchHtmlTab('upload')">Upload File</button>
</div>
<div id="htmlPasteTab" class="tab-content">
<div class="form-group">
<label class="form-label">Paste your HTML code</label>
<textarea id="htmlInput" class="form-textarea font-mono"
placeholder="<!DOCTYPE html>&#10;<html>&#10;<head>&#10; <title>My Page</title>&#10;</head>&#10;<body>&#10; <h1>Hello World</h1>&#10;</body>&#10;</html>"></textarea>
</div>
</div>
<div id="htmlUploadTab" class="tab-content hidden">
<div class="form-group">
<label class="form-label">Upload HTML file</label>
<div class="file-upload" onclick="document.getElementById('htmlFile').click()">
<input type="file" id="htmlFile" accept=".html,.htm" onchange="handleFileUpload(event)">
<svg width="40" height="40" fill="none" stroke="currentColor" viewBox="0 0 24 24"
class="file-upload-icon">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12" />
</svg>
<p class="file-upload-text">Click to upload or drag and drop</p>
<p class="file-upload-hint">HTML files only</p>
</div>
<p id="fileName" class="file-name"></p>
</div>
</div>
<!-- Advanced Settings -->
<div class="advanced-toggle" onclick="toggleAdvancedHtml()">
<svg id="advancedIconHtml" width="18" height="18" fill="none" stroke="currentColor"
viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
</svg>
<span>Advanced Settings</span>
</div>
<div id="advancedSettingsHtml" class="advanced-settings hidden">
<div class="form-row">
<div class="form-group flex-1">
<label class="form-label">Zoom Level</label>
<input type="number" id="htmlZoom" class="form-input" value="2.1" min="1" max="5"
step="0.1">
<p class="form-hint">Default: 2.1× (210%)</p>
</div>
<div class="form-group flex-1">
<label class="form-label">Overlap (px)</label>
<input type="number" id="htmlOverlap" class="form-input" value="20" min="0" max="200"
step="5">
<p class="form-hint">Default: 15px</p>
</div>
</div>
<div class="form-row">
<div class="form-group flex-1">
<label class="form-label">Width</label>
<input type="number" id="htmlViewportWidth" class="form-input" value="1920" min="800"
max="3840" step="80">
<p class="form-hint">Output width in px</p>
</div>
<div class="form-group flex-1">
<label class="form-label">Height</label>
<input type="number" id="htmlViewportHeight" class="form-input" value="1080" min="600"
max="2160" step="60">
<p class="form-hint">Output height in px</p>
</div>
<div class="form-group flex-1">
<label class="form-label">Max Shots</label>
<input type="number" id="htmlMaxScreenshots" class="form-input" value="50" min="1"
max="100" step="1">
<p class="form-hint">Safety limit</p>
</div>
</div>
<button class="btn btn-secondary mt-4" onclick="resetAdvancedHtml()">
<svg width="14" height="14" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
</svg>
Reset Defaults
</button>
</div>
<div id="htmlButtonContainer" class="flex gap-12 mt-20">
<button class="btn btn-primary flex-1" onclick="generateFromHtml()">
<svg width="18" height="18" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
Generate Screenshots
</button>
</div>
</div>
<div id="htmlLoading" class="loading">
<div class="spinner"></div>
<p class="loading-text">Generating screenshots from HTML...</p>
</div>
<div id="htmlError" class="alert alert-error hidden"></div>
<div id="htmlResult" class="result-section">
<div class="alert alert-success">
<svg width="22" height="22" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<div id="htmlResultMessage"></div>
</div>
<div id="htmlScreenshotGrid" class="screenshot-grid"></div>
</div>
</div>
<!-- ═══ Image to Screenshots ═══ -->
<div id="image-to-screenshots" class="tool-section">
<div class="header">
<h2>Image to Screenshots</h2>
<p>Extract text from an image and convert it into a formatted HTML screenshot workflow</p>
</div>
<div class="card">
<div class="form-group">
<label class="form-label">Upload Image or PDF</label>
<div class="file-upload" onclick="document.getElementById('imageFile').click()">
<input type="file" id="imageFile" accept="image/*,application/pdf"
onchange="handleImageSelect(event)">
<svg width="40" height="40" fill="none" stroke="currentColor" viewBox="0 0 24 24"
class="file-upload-icon">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
<p class="file-upload-text">Click to upload a file</p>
<p class="file-upload-hint">JPG, PNG, WebP or PDF supported</p>
</div>
<div id="imagePreview" class="image-preview"></div>
</div>
<div class="form-group mt-20">
<label class="form-label">Optional Instructions (Context for AI)</label>
<textarea id="imageInstructions" class="form-textarea" rows="2"
placeholder="Example: This is a math worksheet. Extract all equations carefully."></textarea>
</div>
<div class="flex gap-12 mt-20">
<button class="btn btn-secondary flex-1" onclick="extractTextFromImage()"
id="btn-extract-stage-1">
<svg width="18" height="18" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
</svg>
Stage 1: Extract &amp; Review Text
</button>
<button class="btn btn-primary flex-1" onclick="processImageComplete()"
id="btn-process-complete">
<svg width="18" height="18" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M13 10V3L4 14h7v7l9-11h-7z" />
</svg>
Complete Workflow (Auto Generate)
</button>
<button class="btn btn-secondary hidden" onclick="cancelImageWorkflow()" id="btn-cancel-image">
❌ Cancel
</button>
</div>
<!-- Advanced Settings Toggle -->
<div class="advanced-toggle" onclick="toggleImageAdvanced()">
<svg width="18" height="18" fill="none" stroke="currentColor" viewBox="0 0 24 24"
id="image-advanced-toggle-icon">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
</svg>
<span id="image-advanced-toggle-text">Advanced Settings</span>
</div>
<div id="image-advanced-settings" class="advanced-settings hidden">
<!-- AI Settings -->
<div class="settings-group">
<h4>AI Settings</h4>
<div class="form-group">
<label class="form-label">System Prompt / Custom Instructions</label>
<textarea id="image-system-prompt" class="form-textarea" rows="3"
placeholder="Custom instructions for AI HTML generation...&#10;Example: Use Urdu language with a dark theme and modern design&#10;&#10;Leave empty to use default prompt"></textarea>
<p class="form-hint">Customize how AI generates HTML from the extracted text</p>
</div>
</div>
<!-- Screenshot Settings -->
<div class="settings-group">
<h4>Screenshot Settings</h4>
<div class="form-row">
<div class="form-group flex-1">
<label class="form-label">Zoom Level</label>
<input type="number" id="image-zoom" class="form-input" value="2.1" min="0.5"
max="5" step="0.1">
<p class="form-hint">Default: 2.1×</p>
</div>
<div class="form-group flex-1">
<label class="form-label">Overlap (px)</label>
<input type="number" id="image-overlap" class="form-input" value="20" min="0"
max="200" step="5">
<p class="form-hint">Default: 20px</p>
</div>
</div>
<div class="form-row">
<div class="form-group flex-1">
<label class="form-label">Viewport Width</label>
<input type="number" id="image-viewport-width" class="form-input" value="1920"
min="800" max="3840" step="10">
</div>
<div class="form-group flex-1">
<label class="form-label">Viewport Height</label>
<input type="number" id="image-viewport-height" class="form-input" value="1080"
min="600" max="2160" step="10">
</div>
<div class="form-group flex-1">
<label class="form-label">Max Screenshots</label>
<input type="number" id="image-max-screenshots" class="form-input" value="50"
min="1" max="100">
</div>
</div>
</div>
</div>
</div>
<!-- Progress Section (for SSE streaming) -->
<div id="image-progress-container" class="card hidden mt-20">
<h3>Progress</h3>
<!-- Step Indicators -->
<div class="step-indicators">
<div class="step-indicator" data-step="1">
<div class="step-icon">1</div>
<div class="step-label">Extract Text</div>
</div>
<div class="step-indicator" data-step="2">
<div class="step-icon">2</div>
<div class="step-label">Generate HTML</div>
</div>
<div class="step-indicator" data-step="3">
<div class="step-icon">3</div>
<div class="step-label">Create Screenshots</div>
</div>
</div>
<!-- Progress Bar -->
<div class="progress-bar-container">
<div class="progress-bar" id="image-progress-bar" role="progressbar" aria-valuenow="0"
aria-valuemin="0" aria-valuemax="100"></div>
</div>
<div class="progress-info">
<span id="image-progress-text">0%</span>
<span id="image-status-text">Starting...</span>
</div>
</div>
<div id="imageLoading" class="loading hidden">
<div class="spinner"></div>
<p class="loading-text">Processing image with Vision AI...</p>
</div>
<div id="imageError" class="alert alert-error hidden mt-20"></div>
<div id="imageResults" class="result-section hidden mt-20">
<!-- Result will be populated here -> Text for review or final Screenshots grid -->
</div>
</div>
<!-- ═══ Resources ═══ -->
<div id="resources" class="tool-section">
<div class="header">
<h2>Resources</h2>
<p>View, download, and manage your generated files</p>
</div>
<div class="card">
<div class="flex justify-between items-center mb-18 flex-wrap gap-10">
<div class="tabs mb-0">
<button class="tab active" onclick="switchResourceTab('screenshots')">Screenshots</button>
<button class="tab" onclick="switchResourceTab('html')">HTML Files</button>
</div>
<div class="flex gap-8 items-center">
<div id="bulkActions" class="hidden gap-8">
<span id="selectedCount" class="progress-text">0 selected</span>
<button class="btn btn-secondary" onclick="selectAll()">Select All</button>
<button class="btn btn-danger" onclick="deleteSelected()">
<svg width="14" height="14" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
</svg>
Delete
</button>
</div>
<button class="btn btn-secondary" onclick="refreshResources()">
<svg width="14" height="14" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
</svg>
Refresh
</button>
</div>
</div>
<div id="resourcesLoading" class="loading">
<div class="spinner"></div>
<p class="loading-text">Loading resources...</p>
</div>
<div id="resourcesError" class="alert alert-error hidden"></div>
<!-- Screenshots Tab -->
<div id="screenshotsTab" class="resource-tab-content">
<div id="screenshotsList" class="resources-grid"></div>
<div id="noScreenshots" class="empty-state hidden">
<svg width="48" height="48" fill="none" stroke="currentColor" viewBox="0 0 24 24"
class="empty-state-icon">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
<p class="empty-state-title">No screenshots yet</p>
<p class="empty-state-hint">Generate some screenshots to see them here</p>
</div>
</div>
<!-- HTML Files Tab -->
<div id="htmlTab" class="resource-tab-content hidden">
<div id="htmlFilesList" class="resources-list"></div>
<div id="noHtmlFiles" class="empty-state hidden">
<svg width="48" height="48" fill="none" stroke="currentColor" viewBox="0 0 24 24"
class="empty-state-icon">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
</svg>
<p class="empty-state-title">No HTML files yet</p>
<p class="empty-state-hint">Generate content to see HTML files here</p>
</div>
</div>
</div>
</div>
</main>
</div>
<!-- Image Preview Modal -->
<div id="imageModal" class="image-modal">
<button class="modal-close" onclick="closeImageModal()">&times;</button>
<button class="modal-download" onclick="downloadCurrentImage()">
<svg width="14" height="14" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" />
</svg>
Download
</button>
<button class="modal-nav modal-nav-prev" onclick="navigateImage(-1)"></button>
<button class="modal-nav modal-nav-next" onclick="navigateImage(1)"></button>
<div class="image-modal-content">
<img id="modalImage" src="" alt="Preview">
</div>
<div class="modal-info" id="modalInfo">1 / 1</div>
</div>
<!-- JavaScript Modules -->
<script src="{{ url_for('static', filename='js/notifications.js') }}"></script>
<script src="{{ url_for('static', filename='js/navigation.js') }}"></script>
<script src="{{ url_for('static', filename='js/settings-manager.js') }}"></script>
<script src="{{ url_for('static', filename='js/generation-manager.js') }}"></script>
<script src="{{ url_for('static', filename='js/text-to-image.js') }}"></script>
<script src="{{ url_for('static', filename='js/html-to-image.js') }}"></script>
<script src="{{ url_for('static', filename='js/image-to-screenshots.js') }}"></script>
<script src="{{ url_for('static', filename='js/resources.js') }}"></script>
<script src="{{ url_for('static', filename='js/utils.js') }}"></script>
<!-- Mobile sidebar control -->
<script>
function toggleSidebar() {
document.getElementById('sidebar').classList.toggle('open');
document.getElementById('sidebarOverlay').classList.toggle('active');
}
function closeSidebar() {
document.getElementById('sidebar').classList.remove('open');
document.getElementById('sidebarOverlay').classList.remove('active');
}
// Close sidebar when a nav item is clicked on mobile
document.querySelectorAll('.nav-item').forEach(item => {
item.addEventListener('click', () => {
if (window.innerWidth <= 768) closeSidebar();
});
});
</script>
</body>
</html>