Some checks failed
CI Check / check (push) Has been cancelled
- 创建统一的Modal组件,采用Apple风格设计 - 实现毛玻璃效果、圆角、动画和细边框描边 - 修复弹窗打开时背景滚动问题 - 修复分类管理中重复卡片和数组字符串显示问题 - 优化选项解析逻辑,添加去重和过滤机制
123 lines
4.2 KiB
TypeScript
123 lines
4.2 KiB
TypeScript
'use client'
|
||
|
||
import { buttonStyles, buttonModifiers, inputStyles, cn } from '@/lib/ui-styles'
|
||
import type { TemplateForm, BuiltinTemplateConfig } from '../types'
|
||
|
||
interface TemplateBasicsFormProps {
|
||
form: TemplateForm
|
||
statusOptions: Array<{ value: string; label: string }>
|
||
materialTypeOptions: string[]
|
||
showPresetSelector: boolean
|
||
selectedPreset: string | null
|
||
presets: BuiltinTemplateConfig[]
|
||
onChange: (patch: Partial<TemplateForm>) => void
|
||
onSelectPreset: (presetKey: string) => void
|
||
}
|
||
|
||
export default function TemplateBasicsForm({
|
||
form,
|
||
statusOptions,
|
||
materialTypeOptions,
|
||
showPresetSelector,
|
||
selectedPreset,
|
||
presets,
|
||
onChange,
|
||
onSelectPreset,
|
||
}: TemplateBasicsFormProps) {
|
||
return (
|
||
<div className="space-y-5">
|
||
<div>
|
||
<label className="block text-sm font-semibold text-slate-900 dark:text-white mb-2">
|
||
模板名称 <span className="text-red-500">*</span>
|
||
</label>
|
||
<input
|
||
type="text"
|
||
value={form.name}
|
||
onChange={(e) => onChange({ name: e.target.value })}
|
||
className={cn(inputStyles.base)}
|
||
placeholder="例如:产品素材模板"
|
||
/>
|
||
<p className="text-xs text-slate-500 dark:text-slate-400 mt-1.5">给模板起一个容易识别的名称</p>
|
||
</div>
|
||
|
||
<div>
|
||
<label className="block text-sm font-semibold text-slate-900 dark:text-white mb-2">模板描述</label>
|
||
<textarea
|
||
rows={2}
|
||
value={form.description}
|
||
onChange={(e) => onChange({ description: e.target.value })}
|
||
className={cn(inputStyles.base, 'resize-none')}
|
||
placeholder="简单描述这个模板的用途"
|
||
/>
|
||
</div>
|
||
|
||
<div>
|
||
<label className="block text-sm font-semibold text-slate-900 dark:text-white mb-2">模板状态</label>
|
||
<select
|
||
value={form.status}
|
||
onChange={(e) => onChange({ status: e.target.value })}
|
||
className={cn(inputStyles.base)}
|
||
>
|
||
{statusOptions.map((option) => (
|
||
<option key={option.value} value={option.value}>
|
||
{option.label}
|
||
</option>
|
||
))}
|
||
</select>
|
||
<p className="text-xs text-slate-500 dark:text-slate-400 mt-1.5">草稿:仅保存,不生效;启用:用户可以使用</p>
|
||
</div>
|
||
|
||
<div>
|
||
<label className="block text-sm font-semibold text-slate-900 dark:text-white mb-2">
|
||
素材类型 <span className="text-red-500">*</span>
|
||
</label>
|
||
<select
|
||
value={form.materialType}
|
||
onChange={(e) => onChange({ materialType: e.target.value })}
|
||
className={cn(inputStyles.base)}
|
||
>
|
||
{materialTypeOptions.map((option) => (
|
||
<option key={option} value={option}>
|
||
{option}
|
||
</option>
|
||
))}
|
||
</select>
|
||
<p className="text-xs text-slate-500 dark:text-slate-400 mt-1.5">新版本中模板即素材类型,这里用于绑定老数据。</p>
|
||
</div>
|
||
|
||
{showPresetSelector && (
|
||
<div>
|
||
<label className="block text-sm font-semibold text-slate-900 dark:text-white mb-2">选择预设模板</label>
|
||
<div className="flex flex-wrap gap-2">
|
||
{presets.map((preset) => {
|
||
const active = selectedPreset === preset.key
|
||
return (
|
||
<button
|
||
key={preset.key}
|
||
type="button"
|
||
onClick={() => onSelectPreset(preset.key)}
|
||
className={cn(
|
||
active ? buttonStyles.primary : buttonStyles.secondary,
|
||
buttonModifiers.compactXs,
|
||
buttonModifiers.pill,
|
||
'flex items-center gap-1.5 shadow-none',
|
||
!active && 'border-dashed',
|
||
)}
|
||
>
|
||
{active && <span className="inline-block w-1.5 h-1.5 rounded-full bg-white" />}
|
||
<span>{preset.name}</span>
|
||
</button>
|
||
)
|
||
})}
|
||
</div>
|
||
<p className="text-xs text-slate-500 dark:text-slate-400 mt-1.5">
|
||
选择一个预设模板后,下方字段会自动填充,可在此基础上继续增删或调整。
|
||
</p>
|
||
</div>
|
||
)}
|
||
</div>
|
||
)
|
||
}
|
||
|
||
|