feat(web): add prompt editor with split-pane and Markdown editing

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-07 02:34:04 +08:00
parent 66f0f82fde
commit e35778ebea
3 changed files with 157 additions and 24 deletions

View File

@@ -0,0 +1,84 @@
import { useState, useEffect } from 'react';
import { useAccounts } from '@/hooks/useAccounts';
import { usePrompts } from '@/hooks/usePrompts';
import { Button } from '@/components/ui/button';
const PROMPT_TYPES = [
{ type: 'storyboard', label: '分镜' },
{ type: 'image', label: '图片提示词' },
{ type: 'video', label: '视频提示词' },
] as const;
export function PromptEditor() {
const { accounts } = useAccounts();
const [selectedAccount, setSelectedAccount] = useState<string>('');
const [selectedType, setSelectedType] = useState<string>('storyboard');
const { content, path, loading, load, save, setContent } = usePrompts();
useEffect(() => {
if (accounts.length > 0 && !selectedAccount) {
setSelectedAccount(accounts[0].id);
}
}, [accounts]);
useEffect(() => {
if (selectedAccount) {
load(selectedAccount, selectedType);
}
}, [selectedAccount, selectedType]);
return (
<div className="flex h-full">
<div className="w-48 border-r border-zinc-800 p-3 space-y-3">
<div>
<label className="text-xs text-zinc-500"></label>
<select
value={selectedAccount}
onChange={(e) => setSelectedAccount(e.target.value)}
className="mt-1 w-full h-9 rounded-md border border-zinc-800 bg-zinc-900 px-2 text-sm"
>
{accounts.map((a) => (
<option key={a.id} value={a.id}>{a.name}</option>
))}
</select>
</div>
<div>
<label className="text-xs text-zinc-500"></label>
<div className="mt-1 space-y-0.5">
{PROMPT_TYPES.map(({ type, label }) => (
<button
key={type}
onClick={() => setSelectedType(type)}
className={`w-full text-left px-2 py-1.5 rounded text-sm ${
selectedType === type ? 'bg-zinc-800 text-white' : 'text-zinc-500 hover:text-zinc-300'
}`}
>
{label}
</button>
))}
</div>
</div>
</div>
<div className="flex-1 flex flex-col">
<div className="flex items-center justify-between px-4 py-2 border-b border-zinc-800">
<span className="text-xs text-zinc-500 font-mono">{path}</span>
<Button
size="sm"
onClick={() => save(selectedAccount, selectedType, content)}
disabled={!selectedAccount || loading}
>
</Button>
</div>
<textarea
value={content}
onChange={(e) => setContent(e.target.value)}
className="flex-1 w-full bg-zinc-950 text-zinc-200 font-mono text-sm p-4 resize-none outline-none"
placeholder="加载中..."
spellCheck={false}
/>
</div>
</div>
);
}