返回 JoyAI-Echo
LanguagePicker.tsx
根目录 / echo_longvideo / Director_Agent / webui / src / components / thread / LanguagePicker.tsx
1 import { ChevronDown, Globe } from "lucide-react";
2
3 import {
4 DropdownMenu,
5 DropdownMenuContent,
6 DropdownMenuItem,
7 DropdownMenuLabel,
8 DropdownMenuSeparator,
9 DropdownMenuTrigger,
10 } from "@/components/ui/dropdown-menu";
11 import { cn } from "@/lib/utils";
12
13 export type StoryLanguage = "zh" | "en";
14
15 export const STORY_LANGUAGE_PRESETS: readonly StoryLanguage[] = [
16 "zh",
17 "en",
18 ] as const;
19
20 export const DEFAULT_STORY_LANGUAGE: StoryLanguage = "zh";
21
22 interface LanguagePickerProps {
23 value: StoryLanguage;
24 onChange: (value: StoryLanguage) => void;
25 disabled?: boolean;
26 size?: "hero" | "thread";
27 }
28
29 export function LanguagePicker({
30 value,
31 onChange,
32 disabled,
33 size = "thread",
34 }: LanguagePickerProps) {
35 const isHero = size === "hero";
36
37 return (
38 <DropdownMenu>
39 <DropdownMenuTrigger asChild disabled={disabled}>
40 <span
41 aria-label="Film language"
42 className={cn(
43 "cursor-pointer",
44 "group inline-flex min-w-0 items-center gap-1.5 rounded-full border px-2.5 py-1",
45 "border-foreground/10 bg-foreground/[0.035] font-medium text-foreground/80",
46 "whitespace-nowrap transition-colors hover:border-foreground/15 hover:bg-foreground/[0.04]",
47 "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/20",
48 "disabled:cursor-not-allowed disabled:opacity-60",
49 "data-[state=open]:border-foreground/15 data-[state=open]:bg-foreground/[0.04]",
50 isHero ? "text-[11px]" : "text-[12px]",
51 )}
52 >
53 <Globe className="h-3 w-3" aria-hidden />
54 <span>{value}</span>
55 <ChevronDown
56 className={cn(
57 "h-2.5 w-2.5 opacity-60 transition-transform duration-200",
58 "group-data-[state=open]:rotate-180",
59 )}
60 aria-hidden
61 />
62 </span>
63 </DropdownMenuTrigger>
64 <DropdownMenuContent
65 side="top"
66 align="start"
67 sideOffset={6}
68 className="w-[var(--radix-dropdown-menu-trigger-width)] min-w-[var(--radix-dropdown-menu-trigger-width)] rounded-xl p-1 shadow-md"
69 >
70 <DropdownMenuLabel
71 style={{
72 wordBreak: "keep-all",
73 }}
74 className="px-2.5 py-1.5 text-[10px] font-semibold text-foreground"
75 >
76 Film Language
77 </DropdownMenuLabel>
78 {STORY_LANGUAGE_PRESETS.map((preset, index) => (
79 <div key={preset}>
80 {index > 0 ? <DropdownMenuSeparator className="my-0.5" /> : null}
81 <DropdownMenuItem
82 onSelect={() => onChange(preset)}
83 className={cn(
84 "cursor-pointer rounded-lg px-2.5 py-1.5 text-[12px]",
85 preset === value &&
86 "bg-foreground/[0.06] font-medium text-foreground/85",
87 )}
88 >
89 {preset}
90 </DropdownMenuItem>
91 </div>
92 ))}
93 </DropdownMenuContent>
94 </DropdownMenu>
95 );
96 }
97
97 lines Plain Text