2025-10-23 15:52:53 +08:00

155 lines
7.0 KiB
TypeScript

"use client";
import {
GlobalOutlined,
ClockCircleOutlined,
DownOutlined
} from '@ant-design/icons';
import { WandSparkles, RectangleHorizontal, RectangleVertical } from 'lucide-react';
import { Dropdown, Tooltip } from 'antd';
import { LanguageOptions, VideoDurationOptions } from './config-options';
import type { ConfigOptions, LanguageValue, VideoDurationValue } from './config-options';
interface ConfigPanelProps {
/** Current configuration options */
configOptions: ConfigOptions;
/** Handler for configuration changes */
onConfigChange: <K extends keyof ConfigOptions>(key: K, value: ConfigOptions[K], exclude?: boolean) => void;
/** Whether it's mobile device */
isMobile?: boolean;
/** Whether it's desktop device */
isDesktop?: boolean;
/** Whether to disable duration selection */
disableDuration?: boolean;
}
/**
* Configuration panel component for video creation settings.
* Includes language, auto script, duration, and aspect ratio selectors.
* @param {ConfigOptions} configOptions - current configuration
* @param {Function} onConfigChange - handler for config changes
* @param {boolean} isMobile - whether it's mobile device
* @param {boolean} isDesktop - whether it's desktop device
* @returns {JSX.Element}
*/
export const ConfigPanel = ({
configOptions,
onConfigChange,
isMobile = false,
isDesktop = true,
disableDuration = false,
}: ConfigPanelProps) => {
/** Language dropdown menu items */
const languageMenuItems = LanguageOptions.map((option) => ({
key: option.value,
label: <span className="text-gray-300">{option.label}</span>,
}));
/** Duration dropdown menu items */
const durationMenuItems = VideoDurationOptions.map((option) => ({
key: option.value,
label: <span className="text-gray-300">{option.label}</span>,
}));
const currentLanguage = LanguageOptions.find((option) => option.value === configOptions.language);
const currentDuration = configOptions.videoDuration === 'unlimited' ? 'auto' : configOptions.videoDuration;
return (
<div data-alt="config-panel" className="flex items-center gap-2">
{/* Language selector */}
<Dropdown
menu={{
items: languageMenuItems,
onClick: ({ key }) => onConfigChange('language', key as LanguageValue),
className: 'bg-[#1a1a1a] border border-white/10'
}}
trigger={['click']}
>
<button
data-alt="config-language"
className="h-8 px-2 rounded-full border border-white/20 bg-transparent text-gray-300 hover:bg-white/5 hover:border-cyan-400/60 transition-all duration-200 flex items-center gap-2 hover:text-cyan-400"
>
<GlobalOutlined className="text-base" />
<span className="text-sm">{currentLanguage?.code}</span>
<DownOutlined className="text-xs" />
</button>
</Dropdown>
{/* Auto script toggle */}
<Tooltip title="AI Story Copilot" placement="top">
<button
data-alt="config-expansion-mode"
className={`h-8 px-2 rounded-full border transition-all duration-200 flex items-center gap-2 text-sm ${
configOptions.videoDuration === '8s'
? 'opacity-40 cursor-not-allowed border-white/20 bg-transparent text-gray-400'
: configOptions.expansion_mode
? 'border-cyan-400 bg-cyan-400/10 text-cyan-400 hover:bg-cyan-400/20'
: 'border-white/20 bg-transparent text-gray-300 hover:bg-white/5 hover:border-cyan-400/60 hover:text-cyan-400'
}`}
disabled={configOptions.videoDuration === '8s'}
onClick={() => {
if (configOptions.videoDuration !== '8s') {
onConfigChange('expansion_mode', !configOptions.expansion_mode);
}
}}
>
<WandSparkles className="w-4 h-4" />
<span>AutoScript</span>
</button>
</Tooltip>
{/* Duration selector */}
<Dropdown
menu={{
items: durationMenuItems,
onClick: ({ key }) => onConfigChange('videoDuration', key as VideoDurationValue),
className: 'bg-[#1a1a1a] border border-white/10'
}}
trigger={['click']}
disabled={disableDuration}
>
<button
data-alt="config-video-duration"
className={`h-8 px-2 rounded-full border transition-all duration-200 flex items-center gap-2 ${
disableDuration
? 'opacity-40 cursor-not-allowed border-white/20 bg-transparent text-gray-400'
: 'border-white/20 bg-transparent hover:bg-white/5 hover:border-cyan-400/60 text-gray-300 hover:text-cyan-400'
}`}
disabled={disableDuration}
>
<ClockCircleOutlined className="text-base" />
<span className="text-sm capitalize">{currentDuration}</span>
<DownOutlined className="text-xs" />
</button>
</Dropdown>
{/* Aspect ratio toggles */}
<div data-alt="aspect-ratio-controls" className="h-8 p-1 flex items-center rounded-full border border-white/20 hover:border-cyan-400/60">
<button
data-alt="portrait-button"
className={`w-8 h-6 rounded-full transition-all duration-200 flex items-center justify-center ${
configOptions.aspect_ratio === 'VIDEO_ASPECT_RATIO_PORTRAIT'
? 'bg-white/10 text-cyan-400 shadow-sm'
: 'bg-transparent text-gray-400 hover:text-gray-300'
}`}
onClick={() => onConfigChange('aspect_ratio', 'VIDEO_ASPECT_RATIO_PORTRAIT')}
>
<RectangleVertical className="w-4 h-4" />
</button>
<button
data-alt="landscape-button"
className={`w-8 h-6 rounded-full transition-all duration-200 flex items-center justify-center ${
configOptions.aspect_ratio === 'VIDEO_ASPECT_RATIO_LANDSCAPE'
? 'bg-white/10 text-cyan-400 shadow-sm'
: 'bg-transparent text-gray-400 hover:text-gray-300'
}`}
onClick={() => onConfigChange('aspect_ratio', 'VIDEO_ASPECT_RATIO_LANDSCAPE')}
>
<RectangleHorizontal className="w-4 h-4" />
</button>
</div>
</div>
);
};