Refactor spacing and layout in forms for improved UI consistency

This commit is contained in:
2026-01-26 16:56:29 +08:00
parent 783e0dc984
commit 23e72f80e5
6 changed files with 51 additions and 39 deletions

View File

@@ -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>

View File

@@ -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,17 +21,34 @@ 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">
<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>
)
}

View File

@@ -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}

View File

@@ -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}

View File

@@ -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}

View File

@@ -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 />}>