Spaces:
Build error
Build error
Sami
Refactor Dockerfile and remove unused React app files; update TypeScript configuration for better compatibility
48530ea
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>VideoGen Pro V2 - Enhanced Video Generator</title> | |
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/tailwind.min.css" rel="stylesheet"> | |
<!-- Add React and other dependencies --> | |
<script src="https://unpkg.com/react@18/umd/react.production.min.js"></script> | |
<script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script> | |
<!-- Lucide Icons --> | |
<script src="https://unpkg.com/lucide@latest"></script> | |
<style> | |
body { | |
margin: 0; | |
padding: 0; | |
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; | |
background-color: #f1f5f9; | |
} | |
.app-container { | |
display: flex; | |
flex-direction: column; | |
min-height: 100vh; | |
max-width: 100vw; | |
overflow-x: hidden; | |
} | |
.header { | |
background-color: white; | |
border-bottom: 1px solid #e2e8f0; | |
padding: 0.75rem 1rem; | |
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1); | |
position: sticky; | |
top: 0; | |
z-index: 50; | |
} | |
.header-content { | |
max-width: 1280px; | |
margin: 0 auto; | |
display: flex; | |
justify-content: space-between; | |
align-items: center; | |
} | |
.logo-container { | |
display: flex; | |
align-items: center; | |
gap: 0.5rem; | |
} | |
.main-container { | |
flex: 1; | |
display: flex; | |
max-width: 1280px; | |
margin: 0 auto; | |
width: 100%; | |
} | |
.sidebar { | |
width: 14rem; | |
background-color: white; | |
border-right: 1px solid #e2e8f0; | |
padding: 1rem; | |
overflow-y: auto; | |
height: calc(100vh - 4rem); | |
position: sticky; | |
top: 4rem; | |
} | |
.main-content { | |
flex: 1; | |
padding: 1.5rem; | |
} | |
.tab-list { | |
display: grid; | |
grid-template-columns: repeat(2, minmax(0, 1fr)); | |
gap: 0.5rem; | |
margin-bottom: 1rem; | |
background-color: #f1f5f9; | |
padding: 0.25rem; | |
border-radius: 0.375rem; | |
} | |
.tab { | |
padding: 0.5rem; | |
text-align: center; | |
border-radius: 0.25rem; | |
font-weight: 500; | |
cursor: pointer; | |
} | |
.tab.active { | |
background-color: white; | |
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05); | |
} | |
.nav-button { | |
display: flex; | |
align-items: center; | |
gap: 0.5rem; | |
width: 100%; | |
padding: 0.5rem 0.75rem; | |
margin-bottom: 0.5rem; | |
border-radius: 0.375rem; | |
cursor: pointer; | |
transition: background-color 0.15s; | |
font-weight: 500; | |
} | |
.nav-button:hover { | |
background-color: #f8fafc; | |
} | |
.nav-button.active { | |
background-color: #3b82f6; | |
color: white; | |
} | |
.blocks-grid { | |
display: grid; | |
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); | |
gap: 1.5rem; | |
} | |
.block-card { | |
background-color: white; | |
border-radius: 0.5rem; | |
overflow: hidden; | |
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1); | |
transition: transform 0.15s, box-shadow 0.15s; | |
} | |
.block-card:hover { | |
transform: translateY(-2px); | |
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); | |
} | |
.block-preview { | |
aspect-ratio: 16/9; | |
position: relative; | |
} | |
.block-content { | |
position: absolute; | |
inset: 0; | |
background-image: linear-gradient(to top, rgba(0, 0, 0, 0.7), transparent); | |
display: flex; | |
flex-direction: column; | |
justify-content: flex-end; | |
padding: 1rem; | |
color: white; | |
} | |
.block-footer { | |
background-color: white; | |
padding: 0.75rem; | |
} | |
.preview-area { | |
aspect-ratio: 16/9; | |
background-color: #1a1a2e; | |
border-radius: 0.5rem; | |
position: relative; | |
overflow: hidden; | |
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); | |
margin-bottom: 1rem; | |
} | |
.preview-element { | |
position: absolute; | |
transition: opacity 0.3s; | |
} | |
.timeline { | |
height: 4rem; | |
background-color: #1a1a2e; | |
border-radius: 0.5rem; | |
position: relative; | |
margin-top: 0.5rem; | |
cursor: pointer; | |
} | |
.timeline-marker { | |
position: absolute; | |
top: 0; | |
height: 100%; | |
border-left: 1px solid rgba(255, 255, 255, 0.3); | |
color: rgba(255, 255, 255, 0.7); | |
font-size: 0.75rem; | |
padding-left: 0.25rem; | |
padding-top: 0.25rem; | |
} | |
.timeline-element { | |
position: absolute; | |
height: 1.25rem; | |
top: 1.5rem; | |
border-radius: 0.125rem; | |
} | |
.playhead { | |
position: absolute; | |
top: 0; | |
height: 100%; | |
width: 2px; | |
background-color: #ef4444; | |
z-index: 10; | |
} | |
.playhead::before { | |
content: ''; | |
display: block; | |
width: 0.75rem; | |
height: 0.75rem; | |
background-color: #ef4444; | |
border-radius: 9999px; | |
position: absolute; | |
top: -0.375rem; | |
left: -0.375rem; | |
} | |
.btn { | |
display: inline-flex; | |
align-items: center; | |
gap: 0.5rem; | |
padding: 0.5rem 1rem; | |
border-radius: 0.375rem; | |
font-weight: 500; | |
cursor: pointer; | |
transition: all 0.15s; | |
} | |
.btn-primary { | |
background-color: #3b82f6; | |
color: white; | |
} | |
.btn-primary:hover { | |
background-color: #2563eb; | |
} | |
.btn-outline { | |
background-color: white; | |
border: 1px solid #d1d5db; | |
} | |
.btn-outline:hover { | |
background-color: #f8fafc; | |
} | |
.content-table { | |
width: 100%; | |
background-color: white; | |
border-radius: 0.5rem; | |
overflow: hidden; | |
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1); | |
} | |
.table-header { | |
background-color: #f8fafc; | |
padding: 0.5rem 1rem; | |
border-bottom: 1px solid #e2e8f0; | |
display: grid; | |
grid-template-columns: 1fr 1fr 2fr 2fr 1fr; | |
gap: 1rem; | |
font-weight: 500; | |
color: #475569; | |
} | |
.table-row { | |
padding: 0.75rem 1rem; | |
border-bottom: 1px solid #e2e8f0; | |
display: grid; | |
grid-template-columns: 1fr 1fr 2fr 2fr 1fr; | |
gap: 1rem; | |
align-items: center; | |
} | |
.table-row:last-child { | |
border-bottom: none; | |
} | |
.table-input-row { | |
padding: 0.75rem 1rem; | |
background-color: #f8fafc; | |
display: grid; | |
grid-template-columns: 1fr 1fr 2fr 2fr 1fr; | |
gap: 1rem; | |
align-items: center; | |
} | |
.input { | |
padding: 0.5rem; | |
border: 1px solid #d1d5db; | |
border-radius: 0.375rem; | |
width: 100%; | |
} | |
.badge { | |
display: inline-flex; | |
align-items: center; | |
padding: 0.25rem 0.5rem; | |
border-radius: 9999px; | |
font-size: 0.75rem; | |
font-weight: 500; | |
} | |
.badge-blue { | |
background-color: #dbeafe; | |
color: #1e40af; | |
} | |
</style> | |
</head> | |
<body> | |
<div class="app-container"> | |
<!-- Header --> | |
<header class="header"> | |
<div class="header-content"> | |
<div class="logo-container"> | |
<i data-lucide="file-video" class="text-blue-600"></i> | |
<h1 class="text-xl font-bold">VideoGen Pro</h1> | |
<input type="text" class="ml-6 border border-gray-300 rounded px-3 py-1.5 w-60" value="Vocabulary Project"> | |
</div> | |
<div class="flex gap-2"> | |
<button class="btn btn-outline"> | |
<i data-lucide="file-text"></i> | |
Project | |
</button> | |
<button class="btn btn-outline"> | |
<i data-lucide="download"></i> | |
Export | |
</button> | |
<button class="btn btn-outline w-10 h-10 p-0 flex items-center justify-center"> | |
<i data-lucide="settings"></i> | |
</button> | |
</div> | |
</div> | |
</header> | |
<!-- Main Content --> | |
<div class="main-container"> | |
<!-- Sidebar --> | |
<div class="sidebar"> | |
<div class="tab-list"> | |
<div class="tab active">Blocks</div> | |
<div class="tab">Content</div> | |
</div> | |
<div class="flex flex-col space-y-2"> | |
<button class="nav-button active"> | |
<i data-lucide="layers"></i> | |
Blocks | |
</button> | |
<button class="nav-button"> | |
<i data-lucide="file-text"></i> | |
Content | |
</button> | |
<button class="nav-button"> | |
<i data-lucide="edit-3"></i> | |
Editor | |
</button> | |
<button class="nav-button"> | |
<i data-lucide="zap"></i> | |
Generate | |
</button> | |
</div> | |
<div class="mt-6 border-t pt-4"> | |
<h3 class="text-sm font-medium text-gray-500 mb-2">Add Elements</h3> | |
<div class="grid grid-cols-3 gap-2"> | |
<button class="p-1 border rounded"> | |
<i data-lucide="file-text"></i> | |
</button> | |
<button class="p-1 border rounded"> | |
<i data-lucide="layers"></i> | |
</button> | |
<button class="p-1 border rounded"> | |
<i data-lucide="volume-2"></i> | |
</button> | |
</div> | |
<h3 class="text-sm font-medium text-gray-500 mt-4 mb-2">Animation Style</h3> | |
<select class="input text-sm"> | |
<option>Fade In</option> | |
<option>Slide In</option> | |
<option>Zoom In</option> | |
<option>Bounce In</option> | |
<option>Flip In</option> | |
</select> | |
<div class="flex items-center justify-between mt-4"> | |
<span class="text-sm">Auto-sync to Audio</span> | |
<label class="relative inline-flex items-center cursor-pointer"> | |
<input type="checkbox" class="sr-only peer" checked> | |
<div class="w-9 h-5 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-300 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all peer-checked:bg-blue-600"></div> | |
</label> | |
</div> | |
</div> | |
</div> | |
<!-- Main Content --> | |
<div class="main-content"> | |
<div> | |
<div class="flex justify-between items-center mb-6"> | |
<h2 class="text-2xl font-bold">Video Blocks</h2> | |
<button class="btn btn-outline"> | |
<i data-lucide="plus"></i> | |
Import Block | |
</button> | |
</div> | |
<div class="blocks-grid"> | |
<!-- Block 1 - Active --> | |
<div class="block-card ring-2 ring-blue-500"> | |
<div class="block-preview" style="background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%)"> | |
<div class="absolute inset-0 flex items-center justify-center"> | |
<div class="w-24 h-24 rounded bg-white/10"></div> | |
</div> | |
<div class="block-content"> | |
<h3 class="text-lg font-medium">Vocabulary Block</h3> | |
<p class="text-sm text-white/80">Standard vocabulary block with word and phrases</p> | |
</div> | |
<span class="badge badge-blue absolute top-2 right-2">15s</span> | |
</div> | |
<div class="block-footer"> | |
<button class="btn btn-primary w-full"> | |
<i data-lucide="check"></i> | |
Selected | |
</button> | |
</div> | |
</div> | |
<!-- Block 2 --> | |
<div class="block-card"> | |
<div class="block-preview" style="background: linear-gradient(135deg, #16213e 0%, #0f3460 100%)"> | |
<div class="absolute inset-0 flex items-center justify-center"> | |
<div class="w-24 h-24 rounded bg-white/10"></div> | |
</div> | |
<div class="block-content"> | |
<h3 class="text-lg font-medium">Grammar Block</h3> | |
<p class="text-sm text-white/80">Block for grammar explanations with examples</p> | |
</div> | |
<span class="badge badge-blue absolute top-2 right-2">20s</span> | |
</div> | |
<div class="block-footer"> | |
<button class="btn btn-outline w-full">Select Block</button> | |
</div> | |
</div> | |
<!-- Block 3 --> | |
<div class="block-card"> | |
<div class="block-preview" style="background: linear-gradient(135deg, #0f3460 0%, #950740 100%)"> | |
<div class="absolute inset-0 flex items-center justify-center"> | |
<div class="w-24 h-24 rounded bg-white/10"></div> | |
</div> | |
<div class="block-content"> | |
<h3 class="text-lg font-medium">Conversation Block</h3> | |
<p class="text-sm text-white/80">Dialog-based block for conversation practice</p> | |
</div> | |
<span class="badge badge-blue absolute top-2 right-2">30s</span> | |
</div> | |
<div class="block-footer"> | |
<button class="btn btn-outline w-full">Select Block</button> | |
</div> | |
</div> | |
</div> | |
<!-- Content View (Hidden) --> | |
<div class="hidden"> | |
<div class="flex justify-between items-center mb-6"> | |
<h2 class="text-2xl font-bold">Content</h2> | |
<div class="flex gap-2"> | |
<select class="input w-40"> | |
<option>Español</option> | |
<option>Français</option> | |
<option>Deutsch</option> | |
<option>Italiano</option> | |
</select> | |
<select class="input w-40"> | |
<option>English</option> | |
<option>Español</option> | |
<option>Français</option> | |
<option>Deutsch</option> | |
</select> | |
</div> | |
</div> | |
<div class="content-table mb-6"> | |
<div class="table-header text-sm"> | |
<div>Target Word</div> | |
<div>Native Word</div> | |
<div>Target Phrase 1</div> | |
<div>Native Phrase 1</div> | |
<div>Actions</div> | |
</div> | |
<div class="table-row"> | |
<div>médico</div> | |
<div>doctor</div> | |
<div>quiere ser médico</div> | |
<div>he wants to be a doctor</div> | |
<div class="flex gap-1"> | |
<button class="p-1 text-gray-500 hover:text-gray-700"> | |
<i data-lucide="eye"></i> | |
</button> | |
<button class="p-1 text-gray-500 hover:text-gray-700"> | |
<i data-lucide="trash-2"></i> | |
</button> | |
</div> | |
</div> | |
<div class="table-row"> | |
<div>abogado</div> | |
<div>lawyer</div> | |
<div>estudia para abogado</div> | |
<div>he studies to be a lawyer</div> | |
<div class="flex gap-1"> | |
<button class="p-1 text-gray-500 hover:text-gray-700"> | |
<i data-lucide="eye"></i> | |
</button> | |
<button class="p-1 text-gray-500 hover:text-gray-700"> | |
<i data-lucide="trash-2"></i> | |
</button> | |
</div> | |
</div> | |
<div class="table-input-row"> | |
<div> | |
<input type="text" class="input" placeholder="Target Word"> | |
</div> | |
<div> | |
<input type="text" class="input" placeholder="Native Word"> | |
</div> | |
<div> | |
<input type="text" class="input" placeholder="Target Phrase 1"> | |
</div> | |
<div> | |
<input type="text" class="input" placeholder="Native Phrase 1"> | |
</div> | |
<div> | |
<button class="btn btn-primary"> | |
<i data-lucide="plus"></i> | |
Add | |
</button> | |
</div> | |
</div> | |
</div> | |
<div class="flex justify-between"> | |
<button class="btn btn-outline"> | |
<i data-lucide="volume-2"></i> | |
Generate Audio | |
</button> | |
<button class="btn btn-primary"> | |
Continue to Editor | |
<i data-lucide="chevron-down" class="rotate-270"></i> | |
</button> | |
</div> | |
</div> | |
<!-- Editor View (Hidden) --> | |
<div class="hidden"> | |
<div class="flex justify-between items-center mb-6"> | |
<h2 class="text-2xl font-bold">Block Editor</h2> | |
</div> | |
<!-- Preview Area --> | |
<div class="preview-area"> | |
<!-- Word Element --> | |
<div class="preview-element" style="left: 50%; top: 20%; transform: translate(-50%, -50%); color: white; font-size: 36px; font-weight: bold; text-shadow: 0 1px 2px rgba(0,0,0,0.5);"> | |
médico | |
</div> | |
<!-- Block Element --> | |
<div class="preview-element" style="left: 30%; top: 35%; transform: translate(-50%, -50%); width: 200px; height: 200px; border-radius: 8px; background: linear-gradient(45deg, #3490dc, #6574cd);"> | |
</div> | |
<!-- Example Phrase 1 --> | |
<div class="preview-element" style="left: 50%; top: 65%; transform: translate(-50%, -50%); color: white; font-size: 24px; text-shadow: 0 1px 2px rgba(0,0,0,0.5);"> | |
quiere ser médico | |
</div> | |
<!-- Example Phrase 2 --> | |
<div class="preview-element" style="left: 50%; top: 80%; transform: translate(-50%, -50%); color: white; font-size: 24px; text-shadow: 0 1px 2px rgba(0,0,0,0.5);"> | |
su médico es bueno | |
</div> | |
<!-- Controls --> | |
<div class="absolute bottom-4 left-1/2 transform -translate-x-1/2 flex space-x-2 bg-black/70 rounded-full p-2"> | |
<button class="text-white px-2"> | |
<i data-lucide="arrow-left" class="w-4 h-4"></i> | |
</button> | |
<button class="text-white px-2"> | |
<i data-lucide="play" class="w-5 h-5"></i> | |
</button> | |
<button class="text-white px-2"> | |
<i data-lucide="arrow-right" class="w-4 h-4"></i> | |
</button> | |
</div> | |
<!-- Timeline Progress --> | |
<div class="absolute bottom-0 left-0 right-0 h-1 bg-gray-700"> | |
<div class="h-full bg-blue-500" style="width: 25%;"></div> | |
</div> | |
</div> | |
<!-- Timeline --> | |
<div class="timeline"> | |
<!-- Time Markers --> | |
<div class="timeline-marker" style="left: 0%">0s</div> | |
<div class="timeline-marker" style="left: 20%">3s</div> | |
<div class="timeline-marker" style="left: 40%">6s</div> | |
<div class="timeline-marker" style="left: 60%">9s</div> | |
<div class="timeline-marker" style="left: 80%">12s</div> | |
<div class="timeline-marker" style="left: 100%">15s</div> | |
<!-- Timeline Elements --> | |
<div class="timeline-element" style="left: 0%; width: 20%; background-color: rgba(59, 130, 246, 0.7); top: 0px;"> | |
<div class="truncate text-xs text-white px-1 py-0.5">Vocabulary Word</div> | |
</div> | |
<div class="timeline-element" style="left: 3.33%; width: 80%; background-color: rgba(16, 185, 129, 0.7);"> | |
<div class="truncate text-xs text-white px-1 py-0.5">Color Block</div> | |
</div> | |
<div class="timeline-element" style="left: 26.67%; width: 20%; background-color: rgba(59, 130, 246, 0.7);"> | |
<div class="truncate text-xs text-white px-1 py-0.5">Example Phrase 1</div> | |
</div> | |
<div class="timeline-element" style="left: 53.33%; width: 20%; background-color: rgba(59, 130, 246, 0.7);"> | |
<div class="truncate text-xs text-white px-1 py-0.5">Example Phrase 2</div> | |
</div> | |
<div class="timeline-element" style="left: 0%; width: 100%; background-color: rgba(124, 58, 237, 0.7); top: 35px;"> | |
<div class="truncate text-xs text-white px-1 py-0.5">audio</div> | |
</div> | |
<!-- Playhead --> | |
<div class="playhead" style="left: 25%;"></div> | |
</div> | |
<div class="flex justify-between mt-4"> | |
<div class="flex gap-2"> | |
<button class="btn btn-outline"> | |
<i data-lucide="arrow-left"></i> | |
Previous | |
</button> | |
<button class="btn btn-outline"> | |
Next | |
<i data-lucide="arrow-right"></i> | |
</button> | |
<div class="bg-gray-100 px-2 py-1 rounded text-sm flex items-center"> | |
Item 1 of 2 | |
</div> | |
</div> | |
<button class="btn btn-primary"> | |
Continue to Generate | |
<i data-lucide="chevron-down" class="rotate-270"></i> | |
</button> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
<script> | |
// Initialize Lucide icons | |
lucide.createIcons(); | |
// Add some basic interactivity | |
document.addEventListener('DOMContentLoaded', function() { | |
// Tab switching | |
const tabs = document.querySelectorAll('.tab'); | |
const navButtons = document.querySelectorAll('.nav-button'); | |
const mainViews = document.querySelectorAll('.main-content > div > div'); | |
tabs.forEach((tab, index) => { | |
tab.addEventListener('click', function() { | |
tabs.forEach(t => t.classList.remove('active')); | |
tab.classList.add('active'); | |
// Activate corresponding nav button | |
navButtons.forEach(btn => btn.classList.remove('active')); | |
navButtons[index].classList.add('active'); | |
// Show corresponding view | |
mainViews.forEach(view => view.classList.add('hidden')); | |
mainViews[index].classList.remove('hidden'); | |
}); | |
}); | |
navButtons.forEach((btn, index) => { | |
btn.addEventListener('click', function() { | |
navButtons.forEach(b => b.classList.remove('active')); | |
btn.classList.add('active'); | |
// Activate corresponding tab if applicable | |
if (index < 2) { | |
tabs.forEach(t => t.classList.remove('active')); | |
tabs[index].classList.add('active'); | |
} | |
// Show corresponding view | |
mainViews.forEach(view => view.classList.add('hidden')); | |
mainViews[index].classList.remove('hidden'); | |
}); | |
}); | |
// Block card selection | |
document.querySelectorAll('.block-card').forEach(card => { | |
card.addEventListener('click', function() { | |
document.querySelectorAll('.block-card').forEach(c => { | |
c.classList.remove('ring-2', 'ring-blue-500'); | |
c.querySelector('.block-footer button').classList.remove('btn-primary'); | |
c.querySelector('.block-footer button').classList.add('btn-outline'); | |
c.querySelector('.block-footer button').innerHTML = 'Select Block'; | |
}); | |
card.classList.add('ring-2', 'ring-blue-500'); | |
card.querySelector('.block-footer button').classList.remove('btn-outline'); | |
card.querySelector('.block-footer button').classList.add('btn-primary'); | |
card.querySelector('.block-footer button').innerHTML = '<i data-lucide="check"></i> Selected'; | |
lucide.createIcons(); | |
// Automatically move to content tab | |
tabs[1].click(); | |
}); | |
}); | |
}); | |
</script> | |
</body> | |
</html> |