Add custom prompt feature and enhance keyboard handling

This commit is contained in:
2026-03-14 00:06:34 +01:00
parent 4432251158
commit d128ac92dc
2 changed files with 79 additions and 11 deletions

View File

@@ -1259,15 +1259,6 @@ export default function App() {
const handleOpenAiToolsMenu = useCallback(async () => {
if (!selectedTextId || !hasText || isViewingHistory || isConverting) return;
if (aiPromptTemplates.length === 0) {
setConfirmState({
title: "AI Tools",
message: "Add at least one prompt template in Settings first.",
actionLabel: "OK",
onConfirm: () => {}
});
return;
}
const menu = await Menu.new({
items: [
@@ -2151,6 +2142,14 @@ export default function App() {
useEffect(() => {
const handleKeyDown = (event: KeyboardEvent) => {
if (event.defaultPrevented) return;
if (customPromptOpen && event.key === "Escape") {
event.preventDefault();
setCustomPromptOpen(false);
return;
}
if (customPromptOpen) {
return;
}
const isFind =
(event.metaKey || event.ctrlKey) && event.key.toLowerCase() === "f";
if (isFind && !settingsOpen && !confirmState) {
@@ -2176,7 +2175,7 @@ export default function App() {
window.addEventListener("keydown", handleKeyDown);
return () => window.removeEventListener("keydown", handleKeyDown);
}, [confirmState, handleSaveVersion, openDocumentSearch, settingsOpen]);
}, [confirmState, customPromptOpen, handleSaveVersion, openDocumentSearch, settingsOpen]);
const renderTextItem = (text: Text) => (
<div
@@ -2528,7 +2527,7 @@ export default function App() {
disabled={
isConverting
? false
: !ollamaModel || isViewingHistory || !hasText || aiPromptTemplates.length === 0
: !ollamaModel || isViewingHistory || !hasText
}
>
{isConverting ? "Cancel AI Edit" : "AI Tools"}
@@ -2899,6 +2898,53 @@ export default function App() {
</div>
) : null}
{customPromptOpen ? (
<div className="modal">
<div className="modal__overlay" onClick={() => setCustomPromptOpen(false)} />
<div className="modal__card modal__card--wide" role="dialog" aria-modal="true">
<div className="modal__title">Custom Prompt</div>
<div className="modal__message">
Tell the AI what it should do with the current text.
</div>
<textarea
className="modal__textarea"
value={customPromptText}
onChange={(event) => setCustomPromptText(event.target.value)}
onKeyDown={(event) => {
if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === "enter") {
event.preventDefault();
handleRunCustomPrompt().catch((error) => {
console.error("Failed to run custom prompt", error);
});
} else if (event.key === "Escape") {
event.preventDefault();
setCustomPromptOpen(false);
}
}}
placeholder="Example: Turn this into a short release note with bullet points."
autoFocus
/>
<div className="modal__hint">Press Cmd/Ctrl+Enter to run.</div>
<div className="modal__actions">
<button className="button" onClick={() => setCustomPromptOpen(false)}>
Cancel
</button>
<button
className="button button--primary"
onClick={() => {
handleRunCustomPrompt().catch((error) => {
console.error("Failed to run custom prompt", error);
});
}}
disabled={customPromptText.trim().length === 0}
>
Run Prompt
</button>
</div>
</div>
</div>
) : null}
{confirmState ? (
<div className="modal">
<div className="modal__overlay" onClick={() => setConfirmState(null)} />

View File

@@ -963,6 +963,10 @@ body:not([data-theme="light"]) .markdown-preview {
gap: 12px;
}
.modal__card--wide {
width: min(560px, 92vw);
}
.modal__title {
font-size: 1.2rem;
}
@@ -971,6 +975,24 @@ body:not([data-theme="light"]) .markdown-preview {
color: var(--muted);
}
.modal__textarea {
width: 100%;
min-height: 170px;
resize: vertical;
border-radius: 12px;
border: 1px solid var(--border);
background: var(--bg-input);
color: var(--ink);
caret-color: var(--ink);
padding: 12px 14px;
font: inherit;
}
.modal__hint {
font-size: 0.8rem;
color: var(--muted);
}
.modal__actions {
display: flex;
justify-content: flex-end;