style: drop all type weight from medium (500) to normal (400)
DM Sans at weight 400 is clean and readable — hierarchy now comes entirely from size, not weight. Lighter overall feel. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
0093b6dc92
commit
c5002b8c6b
8 changed files with 112 additions and 112 deletions
|
|
@ -98,7 +98,7 @@ function AppContent() {
|
|||
<div className="flex flex-col items-end gap-1">
|
||||
{activeProjectName && (
|
||||
<div className="text-sm text-slate-400">
|
||||
Working in: <span className="text-cinema-gold font-medium">{activeProjectName}</span>
|
||||
Working in: <span className="text-cinema-gold font-normal">{activeProjectName}</span>
|
||||
</div>
|
||||
)}
|
||||
<div className="text-xs text-slate-500">
|
||||
|
|
|
|||
|
|
@ -1419,14 +1419,14 @@ Return ONLY the final prompt text. No markdown, no preamble, no "Here is your pr
|
|||
{/* Left Column: Controls */}
|
||||
<div className="lg:col-span-4">
|
||||
<div className="bg-slate-900/50 border border-slate-800 rounded p-6 space-y-6">
|
||||
<h2 className="text-lg font-medium text-slate-200 flex items-center space-x-2">
|
||||
<h2 className="text-lg font-normal text-slate-200 flex items-center space-x-2">
|
||||
<Camera className="w-5 h-5 text-cinema-gold" />
|
||||
<span>Technical Specs</span>
|
||||
</h2>
|
||||
|
||||
{/* Application/Lighting Preset */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-slate-400 flex items-center gap-2">
|
||||
<label className="text-xs font-normal text-slate-400 flex items-center gap-2">
|
||||
Preset
|
||||
<span className="text-xs font-normal normal-case text-slate-500">Lighting / application presets + Styles</span>
|
||||
{customPresets.length > 0 && (
|
||||
|
|
@ -1538,7 +1538,7 @@ Return ONLY the final prompt text. No markdown, no preamble, no "Here is your pr
|
|||
|
||||
{/* Camera Body */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-slate-400">
|
||||
<label className="text-xs font-normal text-slate-400">
|
||||
Camera Body
|
||||
</label>
|
||||
<select
|
||||
|
|
@ -1557,7 +1557,7 @@ Return ONLY the final prompt text. No markdown, no preamble, no "Here is your pr
|
|||
|
||||
{/* Lens Kit */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-slate-400">
|
||||
<label className="text-xs font-normal text-slate-400">
|
||||
Lens Kit
|
||||
</label>
|
||||
<select
|
||||
|
|
@ -1576,7 +1576,7 @@ Return ONLY the final prompt text. No markdown, no preamble, no "Here is your pr
|
|||
|
||||
{/* Aspect Ratio */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-slate-400">
|
||||
<label className="text-xs font-normal text-slate-400">
|
||||
Aspect Ratio
|
||||
</label>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
|
|
@ -1584,7 +1584,7 @@ Return ONLY the final prompt text. No markdown, no preamble, no "Here is your pr
|
|||
<button
|
||||
key={ratio}
|
||||
onClick={() => setAspectRatio(ratio)}
|
||||
className={`px-4 py-2 rounded font-medium transition-all ${
|
||||
className={`px-4 py-2 rounded font-normal transition-all ${
|
||||
aspectRatio === ratio
|
||||
? 'bg-cinema-gold text-slate-950'
|
||||
: 'bg-slate-800 text-slate-400 hover:bg-slate-700'
|
||||
|
|
@ -1609,7 +1609,7 @@ Return ONLY the final prompt text. No markdown, no preamble, no "Here is your pr
|
|||
{/* Creative Freedom Slider - Moved to left column */}
|
||||
<div className="space-y-3 pt-4 border-t border-slate-800">
|
||||
<div className="flex items-center justify-between">
|
||||
<label className="text-xs font-medium text-slate-400 flex items-center gap-2">
|
||||
<label className="text-xs font-normal text-slate-400 flex items-center gap-2">
|
||||
<Sliders className="w-4 h-4" />
|
||||
Creative Freedom
|
||||
</label>
|
||||
|
|
@ -1636,7 +1636,7 @@ Return ONLY the final prompt text. No markdown, no preamble, no "Here is your pr
|
|||
|
||||
{/* Scene Description - Moved to left column */}
|
||||
<div className="space-y-3">
|
||||
<label className="text-xs font-medium text-slate-400">
|
||||
<label className="text-xs font-normal text-slate-400">
|
||||
Scene Description
|
||||
</label>
|
||||
<textarea
|
||||
|
|
@ -1651,7 +1651,7 @@ Return ONLY the final prompt text. No markdown, no preamble, no "Here is your pr
|
|||
<button
|
||||
onClick={generateOptimizedPrompt}
|
||||
disabled={isGenerating}
|
||||
className="flex items-center justify-center space-x-2 w-full px-4 py-3 bg-slate-200 hover:bg-slate-300 text-slate-900 font-medium rounded transition-all disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
className="flex items-center justify-center space-x-2 w-full px-4 py-3 bg-slate-200 hover:bg-slate-300 text-slate-900 font-normal rounded transition-all disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
>
|
||||
{isGenerating ? (
|
||||
<>
|
||||
|
|
@ -1668,7 +1668,7 @@ Return ONLY the final prompt text. No markdown, no preamble, no "Here is your pr
|
|||
|
||||
<button
|
||||
onClick={generateSimplePrompt}
|
||||
className="w-full px-4 py-3 bg-slate-800 hover:bg-slate-700 text-slate-300 font-medium rounded transition-all"
|
||||
className="w-full px-4 py-3 bg-slate-800 hover:bg-slate-700 text-slate-300 font-normal rounded transition-all"
|
||||
>
|
||||
Simple Generate
|
||||
</button>
|
||||
|
|
@ -1688,7 +1688,7 @@ Return ONLY the final prompt text. No markdown, no preamble, no "Here is your pr
|
|||
{/* Generated Prompt Output */}
|
||||
<div className="relative bg-slate-900 border border-slate-800 rounded overflow-hidden">
|
||||
<div className="p-6 space-y-4">
|
||||
<h3 className="text-xs font-medium text-slate-400">
|
||||
<h3 className="text-xs font-normal text-slate-400">
|
||||
Optimized Prompt
|
||||
</h3>
|
||||
<div className="flex items-center gap-1.5 text-xs text-emerald-400/70 mt-1">
|
||||
|
|
@ -1709,7 +1709,7 @@ Return ONLY the final prompt text. No markdown, no preamble, no "Here is your pr
|
|||
<div className="flex items-center justify-between pt-4 border-t border-slate-800">
|
||||
<button
|
||||
onClick={copyToClipboard}
|
||||
className="flex items-center space-x-2 px-5 py-2.5 bg-white hover:bg-slate-100 text-slate-950 font-medium rounded transition-all"
|
||||
className="flex items-center space-x-2 px-5 py-2.5 bg-white hover:bg-slate-100 text-slate-950 font-normal rounded transition-all"
|
||||
>
|
||||
{copied ? (
|
||||
<>
|
||||
|
|
@ -1735,7 +1735,7 @@ Return ONLY the final prompt text. No markdown, no preamble, no "Here is your pr
|
|||
{/* Image Generation Panel */}
|
||||
<div className="bg-slate-900/50 border border-slate-800 rounded p-6 space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<h3 className="text-lg font-medium text-slate-200 flex items-center gap-2">
|
||||
<h3 className="text-lg font-normal text-slate-200 flex items-center gap-2">
|
||||
<Image className="w-5 h-5 text-cinema-gold" />
|
||||
Generated Image
|
||||
</h3>
|
||||
|
|
@ -1758,7 +1758,7 @@ Return ONLY the final prompt text. No markdown, no preamble, no "Here is your pr
|
|||
{/* Reference Images Upload */}
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<label className="text-xs font-medium text-slate-400">Reference Images (Optional)</label>
|
||||
<label className="text-xs font-normal text-slate-400">Reference Images (Optional)</label>
|
||||
<span className="text-xs text-slate-500">{referenceImages.length}/14</span>
|
||||
</div>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
|
|
@ -1812,7 +1812,7 @@ Return ONLY the final prompt text. No markdown, no preamble, no "Here is your pr
|
|||
{showProjectPicker && projectImages.length > 0 && (
|
||||
<div className="bg-slate-800 border border-slate-700 rounded p-3">
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<span className="text-xs font-medium text-slate-400">From Project</span>
|
||||
<span className="text-xs font-normal text-slate-400">From Project</span>
|
||||
<button
|
||||
onClick={() => setShowProjectPicker(false)}
|
||||
className="text-slate-500 hover:text-slate-300"
|
||||
|
|
@ -1850,13 +1850,13 @@ Return ONLY the final prompt text. No markdown, no preamble, no "Here is your pr
|
|||
|
||||
{/* Model Selector */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-slate-400">Model</label>
|
||||
<label className="text-xs font-normal text-slate-400">Model</label>
|
||||
<div className="flex gap-2">
|
||||
{imageModelOptions.map((opt) => (
|
||||
<button
|
||||
key={opt.value}
|
||||
onClick={() => setImageModelType(opt.value)}
|
||||
className={`flex-1 px-3 py-2 rounded font-medium transition-all text-sm ${
|
||||
className={`flex-1 px-3 py-2 rounded font-normal transition-all text-sm ${
|
||||
imageModelType === opt.value
|
||||
? 'bg-cinema-gold text-slate-950'
|
||||
: 'bg-slate-800 text-slate-400 hover:bg-slate-700'
|
||||
|
|
@ -1871,13 +1871,13 @@ Return ONLY the final prompt text. No markdown, no preamble, no "Here is your pr
|
|||
|
||||
{/* Resolution Selector */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-slate-400">Output Resolution</label>
|
||||
<label className="text-xs font-normal text-slate-400">Output Resolution</label>
|
||||
<div className="flex gap-2">
|
||||
{['1K', '2K', '4K'].map((res) => (
|
||||
<button
|
||||
key={res}
|
||||
onClick={() => setImageResolution(res)}
|
||||
className={`px-4 py-2 rounded text-sm font-medium transition-all ${
|
||||
className={`px-4 py-2 rounded text-sm font-normal transition-all ${
|
||||
imageResolution === res
|
||||
? 'bg-cinema-gold text-slate-950'
|
||||
: 'bg-slate-800 text-slate-400 hover:bg-slate-700'
|
||||
|
|
@ -1948,7 +1948,7 @@ Return ONLY the final prompt text. No markdown, no preamble, no "Here is your pr
|
|||
<button
|
||||
onClick={generateImage}
|
||||
disabled={!generatedPrompt || isGeneratingImage}
|
||||
className="flex-1 flex items-center justify-center gap-2 px-4 py-3 bg-cinema-gold hover:bg-amber-400 text-slate-950 font-medium rounded transition-all disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
className="flex-1 flex items-center justify-center gap-2 px-4 py-3 bg-cinema-gold hover:bg-amber-400 text-slate-950 font-normal rounded transition-all disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
>
|
||||
{isGeneratingImage ? (
|
||||
<>
|
||||
|
|
@ -2032,7 +2032,7 @@ Return ONLY the final prompt text. No markdown, no preamble, no "Here is your pr
|
|||
<div className="fixed inset-0 bg-black/60 z-50 flex items-center justify-center p-4">
|
||||
<div className="bg-slate-900 border border-slate-700 rounded w-full max-w-md p-6 space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<h3 className="text-lg font-medium text-slate-200">
|
||||
<h3 className="text-lg font-normal text-slate-200">
|
||||
{editingPreset ? 'Edit Preset' : 'Create New Preset'}
|
||||
</h3>
|
||||
<button onClick={() => setShowPresetModal(false)} className="text-slate-500 hover:text-slate-300">
|
||||
|
|
@ -2042,7 +2042,7 @@ Return ONLY the final prompt text. No markdown, no preamble, no "Here is your pr
|
|||
|
||||
<div className="space-y-3">
|
||||
<div>
|
||||
<label className="text-xs font-medium text-slate-400">Preset Name *</label>
|
||||
<label className="text-xs font-normal text-slate-400">Preset Name *</label>
|
||||
<input
|
||||
type="text"
|
||||
value={presetForm.name}
|
||||
|
|
@ -2053,7 +2053,7 @@ Return ONLY the final prompt text. No markdown, no preamble, no "Here is your pr
|
|||
</div>
|
||||
|
||||
<div>
|
||||
<label className="text-xs font-medium text-slate-400">Lighting Description *</label>
|
||||
<label className="text-xs font-normal text-slate-400">Lighting Description *</label>
|
||||
<textarea
|
||||
value={presetForm.lighting}
|
||||
onChange={(e) => setPresetForm({ ...presetForm, lighting: e.target.value })}
|
||||
|
|
@ -2065,7 +2065,7 @@ Return ONLY the final prompt text. No markdown, no preamble, no "Here is your pr
|
|||
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<div>
|
||||
<label className="text-xs font-medium text-slate-400">Default Camera</label>
|
||||
<label className="text-xs font-normal text-slate-400">Default Camera</label>
|
||||
<select
|
||||
value={presetForm.defaultCamera}
|
||||
onChange={(e) => setPresetForm({ ...presetForm, defaultCamera: e.target.value })}
|
||||
|
|
@ -2078,7 +2078,7 @@ Return ONLY the final prompt text. No markdown, no preamble, no "Here is your pr
|
|||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-xs font-medium text-slate-400">Default Lens</label>
|
||||
<label className="text-xs font-normal text-slate-400">Default Lens</label>
|
||||
<select
|
||||
value={presetForm.defaultLens}
|
||||
onChange={(e) => setPresetForm({ ...presetForm, defaultLens: e.target.value })}
|
||||
|
|
@ -2094,7 +2094,7 @@ Return ONLY the final prompt text. No markdown, no preamble, no "Here is your pr
|
|||
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<label className="text-xs font-medium text-slate-400">Focus Mode</label>
|
||||
<label className="text-xs font-normal text-slate-400">Focus Mode</label>
|
||||
<select
|
||||
value={presetForm.focusType}
|
||||
onChange={(e) => setPresetForm({ ...presetForm, focusType: e.target.value })}
|
||||
|
|
@ -2126,7 +2126,7 @@ Return ONLY the final prompt text. No markdown, no preamble, no "Here is your pr
|
|||
<button
|
||||
onClick={handleSavePreset}
|
||||
disabled={!presetForm.name.trim() || !presetForm.lighting.trim()}
|
||||
className="px-4 py-2 bg-cinema-gold hover:bg-amber-400 text-slate-950 font-medium rounded text-sm transition-all disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
className="px-4 py-2 bg-cinema-gold hover:bg-amber-400 text-slate-950 font-normal rounded text-sm transition-all disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
>
|
||||
{editingPreset ? 'Save Changes' : 'Create Preset'}
|
||||
</button>
|
||||
|
|
@ -2140,7 +2140,7 @@ Return ONLY the final prompt text. No markdown, no preamble, no "Here is your pr
|
|||
<div className="fixed inset-0 bg-black/60 z-50 flex items-center justify-center p-4">
|
||||
<div className="bg-slate-900 border border-slate-700 rounded w-full max-w-lg p-6 space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<h3 className="text-lg font-medium text-slate-200">Manage Custom Presets</h3>
|
||||
<h3 className="text-lg font-normal text-slate-200">Manage Custom Presets</h3>
|
||||
<button onClick={() => setShowManagePresetsModal(false)} className="text-slate-500 hover:text-slate-300">
|
||||
<X className="w-5 h-5" />
|
||||
</button>
|
||||
|
|
@ -2153,7 +2153,7 @@ Return ONLY the final prompt text. No markdown, no preamble, no "Here is your pr
|
|||
{customPresets.map((p) => (
|
||||
<div key={p.id} className="flex items-center justify-between bg-slate-800 rounded px-4 py-3">
|
||||
<div>
|
||||
<div className="text-sm text-slate-200 font-medium">{p.name}</div>
|
||||
<div className="text-sm text-slate-200 font-normal">{p.name}</div>
|
||||
<div className="text-xs text-slate-500 truncate max-w-xs">{p.lighting}</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
|
|
@ -2186,7 +2186,7 @@ Return ONLY the final prompt text. No markdown, no preamble, no "Here is your pr
|
|||
<div className="flex items-center gap-2 pt-2 border-t border-slate-800">
|
||||
<button
|
||||
onClick={openCreatePresetModal}
|
||||
className="flex items-center gap-1.5 px-3 py-2 bg-cinema-gold hover:bg-amber-400 text-slate-950 font-medium rounded text-sm transition-all"
|
||||
className="flex items-center gap-1.5 px-3 py-2 bg-cinema-gold hover:bg-amber-400 text-slate-950 font-normal rounded text-sm transition-all"
|
||||
>
|
||||
<Plus className="w-4 h-4" />
|
||||
New Preset
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ const LoginPage = () => {
|
|||
alt="Lux Studio"
|
||||
className="h-16 w-auto mx-auto mb-6"
|
||||
/>
|
||||
<h1 className="text-3xl font-medium text-slate-100 mb-2">
|
||||
<h1 className="text-3xl font-normal text-slate-100 mb-2">
|
||||
Welcome to Lux Studio
|
||||
</h1>
|
||||
<p className="text-slate-400">
|
||||
|
|
@ -33,7 +33,7 @@ const LoginPage = () => {
|
|||
<div className="bg-slate-900 rounded p-8 shadow-sm border border-slate-800">
|
||||
<button
|
||||
onClick={handleLogin}
|
||||
className="w-full bg-cinema-gold hover:bg-yellow-500 text-slate-950 font-medium py-3 px-6 rounded transition-colors flex items-center justify-center gap-3"
|
||||
className="w-full bg-cinema-gold hover:bg-yellow-500 text-slate-950 font-normal py-3 px-6 rounded transition-colors flex items-center justify-center gap-3"
|
||||
>
|
||||
<svg className="w-5 h-5" viewBox="0 0 21 21" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M0 0h10v10H0V0z" fill="#f25022"/>
|
||||
|
|
|
|||
|
|
@ -577,7 +577,7 @@ const ProjectsTab = ({ onProjectSelect, activeProjectId, onRerunVideo, onEditInI
|
|||
<div className="lg:col-span-4">
|
||||
<div className="bg-slate-900/50 border border-slate-800 rounded p-6 space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<h2 className="text-lg font-medium text-slate-200 flex items-center space-x-2">
|
||||
<h2 className="text-lg font-normal text-slate-200 flex items-center space-x-2">
|
||||
<FolderOpen className="w-5 h-5 text-cinema-gold" />
|
||||
<span>Projects</span>
|
||||
</h2>
|
||||
|
|
@ -683,7 +683,7 @@ const ProjectsTab = ({ onProjectSelect, activeProjectId, onRerunVideo, onEditInI
|
|||
) : (
|
||||
<>
|
||||
<div className="flex items-center justify-between">
|
||||
<h3 className="font-medium text-slate-200 truncate">{project.name}</h3>
|
||||
<h3 className="font-normal text-slate-200 truncate">{project.name}</h3>
|
||||
<div className="flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-opacity">
|
||||
<button
|
||||
onClick={(e) => {
|
||||
|
|
@ -729,7 +729,7 @@ const ProjectsTab = ({ onProjectSelect, activeProjectId, onRerunVideo, onEditInI
|
|||
{/* Project Header */}
|
||||
<div className="flex items-center justify-between pb-4 border-b border-slate-800">
|
||||
<div>
|
||||
<h2 className="text-xl font-medium text-slate-200">{selectedProject.name}</h2>
|
||||
<h2 className="text-xl font-normal text-slate-200">{selectedProject.name}</h2>
|
||||
<p className="text-xs text-slate-500 mt-1">
|
||||
Created {formatDate(selectedProject.createdAt)} · {selectedProjectItems.length} items
|
||||
</p>
|
||||
|
|
@ -802,7 +802,7 @@ const ProjectsTab = ({ onProjectSelect, activeProjectId, onRerunVideo, onEditInI
|
|||
<div className="flex items-center gap-2">
|
||||
<button
|
||||
onClick={handleUpdateStoryboardFrames}
|
||||
className="flex items-center gap-2 px-3 py-1.5 bg-cinema-gold hover:bg-amber-400 text-slate-950 rounded text-sm font-medium transition-all"
|
||||
className="flex items-center gap-2 px-3 py-1.5 bg-cinema-gold hover:bg-amber-400 text-slate-950 rounded text-sm font-normal transition-all"
|
||||
>
|
||||
<Check className="w-4 h-4" />
|
||||
Update Frames
|
||||
|
|
@ -822,7 +822,7 @@ const ProjectsTab = ({ onProjectSelect, activeProjectId, onRerunVideo, onEditInI
|
|||
) : (
|
||||
<button
|
||||
onClick={() => setIsCreatingStoryboard(true)}
|
||||
className="flex items-center gap-2 px-3 py-1.5 bg-cinema-gold hover:bg-amber-400 text-slate-950 rounded text-sm font-medium transition-all"
|
||||
className="flex items-center gap-2 px-3 py-1.5 bg-cinema-gold hover:bg-amber-400 text-slate-950 rounded text-sm font-normal transition-all"
|
||||
>
|
||||
<Layers className="w-4 h-4" />
|
||||
Create Storyboard
|
||||
|
|
@ -895,7 +895,7 @@ const ProjectsTab = ({ onProjectSelect, activeProjectId, onRerunVideo, onEditInI
|
|||
{/* Create Storyboard Modal */}
|
||||
{isCreatingStoryboard && (
|
||||
<div className="bg-slate-800/80 border border-slate-700 rounded p-4">
|
||||
<h3 className="text-sm font-medium text-slate-200 mb-2">Name your storyboard</h3>
|
||||
<h3 className="text-sm font-normal text-slate-200 mb-2">Name your storyboard</h3>
|
||||
<div className="flex gap-2">
|
||||
<input
|
||||
type="text"
|
||||
|
|
@ -909,7 +909,7 @@ const ProjectsTab = ({ onProjectSelect, activeProjectId, onRerunVideo, onEditInI
|
|||
<button
|
||||
onClick={handleCreateStoryboard}
|
||||
disabled={!newStoryboardName.trim()}
|
||||
className="px-4 py-2 bg-cinema-gold hover:bg-amber-400 disabled:bg-slate-700 disabled:text-slate-500 text-slate-950 rounded text-sm font-medium transition-all"
|
||||
className="px-4 py-2 bg-cinema-gold hover:bg-amber-400 disabled:bg-slate-700 disabled:text-slate-500 text-slate-950 rounded text-sm font-normal transition-all"
|
||||
>
|
||||
Create
|
||||
</button>
|
||||
|
|
@ -931,7 +931,7 @@ const ProjectsTab = ({ onProjectSelect, activeProjectId, onRerunVideo, onEditInI
|
|||
<div className="fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4">
|
||||
<div className="bg-slate-900 border border-slate-700 rounded p-6 max-w-4xl w-full max-h-[80vh] overflow-y-auto">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<h2 className="text-xl font-medium text-slate-200">Import from Backend</h2>
|
||||
<h2 className="text-xl font-normal text-slate-200">Import from Backend</h2>
|
||||
<button
|
||||
onClick={() => setShowImportModal(false)}
|
||||
className="p-2 hover:bg-slate-800 rounded transition-colors"
|
||||
|
|
@ -963,7 +963,7 @@ const ProjectsTab = ({ onProjectSelect, activeProjectId, onRerunVideo, onEditInI
|
|||
{availableSessions.map((session) => (
|
||||
<div key={session.session_id} className="bg-slate-800/50 border border-slate-700 rounded p-4">
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<h3 className="text-sm font-medium text-slate-300">
|
||||
<h3 className="text-sm font-normal text-slate-300">
|
||||
Session: {session.session_id.substring(0, 8)}...
|
||||
</h3>
|
||||
<span className="text-xs text-slate-500">
|
||||
|
|
@ -974,7 +974,7 @@ const ProjectsTab = ({ onProjectSelect, activeProjectId, onRerunVideo, onEditInI
|
|||
{/* Images */}
|
||||
{session.images.length > 0 && (
|
||||
<div className="space-y-2">
|
||||
<h4 className="text-xs font-medium text-slate-400">Images</h4>
|
||||
<h4 className="text-xs font-normal text-slate-400">Images</h4>
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-2">
|
||||
{session.images.map((img) => {
|
||||
const fileKey = `${session.session_id}:image:${img.filename}`;
|
||||
|
|
@ -1013,7 +1013,7 @@ const ProjectsTab = ({ onProjectSelect, activeProjectId, onRerunVideo, onEditInI
|
|||
{/* Videos - Hidden for now since import not supported */}
|
||||
{false && session.videos.length > 0 && (
|
||||
<div className="space-y-2 mt-4">
|
||||
<h4 className="text-xs font-medium text-slate-400">Videos (Import Not Supported)</h4>
|
||||
<h4 className="text-xs font-normal text-slate-400">Videos (Import Not Supported)</h4>
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-2">
|
||||
{session.videos.map((vid) => {
|
||||
const expiresIn = Math.floor(vid.time_remaining / 3600);
|
||||
|
|
@ -1055,7 +1055,7 @@ const ProjectsTab = ({ onProjectSelect, activeProjectId, onRerunVideo, onEditInI
|
|||
<button
|
||||
onClick={handleImportFiles}
|
||||
disabled={selectedFiles.length === 0 || importing}
|
||||
className="flex items-center gap-2 px-4 py-2 bg-cinema-gold hover:bg-amber-400 disabled:bg-slate-700 disabled:text-slate-500 text-slate-950 rounded text-sm font-medium transition-all"
|
||||
className="flex items-center gap-2 px-4 py-2 bg-cinema-gold hover:bg-amber-400 disabled:bg-slate-700 disabled:text-slate-500 text-slate-950 rounded text-sm font-normal transition-all"
|
||||
>
|
||||
{importing ? (
|
||||
<>
|
||||
|
|
@ -1161,7 +1161,7 @@ const ProjectsTab = ({ onProjectSelect, activeProjectId, onRerunVideo, onEditInI
|
|||
})()}
|
||||
|
||||
{/* Type Badge */}
|
||||
<div className={`absolute top-2 left-2 px-2 py-1 rounded text-xs font-medium ${
|
||||
<div className={`absolute top-2 left-2 px-2 py-1 rounded text-xs font-normal ${
|
||||
item.type === 'image'
|
||||
? 'bg-blue-900/80 text-blue-300'
|
||||
: item.settings?.engine === 'kling'
|
||||
|
|
@ -1275,7 +1275,7 @@ const ProjectsTab = ({ onProjectSelect, activeProjectId, onRerunVideo, onEditInI
|
|||
<div className="absolute right-0 top-full mt-1 z-20 bg-slate-800 border border-slate-700 rounded py-1 min-w-[180px]"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<div className="px-3 py-1.5 text-xs font-medium text-slate-500 uppercase tracking-wider">Move to...</div>
|
||||
<div className="px-3 py-1.5 text-xs font-normal text-slate-500 uppercase tracking-wider">Move to...</div>
|
||||
{projects
|
||||
.filter(p => p.id !== selectedProject?.id)
|
||||
.map(p => (
|
||||
|
|
@ -1339,7 +1339,7 @@ const ProjectsTab = ({ onProjectSelect, activeProjectId, onRerunVideo, onEditInI
|
|||
setActiveSubTab('library');
|
||||
setIsSelecting(true);
|
||||
}}
|
||||
className="flex items-center gap-2 px-3 py-1.5 bg-cinema-gold hover:bg-amber-400 text-slate-950 rounded text-sm font-medium transition-all"
|
||||
className="flex items-center gap-2 px-3 py-1.5 bg-cinema-gold hover:bg-amber-400 text-slate-950 rounded text-sm font-normal transition-all"
|
||||
>
|
||||
<Plus className="w-4 h-4" />
|
||||
New Storyboard
|
||||
|
|
@ -1357,7 +1357,7 @@ const ProjectsTab = ({ onProjectSelect, activeProjectId, onRerunVideo, onEditInI
|
|||
setActiveSubTab('library');
|
||||
setIsSelecting(true);
|
||||
}}
|
||||
className="mt-4 px-4 py-2 bg-cinema-gold hover:bg-amber-400 text-slate-950 rounded text-sm font-medium transition-all"
|
||||
className="mt-4 px-4 py-2 bg-cinema-gold hover:bg-amber-400 text-slate-950 rounded text-sm font-normal transition-all"
|
||||
>
|
||||
Select Images
|
||||
</button>
|
||||
|
|
@ -1371,7 +1371,7 @@ const ProjectsTab = ({ onProjectSelect, activeProjectId, onRerunVideo, onEditInI
|
|||
className="group p-4 bg-slate-800/50 rounded border border-slate-700 hover:border-cinema-gold transition-all cursor-pointer"
|
||||
>
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<h3 className="font-medium text-slate-200">{board.name}</h3>
|
||||
<h3 className="font-normal text-slate-200">{board.name}</h3>
|
||||
<span className="text-xs text-slate-500">{board.frames?.length || 0} frames</span>
|
||||
</div>
|
||||
{/* Frame thumbnails preview */}
|
||||
|
|
@ -1496,7 +1496,7 @@ const ProjectsTab = ({ onProjectSelect, activeProjectId, onRerunVideo, onEditInI
|
|||
)}
|
||||
{previewItem.type === 'video' && (
|
||||
<div className="mt-2 flex gap-1.5">
|
||||
<span className={`text-xs px-2 py-0.5 rounded-full font-medium ${
|
||||
<span className={`text-xs px-2 py-0.5 rounded-full font-normal ${
|
||||
previewItem.settings?.engine === 'kling'
|
||||
? 'bg-indigo-900/50 text-indigo-300 border border-indigo-700'
|
||||
: 'bg-emerald-900/50 text-emerald-300 border border-emerald-700'
|
||||
|
|
@ -1528,7 +1528,7 @@ const ProjectsTab = ({ onProjectSelect, activeProjectId, onRerunVideo, onEditInI
|
|||
});
|
||||
setPreviewItem(null);
|
||||
}}
|
||||
className="flex items-center gap-2 px-3 py-1.5 bg-slate-200 hover:bg-slate-300 text-slate-900 rounded text-sm font-medium transition-colors"
|
||||
className="flex items-center gap-2 px-3 py-1.5 bg-slate-200 hover:bg-slate-300 text-slate-900 rounded text-sm font-normal transition-colors"
|
||||
>
|
||||
<Wand2 className="w-4 h-4" />
|
||||
Edit in Image Gen
|
||||
|
|
@ -1548,7 +1548,7 @@ const ProjectsTab = ({ onProjectSelect, activeProjectId, onRerunVideo, onEditInI
|
|||
});
|
||||
setPreviewItem(null);
|
||||
}}
|
||||
className="flex items-center gap-2 px-3 py-1.5 bg-cinema-gold hover:bg-amber-400 text-slate-950 rounded text-sm font-medium transition-colors"
|
||||
className="flex items-center gap-2 px-3 py-1.5 bg-cinema-gold hover:bg-amber-400 text-slate-950 rounded text-sm font-normal transition-colors"
|
||||
>
|
||||
<Video className="w-4 h-4" />
|
||||
Generate Video
|
||||
|
|
@ -1565,7 +1565,7 @@ const ProjectsTab = ({ onProjectSelect, activeProjectId, onRerunVideo, onEditInI
|
|||
});
|
||||
setPreviewItem(null);
|
||||
}}
|
||||
className="flex items-center gap-2 px-3 py-1.5 bg-slate-200 hover:bg-slate-300 text-slate-900 rounded text-sm font-medium transition-colors"
|
||||
className="flex items-center gap-2 px-3 py-1.5 bg-slate-200 hover:bg-slate-300 text-slate-900 rounded text-sm font-normal transition-colors"
|
||||
>
|
||||
<RefreshCw className="w-4 h-4" />
|
||||
Re-run
|
||||
|
|
@ -1576,7 +1576,7 @@ const ProjectsTab = ({ onProjectSelect, activeProjectId, onRerunVideo, onEditInI
|
|||
<div className="relative">
|
||||
<button
|
||||
onClick={() => setMovingItemId(movingItemId === previewItem.id ? null : previewItem.id)}
|
||||
className={`flex items-center gap-2 px-3 py-1.5 rounded text-sm font-medium transition-colors ${
|
||||
className={`flex items-center gap-2 px-3 py-1.5 rounded text-sm font-normal transition-colors ${
|
||||
movingItemId === previewItem.id
|
||||
? 'bg-cinema-gold text-slate-950'
|
||||
: 'bg-slate-700 hover:bg-slate-600 text-slate-300'
|
||||
|
|
@ -1615,7 +1615,7 @@ const ProjectsTab = ({ onProjectSelect, activeProjectId, onRerunVideo, onEditInI
|
|||
)}
|
||||
<button
|
||||
onClick={() => downloadItem(previewItem)}
|
||||
className="flex items-center gap-2 px-3 py-1.5 bg-cinema-gold hover:bg-amber-400 text-slate-950 rounded text-sm font-medium transition-colors"
|
||||
className="flex items-center gap-2 px-3 py-1.5 bg-cinema-gold hover:bg-amber-400 text-slate-950 rounded text-sm font-normal transition-colors"
|
||||
>
|
||||
<Download className="w-4 h-4" />
|
||||
Download
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ const SortableFrame = ({ frame, frameItem, index, onAnnotationChange, onDelete,
|
|||
>
|
||||
<GripVertical className="w-4 h-4 text-slate-500" />
|
||||
</button>
|
||||
<span className="text-xs font-medium text-slate-400">Frame {index + 1}</span>
|
||||
<span className="text-xs font-normal text-slate-400">Frame {index + 1}</span>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => onDelete(frame.imageId)}
|
||||
|
|
@ -153,7 +153,7 @@ const SortableFrame = ({ frame, frameItem, index, onAnnotationChange, onDelete,
|
|||
<div className="px-3 pb-3">
|
||||
<button
|
||||
onClick={() => onGenerateVideo(frame, frameItem)}
|
||||
className="w-full flex items-center justify-center gap-2 px-3 py-2 bg-slate-200 hover:bg-slate-300 text-slate-900 rounded text-sm font-medium transition-colors"
|
||||
className="w-full flex items-center justify-center gap-2 px-3 py-2 bg-slate-200 hover:bg-slate-300 text-slate-900 rounded text-sm font-normal transition-colors"
|
||||
>
|
||||
<Video className="w-4 h-4" />
|
||||
Generate Video
|
||||
|
|
@ -586,7 +586,7 @@ const StoryboardEditor = ({
|
|||
</div>
|
||||
) : (
|
||||
<div className="flex items-center gap-2">
|
||||
<h2 className="text-xl font-medium text-slate-200">{name}</h2>
|
||||
<h2 className="text-xl font-normal text-slate-200">{name}</h2>
|
||||
<button
|
||||
onClick={() => setIsEditingName(true)}
|
||||
className="p-1 hover:bg-slate-700 rounded"
|
||||
|
|
@ -609,7 +609,7 @@ const StoryboardEditor = ({
|
|||
<div className="flex items-center gap-2">
|
||||
<button
|
||||
onClick={() => onEditFrames(storyboard.id, frames.map(f => f.imageId))}
|
||||
className="flex items-center gap-2 px-3 py-2 bg-cinema-gold hover:bg-amber-400 text-slate-950 rounded text-sm font-medium transition-colors"
|
||||
className="flex items-center gap-2 px-3 py-2 bg-cinema-gold hover:bg-amber-400 text-slate-950 rounded text-sm font-normal transition-colors"
|
||||
>
|
||||
<Plus className="w-4 h-4" />
|
||||
Edit Frames
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ const TabNavigation = ({ activeTab, onTabChange, activeProjectId }) => {
|
|||
onClick={() => !isDisabled && onTabChange(tab.id)}
|
||||
disabled={isDisabled}
|
||||
title={isDisabled ? 'Select a project first' : tab.label}
|
||||
className={`relative flex items-center gap-2 px-1 py-2 font-medium transition-all ${
|
||||
className={`relative flex items-center gap-2 px-1 py-2 font-normal transition-all ${
|
||||
isDisabled
|
||||
? 'text-slate-600 cursor-not-allowed'
|
||||
: isActive
|
||||
|
|
|
|||
|
|
@ -1031,14 +1031,14 @@ OUTPUT: Two sections separated by --- only. No explanations or labels.`;
|
|||
<div className="lg:col-span-4 space-y-6">
|
||||
{/* Video Settings */}
|
||||
<div className="bg-slate-900/50 border border-slate-800 rounded p-6 space-y-6">
|
||||
<h2 className="text-lg font-medium text-slate-200 flex items-center space-x-2">
|
||||
<h2 className="text-lg font-normal text-slate-200 flex items-center space-x-2">
|
||||
<Video className="w-5 h-5 text-cinema-gold" />
|
||||
<span>Video Settings</span>
|
||||
</h2>
|
||||
|
||||
{/* Engine Selector */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-slate-400">
|
||||
<label className="text-xs font-normal text-slate-400">
|
||||
Engine
|
||||
</label>
|
||||
<div className="flex gap-2">
|
||||
|
|
@ -1046,7 +1046,7 @@ OUTPUT: Two sections separated by --- only. No explanations or labels.`;
|
|||
<button
|
||||
key={opt.value}
|
||||
onClick={() => setEngine(opt.value)}
|
||||
className={`flex-1 px-3 py-2 rounded font-medium transition-all text-sm ${
|
||||
className={`flex-1 px-3 py-2 rounded font-normal transition-all text-sm ${
|
||||
engine === opt.value
|
||||
? 'bg-cinema-gold text-slate-950'
|
||||
: 'bg-slate-800 text-slate-400 hover:bg-slate-700'
|
||||
|
|
@ -1066,7 +1066,7 @@ OUTPUT: Two sections separated by --- only. No explanations or labels.`;
|
|||
<>
|
||||
{/* Model */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-slate-400">
|
||||
<label className="text-xs font-normal text-slate-400">
|
||||
Model
|
||||
</label>
|
||||
<div className="flex gap-2">
|
||||
|
|
@ -1074,7 +1074,7 @@ OUTPUT: Two sections separated by --- only. No explanations or labels.`;
|
|||
<button
|
||||
key={opt.value}
|
||||
onClick={() => setModelType(opt.value)}
|
||||
className={`flex-1 px-3 py-2 rounded font-medium transition-all text-sm ${
|
||||
className={`flex-1 px-3 py-2 rounded font-normal transition-all text-sm ${
|
||||
modelType === opt.value
|
||||
? 'bg-cinema-gold text-slate-950'
|
||||
: 'bg-slate-800 text-slate-400 hover:bg-slate-700'
|
||||
|
|
@ -1089,7 +1089,7 @@ OUTPUT: Two sections separated by --- only. No explanations or labels.`;
|
|||
|
||||
{/* Duration */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-slate-400">
|
||||
<label className="text-xs font-normal text-slate-400">
|
||||
Duration
|
||||
</label>
|
||||
<div className="flex gap-2">
|
||||
|
|
@ -1100,7 +1100,7 @@ OUTPUT: Two sections separated by --- only. No explanations or labels.`;
|
|||
key={opt.value}
|
||||
onClick={() => !isDisabledByInterpolation && setDuration(opt.value)}
|
||||
disabled={isDisabledByInterpolation}
|
||||
className={`flex-1 px-3 py-2 rounded font-medium transition-all text-sm ${
|
||||
className={`flex-1 px-3 py-2 rounded font-normal transition-all text-sm ${
|
||||
duration === opt.value
|
||||
? 'bg-cinema-gold text-slate-950'
|
||||
: isDisabledByInterpolation
|
||||
|
|
@ -1123,7 +1123,7 @@ OUTPUT: Two sections separated by --- only. No explanations or labels.`;
|
|||
|
||||
{/* Aspect Ratio */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-slate-400">
|
||||
<label className="text-xs font-normal text-slate-400">
|
||||
Aspect Ratio
|
||||
</label>
|
||||
<div className="flex gap-2">
|
||||
|
|
@ -1131,7 +1131,7 @@ OUTPUT: Two sections separated by --- only. No explanations or labels.`;
|
|||
<button
|
||||
key={ratio}
|
||||
onClick={() => setAspectRatio(ratio)}
|
||||
className={`flex-1 px-4 py-2 rounded font-medium transition-all ${
|
||||
className={`flex-1 px-4 py-2 rounded font-normal transition-all ${
|
||||
aspectRatio === ratio
|
||||
? 'bg-cinema-gold text-slate-950'
|
||||
: 'bg-slate-800 text-slate-400 hover:bg-slate-700'
|
||||
|
|
@ -1145,7 +1145,7 @@ OUTPUT: Two sections separated by --- only. No explanations or labels.`;
|
|||
|
||||
{/* Resolution */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-slate-400">
|
||||
<label className="text-xs font-normal text-slate-400">
|
||||
Resolution
|
||||
</label>
|
||||
<div className="flex gap-2">
|
||||
|
|
@ -1156,7 +1156,7 @@ OUTPUT: Two sections separated by --- only. No explanations or labels.`;
|
|||
key={res}
|
||||
onClick={() => !isHighResDisabled && setResolution(res)}
|
||||
disabled={isHighResDisabled}
|
||||
className={`flex-1 px-4 py-2 rounded font-medium transition-all ${
|
||||
className={`flex-1 px-4 py-2 rounded font-normal transition-all ${
|
||||
resolution === res
|
||||
? 'bg-cinema-gold text-slate-950'
|
||||
: isHighResDisabled
|
||||
|
|
@ -1180,12 +1180,12 @@ OUTPUT: Two sections separated by --- only. No explanations or labels.`;
|
|||
|
||||
{/* Audio Toggle */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-slate-400">
|
||||
<label className="text-xs font-normal text-slate-400">
|
||||
Audio
|
||||
</label>
|
||||
<button
|
||||
onClick={() => setGenerateAudio(!generateAudio)}
|
||||
className={`w-full flex items-center justify-between px-4 py-2.5 rounded font-medium transition-all text-sm ${
|
||||
className={`w-full flex items-center justify-between px-4 py-2.5 rounded font-normal transition-all text-sm ${
|
||||
generateAudio
|
||||
? 'bg-green-900/50 text-green-400 border border-green-800'
|
||||
: 'bg-slate-800 text-slate-400 border border-slate-700'
|
||||
|
|
@ -1208,7 +1208,7 @@ OUTPUT: Two sections separated by --- only. No explanations or labels.`;
|
|||
<>
|
||||
{/* Kling Workflow Selector */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-slate-400">
|
||||
<label className="text-xs font-normal text-slate-400">
|
||||
Workflow
|
||||
</label>
|
||||
<div className="flex gap-1.5">
|
||||
|
|
@ -1216,7 +1216,7 @@ OUTPUT: Two sections separated by --- only. No explanations or labels.`;
|
|||
<button
|
||||
key={opt.value}
|
||||
onClick={() => setKlingWorkflow(opt.value)}
|
||||
className={`flex-1 px-2 py-1.5 rounded font-medium transition-all text-sm ${
|
||||
className={`flex-1 px-2 py-1.5 rounded font-normal transition-all text-sm ${
|
||||
klingWorkflow === opt.value
|
||||
? 'bg-cinema-gold text-slate-950'
|
||||
: 'bg-slate-800 text-slate-400 hover:bg-slate-700'
|
||||
|
|
@ -1235,13 +1235,13 @@ OUTPUT: Two sections separated by --- only. No explanations or labels.`;
|
|||
<>
|
||||
{/* Kling Model */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-slate-400">Model</label>
|
||||
<label className="text-xs font-normal text-slate-400">Model</label>
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
{klingModelOptions.map((opt) => (
|
||||
<button
|
||||
key={opt.value}
|
||||
onClick={() => setKlingModel(opt.value)}
|
||||
className={`px-2 py-1.5 rounded font-medium transition-all text-sm ${
|
||||
className={`px-2 py-1.5 rounded font-normal transition-all text-sm ${
|
||||
klingModel === opt.value
|
||||
? 'bg-cinema-gold text-slate-950'
|
||||
: 'bg-slate-800 text-slate-400 hover:bg-slate-700'
|
||||
|
|
@ -1256,13 +1256,13 @@ OUTPUT: Two sections separated by --- only. No explanations or labels.`;
|
|||
|
||||
{/* Duration */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-slate-400">Duration</label>
|
||||
<label className="text-xs font-normal text-slate-400">Duration</label>
|
||||
<div className="flex gap-2">
|
||||
{[5, 10].map((d) => (
|
||||
<button
|
||||
key={d}
|
||||
onClick={() => setDuration(d)}
|
||||
className={`flex-1 px-3 py-2 rounded font-medium transition-all text-sm ${
|
||||
className={`flex-1 px-3 py-2 rounded font-normal transition-all text-sm ${
|
||||
duration === d
|
||||
? 'bg-cinema-gold text-slate-950'
|
||||
: 'bg-slate-800 text-slate-400 hover:bg-slate-700'
|
||||
|
|
@ -1276,13 +1276,13 @@ OUTPUT: Two sections separated by --- only. No explanations or labels.`;
|
|||
|
||||
{/* Aspect Ratio */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-slate-400">Aspect Ratio</label>
|
||||
<label className="text-xs font-normal text-slate-400">Aspect Ratio</label>
|
||||
<div className="flex gap-2">
|
||||
{['16:9', '9:16', '1:1'].map((ratio) => (
|
||||
<button
|
||||
key={ratio}
|
||||
onClick={() => setAspectRatio(ratio)}
|
||||
className={`flex-1 px-3 py-2 rounded font-medium transition-all text-sm ${
|
||||
className={`flex-1 px-3 py-2 rounded font-normal transition-all text-sm ${
|
||||
aspectRatio === ratio
|
||||
? 'bg-cinema-gold text-slate-950'
|
||||
: 'bg-slate-800 text-slate-400 hover:bg-slate-700'
|
||||
|
|
@ -1296,13 +1296,13 @@ OUTPUT: Two sections separated by --- only. No explanations or labels.`;
|
|||
|
||||
{/* Mode (Std/Pro) */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-slate-400">Quality Mode</label>
|
||||
<label className="text-xs font-normal text-slate-400">Quality Mode</label>
|
||||
<div className="flex gap-2">
|
||||
{[{ value: 'std', label: 'Standard' }, { value: 'pro', label: 'Pro' }].map((opt) => (
|
||||
<button
|
||||
key={opt.value}
|
||||
onClick={() => setKlingMode(opt.value)}
|
||||
className={`flex-1 px-3 py-2 rounded font-medium transition-all text-sm ${
|
||||
className={`flex-1 px-3 py-2 rounded font-normal transition-all text-sm ${
|
||||
klingMode === opt.value
|
||||
? 'bg-cinema-gold text-slate-950'
|
||||
: 'bg-slate-800 text-slate-400 hover:bg-slate-700'
|
||||
|
|
@ -1316,10 +1316,10 @@ OUTPUT: Two sections separated by --- only. No explanations or labels.`;
|
|||
|
||||
{/* Sound Toggle */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-slate-400">Sound</label>
|
||||
<label className="text-xs font-normal text-slate-400">Sound</label>
|
||||
<button
|
||||
onClick={() => setKlingSound(!klingSound)}
|
||||
className={`w-full flex items-center justify-between px-4 py-2.5 rounded font-medium transition-all text-sm ${
|
||||
className={`w-full flex items-center justify-between px-4 py-2.5 rounded font-normal transition-all text-sm ${
|
||||
klingSound
|
||||
? 'bg-green-900/50 text-green-400 border border-green-800'
|
||||
: 'bg-slate-800 text-slate-400 border border-slate-700'
|
||||
|
|
@ -1335,7 +1335,7 @@ OUTPUT: Two sections separated by --- only. No explanations or labels.`;
|
|||
|
||||
{/* CFG Scale Slider */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-slate-400 flex items-center justify-between">
|
||||
<label className="text-xs font-normal text-slate-400 flex items-center justify-between">
|
||||
<span>CFG Scale</span>
|
||||
<span className="text-cinema-gold font-mono">{klingCfgScale.toFixed(1)}</span>
|
||||
</label>
|
||||
|
|
@ -1356,13 +1356,13 @@ OUTPUT: Two sections separated by --- only. No explanations or labels.`;
|
|||
|
||||
{/* Camera Control */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-slate-400">Camera Control</label>
|
||||
<label className="text-xs font-normal text-slate-400">Camera Control</label>
|
||||
<div className="grid grid-cols-3 gap-1.5">
|
||||
{cameraPresets.map((preset) => (
|
||||
<button
|
||||
key={preset.value}
|
||||
onClick={() => setKlingCameraControl(preset.value)}
|
||||
className={`px-2 py-1.5 rounded font-medium transition-all text-xs ${
|
||||
className={`px-2 py-1.5 rounded font-normal transition-all text-xs ${
|
||||
klingCameraControl === preset.value
|
||||
? 'bg-cinema-gold text-slate-950'
|
||||
: 'bg-slate-800 text-slate-400 hover:bg-slate-700'
|
||||
|
|
@ -1383,7 +1383,7 @@ OUTPUT: Two sections separated by --- only. No explanations or labels.`;
|
|||
<>
|
||||
{/* Video ID */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-slate-400">
|
||||
<label className="text-xs font-normal text-slate-400">
|
||||
Video ID
|
||||
</label>
|
||||
<input
|
||||
|
|
@ -1405,7 +1405,7 @@ OUTPUT: Two sections separated by --- only. No explanations or labels.`;
|
|||
|
||||
{/* Extension Prompt */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-slate-400">
|
||||
<label className="text-xs font-normal text-slate-400">
|
||||
Extension Prompt (Optional)
|
||||
</label>
|
||||
<textarea
|
||||
|
|
@ -1418,7 +1418,7 @@ OUTPUT: Two sections separated by --- only. No explanations or labels.`;
|
|||
|
||||
{/* CFG Scale */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-slate-400 flex items-center justify-between">
|
||||
<label className="text-xs font-normal text-slate-400 flex items-center justify-between">
|
||||
<span>CFG Scale</span>
|
||||
<span className="text-cinema-gold font-mono">{klingCfgScale.toFixed(1)}</span>
|
||||
</label>
|
||||
|
|
@ -1446,7 +1446,7 @@ OUTPUT: Two sections separated by --- only. No explanations or labels.`;
|
|||
<>
|
||||
{/* Face Image Upload */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-slate-400">
|
||||
<label className="text-xs font-normal text-slate-400">
|
||||
Face Image
|
||||
</label>
|
||||
{klingLipSyncImage ? (
|
||||
|
|
@ -1480,7 +1480,7 @@ OUTPUT: Two sections separated by --- only. No explanations or labels.`;
|
|||
|
||||
{/* Audio File Upload */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-slate-400">
|
||||
<label className="text-xs font-normal text-slate-400">
|
||||
Audio File
|
||||
</label>
|
||||
{klingAudioFile ? (
|
||||
|
|
@ -1510,7 +1510,7 @@ OUTPUT: Two sections separated by --- only. No explanations or labels.`;
|
|||
|
||||
{/* Lip Sync Prompt */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-slate-400">
|
||||
<label className="text-xs font-normal text-slate-400">
|
||||
Action/Emotion Prompt (Optional)
|
||||
</label>
|
||||
<textarea
|
||||
|
|
@ -1523,13 +1523,13 @@ OUTPUT: Two sections separated by --- only. No explanations or labels.`;
|
|||
|
||||
{/* Lip Sync Mode */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-slate-400">Quality Mode</label>
|
||||
<label className="text-xs font-normal text-slate-400">Quality Mode</label>
|
||||
<div className="flex gap-2">
|
||||
{[{ value: 'std', label: 'Standard' }, { value: 'pro', label: 'Pro' }].map((opt) => (
|
||||
<button
|
||||
key={opt.value}
|
||||
onClick={() => setKlingLipSyncMode(opt.value)}
|
||||
className={`flex-1 px-3 py-2 rounded font-medium transition-all text-sm ${
|
||||
className={`flex-1 px-3 py-2 rounded font-normal transition-all text-sm ${
|
||||
klingLipSyncMode === opt.value
|
||||
? 'bg-cinema-gold text-slate-950'
|
||||
: 'bg-slate-800 text-slate-400 hover:bg-slate-700'
|
||||
|
|
@ -1549,7 +1549,7 @@ OUTPUT: Two sections separated by --- only. No explanations or labels.`;
|
|||
{/* Scene Description & Inputs — shown for Veo always, and Kling Generate */}
|
||||
{(engine === 'veo' || (engine === 'kling' && klingWorkflow === 'generate')) && (
|
||||
<div className="bg-slate-900/50 border border-slate-800 rounded p-6 space-y-4">
|
||||
<label className="text-xs font-medium text-slate-400">
|
||||
<label className="text-xs font-normal text-slate-400">
|
||||
Scene Description {engine === 'veo' || referenceImages.length === 0 ? <span className="text-cinema-gold">*</span> : null}
|
||||
</label>
|
||||
<textarea
|
||||
|
|
@ -1566,7 +1566,7 @@ OUTPUT: Two sections separated by --- only. No explanations or labels.`;
|
|||
{/* Dialogue (optional) — Veo only (Kling uses sound/lip sync instead) */}
|
||||
{engine === 'veo' && (
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-slate-400 flex items-center gap-2">
|
||||
<label className="text-xs font-normal text-slate-400 flex items-center gap-2">
|
||||
<MessageSquare className="w-3 h-3" />
|
||||
Dialogue (optional)
|
||||
</label>
|
||||
|
|
@ -1589,7 +1589,7 @@ OUTPUT: Two sections separated by --- only. No explanations or labels.`;
|
|||
<button
|
||||
onClick={generateOptimizedVideoPrompt}
|
||||
disabled={isOptimizing || isGenerating || !sceneDescription.trim()}
|
||||
className="w-full flex items-center justify-center gap-2 px-4 py-3 bg-slate-200 hover:bg-slate-300 text-slate-900 font-medium rounded transition-all disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
className="w-full flex items-center justify-center gap-2 px-4 py-3 bg-slate-200 hover:bg-slate-300 text-slate-900 font-normal rounded transition-all disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
>
|
||||
{isOptimizing ? (
|
||||
<>
|
||||
|
|
@ -1613,7 +1613,7 @@ OUTPUT: Two sections separated by --- only. No explanations or labels.`;
|
|||
<button
|
||||
onClick={() => generateVideo(true)}
|
||||
disabled={isGenerating || (klingWorkflow === 'extend' && !klingVideoId.trim()) || (klingWorkflow === 'lipsync' && (!klingLipSyncImage || !klingAudioFile))}
|
||||
className="w-full flex items-center justify-center gap-2 px-4 py-3 bg-cinema-gold hover:bg-amber-400 text-slate-950 font-medium rounded transition-all disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
className="w-full flex items-center justify-center gap-2 px-4 py-3 bg-cinema-gold hover:bg-amber-400 text-slate-950 font-normal rounded transition-all disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
>
|
||||
{isGenerating ? (
|
||||
<>
|
||||
|
|
@ -1637,7 +1637,7 @@ OUTPUT: Two sections separated by --- only. No explanations or labels.`;
|
|||
<div className="relative bg-slate-900 border border-slate-800 rounded overflow-hidden">
|
||||
<div className="p-6 space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<h3 className="text-xs font-medium text-slate-400">
|
||||
<h3 className="text-xs font-normal text-slate-400">
|
||||
Optimized Prompt
|
||||
</h3>
|
||||
{optimizedPrompt && (
|
||||
|
|
@ -1657,7 +1657,7 @@ OUTPUT: Two sections separated by --- only. No explanations or labels.`;
|
|||
<div className="border-t border-slate-800 pt-3">
|
||||
<button
|
||||
onClick={() => setShowNegativePrompt(!showNegativePrompt)}
|
||||
className="flex items-center gap-1.5 text-xs font-medium text-slate-400 hover:text-slate-300 transition-colors"
|
||||
className="flex items-center gap-1.5 text-xs font-normal text-slate-400 hover:text-slate-300 transition-colors"
|
||||
>
|
||||
{showNegativePrompt ? <ChevronDown className="w-3 h-3" /> : <ChevronRight className="w-3 h-3" />}
|
||||
Negative Prompt
|
||||
|
|
@ -1678,7 +1678,7 @@ OUTPUT: Two sections separated by --- only. No explanations or labels.`;
|
|||
<button
|
||||
onClick={() => generateVideo(false)}
|
||||
disabled={isGenerating}
|
||||
className="w-full flex items-center justify-center gap-2 px-4 py-3 bg-cinema-gold hover:bg-amber-400 text-slate-950 font-medium rounded transition-all disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
className="w-full flex items-center justify-center gap-2 px-4 py-3 bg-cinema-gold hover:bg-amber-400 text-slate-950 font-normal rounded transition-all disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
>
|
||||
{isGenerating ? (
|
||||
<>
|
||||
|
|
@ -1700,7 +1700,7 @@ OUTPUT: Two sections separated by --- only. No explanations or labels.`;
|
|||
{(engine === 'veo' || (engine === 'kling' && klingWorkflow === 'generate')) && (
|
||||
<div className="bg-slate-900/50 border border-slate-800 rounded p-6 space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<label className="text-xs font-medium text-slate-400">
|
||||
<label className="text-xs font-normal text-slate-400">
|
||||
Reference Frames (Optional)
|
||||
</label>
|
||||
<span className="text-xs text-slate-500">
|
||||
|
|
@ -1742,7 +1742,7 @@ OUTPUT: Two sections separated by --- only. No explanations or labels.`;
|
|||
{showProjectPicker && projectImages.length > 0 && (
|
||||
<div className="bg-slate-800 border border-slate-700 rounded p-3">
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<span className="text-xs font-medium text-slate-400">From Project</span>
|
||||
<span className="text-xs font-normal text-slate-400">From Project</span>
|
||||
<button
|
||||
onClick={() => setShowProjectPicker(false)}
|
||||
className="text-slate-500 hover:text-slate-300"
|
||||
|
|
@ -1817,7 +1817,7 @@ OUTPUT: Two sections separated by --- only. No explanations or labels.`;
|
|||
{/* Generated Video */}
|
||||
<div className="bg-slate-900/50 border border-slate-800 rounded p-6 space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<h3 className="text-lg font-medium text-slate-200 flex items-center gap-2">
|
||||
<h3 className="text-lg font-normal text-slate-200 flex items-center gap-2">
|
||||
<Video className="w-5 h-5 text-cinema-gold" />
|
||||
Generated Video
|
||||
</h3>
|
||||
|
|
@ -1903,7 +1903,7 @@ OUTPUT: Two sections separated by --- only. No explanations or labels.`;
|
|||
link.download = generatedVideo.filename || `lux-studio-video-${Date.now()}.mp4`;
|
||||
link.click();
|
||||
}}
|
||||
className="flex-1 flex items-center justify-center gap-2 px-4 py-3 bg-cinema-gold hover:bg-amber-400 text-slate-950 font-medium rounded transition-all"
|
||||
className="flex-1 flex items-center justify-center gap-2 px-4 py-3 bg-cinema-gold hover:bg-amber-400 text-slate-950 font-normal rounded transition-all"
|
||||
>
|
||||
<Download className="w-5 h-5" />
|
||||
<span>Download</span>
|
||||
|
|
|
|||
|
|
@ -416,7 +416,7 @@ const VideoPlayer = ({ src, onFrameExtract, onSaveToProject, className = '', aut
|
|||
{showFramePreview && extractedFrame && (
|
||||
<div className="fixed inset-0 bg-black/80 flex items-center justify-center z-50 p-8" onClick={() => setShowFramePreview(false)}>
|
||||
<div className="bg-slate-900 rounded p-6 max-w-2xl w-full" onClick={(e) => e.stopPropagation()}>
|
||||
<h3 className="text-lg font-medium text-slate-200 mb-4 flex items-center gap-2">
|
||||
<h3 className="text-lg font-normal text-slate-200 mb-4 flex items-center gap-2">
|
||||
<Image className="w-5 h-5 text-cinema-gold" />
|
||||
Extracted Frame
|
||||
</h3>
|
||||
|
|
@ -437,7 +437,7 @@ const VideoPlayer = ({ src, onFrameExtract, onSaveToProject, className = '', aut
|
|||
<div className="flex gap-3">
|
||||
<button
|
||||
onClick={downloadFrame}
|
||||
className="flex-1 flex items-center justify-center gap-2 px-4 py-2 bg-slate-800 hover:bg-slate-700 text-slate-200 font-medium rounded transition-colors"
|
||||
className="flex-1 flex items-center justify-center gap-2 px-4 py-2 bg-slate-800 hover:bg-slate-700 text-slate-200 font-normal rounded transition-colors"
|
||||
>
|
||||
<Download className="w-4 h-4" />
|
||||
Download
|
||||
|
|
@ -455,7 +455,7 @@ const VideoPlayer = ({ src, onFrameExtract, onSaveToProject, className = '', aut
|
|||
});
|
||||
setSavedToProject(true);
|
||||
}}
|
||||
className={`flex-1 flex items-center justify-center gap-2 px-4 py-2 font-medium rounded transition-colors ${
|
||||
className={`flex-1 flex items-center justify-center gap-2 px-4 py-2 font-normal rounded transition-colors ${
|
||||
savedToProject
|
||||
? 'bg-green-600 text-white cursor-default'
|
||||
: 'bg-cinema-gold hover:bg-amber-400 text-slate-950'
|
||||
|
|
@ -476,7 +476,7 @@ const VideoPlayer = ({ src, onFrameExtract, onSaveToProject, className = '', aut
|
|||
) : (
|
||||
<button
|
||||
onClick={() => setShowFramePreview(false)}
|
||||
className="flex-1 flex items-center justify-center gap-2 px-4 py-2 bg-slate-700 hover:bg-slate-600 text-slate-200 font-medium rounded transition-colors"
|
||||
className="flex-1 flex items-center justify-center gap-2 px-4 py-2 bg-slate-700 hover:bg-slate-600 text-slate-200 font-normal rounded transition-colors"
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue