文档索引

故事模块

概述

故事模块是一个基于文件系统的内容管理模块,支持 Markdown 小说 和 Cattca 互动小说 两种格式,合集可以无限嵌套。

文件结构

所有内容存放在 instance/stories/ 下:

instance/stories/
  info.json                   ← 根合集元数据(可选)
  
  互动小说/                   ← 子合集
    info.json                 ← 合集元数据
    防御.cattca               ← Cattca 互动小说
    逃出房间.cattca
    
  小说集/                     ← 子合集
    info.json
    北斗赋.md                 ← Markdown 小说
    厘米世界记.md
    
  子合集/                     ← 可以继续嵌套
    info.json
    孙合集/                   ← 更深一层
      info.json
      某个故事.md

合集 (Collection)

合集就是 instance/stories/ 下的目录。每个合集可以包含:

  • .md 文件 — Markdown 故事
  • .cattca 文件 — Cattca 互动小说
  • 子目录 — 嵌套的合集

合集根目录下的 info.json 是可选的,格式:

{
  "title": "合集名称",
  "description": "简介",
  "author": "默认作者",
  "priority": 100,
  "ignore": false
}
字段 类型 默认值 说明
title string 目录名 合集显示名称
description string "" 合集简介
author string "未知作者" 默认作者(子故事未指定时使用)
priority int 0 排序优先级,越大越靠前
ignore bool false 设为 true 隐藏此合集

故事 (Story)

故事是单个文件,支持两种格式。元数据统一使用 YAML frontmatter(--- 包裹的 YAML 头):

---
title: 故事标题
author: 作者名
genre: 小说
ai_assisted: false
description: 一句话简介
priority: 100
ignore: false
---
(正文内容)
字段 类型 默认值 说明
title string 文件名 故事标题
author string 合集作者 作者
genre string "" 类型标签,不设则不显示
ai_assisted bool 继承合集 设为 true 显示「AI辅助创作」标记;不写则继承所属合集的 ai_assisted(合集也没写才是 false)
description string "" 简介
priority int 0 排序优先级
ignore bool false 设为 true 隐藏此故事

Markdown 故事(.md)

标准 Markdown 文件,文件开头使用 YAML frontmatter。正文由服务端渲染 (src/lib/story-service.ts 的 marked + stripScripts),支持 GFM 表格、任务列表等。

⚠️ 与博客正文不同,故事正文不走 DOMPurify、也没有 highlight.js:故事文件由站长 直接写在 instance/stories/ 下,按可信内容处理(详见 docs/architecture.md §6.7)。

排版规则

段落缩进:正文段落首行自动缩进两字符(text-indent: 2em)。以下情况不会缩进:

  • 引用块内的段落 — 自动取消缩进
  • 手动标记 — 在段落上添加 class="u-no-indent" 可取消缩进:
> 这是引用块,里面的段落不会缩进。

<p class="u-no-indent">这一段也不会缩进。适合题记后的首段、独立引言等场景。</p>

这里恢复正常缩进。

链接:正文中的链接显示为品牌色,hover 时出现下划线。

博客正文会自动给外链加 target="_blank" rel="noopener noreferrer nofollow",故事页不会 —— 故事走的是服务端 marked,没有这层后处理。需要新窗口打开的链接请在正文里自己写 HTML。

代码块:无复制按钮,也没有语法高亮 —— 那两项是博客渲染器(MarkdownRenderer.tsx) 的能力,故事页不走它。

Cattca 互动小说(.cattca)

单文件格式。文件顶部是 YAML frontmatter,之后是 Cattca 脚本。Cattca 是一种自定义的互动小说脚本语言,在浏览器端由 cattca.js 解释执行。

排序规则

合集内的所有项目(故事 + 子合集)按以下规则排序:

  1. priority 从大到小
  2. 有 description 的排在无 description 的前面

URL 结构

URL 行为
/story/ 根合集页
/story/<合集路径>/ 合集页,列出内容和子合集
/story/<合集路径>/<故事id> 故事阅读/播放页

路由解析逻辑:路径若映射到存在的目录 → 合集页;否则 → 故事页。

合集嵌套示例

假设文件结构:

instance/stories/
  info.json            {"title": "故事中心"}
  短篇/
    info.json          {"title": "短篇小说"}
    雨夜.md
  长篇/
    info.json          {"title": "长篇小说"}
    科幻/
      info.json        {"title": "科幻长篇"}
      星际迷航.md

生成的 URL:

  • /story/ — "故事中心"合集页,展示"短篇"和"长篇"两个子合集
  • /story/短篇/ — "短篇小说"合集页,展示"雨夜"
  • /story/长篇/ — "长篇小说"合集页,展示"科幻"子合集
  • /story/长篇/科幻/ — "科幻长篇"合集页,展示"星际迷航"
  • /story/长篇/科幻/星际迷航 — 故事阅读页

添加新内容

添加故事: 在目标合集目录下放入 .md 或 .cattca 文件,带上 YAML frontmatter。

添加子合集: 创建新目录,放入 info.json(可选),再放入故事文件。

Cattca 脚本简要说明

Cattca 使用 </.../> 作为控制分隔符。变量用 </let> / </set> 声明,流程用 </goto> / </if> / </label> 控制,交互用 </input text> / </input case> 获取用户输入。

详见 public/static/js/cattca.js 中的 CattcaInterpreter 类。

本页内容来自仓库 docs/guide/story-module.md·在 GitHub 上查看