20 lines
3.5 KiB
TypeScript
20 lines
3.5 KiB
TypeScript
'use client'
|
|
|
|
import { Plus, Trash2 } from 'lucide-react'
|
|
import { DETAIL_MAX_SCREENS, type DetailAnalysis } from '@/lib/detail-generator/types'
|
|
import { actionKey } from './client'
|
|
import { detailButtonClass, detailFieldClass } from './DetailProductForm'
|
|
|
|
export default function DetailOutlineEditor({ analysis, busy, onChange }: { analysis: DetailAnalysis; busy: boolean; onChange: (analysis: DetailAnalysis) => void }) {
|
|
const updateScreen = (id: string, key: 'title' | 'body' | 'imagePrompt', value: string) => onChange({ ...analysis, screens: analysis.screens.map((screen) => screen.id === id ? { ...screen, [key]: value } : screen) })
|
|
return <div className="space-y-5">
|
|
<label className="block space-y-1.5 text-sm font-semibold">产品卖点<textarea disabled={busy} className={`${detailFieldClass} min-h-24 resize-y font-normal`} value={analysis.sellingPoints.join('\n')} onChange={(event) => onChange({ ...analysis, sellingPoints: event.target.value.split('\n').filter((line) => line.trim()) })} /></label>
|
|
{!!analysis.warnings.length && <div role="status" className="rounded-lg bg-[#fffaeb] p-3 text-sm text-[#854a0e]"><p className="font-semibold">需要确认</p><ul className="mt-1 list-inside list-disc">{analysis.warnings.map((warning, index) => <li key={index}>{warning}</li>)}</ul></div>}
|
|
<div className="flex items-center justify-between gap-3"><h2 className="text-base font-semibold">页面大纲 <span className="ml-1 text-sm font-normal text-[#66758b]">{analysis.screens.length} 屏</span></h2><button type="button" disabled={busy || analysis.screens.length >= DETAIL_MAX_SCREENS} className={detailButtonClass} onClick={() => onChange({ ...analysis, screens: [...analysis.screens, { id: actionKey(), title: '', body: '', imagePrompt: '' }] })}><Plus className="h-4 w-4" aria-hidden="true" />添加一屏</button></div>
|
|
<div className="divide-y divide-[#e2e8f0]">{analysis.screens.map((screen, index) => <fieldset key={screen.id} disabled={busy} className="py-4 first:pt-0">
|
|
<legend className="sr-only">第 {index + 1} 屏</legend>
|
|
<div className="flex items-start gap-3"><span className="flex h-11 w-8 shrink-0 items-center justify-center text-sm font-semibold tabular-nums text-[#66758b]">{index + 1}</span><div className="min-w-0 flex-1 space-y-3"><label className="block space-y-1.5 text-sm font-medium">标题<input aria-label={`第 ${index + 1} 屏标题`} className={detailFieldClass} value={screen.title} maxLength={120} onChange={(event) => updateScreen(screen.id, 'title', event.target.value)} /></label><label className="block space-y-1.5 text-sm font-medium">正文<textarea aria-label={`第 ${index + 1} 屏正文`} className={`${detailFieldClass} min-h-20 resize-y`} value={screen.body} maxLength={1800} onChange={(event) => updateScreen(screen.id, 'body', event.target.value)} /></label><details><summary className="cursor-pointer text-sm text-[#4f6077]">画面要求</summary><textarea aria-label={`第 ${index + 1} 屏画面要求`} className={`${detailFieldClass} mt-2 min-h-20 resize-y`} value={screen.imagePrompt} maxLength={4000} onChange={(event) => updateScreen(screen.id, 'imagePrompt', event.target.value)} /></details></div><button type="button" className={`${detailButtonClass} shrink-0 px-2`} aria-label={`移除第 ${index + 1} 屏`} disabled={busy || analysis.screens.length <= 1} onClick={() => onChange({ ...analysis, screens: analysis.screens.filter((item) => item.id !== screen.id) })}><Trash2 className="h-4 w-4" aria-hidden="true" /></button></div>
|
|
</fieldset>)}</div>
|
|
</div>
|
|
}
|