feat(journal): improve command completion behavior
- Scroll the selected completion item into view - Filter commands based on prefix when typing a slash command - Keep completion menu open while typing a command - Add data attributes to track completion indices for scrolling
This commit is contained in:
parent
e0d61cf91e
commit
276241f3b0
|
|
@ -12,6 +12,7 @@
|
||||||
import {
|
import {
|
||||||
Component,
|
Component,
|
||||||
createSignal,
|
createSignal,
|
||||||
|
createEffect,
|
||||||
onMount,
|
onMount,
|
||||||
onCleanup,
|
onCleanup,
|
||||||
Show,
|
Show,
|
||||||
|
|
@ -126,18 +127,34 @@ export const JournalInput: Component = () => {
|
||||||
revertLatest();
|
revertLatest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---- Scroll selected completion into view ----
|
||||||
|
|
||||||
|
createEffect(() => {
|
||||||
|
const idx = selectedIdx();
|
||||||
|
if (!showCompletions() || !completionsRef) return;
|
||||||
|
const el = completionsRef.querySelector(`[data-comp-idx="${idx}"]`);
|
||||||
|
if (el) el.scrollIntoView({ block: "nearest" });
|
||||||
|
});
|
||||||
|
|
||||||
// ---- Completions ----
|
// ---- Completions ----
|
||||||
|
|
||||||
function buildCompletions(): CompletionItem[] {
|
function buildCompletions(): CompletionItem[] {
|
||||||
const raw = text().trim();
|
const raw = text().trim();
|
||||||
const data = comp.data;
|
const data = comp.data;
|
||||||
|
const commands = [
|
||||||
// Show commands when user types /
|
{ label: "/roll", kind: "command" as const, insertText: "/roll " },
|
||||||
if (raw === "" || raw === "/") {
|
{ label: "/link", kind: "command" as const, insertText: "/link " },
|
||||||
return [
|
|
||||||
{ label: "/roll", kind: "command", insertText: "/roll " },
|
|
||||||
{ label: "/link", kind: "command", insertText: "/link " },
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// Show commands when user types / or starts typing a command name
|
||||||
|
if (raw.startsWith("/") && !raw.includes(" ")) {
|
||||||
|
const prefix = raw.toLowerCase();
|
||||||
|
const matches = commands.filter((c) =>
|
||||||
|
c.label.toLowerCase().startsWith(prefix),
|
||||||
|
);
|
||||||
|
return matches.length > 0
|
||||||
|
? matches
|
||||||
|
: [{ label: "Unknown command", kind: "no-results", insertText: "" }];
|
||||||
}
|
}
|
||||||
|
|
||||||
// After /roll — show dice suggestions
|
// After /roll — show dice suggestions
|
||||||
|
|
@ -226,9 +243,9 @@ export const JournalInput: Component = () => {
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// If not open and typing /, open completions
|
// If not open and starts with /, open completions
|
||||||
const raw = text();
|
const raw = text();
|
||||||
if (raw === "/" || raw.startsWith("/roll") || raw.startsWith("/link")) {
|
if (raw.startsWith("/")) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
setShowCompletions(true);
|
setShowCompletions(true);
|
||||||
setSelectedIdx(0);
|
setSelectedIdx(0);
|
||||||
|
|
@ -271,14 +288,8 @@ export const JournalInput: Component = () => {
|
||||||
const raw = input.value;
|
const raw = input.value;
|
||||||
setText(raw);
|
setText(raw);
|
||||||
|
|
||||||
// Completions visibility
|
// Completions visibility — keep open while user types any /
|
||||||
if (
|
if (raw.startsWith("/")) {
|
||||||
raw === "/" ||
|
|
||||||
raw.startsWith("/roll ") ||
|
|
||||||
raw.startsWith("/link ") ||
|
|
||||||
raw === "/roll" ||
|
|
||||||
raw === "/link"
|
|
||||||
) {
|
|
||||||
setShowCompletions(true);
|
setShowCompletions(true);
|
||||||
setSelectedIdx(0);
|
setSelectedIdx(0);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -317,6 +328,7 @@ export const JournalInput: Component = () => {
|
||||||
<For each={comps}>
|
<For each={comps}>
|
||||||
{(item, idx) => (
|
{(item, idx) => (
|
||||||
<div
|
<div
|
||||||
|
data-comp-idx={idx()}
|
||||||
class={`flex items-center gap-2 px-3 py-1.5 cursor-pointer text-sm ${
|
class={`flex items-center gap-2 px-3 py-1.5 cursor-pointer text-sm ${
|
||||||
item.kind === "no-results"
|
item.kind === "no-results"
|
||||||
? "text-gray-400 italic cursor-default"
|
? "text-gray-400 italic cursor-default"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue