Refactor spacing and layout in forms for improved UI consistency
This commit is contained in:
@@ -28,8 +28,8 @@ export function ParamInput<T extends FieldValues>({
|
||||
max,
|
||||
}: ParamInputProps<T>) {
|
||||
return (
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="space-y-1">
|
||||
<div className="flex items-center gap-1.5">
|
||||
<Label htmlFor={name}>{label}</Label>
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { memo, useMemo } from 'react'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Shuffle } from 'lucide-react'
|
||||
|
||||
interface Preset {
|
||||
label: string
|
||||
@@ -20,16 +21,33 @@ const PresetSelectorInner = <T extends Preset>({ presets, onSelect }: PresetSele
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => onSelect(preset)}
|
||||
className="text-xs md:text-sm px-2.5 md:px-3 h-7 md:h-8"
|
||||
className="text-xs md:text-sm px-2 h-6 md:h-7"
|
||||
>
|
||||
{preset.label}
|
||||
</Button>
|
||||
))
|
||||
}, [presets, onSelect])
|
||||
|
||||
const handleRandomSelect = () => {
|
||||
const randomIndex = Math.floor(Math.random() * presets.length)
|
||||
onSelect(presets[randomIndex])
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-wrap gap-1.5 md:gap-2 mt-1.5 md:mt-2">
|
||||
{presetButtons}
|
||||
<div className="flex items-center gap-2 mt-1">
|
||||
<div className="flex flex-wrap gap-1 flex-1">
|
||||
{presetButtons}
|
||||
</div>
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={handleRandomSelect}
|
||||
className="h-6 md:h-7 px-2 flex-shrink-0"
|
||||
title="随机选择"
|
||||
>
|
||||
<Shuffle className="h-3.5 w-3.5" />
|
||||
</Button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -116,8 +116,8 @@ const CustomVoiceForm = forwardRef<CustomVoiceFormHandle>((_props, ref) => {
|
||||
}, [currentJob?.id, currentJob?.audio_url])
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit(onSubmit)} className="space-y-4 md:space-y-6">
|
||||
<div className="space-y-1.5 md:space-y-2">
|
||||
<form onSubmit={handleSubmit(onSubmit)} className="space-y-3">
|
||||
<div className="space-y-1">
|
||||
<Label htmlFor="language">语言</Label>
|
||||
<Select
|
||||
value={watch('language')}
|
||||
@@ -139,7 +139,7 @@ const CustomVoiceForm = forwardRef<CustomVoiceFormHandle>((_props, ref) => {
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="space-y-1.5 md:space-y-2">
|
||||
<div className="space-y-1">
|
||||
<Label htmlFor="speaker">发音人</Label>
|
||||
<Select
|
||||
value={watch('speaker')}
|
||||
@@ -161,26 +161,24 @@ const CustomVoiceForm = forwardRef<CustomVoiceFormHandle>((_props, ref) => {
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="space-y-1.5 md:space-y-2">
|
||||
<div className="space-y-1">
|
||||
<Label htmlFor="text">合成文本</Label>
|
||||
<Textarea
|
||||
{...register('text')}
|
||||
placeholder="输入要合成的文本..."
|
||||
rows={2}
|
||||
className="min-h-[60px] md:min-h-[96px]"
|
||||
className="min-h-[40px] md:min-h-[60px]"
|
||||
/>
|
||||
{errors.text && (
|
||||
<p className="text-sm text-destructive">{errors.text.message}</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="space-y-1.5 md:space-y-2">
|
||||
<div className="space-y-1">
|
||||
<Label htmlFor="instruct">情绪指导(可选)</Label>
|
||||
<Textarea
|
||||
{...register('instruct')}
|
||||
placeholder="例如:温柔体贴,语速平缓,充满关怀"
|
||||
rows={2}
|
||||
className="min-h-[60px] md:min-h-[80px]"
|
||||
className="min-h-[40px] md:min-h-[60px]"
|
||||
/>
|
||||
<PresetSelector
|
||||
presets={PRESET_INSTRUCTS}
|
||||
@@ -198,12 +196,12 @@ const CustomVoiceForm = forwardRef<CustomVoiceFormHandle>((_props, ref) => {
|
||||
|
||||
<Collapsible open={advancedOpen} onOpenChange={setAdvancedOpen}>
|
||||
<CollapsibleTrigger asChild>
|
||||
<Button type="button" variant="ghost" className="w-full">
|
||||
<Button type="button" variant="ghost" className="w-full py-1.5">
|
||||
高级选项
|
||||
<ChevronDown className="ml-2 h-4 w-4" />
|
||||
</Button>
|
||||
</CollapsibleTrigger>
|
||||
<CollapsibleContent className="space-y-3 md:space-y-4 pt-3 md:pt-4">
|
||||
<CollapsibleContent className="space-y-2 pt-2">
|
||||
<ParamInput
|
||||
name="max_new_tokens"
|
||||
label={ADVANCED_PARAMS_INFO.max_new_tokens.label}
|
||||
|
||||
@@ -101,14 +101,13 @@ function VoiceCloneForm() {
|
||||
}, [currentJob?.id, currentJob?.audio_url])
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit(onSubmit)} className="space-y-4 md:space-y-6">
|
||||
<div className="space-y-1.5 md:space-y-2">
|
||||
<form onSubmit={handleSubmit(onSubmit)} className="space-y-3">
|
||||
<div className="space-y-1">
|
||||
<Label htmlFor="ref_text">参考文稿(可选)</Label>
|
||||
<Textarea
|
||||
{...register('ref_text')}
|
||||
placeholder="参考音频对应的文本..."
|
||||
rows={2}
|
||||
className="min-h-[60px] md:min-h-[80px]"
|
||||
className="min-h-[40px] md:min-h-[60px]"
|
||||
/>
|
||||
<PresetSelector
|
||||
presets={PRESET_REF_TEXTS}
|
||||
@@ -119,7 +118,7 @@ function VoiceCloneForm() {
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="space-y-1.5 md:space-y-2">
|
||||
<div className="space-y-1">
|
||||
<Label htmlFor="ref_audio">参考音频</Label>
|
||||
<Controller
|
||||
name="ref_audio"
|
||||
@@ -134,7 +133,7 @@ function VoiceCloneForm() {
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-1.5 md:space-y-2">
|
||||
<div className="space-y-1">
|
||||
<Label htmlFor="language">语言(可选)</Label>
|
||||
<Select
|
||||
value={watch('language')}
|
||||
@@ -153,13 +152,12 @@ function VoiceCloneForm() {
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<div className="space-y-1.5 md:space-y-2">
|
||||
<div className="space-y-1">
|
||||
<Label htmlFor="text">合成文本</Label>
|
||||
<Textarea
|
||||
{...register('text')}
|
||||
placeholder="输入要合成的文本..."
|
||||
rows={2}
|
||||
className="min-h-[60px] md:min-h-[96px]"
|
||||
className="min-h-[40px] md:min-h-[60px]"
|
||||
/>
|
||||
<PresetSelector
|
||||
presets={PRESET_REF_TEXTS}
|
||||
@@ -170,7 +168,7 @@ function VoiceCloneForm() {
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex items-center space-x-4">
|
||||
<div className="flex items-center space-x-3">
|
||||
<div className="flex items-center space-x-2">
|
||||
<Controller
|
||||
name="x_vector_only_mode"
|
||||
@@ -208,12 +206,12 @@ function VoiceCloneForm() {
|
||||
|
||||
<Collapsible open={advancedOpen} onOpenChange={setAdvancedOpen}>
|
||||
<CollapsibleTrigger asChild>
|
||||
<Button type="button" variant="ghost" className="w-full">
|
||||
<Button type="button" variant="ghost" className="w-full py-1.5">
|
||||
高级选项
|
||||
<ChevronDown className="ml-2 h-4 w-4" />
|
||||
</Button>
|
||||
</CollapsibleTrigger>
|
||||
<CollapsibleContent className="space-y-3 md:space-y-4 pt-3 md:pt-4">
|
||||
<CollapsibleContent className="space-y-2 pt-2">
|
||||
<ParamInput
|
||||
name="max_new_tokens"
|
||||
label={ADVANCED_PARAMS_INFO.max_new_tokens.label}
|
||||
|
||||
@@ -107,8 +107,8 @@ const VoiceDesignForm = forwardRef<VoiceDesignFormHandle>((_props, ref) => {
|
||||
}, [currentJob?.id, currentJob?.audio_url])
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit(onSubmit)} className="space-y-4 md:space-y-6">
|
||||
<div className="space-y-1.5 md:space-y-2">
|
||||
<form onSubmit={handleSubmit(onSubmit)} className="space-y-3">
|
||||
<div className="space-y-1">
|
||||
<Label htmlFor="language">语言</Label>
|
||||
<Select
|
||||
value={watch('language')}
|
||||
@@ -130,26 +130,24 @@ const VoiceDesignForm = forwardRef<VoiceDesignFormHandle>((_props, ref) => {
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="space-y-1.5 md:space-y-2">
|
||||
<div className="space-y-1">
|
||||
<Label htmlFor="text">合成文本</Label>
|
||||
<Textarea
|
||||
{...register('text')}
|
||||
placeholder="输入要合成的文本..."
|
||||
rows={2}
|
||||
className="min-h-[60px] md:min-h-[96px]"
|
||||
className="min-h-[40px] md:min-h-[60px]"
|
||||
/>
|
||||
{errors.text && (
|
||||
<p className="text-sm text-destructive">{errors.text.message}</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="space-y-1.5 md:space-y-2">
|
||||
<div className="space-y-1">
|
||||
<Label htmlFor="instruct">音色描述</Label>
|
||||
<Textarea
|
||||
{...register('instruct')}
|
||||
placeholder="例如:成熟男性,低沉磁性,充满权威感"
|
||||
rows={2}
|
||||
className="min-h-[60px] md:min-h-[80px]"
|
||||
className="min-h-[40px] md:min-h-[60px]"
|
||||
/>
|
||||
<PresetSelector
|
||||
presets={PRESET_VOICE_DESIGNS}
|
||||
@@ -167,12 +165,12 @@ const VoiceDesignForm = forwardRef<VoiceDesignFormHandle>((_props, ref) => {
|
||||
|
||||
<Collapsible open={advancedOpen} onOpenChange={setAdvancedOpen}>
|
||||
<CollapsibleTrigger asChild>
|
||||
<Button type="button" variant="ghost" className="w-full">
|
||||
<Button type="button" variant="ghost" className="w-full py-1.5">
|
||||
高级选项
|
||||
<ChevronDown className="ml-2 h-4 w-4" />
|
||||
</Button>
|
||||
</CollapsibleTrigger>
|
||||
<CollapsibleContent className="space-y-3 md:space-y-4 pt-3 md:pt-4">
|
||||
<CollapsibleContent className="space-y-2 pt-2">
|
||||
<ParamInput
|
||||
name="max_new_tokens"
|
||||
label={ADVANCED_PARAMS_INFO.max_new_tokens.label}
|
||||
|
||||
@@ -71,7 +71,7 @@ function Home() {
|
||||
</Tabs>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent className="pt-4 md:pt-6 px-3 md:px-6">
|
||||
<CardContent className="pt-0 px-3 md:px-6">
|
||||
<Tabs value={currentTab}>
|
||||
<TabsContent value="custom-voice" className="mt-0">
|
||||
<Suspense fallback={<FormSkeleton />}>
|
||||
|
||||
Reference in New Issue
Block a user