Files
ttrpg-tools/docs/icon-migration.md
hypercross 49bed7d279 docs: add icon migration reference
Record the Tabler pack choice, icon conventions, and the per-file
glyph-to-icon mapping for the unicode-to-solid-icons migration.
2026-09-13 14:01:10 +08:00

10 KiB
Raw Permalink Blame History

Icon migration — unicode/emoji → solid-icons

Status: implemented. This document is both the audit and the record of the migration. It lists the pack/conventions used and the per-file mapping.

Goal

Replace ad-hoc unicode symbols and emoji in UI chrome with real SVG icon components from solid-icons, so icons are consistent, themeable (currentColor, size), and render identically across platforms (emoji fonts vary wildly between OSes).

Scope

In scope — UI chrome (src/components/**, src/App.tsx, doc-entry frontmatter, RevealManager inline SVGs, the editor-panel align PNGs).

Out of scope — left as-is:

Thing Why
:[icon-name] content directive (src/markdown/icon.ts, assets/) Game-content icons resolved from user assets/ dirs via CSS background-image. Not UI chrome.
CLI console output (✅ ❌ 📦 in src/cli/**) Terminal output, not a browser. solid-icons is a SolidJS/browser library.
Emoji in README.md, docs/*.md prose Documentation text, not rendered UI.
Dimension text × in PltPreview / PrintPreviewHeader A multiplication sign in "100mm × 50mm", not an icon.
content/** sample content User-authored data.
PltPreview.tsx / PrintPreview.tsx <svg> Rendered card/page artwork, not icons.

Pack

Tabler (solid-icons/tb). solid-icons@1.2.0 does not ship Lucide; the available packs are ai, bi, bs, cg, fa, fi, hi, im, io, md, oc, ri, si, tb, ti, vs, wi. Tabler was chosen because it is stroke-based, uses currentColor, and covers everything needed (dice, ruler, grip, alignment, arrows, …).

Exports are prefixed TbOutline* (outline) and TbFill* (filled). Always use TbOutline*.

Conventions

import { TbOutlineFolderOpen, TbOutlineX } from "solid-icons/tb";

<TbOutlineFolderOpen size={16} class="text-gray-400" />
  • size?: string | number defaults to "1em"; color defaults to currentColor. Icons therefore inherit the surrounding font-size and text color, so existing Tailwind text-color/size classes keep working.
  • Inline alignment: an inline SVG sits on the text baseline, so icons placed inline next to text get class="inline-block align-[-0.125em]". Icons inside a flex/inline-flex container don't need it.
  • Fixed-size buttons get an explicit size (16 for w-7 h-7/w-8 h-8, 14 for w-5 h-5/w-6 h-6).
  • Text labels next to a glyph (e.g. 📥 导出 PDF) are preserved; only the glyph is replaced.

Shared modules

  • src/components/doc-icons.ts — maps doc-entry frontmatter icon: keys (e.g. dice, table) to Tabler components. Frontmatter is YAML, so it can't hold a component; it stores a semantic key instead. docIcon(key) falls back to TbOutlineFile.
  • CompletionItem.icon (src/components/journal/command-parser.ts) — an optional IconTypes rendered by CompletionsDropdown.tsx before the label, so completion entries carry real icons instead of emoji in the label string.

Inventory

Shell / navigation

File Glyph Purpose Icon
src/App.tsx ☰ mobile menu TbOutlineMenu2
src/App.tsx 📋 journal panel toggle TbOutlineClipboardList
src/App.tsx ? docs/help TbOutlineHelpCircle
src/components/Sidebar.tsx 📂 content source TbOutlineFolderOpen
src/components/Sidebar.tsx ✕ close sidebar TbOutlineX
src/components/FileTree.tsx 📂 / 📁 folder open / closed TbOutlineFolderOpen / TbOutlineFolder
src/components/FileTree.tsx 📄 file TbOutlineFile
src/components/FileTree.tsx ▶ expand chevron TbOutlineChevronRight
src/components/DocDialog.tsx ▾ dropdown caret TbOutlineChevronDown
src/components/DocDialog.tsx 📖 directives doc set TbOutlineBook2
src/components/DocDialog.tsx ✓ selected doc set TbOutlineCheck
src/components/DocDialog.tsx 📋 journal doc set TbOutlineClipboardList
src/components/DocDialog.tsx ✕ close dialog TbOutlineX
src/components/DocDialog.tsx entry icon: doc entry icon <Dynamic component={docIcon(entry.icon)} />

md-* components

File Glyph Purpose Icon
src/components/md-dice.tsx 🎲 dice reset TbOutlineDice5
src/components/md-table.tsx 🎲 random row TbOutlineDice5
src/components/md-pins.tsx 📋 copy pin coords TbOutlineCopy
src/components/md-yarn-spinner.tsx 🔄 restart TbOutlineRotate
src/components/md-yarn-spinner.tsx ⏩ advance TbOutlinePlayerTrackNext
src/components/md-yarn-spinner.tsx → option bullet TbOutlineArrowRight

Journal

File Glyph Purpose Icon
src/components/journal/ConnectDialog.tsx 🗑 delete session TbOutlineTrash
src/components/journal/CreateSessionDialog.tsx ✕ close TbOutlineX
src/components/journal/DeleteSessionDialog.tsx ✕ close TbOutlineX
src/components/journal/ErrorPopup.tsx ✕ close TbOutlineX
src/components/journal/InviteDialog.tsx ✕ close TbOutlineX
src/components/journal/JournalHeader.tsx ← back to session list TbOutlineArrowLeft
src/components/journal/JournalHeader.tsx ▸ hide panel TbOutlineLayoutSidebarRightCollapse
src/components/journal/SessionDropdown.tsx ▾ dropdown caret TbOutlineChevronDown
src/components/journal/SessionDropdown.tsx ✓ active session TbOutlineCheck
src/components/journal/SessionDropdown.tsx 🗑 delete session TbOutlineTrash
src/components/journal/StreamMessage.tsx × revert message TbOutlineArrowBackUp
src/components/journal/types/intent.tsx 🙋 intent TbOutlineHandStop
src/components/journal/types/intent.tsx ✅ verdict TbOutlineCircleCheck
src/components/journal/types/link.tsx 📄 link TbOutlineFileText
src/components/journal/types/roll.tsx 🎲 roll TbOutlineDice5
src/components/journal/types/roll.tsx → notation → total TbOutlineArrowRight
src/components/journal/types/var.tsx 🔢 variable TbOutlineHash
src/components/journal/command-completions.ts 🎲 dice completion TbOutlineDice5 (via item.icon)
src/components/journal/command-completions.ts ✨ spark completion TbOutlineSparkles (via item.icon)

md-deck

File Glyph Purpose Icon
src/components/md-deck/DeckHeader.tsx ✓ / ✏️ editing toggle TbOutlineCheck / TbOutlinePencil
src/components/md-deck/DeckHeader.tsx 📥 export PDF TbOutlineDownload
src/components/md-deck/DeckHeader.tsx 📋 copy code TbOutlineCopy
src/components/md-deck/PltPreview.tsx 📥 download PLT TbOutlineDownload
src/components/md-deck/PrintPreviewFooter.tsx ❌ export error TbOutlineCircleX
src/components/md-deck/PrintPreviewFooter.tsx ✕ close TbOutlineX
src/components/md-deck/PrintPreviewHeader.tsx ➕ add deck TbOutlinePlus
src/components/md-deck/PrintPreviewHeader.tsx 📐 PLT preview TbOutlineRuler
src/components/md-deck/PrintPreviewHeader.tsx 📥 export PDF TbOutlineDownload
src/components/md-deck/CardList.tsx ‹ previous page TbOutlineChevronLeft
src/components/md-deck/CardList.tsx › next page TbOutlineChevronRight
src/components/md-deck/editor-panel/LayerRow.tsx ⠿ drag handle TbOutlineGripVertical
src/components/md-deck/editor-panel/LayerRow.tsx 👁 / 👁‍🗨 visible / hidden TbOutlineEye / TbOutlineEyeOff
src/components/md-deck/editor-panel/LayerRow.tsx ↑ → ↓ ← orientation TbOutlineArrowUp / TbOutlineArrowRight / TbOutlineArrowDown / TbOutlineArrowLeft
src/components/md-deck/editor-panel/LayerRow.tsx ↖ ↑ ↗ ↙ ↓ ↘ alignment TbOutlineArrowUpLeft / TbOutlineArrowUp / TbOutlineArrowUpRight / TbOutlineArrowDownLeft / TbOutlineArrowDown / TbOutlineArrowDownRight
src/components/md-deck/editor-panel/LayerRow.tsx ✕ delete layer TbOutlineTrash
src/components/md-deck/editor-panel/LayerRow.tsx align-*.png align presets TbOutlineAlignLeft / TbOutlineAlignCenter / TbOutlineAlignRight

The three align-*.png assets were deleted; the icons/ directory is gone.

RevealManager.tsx (formerly inline SVG strings)

Former Purpose Icon
LINK_SVG floating /link action TbOutlineLink
SPARK_SVG floating /roll spark action TbOutlineSparkles

FloatingButton.svg: string (rendered via innerHTML) became FloatingButton.icon: IconTypes, rendered as <Dynamic component={icon} /> children.

src/doc-entries/*.md frontmatter icon:

File / tag Key
journal-gm.md gm
journal-link.md link
journal-player.md player
journal-roll.md roll
journal-set.md set
journal-spark.md spark
md-bg.md background
md-border.md border
md-deck.md deck
md-dice.md dice
md-embed.md embed
md-font.md font
md-link.md link
md-pins.md pins
md-table.md table
md-yarn-spinner.md yarn

Keys are resolved through docIcon() in src/components/doc-icons.ts.

Follow-ups / not migrated (by design)

  • Doc-entry body prose that referenced a replaced button glyph was reworded to name the button (e.g. md-dice.md now says "点击骰子图标"). Remaining emoji in src/doc-entries/*.md are illustrative — coloured status dots (🟢🟡🔴⚪ in journal-gm.md) — not UI icons.
  • CLI console / MCP output (✅ ❌ 📦 in src/cli/**) keeps its emoji: it is terminal text, not rendered UI.
  • command-completions.ts CompletionItem now carries an optional icon; any future completion source can use it.