forked from innovacion/playground
Initial commit
This commit is contained in:
118
frontend/components/video-config.tsx
Normal file
118
frontend/components/video-config.tsx
Normal file
@@ -0,0 +1,118 @@
|
||||
'use client';
|
||||
|
||||
import { aspectRatioSizes, videoDurations } from '@/lib/google-ai';
|
||||
|
||||
interface VideoConfigProps {
|
||||
model: string;
|
||||
aspectRatio: string;
|
||||
onAspectRatioChange: (ratio: string) => void;
|
||||
duration: number;
|
||||
onDurationChange: (duration: number) => void;
|
||||
negativePrompt: string;
|
||||
onNegativePromptChange: (prompt: string) => void;
|
||||
safetyLevel: 'block_none' | 'block_some' | 'block_most';
|
||||
onSafetyLevelChange: (level: 'block_none' | 'block_some' | 'block_most') => void;
|
||||
}
|
||||
|
||||
export function VideoConfig({
|
||||
aspectRatio,
|
||||
onAspectRatioChange,
|
||||
duration,
|
||||
onDurationChange,
|
||||
negativePrompt,
|
||||
onNegativePromptChange,
|
||||
safetyLevel,
|
||||
onSafetyLevelChange,
|
||||
}: VideoConfigProps) {
|
||||
const availableRatios = Object.keys(aspectRatioSizes);
|
||||
const size = aspectRatioSizes[aspectRatio];
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<h3 className="text-sm font-medium text-foreground">Configuración de Video</h3>
|
||||
|
||||
{/* Aspect Ratio */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-muted-foreground">
|
||||
Aspect Ratio
|
||||
</label>
|
||||
<div className="grid grid-cols-5 gap-2">
|
||||
{availableRatios.map((ratio) => (
|
||||
<button
|
||||
key={ratio}
|
||||
onClick={() => onAspectRatioChange(ratio)}
|
||||
className={`
|
||||
px-3 py-2 text-xs rounded-lg font-medium transition-all
|
||||
${aspectRatio === ratio
|
||||
? 'bg-primary text-primary-foreground'
|
||||
: 'bg-secondary hover:bg-accent'
|
||||
}
|
||||
`}
|
||||
>
|
||||
{ratio}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
{size && (
|
||||
<p className="text-xs text-muted-foreground">
|
||||
Dimensiones: {size.width}x{size.height}px
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Duración */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-muted-foreground">
|
||||
Duración: {duration} segundos
|
||||
</label>
|
||||
<div className="flex gap-2">
|
||||
{videoDurations.map((dur) => (
|
||||
<button
|
||||
key={dur.value}
|
||||
onClick={() => onDurationChange(dur.value)}
|
||||
className={`
|
||||
flex-1 px-3 py-2 text-xs rounded-lg font-medium transition-all
|
||||
${duration === dur.value
|
||||
? 'bg-primary text-primary-foreground'
|
||||
: 'bg-secondary hover:bg-accent'
|
||||
}
|
||||
`}
|
||||
>
|
||||
{dur.label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Negative Prompt */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-muted-foreground">
|
||||
Negative Prompt (opcional)
|
||||
</label>
|
||||
<textarea
|
||||
value={negativePrompt}
|
||||
onChange={(e) => onNegativePromptChange(e.target.value)}
|
||||
placeholder="Elementos que NO quieres en el video..."
|
||||
className="w-full px-3 py-2 bg-secondary border border-border rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-primary resize-none"
|
||||
rows={2}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Safety Level */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-muted-foreground">
|
||||
Nivel de Seguridad
|
||||
</label>
|
||||
<select
|
||||
value={safetyLevel}
|
||||
onChange={(e) => onSafetyLevelChange(e.target.value as any)}
|
||||
className="w-full px-3 py-2 bg-secondary border border-border rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-primary"
|
||||
>
|
||||
<option value="block_none">Sin bloqueo</option>
|
||||
<option value="block_some">Bloqueo moderado</option>
|
||||
<option value="block_most">Bloqueo alto</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user