Compare commits

..

2 Commits

Author SHA1 Message Date
hypercross b8cfb05e53 feat(journal): add ErrorPopup to display full error messages
Introduces an ErrorPopup component that allows users to view the
complete error message by clicking on the truncated error text in
the JournalInput.
2026-07-11 10:00:05 +08:00
hypercross 841fbc7bae refactor: simplify spark table detection logic 2026-07-11 09:56:18 +08:00
3 changed files with 48 additions and 11 deletions

View File

@ -208,16 +208,8 @@ export function scanDirectives(
const [, headerRow, separatorRow, bodyRowsText] = mdMatch; const [, headerRow, separatorRow, bodyRowsText] = mdMatch;
const headers = splitTableRow(headerRow); const headers = splitTableRow(headerRow);
// Check if this is a spark-shaped table: first column is a dice formula // Check if this looks like a spark table: first column is a dice formula
// and one of the headers is a label marker const isSpark = DICE_HEADER_RE.test(headers[0]);
const isSpark =
DICE_HEADER_RE.test(headers[0]) &&
headers.some(
(h) =>
h === "label" ||
h === "md-table-label" ||
h === "md-roll-label",
);
if (!isSpark) continue; if (!isSpark) continue;

View File

@ -0,0 +1,30 @@
/**
* ErrorPopup shows the full error message in a floating panel above
* the journal input area. Toggled by clicking the truncated error text.
*/
import { Component, Show } from "solid-js";
interface ErrorPopupProps {
message: string | null;
show: boolean;
onClose: () => void;
}
export const ErrorPopup: Component<ErrorPopupProps> = (props) => {
return (
<Show when={props.show && props.message}>
<div class="absolute bottom-full left-2 right-2 mb-1 bg-red-50 border border-red-200 rounded shadow-lg z-50">
<div class="flex items-start justify-between px-2 pt-2 pb-1">
<p class="text-red-700 text-xs break-words">{props.message}</p>
<button
onClick={props.onClose}
class="text-red-400 hover:text-red-600 text-xs leading-none ml-2 shrink-0"
title="关闭"
>
</button>
</div>
</div>
</Show>
);
};

View File

@ -26,6 +26,7 @@ import { parseInput } from "./command-parser";
import type { CompletionItem } from "./command-parser"; import type { CompletionItem } from "./command-parser";
import { buildCompletions } from "./command-completions"; import { buildCompletions } from "./command-completions";
import { CompletionsDropdown } from "./CompletionsDropdown"; import { CompletionsDropdown } from "./CompletionsDropdown";
import { ErrorPopup } from "./ErrorPopup";
// ---- Component ---- // ---- Component ----
@ -39,6 +40,7 @@ export const JournalInput: Component = () => {
const [text, setText] = createSignal(""); const [text, setText] = createSignal("");
const [error, setError] = createSignal<string | null>(null); const [error, setError] = createSignal<string | null>(null);
const [showErrorPopup, setShowErrorPopup] = createSignal(false);
const [sending, setSending] = createSignal(false); const [sending, setSending] = createSignal(false);
const [showCompletions, setShowCompletions] = createSignal(false); const [showCompletions, setShowCompletions] = createSignal(false);
const [selectedIdx, setSelectedIdx] = createSignal(0); const [selectedIdx, setSelectedIdx] = createSignal(0);
@ -406,7 +408,13 @@ export const JournalInput: Component = () => {
<div class="flex items-center justify-between px-2 pb-2"> <div class="flex items-center justify-between px-2 pb-2">
<Show when={error()}> <Show when={error()}>
<p class="text-red-500 text-xs truncate max-w-[60%]">{error()}</p> <button
onClick={() => setShowErrorPopup((v) => !v)}
class="text-red-500 text-xs truncate max-w-[60%] text-left hover:underline"
title={error() ?? undefined}
>
{error()}
</button>
</Show> </Show>
<div class="flex items-center gap-1 ml-auto"> <div class="flex items-center gap-1 ml-auto">
<button <button
@ -422,6 +430,13 @@ export const JournalInput: Component = () => {
</div> </div>
</Show> </Show>
</div> </div>
{/* Error popup */}
<ErrorPopup
message={error()}
show={showErrorPopup()}
onClose={() => setShowErrorPopup(false)}
/>
</div> </div>
); );
}; };