From 40b6fbe15797be29b4964781f4412a3b60572408 Mon Sep 17 00:00:00 2001 From: hypercross Date: Sun, 13 Sep 2026 14:01:03 +0800 Subject: [PATCH] feat(ui): replace unicode icons with solid-icons Swap emoji and unicode glyphs for Tabler components so icons inherit currentColor and font-size and render consistently across platforms. - add src/components/doc-icons.ts to resolve doc-entry frontmatter icon keys to components; frontmatter now stores semantic keys - replace the align-*.png assets with TbOutlineAlign* icons - render RevealManager action SVGs as components instead of injected innerHTML strings - carry completion icons via an optional CompletionItem.icon field --- src/App.tsx | 11 +- src/components/DocDialog.tsx | 32 +++-- src/components/FileTree.tsx | 16 ++- src/components/RevealManager.tsx | 34 ++--- src/components/Sidebar.tsx | 5 +- src/components/doc-icons.ts | 48 +++++++ .../journal/CompletionsDropdown.tsx | 6 + src/components/journal/ConnectDialog.tsx | 3 +- .../journal/CreateSessionDialog.tsx | 3 +- .../journal/DeleteSessionDialog.tsx | 3 +- src/components/journal/ErrorPopup.tsx | 3 +- src/components/journal/InviteDialog.tsx | 3 +- src/components/journal/JournalHeader.tsx | 8 +- src/components/journal/SessionDropdown.tsx | 11 +- src/components/journal/StreamMessage.tsx | 3 +- src/components/journal/command-completions.ts | 7 +- src/components/journal/command-parser.ts | 4 + src/components/journal/types/intent.tsx | 5 +- src/components/journal/types/link.tsx | 3 +- src/components/journal/types/roll.tsx | 6 +- src/components/journal/types/var.tsx | 3 +- src/components/md-deck/CardList.tsx | 5 +- src/components/md-deck/DeckHeader.tsx | 20 ++- src/components/md-deck/PltPreview.tsx | 3 +- src/components/md-deck/PrintPreviewFooter.tsx | 5 +- src/components/md-deck/PrintPreviewHeader.tsx | 11 +- .../md-deck/editor-panel/LayerRow.tsx | 127 +++++++++++------- .../editor-panel/icons/align-center.png | Bin 1002 -> 0 bytes .../md-deck/editor-panel/icons/align-left.png | Bin 1006 -> 0 bytes .../editor-panel/icons/align-right.png | Bin 996 -> 0 bytes src/components/md-dice.tsx | 3 +- src/components/md-pins.tsx | 3 +- src/components/md-table.tsx | 3 +- src/components/md-yarn-spinner.tsx | 11 +- src/doc-entries/journal-gm.md | 6 +- src/doc-entries/journal-link.md | 2 +- src/doc-entries/journal-player.md | 4 +- src/doc-entries/journal-roll.md | 2 +- src/doc-entries/journal-set.md | 2 +- src/doc-entries/journal-spark.md | 2 +- src/doc-entries/md-bg.md | 2 +- src/doc-entries/md-border.md | 2 +- src/doc-entries/md-deck.md | 2 +- src/doc-entries/md-dice.md | 4 +- src/doc-entries/md-embed.md | 2 +- src/doc-entries/md-font.md | 2 +- src/doc-entries/md-link.md | 2 +- src/doc-entries/md-pins.md | 4 +- src/doc-entries/md-table.md | 4 +- src/doc-entries/md-yarn-spinner.md | 6 +- 50 files changed, 304 insertions(+), 152 deletions(-) create mode 100644 src/components/doc-icons.ts delete mode 100644 src/components/md-deck/editor-panel/icons/align-center.png delete mode 100644 src/components/md-deck/editor-panel/icons/align-left.png delete mode 100644 src/components/md-deck/editor-panel/icons/align-right.png diff --git a/src/App.tsx b/src/App.tsx index ab31de8..c506610 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -7,6 +7,11 @@ import { createSignal, } from "solid-js"; import { useLocation } from "@solidjs/router"; +import { + TbOutlineMenu2, + TbOutlineClipboardList, + TbOutlineHelpCircle, +} from "solid-icons/tb"; import { useJournalStream } from "./components/stores/journalStream"; // 导入组件以注册自定义元素 @@ -99,7 +104,7 @@ const App: Component = () => { class="md:hidden text-gray-600 hover:text-gray-900 p-1 rounded hover:bg-gray-100" title="目录" > - ☰ +

Tabletop Toolkit

@@ -122,14 +127,14 @@ const App: Component = () => { "bg-red-500": stream.connectionStatus === "error", }} /> - 📋 +
diff --git a/src/components/DocDialog.tsx b/src/components/DocDialog.tsx index 8212680..360bda4 100644 --- a/src/components/DocDialog.tsx +++ b/src/components/DocDialog.tsx @@ -6,8 +6,17 @@ import { onCleanup, onMount, } from "solid-js"; +import { Dynamic } from "solid-js/web"; +import { + TbOutlineBook2, + TbOutlineCheck, + TbOutlineChevronDown, + TbOutlineClipboardList, + TbOutlineX, +} from "solid-icons/tb"; import { docEntries, type DocEntry } from "./doc-data"; import { journalDocEntries, type JournalDocEntry } from "./journal-doc-data"; +import { docIcon } from "./doc-icons"; import { parseMarkdown } from "../markdown"; type DocSet = "directives" | "journal"; @@ -77,7 +86,7 @@ const DocDialog: Component = (props) => { class="text-lg font-bold text-gray-900 hover:text-blue-600 flex items-center gap-1" > {docSetLabel()} - ▾ +
@@ -89,10 +98,10 @@ const DocDialog: Component = (props) => { : "text-gray-700" }`} > - 📖 + 指令组件文档 - ✓ +
@@ -117,7 +126,7 @@ const DocDialog: Component = (props) => { class="text-gray-400 hover:text-gray-600 text-xl leading-none p-1" title="关闭" > - ✕ + @@ -133,7 +142,10 @@ const DocDialog: Component = (props) => { : "text-gray-700 hover:bg-gray-100" }`} > - {entry.icon} + {entry.title}} @@ -164,7 +176,11 @@ const DocContent: Component<{ entry: AnyEntry }> = (props) => { return (

- {e.icon} {e.title} + {" "} + {e.title}

- {isExpanded() ? "📂" : "📁"} + {isExpanded() ? ( + + ) : ( + + )} - 📄 + {props.node.name} @@ -151,7 +161,7 @@ export const HeadingNode: Component<{ - ▶ + ' + - '' + - '' + - ""; - -const SPARK_SVG = - '' + - '' + - ""; - // --------------------------------------------------------------------------- // Floating button state // --------------------------------------------------------------------------- @@ -54,7 +37,7 @@ interface FloatingButton { rect: DOMRect; action: () => void; title: string; - svg: string; + icon: IconTypes; color: string; } @@ -130,7 +113,7 @@ export const RevealManager: Component = () => { text: combinedSlug, }), title: "Roll spark table", - svg: SPARK_SVG, + icon: TbOutlineSparkles, color: "text-purple-400 hover:text-purple-600 hover:bg-purple-50", }); return; @@ -150,7 +133,7 @@ export const RevealManager: Component = () => { text: `${normalized}#${text}`, }), title: "Send /link to stream", - svg: LINK_SVG, + icon: TbOutlineLink, color: "text-blue-500 hover:bg-blue-50", }); } @@ -183,14 +166,15 @@ export const RevealManager: Component = () => { left: `${btn().rect.left - 20}px`, }} title={btn().title} - innerHTML={btn().svg} onClick={(e) => { e.stopPropagation(); btn().action(); }} onMouseEnter={() => clearTimeout(hideTimer)} onMouseLeave={hide} - /> + > + + )} diff --git a/src/components/Sidebar.tsx b/src/components/Sidebar.tsx index 9cb4457..53c29c8 100644 --- a/src/components/Sidebar.tsx +++ b/src/components/Sidebar.tsx @@ -1,6 +1,7 @@ import { Component, createMemo, createSignal, onMount, Show } from "solid-js"; import { generateToc, type FileNode, type TocNode } from "../data-loader"; import { useLocation } from "@solidjs/router"; +import { TbOutlineFolderOpen, TbOutlineX } from "solid-icons/tb"; import { FileTreeNode, HeadingNode } from "./FileTree"; import { isPathRevealed } from "./stores/reveal"; @@ -57,7 +58,7 @@ const SidebarContent: Component = (props) => { class="text-gray-400 hover:text-gray-600 p-1 rounded hover:bg-gray-100" title="Content Source" > - 📂 +
diff --git a/src/components/doc-icons.ts b/src/components/doc-icons.ts new file mode 100644 index 0000000..8d35464 --- /dev/null +++ b/src/components/doc-icons.ts @@ -0,0 +1,48 @@ +/** + * Icon registry for built-in doc entries. + * + * Doc-entry frontmatter `icon:` values are semantic keys (e.g. `dice`), not + * glyphs — YAML can't reference a component. This maps each key to a Tabler + * icon component; unknown keys fall back to a generic file icon. + */ + +import type { IconTypes } from "solid-icons"; +import { + TbOutlineCards, + TbOutlineDice5, + TbOutlineFile, + TbOutlineFileText, + TbOutlineGitBranch, + TbOutlineHash, + TbOutlineLink, + TbOutlineMapPin, + TbOutlinePhoto, + TbOutlineSparkles, + TbOutlineSquare, + TbOutlineTable, + TbOutlineTheater, + TbOutlineTypography, +} from "solid-icons/tb"; + +const DOC_ICONS: Record = { + dice: TbOutlineDice5, + table: TbOutlineTable, + link: TbOutlineLink, + pins: TbOutlineMapPin, + font: TbOutlineTypography, + background: TbOutlinePhoto, + border: TbOutlineSquare, + embed: TbOutlineFileText, + deck: TbOutlineCards, + yarn: TbOutlineGitBranch, + gm: TbOutlineTheater, + player: TbOutlineDice5, + roll: TbOutlineDice5, + set: TbOutlineHash, + spark: TbOutlineSparkles, +}; + +/** Resolve a frontmatter icon key to a Tabler icon component. */ +export function docIcon(key: string): IconTypes { + return DOC_ICONS[key] ?? TbOutlineFile; +} diff --git a/src/components/journal/CompletionsDropdown.tsx b/src/components/journal/CompletionsDropdown.tsx index ba7c39a..4771f26 100644 --- a/src/components/journal/CompletionsDropdown.tsx +++ b/src/components/journal/CompletionsDropdown.tsx @@ -3,6 +3,7 @@ */ import { Component, For, Show, createEffect, onMount, onCleanup } from "solid-js"; +import { Dynamic } from "solid-js/web"; import type { CompletionItem } from "./command-parser"; import type { CompletionsState } from "./completions"; @@ -102,6 +103,11 @@ export const CompletionsDropdown: Component = ( {item.kind === "command" ? "cmd" : "val"}
+ + {(icon) => ( + + )} + {item.label} )} diff --git a/src/components/journal/ConnectDialog.tsx b/src/components/journal/ConnectDialog.tsx index 2565ecb..c252d8d 100644 --- a/src/components/journal/ConnectDialog.tsx +++ b/src/components/journal/ConnectDialog.tsx @@ -6,6 +6,7 @@ * or creating a session is a separate step that reuses that connection. */ import { Component, createSignal, For, onMount, Show } from "solid-js"; +import { TbOutlineTrash } from "solid-icons/tb"; import { connectBroker, createSession, @@ -167,7 +168,7 @@ export const ConnectDialog: Component = () => { class="shrink-0 px-2 py-1.5 text-[10px] text-gray-300 hover:text-red-500 disabled:opacity-50" title="删除会话" > - 🗑 +
diff --git a/src/components/journal/CreateSessionDialog.tsx b/src/components/journal/CreateSessionDialog.tsx index 67b30b8..f07ae2f 100644 --- a/src/components/journal/CreateSessionDialog.tsx +++ b/src/components/journal/CreateSessionDialog.tsx @@ -2,6 +2,7 @@ * CreateSessionDialog — modal for naming a new session */ import { Component, createSignal, onMount } from "solid-js"; +import { TbOutlineX } from "solid-icons/tb"; import { createSession, joinSession } from "../stores/journalStream"; interface CreateSessionDialogProps { @@ -48,7 +49,7 @@ export const CreateSessionDialog: Component = ( onClick={props.onClose} class="text-gray-400 hover:text-gray-600 text-sm" > - ✕ +

输入新会话的名称。

diff --git a/src/components/journal/DeleteSessionDialog.tsx b/src/components/journal/DeleteSessionDialog.tsx index 3afc080..baf35c4 100644 --- a/src/components/journal/DeleteSessionDialog.tsx +++ b/src/components/journal/DeleteSessionDialog.tsx @@ -5,6 +5,7 @@ * log), so the warning spells out that it cannot be undone. */ import { Component, createSignal, Show } from "solid-js"; +import { TbOutlineX } from "solid-icons/tb"; import { deleteSession } from "../stores/journalStream"; interface DeleteSessionDialogProps { @@ -49,7 +50,7 @@ export const DeleteSessionDialog: Component = ( onClick={props.onClose} class="text-gray-400 hover:text-gray-600 text-sm" > - ✕ +

diff --git a/src/components/journal/ErrorPopup.tsx b/src/components/journal/ErrorPopup.tsx index 73c2558..81291dd 100644 --- a/src/components/journal/ErrorPopup.tsx +++ b/src/components/journal/ErrorPopup.tsx @@ -3,6 +3,7 @@ * the journal input area. Toggled by clicking the truncated error text. */ import { Component, Show } from "solid-js"; +import { TbOutlineX } from "solid-icons/tb"; interface ErrorPopupProps { message: string | null; @@ -21,7 +22,7 @@ export const ErrorPopup: Component = (props) => { class="text-red-400 hover:text-red-600 text-xs leading-none ml-2 shrink-0" title="关闭" > - ✕ + diff --git a/src/components/journal/InviteDialog.tsx b/src/components/journal/InviteDialog.tsx index 1d79427..49b0993 100644 --- a/src/components/journal/InviteDialog.tsx +++ b/src/components/journal/InviteDialog.tsx @@ -2,6 +2,7 @@ * InviteDialog — input player name, copy invite link */ import { Component, createSignal } from "solid-js"; +import { TbOutlineX } from "solid-icons/tb"; import { useJournalStream } from "../stores/journalStream"; interface InviteDialogProps { @@ -51,7 +52,7 @@ export const InviteDialog: Component = (props) => { onClick={props.onClose} class="text-gray-400 hover:text-gray-600 text-sm" > - ✕ +

diff --git a/src/components/journal/JournalHeader.tsx b/src/components/journal/JournalHeader.tsx index 7ec593f..ee2fb87 100644 --- a/src/components/journal/JournalHeader.tsx +++ b/src/components/journal/JournalHeader.tsx @@ -2,6 +2,10 @@ * JournalHeader — status dot, player name, session dropdown, leave & close */ import { Component, Show } from "solid-js"; +import { + TbOutlineArrowLeft, + TbOutlineLayoutSidebarRightCollapse, +} from "solid-icons/tb"; import { useJournalStream, leaveSession } from "../stores/journalStream"; import { SessionDropdown } from "./SessionDropdown"; @@ -70,7 +74,7 @@ export const JournalHeader: Component = (props) => { class="text-xs text-gray-400 hover:text-blue-500 px-1" title="返回会话列表" > - ← + diff --git a/src/components/journal/SessionDropdown.tsx b/src/components/journal/SessionDropdown.tsx index d97ead4..6e04e56 100644 --- a/src/components/journal/SessionDropdown.tsx +++ b/src/components/journal/SessionDropdown.tsx @@ -2,6 +2,11 @@ * SessionDropdown — session switcher for the journal header (GM only) */ import { Component, createSignal, For, Show } from "solid-js"; +import { + TbOutlineCheck, + TbOutlineChevronDown, + TbOutlineTrash, +} from "solid-icons/tb"; import { sessions, joinSession, @@ -46,7 +51,7 @@ export const SessionDropdown: Component = (props) => { class="text-[10px] text-gray-400 hover:text-gray-600 truncate leading-tight cursor-pointer text-left" > {stream.sessionName || stream.sessionId}{" "} - ▾ +

= (props) => { > {meta.name || id} - ✓ +
)} diff --git a/src/components/journal/StreamMessage.tsx b/src/components/journal/StreamMessage.tsx index f6919af..b16b8b1 100644 --- a/src/components/journal/StreamMessage.tsx +++ b/src/components/journal/StreamMessage.tsx @@ -3,6 +3,7 @@ */ import { Component, Show, createMemo } from "solid-js"; +import { TbOutlineArrowBackUp } from "solid-icons/tb"; import type { StreamMessage as StreamMessageType } from "./registry"; import { getMessageType } from "./registry"; import { revertLatest, useJournalStream } from "../stores/journalStream"; @@ -47,7 +48,7 @@ export const StreamMessageCard: Component<{ class="text-xs text-gray-300 hover:text-red-500 ml-auto px-0.5 leading-none" title="撤回此消息" > - × + ({ render: (p) => (
- 🙋 + 意图

{p.description}

@@ -58,7 +59,7 @@ registerMessageType({ render: (p) => (
- ✅ + 裁决 re: {p.intentId}
diff --git a/src/components/journal/types/link.tsx b/src/components/journal/types/link.tsx index c3960fa..80b757c 100644 --- a/src/components/journal/types/link.tsx +++ b/src/components/journal/types/link.tsx @@ -6,6 +6,7 @@ */ import { Component } from "solid-js"; +import { TbOutlineFileText } from "solid-icons/tb"; import { useNavigateWithParams } from "../../useNavigateWithParams"; import { z } from "zod"; import { registerMessageType } from "../registry"; @@ -69,7 +70,7 @@ const RevealLink: Component = (p) => { return (
- 📄 +
({ return (
- 🎲 + - {p.notation} →{" "} + {p.notation}{" "} + {" "} {result.total}
diff --git a/src/components/journal/types/var.tsx b/src/components/journal/types/var.tsx index 6e21eac..976e616 100644 --- a/src/components/journal/types/var.tsx +++ b/src/components/journal/types/var.tsx @@ -10,6 +10,7 @@ */ import { z } from "zod"; +import { TbOutlineHash } from "solid-icons/tb"; import { registerMessageType } from "../registry"; import { journalSetState } from "../../stores/journalStream"; import { produce } from "solid-js/store"; @@ -35,7 +36,7 @@ registerMessageType({ render: (p) => { return (
- 🔢 + {p.key} = {p.value} diff --git a/src/components/md-deck/CardList.tsx b/src/components/md-deck/CardList.tsx index ca79821..c404107 100644 --- a/src/components/md-deck/CardList.tsx +++ b/src/components/md-deck/CardList.tsx @@ -1,4 +1,5 @@ import { For, Show, createEffect, createSignal, on } from "solid-js"; +import { TbOutlineChevronLeft, TbOutlineChevronRight } from "solid-icons/tb"; import type { DeckStore } from "./hooks/deckStore"; export interface CardListProps { @@ -67,7 +68,7 @@ export function CardList(props: CardListProps) { disabled={page() === 0} class="px-2 py-1 rounded text-sm text-gray-600 hover:bg-gray-100 disabled:opacity-40 disabled:cursor-not-allowed cursor-pointer" > - ‹ + {page() + 1} / {totalPages()} @@ -77,7 +78,7 @@ export function CardList(props: CardListProps) { disabled={page() >= totalPages() - 1} class="px-2 py-1 rounded text-sm text-gray-600 hover:bg-gray-100 disabled:opacity-40 disabled:cursor-not-allowed cursor-pointer" > - › +
diff --git a/src/components/md-deck/DeckHeader.tsx b/src/components/md-deck/DeckHeader.tsx index d7ba752..8f9b3b0 100644 --- a/src/components/md-deck/DeckHeader.tsx +++ b/src/components/md-deck/DeckHeader.tsx @@ -1,5 +1,11 @@ import { Show, createSignal, onMount } from "solid-js"; import { Portal } from "solid-js/web"; +import { + TbOutlineCheck, + TbOutlineCopy, + TbOutlineDownload, + TbOutlinePencil, +} from "solid-icons/tb"; import type { DeckStore } from "./hooks/deckStore"; export interface DeckHeaderProps { @@ -43,7 +49,15 @@ export function DeckHeader(props: DeckHeaderProps) { : "bg-gray-100 text-gray-600 hover:bg-gray-200" }`} > - {store.state.isEditing ? "✓ 编辑中" : "✏️ 编辑"} + {store.state.isEditing ? ( + <> + 编辑中 + + ) : ( + <> + 编辑 + + )} {/* 导出 PDF 按钮 */} @@ -51,7 +65,7 @@ export function DeckHeader(props: DeckHeaderProps) { onClick={() => store.actions.exportDeck()} class="px-2 py-1 rounded text-xs font-medium transition-colors cursor-pointer bg-green-100 text-green-600 hover:bg-green-200" > - 📥 导出 PDF + 导出 PDF {/* 复制代码按钮 */} @@ -59,7 +73,7 @@ export function DeckHeader(props: DeckHeaderProps) { onClick={handleCopy} class="px-2 py-1 rounded text-xs font-medium transition-colors cursor-pointer bg-purple-100 text-purple-600 hover:bg-purple-200" > - 📋 复制代码 + 复制代码
diff --git a/src/components/md-deck/PltPreview.tsx b/src/components/md-deck/PltPreview.tsx index 35be583..2d98f22 100644 --- a/src/components/md-deck/PltPreview.tsx +++ b/src/components/md-deck/PltPreview.tsx @@ -1,5 +1,6 @@ import { createSignal, For, Show, createMemo } from "solid-js"; import { Portal } from "solid-js/web"; +import { TbOutlineDownload } from "solid-icons/tb"; import { parsePlt, extractCutPaths } from "../../plotcutter/parser"; import { generateTravelPaths, travelPathsToSvg } from "../../plotcutter/layout"; import type { CardPath } from "../../plotcutter/types"; @@ -115,7 +116,7 @@ export function PltPreview(props: PltPreviewProps) { class="bg-blue-600 hover:bg-blue-700 text-white px-3 py-1.5 rounded text-sm font-medium cursor-pointer flex items-center gap-1" disabled={parsedData().cardPaths.length === 0} > - 📥 下载 PLT + 下载 PLT
diff --git a/src/components/md-deck/PrintPreviewHeader.tsx b/src/components/md-deck/PrintPreviewHeader.tsx index e864ffe..63ca049 100644 --- a/src/components/md-deck/PrintPreviewHeader.tsx +++ b/src/components/md-deck/PrintPreviewHeader.tsx @@ -1,4 +1,9 @@ import { createSignal, For, onCleanup, onMount, Show } from "solid-js"; +import { + TbOutlineDownload, + TbOutlinePlus, + TbOutlineRuler, +} from "solid-icons/tb"; import type { DeckStore } from "./hooks/deckStore"; import { getCompatibleDecks } from "./hooks/deck-registry"; @@ -77,7 +82,7 @@ export function PrintPreviewHeader(props: PrintPreviewHeaderProps) { : "添加其他牌组到打印" } > - ➕ + 添加牌组 0}> @@ -232,14 +237,14 @@ export function PrintPreviewHeader(props: PrintPreviewHeaderProps) { onClick={props.onOpenPltPreview} class="bg-green-600 hover:bg-green-700 text-white px-4 py-1.5 rounded text-sm font-medium cursor-pointer flex items-center gap-2" > - 📐 + PLT 预览 @@ -162,6 +185,10 @@ export function LayerRow(props: LayerRowProps) { onClick={() => props.onUpdateOrientation(o.value)} class="block w-full text-left px-3 py-1.5 text-sm hover:bg-gray-100 cursor-pointer whitespace-nowrap" > + {" "} {o.label} )} @@ -187,13 +214,11 @@ export function LayerRow(props: LayerRowProps) { onClick={() => props.onUpdateAlign(o.value || undefined)} class="flex items-center gap-2 w-full px-3 py-1.5 text-sm hover:bg-gray-100 cursor-pointer whitespace-nowrap" > - {o.icon.endsWith(".png") ? ( - - ) : ( - - {o.icon} - - )} + )} @@ -260,19 +285,19 @@ export function LayerRow(props: LayerRowProps) { class={`shrink-0 w-5 h-5 text-xs rounded cursor-pointer flex items-center justify-center text-red-400 hover:text-red-600 hover:bg-red-50 transition-opacity ${props.hovered ? "opacity-100" : "opacity-0"}`} title="删除图层" > - ✕ +
); } function DropdownButton(props: { - icon: import("solid-js").JSX.Element; + icon: IconTypes; visible: boolean; open: boolean; onToggle: () => void; title: string; - children: import("solid-js").JSX.Element; + children: JSX.Element; }) { return (
@@ -284,7 +309,7 @@ function DropdownButton(props: { class={`w-7 h-7 rounded cursor-pointer flex items-center justify-center bg-gray-200 hover:bg-gray-300 ${!props.visible ? "invisible pointer-events-none" : ""}`} title={props.title} > - {props.icon} + {props.open && (
4nJ zFmD85#;?t9J%NIfC9V-A!TD(=<%vb94CUqJdYO6I#mR{Use1WE>9gP2NC8!+d%8G= zRLpsM*S{kyRHEVIaly5crb{(qR2C))u4KJtbf;6L!+K$>#kMuQzc-kzbIs7qD_z;9 zds`yST6dxX>%>bzQx45sBX~^A-81pevw7CW@2lU}oac|*cXsdn%J-J-zx#{Nv3gEY zfujhn8m1b4ABO&(D>E3*F+VZI`02*=lliX9u=Qg;J@0mvaYWQ+!vYD5fSvu1 z_PAzV&Y%5m!;(km!x_pOE}mK<@;d*))#Lj&uiBYb)6jdLJ^8?IU-NY@8T79{U!<~n zc3#9~#=I>aE|yZ;L(keC;P}A3VWE|*>n^T6o|RfNLeEMjNLk$Y(m(Z)AY-mcpMJwG ziSLcI%(rsgOs6+2U(5Q9>3yIa|I~D$9UOC5{&}2pMRL36&0BpOvsN1>h;NXrP}FQ+ z_d|RK&zz+XQ~LJ(=Gfu-Ph!`)qrM5xWnOI+-^LvLB)lvD#h9)=$Fo;vc=8RvMFgP+X*<%eZUSZHdr;6n2R&>pPV~Vc`?|8?zg3hpbC5Y+2TD zyJ&bw1%JT_t^}2sd(T9h;=cGqxOC3%~J$U-l!)5K=#XZ}3jJaw&f9iOC3(#78 zg!chAQ`?laOm!YM0m%h13wZYAuK9L&Vm#w+?eBqeu4_(zve~zM#ZLBuBzOA|U!9dR zB{uO&@8_Qud~4OjS$qaz^SdXRic^&r;`)tv}Gm_||Okw)IW!KkH|1|G?Q>b_h<71 z%}-(w3CDBN6y5BtAGRJien6}(q4rOt50gEUdc*z6#hir=MHg-+zt|-veBj@=tGD>8 z8!|s>?_O=_`{B;%6W#|nQV$*ab-?KN3#kpAmlVZfp13c*cl20(lJW-ARU1z5ZP44W zW?!}Pss$(b9+Vf(;*S2L`bjQ4nJ zFmD85#;?t9J%NIfC9V-A!TD(=<%vb94CUqJdYO6I#mR{Use1WE>9gP2NC8!6d%8G= zRLpsM*S146T;#yV`Y@Asvs?m2x?2QPIS=}GOiNN1a=gSE#1ig(d5QRBwNj3VuC>$Z z7A*BW((flM=*T*;Mr$HVd2eLm)*W6#H}>pJ|F(B$@%`WbA8a^#=Jw}zJJ0Nqd^eNP zbCL=iMX<;)=rIN#FkYPD!zkY9nXtzF?yn@yf@K%PO`r7#A9(bC?L8SWS2MPKY~R?w z2Ug!xzxt)-9p8EuyBf(43=;fmOUrE8!uJ2LUVp+e*;;HroA7~ccY2kDAM{q}X{A)Y zYn#Yfu-;KgOL=$L#QO}%2Xqr+Eo8U8H2Wa;a#cdyMCAiIA6(zDukJ|S60q2F595`i z6)ZK^7Uvar&0+eNtNVd-!_<<>6-CP$S0CVfu>H_Z4sRuAGn`hKTxV$$5y7F5VLxN@Qj6j63R`}8f1Ijw=-SWv_BEspABR_ zHVddL$nNBq>MMM$)T>y=@-#Z$sxf9Fr-9J^g5OJKZS0C+TgUKDxQ6K{$1KKc4E59e zRNS9%d|)rg3FzdRxHu%}k6IkFUhqHnu<*x9$``b@i&*g7S^B4;T=gAOdt8ri=&XBO zb(xkMR>^mUyeV({F+m?5@Sc-iZN9*&sNFF2uZK&ot;*W#IcF_Ch`!vavUGZqq~<%u z_)CW-ZMoj4&ANZZMQgpuV(-$r_gQ@6*kHb+|JG-OxX1fHDsNcre)rjxFJT`n{@bXn+tqeL@pDT_mL2<_Pz!M+r>ji8 zR^oag>OpXVu=0nRKb1br_nD73#&bWv)b)3Xery$Q%=IL$8`o9$d|sXIho8${vJ|~XfdTv(g~6;e=?MDemC=db$4nJ zFmD85#;?t9J%NIfC9V-A!TD(=<%vb94CUqJdYO6I#mR{Use1WE>9gP2NC8zRdb&7< zRLpsM*SaIrUE;vU{n}FHwYr>Lu1zZ>IJ1NTPEYVtX`JA_L6PCE|KHJ%Pz~50l>q~#|fu`%*?&&<6F2csgw41v>u-a_G ztuH?B7(a8>)fj#dH;9@s<wr*<5j=+c^VGw_y*AK2E*!b;pezW!8Dh zAE!op*G!3C$s8Y$z-Otfd4JcPCezY}g%yY9D&H&(y`25PqG0|ZQG>P%CL4q*CIs(T zrhQ=lfsHRzv~%d*_kiuA=)I{s7;FA7%ImuFg~wp_ z(*xBPJz0Lw-u`2fK9cKC?S0uWq42@oogOZ|f1RcDZ_WyQz!{RKsJlJElYIwMjMjNq-Q659XLVz&EKB4+tob0Z^||DR z@(ce{*gvR$e81<||Hon*_5x#n)yw4%0^{^9n|)aC|LP^@%WHp(KUi3ZBe`A0b#>|1 z51|M25{#WU*wx7gA9#PD@IhXI-r5_!Rxe)|R>XFDKDhntYE=9BM#)FoyH^`JKfH5x zRvx4B5>Ec?MZzz4ygpDB)c#`iGT+5^2alcK$oIoydx5X)gXR}3TAQr4C-}-9s4e`I zsxKLQ+4w-xrC%)Pg5KqJZLxE>_HLnREaS3 { class="text-blue-600 hover:text-blue-800 cursor-pointer" title={rollDetail() || "掷骰子"} > - 🎲 + - 📋 复制 + 复制
diff --git a/src/components/md-table.tsx b/src/components/md-table.tsx index b611161..081c2f5 100644 --- a/src/components/md-table.tsx +++ b/src/components/md-table.tsx @@ -7,6 +7,7 @@ import { createMemo, createResource, } from "solid-js"; +import { TbOutlineDice5 } from "solid-icons/tb"; import { parseMarkdown } from "../markdown"; import { parseCSVString, CSV, processVariables } from "./utils/csv-loader"; import { resolveContentRef } from "./utils/resolve-content"; @@ -210,7 +211,7 @@ customElement( class="text-gray-500 hover:text-gray-700 shrink-0 cursor-pointer" title="随机切换" > - 🎲 +
('md-yarn-spinner', {start: 'start'}, (props, { el rounded-bl-md transition-colors cursor-pointer" title="重新开始" > - 🔄 +
@@ -104,7 +109,7 @@ customElement<{start: string}>('md-yarn-spinner', {start: 'start'}, (props, { el class="option-button text-left px-4 py-2 bg-blue-50 hover:bg-blue-100 rounded border border-blue-200 transition-colors cursor-pointer" > - → {option.text} + {option.text} )} diff --git a/src/doc-entries/journal-gm.md b/src/doc-entries/journal-gm.md index 03146e0..78f2139 100644 --- a/src/doc-entries/journal-gm.md +++ b/src/doc-entries/journal-gm.md @@ -1,16 +1,16 @@ --- tag: journal-gm -icon: 🎭 +icon: gm title: 主持人指南 --- 作为 GM 创建会话、管理玩家、使用命令与玩家互动。 -点击顶部导航栏的 📋 按钮打开 Journal 面板。 +点击顶部导航栏的剪贴板按钮打开 Journal 面板。 ## 快速开始 -1. 点击顶部导航栏的 📋 按钮打开 Journal 面板 +1. 点击顶部导航栏的剪贴板按钮打开 Journal 面板 2. 输入你的名字,选择"主持人"角色,点击"加入" 3. 连接成功后,你可以创建新会话或选择已有会话 diff --git a/src/doc-entries/journal-link.md b/src/doc-entries/journal-link.md index de17a18..3b0ab20 100644 --- a/src/doc-entries/journal-link.md +++ b/src/doc-entries/journal-link.md @@ -1,6 +1,6 @@ --- tag: journal-link -icon: 🔗 +icon: link title: 链接命令 --- diff --git a/src/doc-entries/journal-player.md b/src/doc-entries/journal-player.md index a7e5802..ba67ca9 100644 --- a/src/doc-entries/journal-player.md +++ b/src/doc-entries/journal-player.md @@ -1,6 +1,6 @@ --- tag: journal-player -icon: 🎲 +icon: player title: 玩家指南 --- @@ -19,7 +19,7 @@ GM 会发送一个包含 `?session=xxx&player=你的名字&autojoin=1` 的链接 ### 手动加入 -1. 点击顶部导航栏的 📋 按钮打开 Journal 面板 +1. 点击顶部导航栏的剪贴板按钮打开 Journal 面板 2. 输入你的名字 3. 选择"玩家"角色 4. 点击"加入" diff --git a/src/doc-entries/journal-roll.md b/src/doc-entries/journal-roll.md index c9da05b..fec957e 100644 --- a/src/doc-entries/journal-roll.md +++ b/src/doc-entries/journal-roll.md @@ -1,6 +1,6 @@ --- tag: journal-roll -icon: 🎲 +icon: roll title: 掷骰与火花表命令 --- diff --git a/src/doc-entries/journal-set.md b/src/doc-entries/journal-set.md index f81309d..d51e4e1 100644 --- a/src/doc-entries/journal-set.md +++ b/src/doc-entries/journal-set.md @@ -1,6 +1,6 @@ --- tag: journal-set -icon: 🔢 +icon: set title: 变量系统 description: 在文档中声明变量和标签,通过 /set 命令设置变量值,自动计算派生变量和标签效果。 syntax: '```yaml role=declare' diff --git a/src/doc-entries/journal-spark.md b/src/doc-entries/journal-spark.md index dbb4fd1..c61de33 100644 --- a/src/doc-entries/journal-spark.md +++ b/src/doc-entries/journal-spark.md @@ -1,6 +1,6 @@ --- tag: journal-spark -icon: 🎰 +icon: spark title: 火花表 --- diff --git a/src/doc-entries/md-bg.md b/src/doc-entries/md-bg.md index b59dbc9..d0fe264 100644 --- a/src/doc-entries/md-bg.md +++ b/src/doc-entries/md-bg.md @@ -1,6 +1,6 @@ --- tag: md-bg -icon: 🖼️ +icon: background title: 背景组件 --- diff --git a/src/doc-entries/md-border.md b/src/doc-entries/md-border.md index 48eb7c7..4325a3f 100644 --- a/src/doc-entries/md-border.md +++ b/src/doc-entries/md-border.md @@ -1,6 +1,6 @@ --- tag: md-border -icon: 🖼️ +icon: border title: 边框组件 --- diff --git a/src/doc-entries/md-deck.md b/src/doc-entries/md-deck.md index 5656020..426b3fc 100644 --- a/src/doc-entries/md-deck.md +++ b/src/doc-entries/md-deck.md @@ -1,6 +1,6 @@ --- tag: md-deck -icon: 🃏 +icon: deck title: 卡牌组件 --- diff --git a/src/doc-entries/md-dice.md b/src/doc-entries/md-dice.md index f6ebca6..c30c696 100644 --- a/src/doc-entries/md-dice.md +++ b/src/doc-entries/md-dice.md @@ -1,6 +1,6 @@ --- tag: md-dice -icon: 🎲 +icon: dice title: 骰子组件 --- @@ -23,7 +23,7 @@ title: 骰子组件 :md-dice[2d20k1+5]{key="advantage"} ``` -点击 🎲 图标执行投掷,显示结果;点击文字重置为原始公式。 +点击骰子图标执行投掷,显示结果;点击文字重置为原始公式。 ## 属性 diff --git a/src/doc-entries/md-embed.md b/src/doc-entries/md-embed.md index a866f99..6ca394a 100644 --- a/src/doc-entries/md-embed.md +++ b/src/doc-entries/md-embed.md @@ -1,6 +1,6 @@ --- tag: md-embed -icon: 📄 +icon: embed title: 嵌入组件 --- diff --git a/src/doc-entries/md-font.md b/src/doc-entries/md-font.md index 9c873ba..c5a6405 100644 --- a/src/doc-entries/md-font.md +++ b/src/doc-entries/md-font.md @@ -1,6 +1,6 @@ --- tag: md-font -icon: 🔤 +icon: font title: 字体组件 --- diff --git a/src/doc-entries/md-link.md b/src/doc-entries/md-link.md index 35bb853..22bb1e1 100644 --- a/src/doc-entries/md-link.md +++ b/src/doc-entries/md-link.md @@ -1,6 +1,6 @@ --- tag: md-link -icon: 🔗 +icon: link title: 链接组件 --- diff --git a/src/doc-entries/md-pins.md b/src/doc-entries/md-pins.md index e87ec23..82487a9 100644 --- a/src/doc-entries/md-pins.md +++ b/src/doc-entries/md-pins.md @@ -1,6 +1,6 @@ --- tag: md-pins -icon: 📍 +icon: pins title: 标记组件 --- @@ -27,7 +27,7 @@ title: 标记组件 ## 复制坐标 -非 `fixed` 模式下,图片右上角会显示 📋 复制按钮,点击可将所有标记的坐标复制到剪贴板,方便粘贴回文档的 `pins` 属性中。 +非 `fixed` 模式下,图片右上角会显示复制按钮,点击可将所有标记的坐标复制到剪贴板,方便粘贴回文档的 `pins` 属性中。 ## 属性 diff --git a/src/doc-entries/md-table.md b/src/doc-entries/md-table.md index 871d6b7..011e448 100644 --- a/src/doc-entries/md-table.md +++ b/src/doc-entries/md-table.md @@ -1,6 +1,6 @@ --- tag: md-table -icon: 📊 +icon: table title: 表格组件 --- @@ -38,7 +38,7 @@ B,另一段描述,第二章]{} ## 随机抽取 -当 `roll=true` 时,表格顶部显示 🎲 随机按钮: +当 `roll=true` 时,表格顶部显示骰子随机按钮: - 普通随机:从所有行中均匀随机选取 - **加权随机**:当 `label` 列全部为整数或整数范围格式(如 `1-3`)时,以 label 值为权重进行加权随机抽取 diff --git a/src/doc-entries/md-yarn-spinner.md b/src/doc-entries/md-yarn-spinner.md index 047747e..be5681a 100644 --- a/src/doc-entries/md-yarn-spinner.md +++ b/src/doc-entries/md-yarn-spinner.md @@ -1,6 +1,6 @@ --- tag: md-yarn-spinner -icon: 🧶 +icon: yarn title: 叙事线组件 --- @@ -19,8 +19,8 @@ Yarn Spinner 是用于游戏对话系统的格式,支持选项、条件分支 - **对话历史**:上半部分显示已进行的对话,说话者以蓝色粗体显示,命令以灰色斜体显示 - **当前选项**:下半部分显示可选的对话选项,点击选项推进剧情 -- **⏩ 继续**:点击右上角继续按钮推进到下一段对话 -- **🔄 重新开始**:点击右上角重启按钮从头开始对话 +- **继续**:点击右上角继续按钮推进到下一段对话 +- **重新开始**:点击右上角重启按钮从头开始对话 ## 属性