diff --git a/README.md b/README.md index 5ef0154..eee1166 100644 --- a/README.md +++ b/README.md @@ -1,89 +1,52 @@ # TTRPG Tools -一个基于 `solid.js` 和 `rsbuild` 的 `ttrpg` 工具箱。 +一个基于 `solid.js` 和 `rsbuild` 的 TTRPG 工具箱,支持 Markdown 解析、自定义组件和 CLI 工具。 -## 功能 - -- **CLI**: 提供一个 cli 工具,用于将目录内的各种 ttrpg 文档编译为 html。 -- **Markdown**: 解析以各种格式编写的 ttrpg 内容,并支持扩展的语法。 -- **TTRPG 组件**: 用于 ttrpg 内容的各种 UI 组件,且可以在 markdown 中通过扩展语法插入。 - -## CLI 命令 - -```bash -# 克隆仓库后,npm install & npm link安装 - -# 在项目文件夹内运行 -ttrpg serve [dir] -p 3000 - -``` - -## 组件语法 - -### csv - -所有csv使用英文逗号分割。可使用空行。以#为注释。所有包含#或者英文逗号的字段,都应该使用双引号包裹。 - -### 骰子组件 - -```markdown -:dice[2d6+d8] -:dice[1d20+5]{key="attack"} -``` - -### 表格组件 - -```markdown -:table[./sparks.csv] -:table[./sparks.csv]{roll=true} -:table[./sparks.csv]{roll=true remix=true} -``` - -### 卡牌组件 - -假设准备有`./cards.csv`内容如下: - -```csv -label,title,body -1,卡牌1,这张卡牌的**效果**的markdown文本 -2,卡牌2,更多卡牌效果 -``` - -```markdown -:md-deck[./cards.csv]{grid="5x8" layers="title:1,1-5,1f8 body:1,5-5,8f3"} -``` - -上述卡牌将生成5x8的卡牌牌面排版,其中title层占第1行1-5列,8mm字体。 - -## 开发 +## 快速开始 ```bash # 安装依赖 npm install -# 开发模式 -npm run dev +# 全局安装 CLI +npm link -# 构建 -npm run build - -# 预览 -npm run preview +# 预览内容 +ttrpg serve ./content ``` -## 项目结构 +## 文档导航 -``` -ttrpg-tools/ -├── src/ -│ ├── cli/ # CLI 工具源码 -│ ├── components/ # TTRPG 组件 -│ ├── markdown/ # Markdown 解析器 -│ ├── App.tsx # 主应用组件 -│ ├── main.tsx # 入口文件 -│ └── styles.css # 样式文件 -├── content/ # 示例内容 -├── package.json -├── tsconfig.json -└── rsbuild.config.ts -``` +| 文档 | 说明 | +|------|------| +| [📖 CLI 使用说明](./docs/cli.md) | CLI 安装、命令和用法 | +| [🛠️ 开发指南](./docs/development.md) | 项目结构、开发规范和构建 | +| [📝 Markdown 编写说明](./docs/markdown.md) | Markdown 语法和组件用法 | + +## 功能概览 + +- **CLI 工具**: `serve` 预览模式 和 `compile` 编译模式 +- **Markdown 解析**: 支持指令语法、YAML 标签、mermaid 图表 +- **TTRPG 组件**: 骰子、表格、卡牌、标记、命令追踪器等 + +## 核心组件 + +| 组件 | 语法 | 说明 | +|------|------|------| +| 🎲 骰子 | `:dice[2d6+d8]` | 掷骰并记录结果 | +| 📊 表格 | `:table[./data.csv]` | 标签页式表格 | +| 🃏 卡牌 | `:md-deck[./cards.csv]` | 卡牌布局 | +| 📍 标记 | `:md-pin[A]{x=40 y=40}` | 图片标记 | +| 📋 追踪器 | `:md-commander` | 命令历史和状态追踪 | + +## 技术栈 + +- **前端**: Solid.js 1.9+ +- **构建**: Rsbuild +- **样式**: Tailwind CSS 4 +- **Markdown**: marked + marked-directive +- **测试**: Jest + +## 许可证 + +MIT diff --git a/docs/cli.md b/docs/cli.md new file mode 100644 index 0000000..9b63beb --- /dev/null +++ b/docs/cli.md @@ -0,0 +1,177 @@ +# CLI 使用说明 + +TTRPG Tools 提供一个 CLI 工具,用于将目录内的各种 TTRPG 文档编译为 HTML。 + +## 安装 + +```bash +# 克隆仓库后安装依赖 +npm install + +# 全局链接 CLI 工具 +npm link +``` + +安装完成后,可在任意目录使用 `ttrpg` 命令。 + +## 命令 + +CLI 使用子命令组织: + +### serve - 预览模式 + +运行一个 Web 服务器预览目录中的内容,并实时监听文件更新。 + +```bash +ttrpg serve [dir] -p 3000 +``` + +**参数:** + +| 参数 | 说明 | 默认值 | +|------|------|--------| +| `[dir]` | 要预览的目录 | `.` (当前目录) | + +**选项:** + +| 选项 | 说明 | 默认值 | +|------|------|--------| +| `-p, --port ` | 端口号 | `3000` | + +**功能:** + +- 扫描目录下的所有 `.md`、`.csv`、`.yarn` 文件 +- 为每个文件创建路由 +- 提供实时文件监听,修改后自动刷新 +- 通过 `/__CONTENT_INDEX.json` 提供文件索引 + +**示例:** + +```bash +# 预览当前目录 +ttrpg serve + +# 预览指定目录 +ttrpg serve ./my-ttrpg-content + +# 指定端口 +ttrpg serve ./docs -p 8080 +``` + +### compile - 编译模式 + +将目录中的内容输出为带 hash 路由、单个 HTML 入口的 Web 应用。 + +```bash +ttrpg compile [dir] -o ./dist/output +``` + +**参数:** + +| 参数 | 说明 | 默认值 | +|------|------|--------| +| `[dir]` | 要编译的目录 | `.` (当前目录) | + +**选项:** + +| 选项 | 说明 | 默认值 | +|------|------|--------| +| `-o, --output ` | 输出目录 | `./dist/output` | + +**功能:** + +- 扫描目录下的所有 `.md` 文件 +- 解析 Markdown 并生成路由 +- 打包为带 hash 路由的单个 HTML 入口 +- 复制引用的资源文件(图片、CSV 等) + +**示例:** + +```bash +# 编译当前目录 +ttrpg compile + +# 编译指定目录并输出到指定位置 +ttrpg compile ./content -o ./build + +# 编译并部署 +ttrpg compile ./docs -o ./public && npm run preview +``` + +## 输入文件 + +CLI 会搜索目录下的以下文件: + +- `.md` - Markdown 文档 +- `.csv` - 表格数据 +- `.yarn` - Yarn Spinner 叙事文件 + +### 文件组织建议 + +``` +my-ttrpg-content/ +├── index.md # 首页 +├── rules/ +│ ├── index.md # 规则首页 +│ ├── combat.md # 战斗规则 +│ └── magic.md # 魔法系统 +├── characters/ +│ ├── index.md +│ └── npc-list.csv # NPC 列表 +└── assets/ + ├── images/ # 图片资源 + └── icons/ # 图标资源 +``` + +### 相对路径引用 + +若 Markdown 文件通过相对路径引用了其他文件(如图片、CSV),CLI 会在打包时自动处理这些引用: + +```markdown + +:table[./sparks.csv] + + +![地图](./maps/city-map.png) + + +:deck[../data/cards.csv] +``` + +## 开发服务器特性 + +### 实时索引 + +访问 `http://localhost:3000/__CONTENT_INDEX.json` 可获取当前内容目录的文件索引。 + +### 自动刷新 + +文件变化时,服务器会自动重新加载内容,无需手动刷新页面。 + +### SPA 路由 + +使用 hash 路由支持单页应用导航: + +- `/content/rules/combat.md` → `#/content/rules/combat.md` +- 支持浏览器前进/后退 + +## 常见问题 + +### 端口被占用 + +```bash +# 使用其他端口 +ttrpg serve -p 8080 +``` + +### 编译输出为空 + +检查输入目录是否包含 `.md` 文件: + +```bash +# 查看目录内容 +ls -R ./content + +# 重新编译 +ttrpg compile ./content -o ./dist/output +``` diff --git a/docs/development.md b/docs/development.md new file mode 100644 index 0000000..f9a8302 --- /dev/null +++ b/docs/development.md @@ -0,0 +1,274 @@ +# 开发和项目说明 + +## 快速开始 + +```bash +# 安装依赖 +npm install + +# 开发模式(Web) +npm run dev + +# 构建(Web) +npm run build + +# 预览构建结果 +npm run preview + +# CLI 开发模式 +npm run cli:dev + +# CLI 构建 +npm run cli:build + +# 运行测试 +npm test +``` + +## 项目结构 + +``` +ttrpg-tools/ +├── src/ +│ ├── cli/ # CLI 工具源码 +│ │ ├── commands/ # 命令实现 (serve, compile) +│ │ ├── index.ts # CLI 入口 +│ │ └── types.ts # 类型定义 +│ ├── components/ # TTRPG 组件 +│ │ ├── md-dice.tsx # 骰子组件 +│ │ ├── md-table.tsx # 表格组件 +│ │ ├── md-deck/ # 卡牌组件 +│ │ ├── md-pins.tsx # 标记组件 +│ │ ├── md-commander/ # 命令追踪器 +│ │ ├── md-yarn-spinner.tsx # 叙事线组件 +│ │ ├── md-token.tsx # 代币组件 +│ │ ├── Article.tsx # 文章组件 +│ │ ├── Sidebar.tsx # 侧边栏 +│ │ ├── FileTree.tsx # 文件树 +│ │ └── utils/ # 工具函数 +│ ├── markdown/ # Markdown 解析器 +│ │ ├── index.ts # marked 配置 +│ │ └── mermaid.ts # mermaid 支持 +│ ├── data-loader/ # 数据加载器 +│ ├── plotcutter/ # 剧情切割工具 +│ ├── yarn-spinner/ # 叙事线解析 +│ ├── App.tsx # 主应用 +│ ├── main.tsx # 入口文件 +│ ├── styles.css # 样式 +│ ├── index.html # HTML 模板 +│ └── global.d.ts # 类型声明 +├── bin/ +│ └── cli/ # CLI 二进制文件 +├── content/ # 示例内容 +├── docs/ # 文档 +├── package.json +├── tsconfig.json +├── tsconfig.cli.json +├── rsbuild.config.ts +└── jest.config.js +``` + +## 技术栈 + +| 类别 | 技术 | +|------|------| +| 前端框架 | Solid.js 1.9+ | +| 构建工具 | Rsbuild | +| 样式 | Tailwind CSS 4 + @tailwindcss/typography | +| Markdown | marked + marked-directive + marked-alert + marked-gfm-heading-id | +| 图表 | mermaid | +| 3D | three.js | +| 测试 | Jest | +| CLI | commander + chokidar | + +## 开发规范 + +### Solid.js 最佳实践 + +- **优先使用 `createEffect` 和 `createMemo`** 实现响应式 +- 在 JSX 中直接引用 `props` 保持响应式 +- 避免滥用 `onMount` + `createSignal` + +```tsx +// ✅ 推荐 +const doubled = createMemo(() => count() * 2); +createEffect(() => console.log(count())); + +// ❌ 避免 +onMount(() => { + const [value, setValue] = createSignal(0); +}); +``` + +### 组件开发 + +- **不使用 Shadow DOM**:使用 `noShadowDOM()` +- **继承 Tailwind CSS 样式系统** +- 使用 `customElement` 注册自定义元素 + +```tsx +import { customElement, noShadowDOM } from "solid-element"; + +customElement("md-dice", { key: "" }, (props, { element }) => { + noShadowDOM(); + // 组件逻辑 +}); +``` + +### 类型检查 + +开发完成后检查类型错误: + +```bash +npx tsc --noEmit +``` + +### 代码风格 + +- 使用 TypeScript 严格模式 +- 遵循 ESLint 配置(如有) +- 使用 2 空格缩进 + +## 添加新组件 + +### 1. 创建组件文件 + +```tsx +// src/components/md-new-component.tsx +import { customElement, noShadowDOM } from "solid-element"; +import { createSignal } from "solid-js"; + +export interface NewComponentProps { + prop1?: string; +} + +customElement("md-new-component", { prop1: "" }, (props, { element }) => { + noShadowDOM(); + + const [state, setState] = createSignal(""); + + return ( +
+ {/* 组件内容 */} +
+ ); +}); +``` + +### 2. 注册组件 + +```tsx +// src/components/index.ts +import './md-new-component'; +``` + +### 3. 导出类型(可选) + +```tsx +// src/components/index.ts +export type { NewComponentProps } from './md-new-component'; +``` + +## 构建配置 + +### Rsbuild 配置 + +```ts +// rsbuild.config.ts +import { defineConfig } from '@rsbuild/core'; +import { pluginBabel } from '@rsbuild/plugin-babel'; +import { pluginSolid } from '@rsbuild/plugin-solid'; +import tailwindcss from '@tailwindcss/postcss'; + +export default defineConfig({ + plugins: [pluginBabel(), pluginSolid()], + tools: { + postcss: { + postcssOptions: { + plugins: [tailwindcss()], + }, + }, + }, + html: { + template: './src/index.html', + }, +}); +``` + +### TypeScript 配置 + +- `tsconfig.json` - 主项目配置(Web) +- `tsconfig.cli.json` - CLI 工具配置(Node.js) + +## 测试 + +```bash +# 运行所有测试 +npm test + +# 运行特定测试文件 +npm test -- src/components/md-dice.test.ts + +# 监听模式 +npm test -- --watch +``` + +## 调试 + +### Web 开发 + +```bash +npm run dev +# 访问 http://localhost:3000 +``` + +### CLI 调试 + +```bash +# 使用 ts-node 直接运行 +npm run ttrpg serve ./content + +# 或构建后运行 +npm run cli:build +node dist/cli/index.js serve ./content +``` + +## 发布流程 + +1. 更新版本号 +2. 运行测试和类型检查 +3. 构建 Web 和 CLI +4. 发布到 npm + +```bash +npm run build +npm run cli:build +npm test +npx tsc --noEmit +npm publish +``` + +## 常见问题 + +### Windows 换行符 + +开发环境主要在 Windows 上,注意使用 CRLF 换行符。 + +### 依赖安装失败 + +```bash +# 清理缓存 +npm cache clean --force +rm -rf node_modules package-lock.json +npm install +``` + +### 构建错误 + +```bash +# 检查类型 +npx tsc --noEmit + +# 重新构建 +npm run build +``` diff --git a/docs/markdown.md b/docs/markdown.md new file mode 100644 index 0000000..d1844b6 --- /dev/null +++ b/docs/markdown.md @@ -0,0 +1,461 @@ +# Markdown 编写说明 + +本文档介绍 TTRPG Tools 支持的 Markdown 扩展语法和组件用法。 + +## 基础语法 + +使用标准 Markdown 语法,支持以下扩展: + +- [GFM](https://github.github.com/gfm/) - GitHub Flavored Markdown +- [marked-alert](https://github.com/Insidify/marked-alert) - 警告/提示块 +- [marked-gfm-heading-id](https://github.com/markedjs/marked-gfm-heading-id) - 标题 ID +- [marked-directive](https://github.com/fengzilong/marked-directive) - 指令语法 + +## 指令语法 + +通过 `marked-directive` 支持自定义组件插入: + +```markdown +:component-name[content]{key="value" another="test"} +``` + +### 语法说明 + +| 部分 | 说明 | 示例 | +|------|------|------| +| `:name` | 组件名称 | `:dice` | +| `[content]` | 内容参数 | `[2d6+d8]` | +| `{attrs}` | 属性对象 | `{key="attack"}` | + +### 嵌套指令 + +```markdown +::: container +这里是容器内容 +:dice[1d20] +::: +``` + +## 图标语法 + +使用简单的 `:icon-name` 语法插入图标: + +```markdown +:attack :defense :potion :sword +``` + +图标会渲染为 `` 形式。 + +### 配置图标前缀 + +可通过 `iconPath` 属性指定图标目录: + +```markdown +
+``` + +或使用空字符串禁用图标前缀: + +```markdown +
+``` + +## 组件库 + +### 🎲 骰子组件 (md-dice) + +```markdown +:dice[2d6+d8] +:dice[1d20+5]{key="attack"} +``` + +**功能:** +- 点击骰子图标执行掷骰 +- 点击文本重置为公式 +- `key` 属性将结果记录到 URL 参数中 (`?dice-attack=15`) + +**属性:** + +| 属性 | 类型 | 说明 | +|------|------|------| +| `key` | string | 用于 URL 参数记录的标识 | + +**示例:** + +```markdown +攻击检定 :dice[1d20+5]{key="attack"} +伤害掷骰 :dice[2d6+3]{key="damage"} +``` + +### 🔗 链接组件 (md-link) + +```markdown +:link[./other-page.md] +:link[./rules.md#combat-section] +``` + +**功能:** +- 点击链接在当前页面内展开显示目标文章内容 +- 支持 `#section` 语法显示特定章节 +- 支持相对路径引用 + +**属性:** + +| 属性 | 类型 | 说明 | +|------|------|------| +| (无) | - | 内容即为链接目标路径 | + +**示例:** + +```markdown +查看完整规则 :link[./rules.md] + +查看战斗章节 :link[./rules.md#combat] +``` + +### 🖼️ 背景组件 (md-bg) + +```markdown +:bg[./images/background.jpg] +:bg[./images/pattern.png]{fit="contain"} +``` + +**功能:** +- 将图片设置为当前文章卡片的背景 +- 自动覆盖整个卡片区域 + +**属性:** + +| 属性 | 类型 | 默认值 | 说明 | +|------|------|--------|------| +| `fit` | `cover` \| `contain` \| `fill` \| `none` \| `scale-down` | `cover` | 背景适配方式 | + +**示例:** + +```markdown +:bg[./images/dungeon-bg.jpg]{fit="cover"} + +# 地牢探险 + +这里是地牢的描述内容... +``` + +### 🪙 代币组件 (md-token) + +```markdown +:md-token[./token-image.png] +:md-token[./hero.png]{size=60 defaultThickness=2.5} +``` + +**功能:** +- 将 2D 图片转换为 3D 打印模型 +- 自动进行图像矢量追踪分层 +- 支持预览和导出 STL 文件 + +**属性:** + +| 属性 | 类型 | 默认值 | 说明 | +|------|------|--------|------| +| `size` | number | `50` | 模型整体尺寸 (mm) | +| `defaultThickness` | number | `2` | 默认图层厚度 (mm) | + +**使用流程:** + +1. 引用图片(PNG/JPG 等) +2. 等待矢量追踪完成 +3. 在设置面板调整图层厚度 +4. 点击「生成 3D 模型」 +5. 预览并下载 STL 文件 + +**示例:** + +```markdown + +:md-token[./images/warrior-token.png] + + +:md-token[./images/dragon.png]{size=75 defaultThickness=3} +``` + +### 🧶 叙事线组件 (md-yarn-spinner) + +```markdown +:md-yarn-spinner[./story.yarn]{start="start"} +``` + +**功能:** +- 运行 Yarn Spinner 叙事脚本 +- 显示对话历史和选项 +- 支持命令和变量替换 + +**属性:** + +| 属性 | 类型 | 默认值 | 说明 | +|------|------|--------|------| +| `start` | string | `start` | 起始节点名称 | + +**Yarn 文件格式:** + +```yarn +title: start +tags: +colorID: 0 +position: 0,0 +--- +NPC: 欢迎来到村庄! +玩家:谢谢![[继续]] +=== + +title: 继续 +tags: +colorID: 0 +position: 200,0 +--- +NPC: 有什么我可以帮你的吗? +-> 询问任务 + 最近有什么危险的任务吗? +-> 离开 + 再见! + [[结束]] +=== +``` + +**示例:** + +```markdown +:md-yarn-spinner[./dialogues/village-elder.yarn] + +:md-yarn-spinner[./quest-branch.yarn]{start="intro"} +``` + +### 📋 命令追踪器 (md-commander) + +```markdown +:md-commander +:md-commander[./commands.csv]{placeholder="输入命令..."} +``` + +**功能:** +- 命令历史视图 +- 追踪器视图(角色状态、进度等) +- 支持 Emmet 简写语法 +- 命令自动补全 + +**属性:** + +| 属性 | 类型 | 默认值 | 说明 | +|------|------|--------|------| +| `placeholder` | string | - | 输入框占位符 | +| `class` | string | - | 额外 CSS 类 | +| `height` | string | `400px` | 组件高度 | +| `commandTemplates` | string | - | CSV 模板文件路径 | + +**追踪器命令语法:** + +``` +track npc#john.dwarf.warrior[hp=4/4 ac=15 name="John"] +``` + +**Emmet 简写语法:** + +- `#id` - 设置 ID +- `.class` - 添加类别 +- `[attr=value]` - 设置属性 + +**属性类型:** + +| 类型 | 格式 | 显示 | +|------|------|------| +| `progress` | `x/y` | 进度条 (如 `hp=4/4`) | +| `count` | 整数 | 数字计数器 (如 `ac=15`) | +| `string` | 文本 | 文本字段 (如 `name="John"`) | + +**内置命令:** + +| 命令 | 说明 | +|------|------| +| `track` | 添加追踪项 | +| `remove` | 移除追踪项 | +| `update` | 更新属性 | +| `clear` | 清空追踪 | + +**示例:** + +```markdown + +:md-commander + + +:md-commander{placeholder="输入 /help 查看命令"} + + +:md-commander[./my-commands.csv] + + +track enemy#goblin.soldier[hp=7/7 ac=12] +track ally#cleric[hp=24/24 spells=4/4] +``` + +### 📁 文件树 (FileTree) + +文件树组件自动在侧边栏显示,无需手动插入。 + +**功能:** +- 自动扫描内容目录 +- 显示文件层级结构 +- 支持文件夹展开/收起 +- 显示当前文件的标题导航 + +**目录结构示例:** + +``` +content/ +├── index.md # 首页 +├── rules/ +│ ├── index.md # 规则首页 +│ ├── combat.md # 战斗规则 +│ └── magic.md # 魔法系统 +└── characters/ + └── npc-list.md # NPC 列表 +``` + +侧边栏会自动显示: +- 📁 rules/ + - 📄 combat.md + - 📄 magic.md + +## YAML 标签 + +使用 ```yaml/tag 代码块创建自定义标签: + +````markdown +```yaml/tag +tag: tag-name +class: custom-class +id: my-id +body: 标签内容 +``` +```` + +渲染为: + +```html +标签内容 +``` + +## Mermaid 图表 + +支持 mermaid 流程图: + +````markdown +```mermaid +graph TD + A[开始] --> B{选择} + B -->|选项 1| C[结果 1] + B -->|选项 2| D[结果 2] +``` +```` + +支持的图表类型: + +- flowchart - 流程图 +- sequenceDiagram - 时序图 +- classDiagram - 类图 +- stateDiagram - 状态图 +- erDiagram - ER 图 +- pie - 饼图 + +## 警告/提示块 + +```markdown +> [!NOTE] +> 这是一条备注 + +> [!TIP] +> 这是一条提示 + +> [!IMPORTANT] +> 这是重要信息 + +> [!WARNING] +> 这是警告信息 + +> [!CAUTION] +> 这是危险警告 +``` + +## 文件引用 + +### 相对路径 + +```markdown + +:table[./data.csv] + + +:deck[./cards/deck.csv] + + +:table[../shared/npcs.csv] + + +![地图](./images/map.png) +``` + +### 路径解析规则 + +- 所有路径相对于当前 Markdown 文件 +- 支持 `.` 和 `..` 导航 +- 自动处理 URL 编码 + +## 样式定制 + +### 使用 Tailwind 类 + +组件支持 Tailwind CSS 类: + +```markdown +:dice[1d20]{class="text-red-500"} +``` + +### 自定义 CSS + +```css +/* 在 styles.css 中添加 */ +.md-dice { + @apply text-blue-600 hover:text-blue-800; +} +``` + +## 最佳实践 + +### 内容组织 + +```markdown +# 章节标题 + +这里是章节内容。 + +## 子章节 + +### 规则说明 + +:dice[2d6] 掷骰决定结果。 + +:table[./options.csv]{roll=true} + +> [!TIP] +> 这是一个有用的提示。 +``` + +### 性能优化 + +- 大型 CSV 文件使用 `group` 列分组 +- 图片使用适当分辨率 +- 避免过多嵌套组件 + +### 可访问性 + +- 为图片添加 `alt` 文本 +- 使用语义化标题层级 +- 确保颜色对比度