首次发布git
This commit is contained in:
@@ -0,0 +1,171 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { Plus, Trash2, Edit2, X, Sparkles } from "lucide-react";
|
||||
import { useSettingsStore, AIPrompt } from "@/lib/settings-store";
|
||||
|
||||
export function PromptManagement() {
|
||||
const { prompts, addPrompt, updatePrompt, deletePrompt, resetPrompts } = useSettingsStore();
|
||||
const [editing, setEditing] = useState<AIPrompt | null>(null);
|
||||
const [isNew, setIsNew] = useState(false);
|
||||
|
||||
const handleSave = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
if (!editing) return;
|
||||
if (isNew) {
|
||||
addPrompt(editing);
|
||||
} else {
|
||||
updatePrompt(editing.id, editing);
|
||||
}
|
||||
setEditing(null);
|
||||
setIsNew(false);
|
||||
};
|
||||
|
||||
const startNew = () => {
|
||||
setEditing({
|
||||
id: `custom_${Date.now()}`,
|
||||
label: "新功能",
|
||||
description: "描述...",
|
||||
systemPrompt: "你是...",
|
||||
});
|
||||
setIsNew(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<section className="space-y-6">
|
||||
<div className="flex items-center justify-between gap-2 pb-2 border-b">
|
||||
<div className="flex items-center gap-2">
|
||||
<Sparkles size={20} className="text-primary" />
|
||||
<h2 className="text-xl font-semibold">自定义 AI 提示词</h2>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<button
|
||||
onClick={startNew}
|
||||
className="flex items-center gap-1 px-3 py-1.5 text-xs font-medium bg-primary text-primary-foreground rounded hover:bg-primary/90 transition-colors"
|
||||
>
|
||||
<Plus size={14} />
|
||||
添加新功能
|
||||
</button>
|
||||
<button
|
||||
onClick={resetPrompts}
|
||||
className="px-3 py-1.5 text-xs font-medium border rounded hover:bg-muted transition-colors text-muted-foreground hover:text-foreground"
|
||||
>
|
||||
重置默认
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
<div className="grid gap-3 md:grid-cols-2">
|
||||
{prompts.map((prompt) => (
|
||||
<div key={prompt.id} className="flex items-start justify-between p-3 bg-muted/30 border rounded-lg group">
|
||||
<div>
|
||||
<h3 className="font-medium text-sm flex items-center gap-2">
|
||||
{prompt.label}
|
||||
<span className="text-[10px] bg-muted px-1.5 py-0.5 rounded text-muted-foreground font-mono">
|
||||
{prompt.id}
|
||||
</span>
|
||||
</h3>
|
||||
<p className="text-xs text-muted-foreground mt-1 line-clamp-1">
|
||||
{prompt.description}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-1 opacity-100 md:opacity-0 group-hover:opacity-100 transition-opacity">
|
||||
<button
|
||||
onClick={() => {
|
||||
setEditing(prompt);
|
||||
setIsNew(false);
|
||||
}}
|
||||
className="p-1.5 hover:bg-muted rounded text-muted-foreground hover:text-foreground"
|
||||
>
|
||||
<Edit2 size={14} />
|
||||
</button>
|
||||
<button
|
||||
onClick={() => deletePrompt(prompt.id)}
|
||||
className="p-1.5 hover:bg-red-500/10 rounded text-muted-foreground hover:text-red-500"
|
||||
>
|
||||
<Trash2 size={14} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Edit/Create Dialog (Simple Overlay) */}
|
||||
{editing && (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4">
|
||||
<div className="bg-background border rounded-xl shadow-2xl w-full max-w-lg p-6 space-y-4 animate-in zoom-in-95 duration-200">
|
||||
<div className="flex items-center justify-between pb-2 border-b">
|
||||
<h3 className="font-semibold text-lg">{isNew ? "新建 AI 功能" : "编辑 AI 功能"}</h3>
|
||||
<button onClick={() => setEditing(null)}>
|
||||
<X size={20} />
|
||||
</button>
|
||||
</div>
|
||||
<form onSubmit={handleSave} className="space-y-4">
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium">名称 (Label)</label>
|
||||
<input
|
||||
type="text"
|
||||
value={editing.label}
|
||||
onChange={e => setEditing({ ...editing!, label: e.target.value })}
|
||||
className="w-full p-2 bg-muted/50 border rounded text-sm"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium">唯一标识 (ID)</label>
|
||||
<input
|
||||
type="text"
|
||||
value={editing.id}
|
||||
onChange={e => setEditing({ ...editing!, id: e.target.value })}
|
||||
className="w-full p-2 bg-muted/50 border rounded text-sm"
|
||||
readOnly={!isNew}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium">简短描述</label>
|
||||
<input
|
||||
type="text"
|
||||
value={editing.description}
|
||||
onChange={e => setEditing({ ...editing!, description: e.target.value })}
|
||||
className="w-full p-2 bg-muted/50 border rounded text-sm"
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium">系统提示词 (System Prompt)</label>
|
||||
<textarea
|
||||
value={editing.systemPrompt}
|
||||
onChange={e => setEditing({ ...editing!, systemPrompt: e.target.value })}
|
||||
className="w-full h-32 p-2 bg-muted/50 border rounded text-sm font-mono leading-relaxed"
|
||||
required
|
||||
/>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
这是发送给 AI 的指令,定义了它的角色和行为。
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex justify-end gap-2 pt-2">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setEditing(null)}
|
||||
className="px-4 py-2 text-sm font-medium bg-muted hover:bg-muted/80 rounded"
|
||||
>
|
||||
取消
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
className="px-4 py-2 text-sm font-medium bg-primary text-primary-foreground hover:bg-primary/90 rounded"
|
||||
>
|
||||
保存
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user