diff --git a/docs/evidence/pr-1260-magic-rewrite/after.png b/docs/evidence/pr-1260-magic-rewrite/after.png new file mode 100644 index 000000000..d0e4f004e Binary files /dev/null and b/docs/evidence/pr-1260-magic-rewrite/after.png differ diff --git a/docs/evidence/pr-1260-magic-rewrite/provider-request.json b/docs/evidence/pr-1260-magic-rewrite/provider-request.json new file mode 100644 index 000000000..90c644b87 --- /dev/null +++ b/docs/evidence/pr-1260-magic-rewrite/provider-request.json @@ -0,0 +1,18 @@ +[ + { + "max_tokens": 4000, + "messages": [ + { + "content": "You are a rewriting assistant for roleplay, fiction, and worldbuilding content.\nRewrite or generate the requested text according to the user's instructions.\nReturn ONLY the rewritten text -- no explanations, no markdown fences, no preamble.", + "role": "system" + }, + { + "content": "Instruction:\nMake this sharper and more dramatic, but preserve the core identity.\n\n---\n\nText to rewrite:\nA flat sentinel character waits in a quiet room with plain motives.", + "role": "user" + } + ], + "model": "proof-model", + "stream": false, + "temperature": 0.7 + } +] diff --git a/src/features/catalog/lorebooks/components/LorebookFormFields.tsx b/src/features/catalog/lorebooks/components/LorebookFormFields.tsx index bc3919113..8d845dc7e 100644 --- a/src/features/catalog/lorebooks/components/LorebookFormFields.tsx +++ b/src/features/catalog/lorebooks/components/LorebookFormFields.tsx @@ -4,10 +4,24 @@ // and LorebookEntryRow (the per-entry inline drawer). // Extracted from LorebookEditor.tsx so styling stays consistent. // ────────────────────────────────────────────── -import { useEffect, useRef, useState, type KeyboardEvent as ReactKeyboardEvent } from "react"; -import { FileText, Maximize2, ToggleLeft, ToggleRight, X } from "lucide-react"; +import { + useCallback, + useEffect, + useRef, + useState, + type KeyboardEvent as ReactKeyboardEvent, +} from "react"; +import { + FileText, + Maximize2, + Sparkles, + ToggleLeft, + ToggleRight, + X, +} from "lucide-react"; import { cn } from "../../../../shared/lib/utils"; import { HelpTooltip } from "../../../../shared/components/ui/HelpTooltip"; +import { MagicRewritePanel } from "../../../../shared/components/ui/MagicRewritePanel"; export function FieldGroup({ label, @@ -32,7 +46,13 @@ export function FieldGroup({ ); } -export function KeysEditor({ keys, onChange }: { keys: string[]; onChange: (keys: string[]) => void }) { +export function KeysEditor({ + keys, + onChange, +}: { + keys: string[]; + onChange: (keys: string[]) => void; +}) { const [input, setInput] = useState(""); const addKey = () => { @@ -123,7 +143,9 @@ export function NumberField({ }) { return (
- + void, ) { - if (event.key !== "Tab" || event.shiftKey || event.altKey || event.metaKey || event.ctrlKey) return; + if ( + event.key !== "Tab" || + event.shiftKey || + event.altKey || + event.metaKey || + event.ctrlKey + ) + return; event.preventDefault(); insertTabAtSelection(event.currentTarget, value, applyValue); } @@ -233,6 +262,8 @@ export function ExpandedContentModal({ placeholder?: string; }) { const [local, setLocal] = useState(value); + const [magicRewriteMode, setMagicRewriteMode] = useState(false); + const [magicRewriteResult, setMagicRewriteResult] = useState(""); const textareaRef = useRef(null); useEffect(() => { @@ -241,7 +272,7 @@ export function ExpandedContentModal({ useEffect(() => { const handler = (e: KeyboardEvent) => { - if (e.key === "Escape") { + if (e.key === "Escape" && !magicRewriteMode) { onChange(local); onCommit?.(); onClose(); @@ -249,7 +280,7 @@ export function ExpandedContentModal({ }; document.addEventListener("keydown", handler); return () => document.removeEventListener("keydown", handler); - }, [onClose, onChange, onCommit, local]); + }, [onClose, onChange, onCommit, local, magicRewriteMode]); const handleClose = () => { onChange(local); @@ -257,36 +288,105 @@ export function ExpandedContentModal({ onClose(); }; + const handleMagicRewriteBack = () => { + setMagicRewriteMode(false); + setMagicRewriteResult(""); + }; + + const handleMagicRewriteApply = () => { + if (!magicRewriteResult) return; + setLocal(magicRewriteResult); + setMagicRewriteMode(false); + setMagicRewriteResult(""); + window.setTimeout(() => textareaRef.current?.focus(), 100); + }; + + const handleMagicRewriteResultChange = useCallback((next: string) => { + setMagicRewriteResult(next); + }, []); + return (
-
-
+
+
-

{title}

- +

+ {magicRewriteMode ? "Magic Rewrite" : title} +

+
+ +
-