|
@@ -1,38 +1,141 @@
|
|
|
-import { Book } from "@/types/book";
|
|
|
|
|
|
|
+import { Book, BookEntry, BookEntryKind, BookSection } from "@/types/book";
|
|
|
|
|
+
|
|
|
|
|
+function makeEntries(sectionId: string, kind: BookEntryKind, titles: string[][]): BookEntry[] {
|
|
|
|
|
+ return titles.map(([title, ...content], index) => ({
|
|
|
|
|
+ id: `${sectionId}-${index + 1}`,
|
|
|
|
|
+ title,
|
|
|
|
|
+ kind,
|
|
|
|
|
+ order: index + 1,
|
|
|
|
|
+ content
|
|
|
|
|
+ }));
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function makeSection(
|
|
|
|
|
+ id: string,
|
|
|
|
|
+ title: string,
|
|
|
|
|
+ kind: BookEntryKind,
|
|
|
|
|
+ order: number,
|
|
|
|
|
+ titles: string[][]
|
|
|
|
|
+): BookSection {
|
|
|
|
|
+ return {
|
|
|
|
|
+ id,
|
|
|
|
|
+ title,
|
|
|
|
|
+ kind,
|
|
|
|
|
+ order,
|
|
|
|
|
+ entries: makeEntries(id, kind, titles)
|
|
|
|
|
+ };
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
export const demoBooks: Book[] = [
|
|
export const demoBooks: Book[] = [
|
|
|
{
|
|
{
|
|
|
|
|
+ id: "memory-catcher",
|
|
|
|
|
+ title: "记忆捕手",
|
|
|
|
|
+ author: "墨尘",
|
|
|
|
|
+ category: "悬疑",
|
|
|
|
|
+ description:
|
|
|
|
|
+ "一间只在深夜营业的记忆事务所,一群替人打捞记忆碎片的人,以及越来越像真实案件的委托记录。",
|
|
|
|
|
+ wordCount: "约 6 万字(演示)",
|
|
|
|
|
+ coverStyle: "linear-gradient(135deg, #7089a8, #2e405a)",
|
|
|
|
|
+ sections: [
|
|
|
|
|
+ makeSection("mc-lore-world", "世界观设定", "lore", 1, [
|
|
|
|
|
+ [
|
|
|
|
|
+ "资料一 事务所规则",
|
|
|
|
|
+ "记忆事务所只在每天凌晨零点到五点营业,所有委托都需要经过双重验证,且不得跨越自然死亡边界回收记忆。",
|
|
|
|
|
+ "每次进入记忆深层前,执行者必须留下现实锚点,否则在高损耗片段中极易失去自我定位。"
|
|
|
|
|
+ ],
|
|
|
|
|
+ [
|
|
|
|
|
+ "资料二 回收协议",
|
|
|
|
|
+ "记忆回收分为取样、修复、归还三个阶段,资料类委托和正文类案件都必须标记来源与完整度。",
|
|
|
|
|
+ "当完整度低于百分之三十时,系统会自动建议多人协同解析。"
|
|
|
|
|
+ ]
|
|
|
|
|
+ ]),
|
|
|
|
|
+ makeSection("mc-lore-roles", "人物档案", "lore", 2, [
|
|
|
|
|
+ [
|
|
|
|
|
+ "资料三 林夜",
|
|
|
|
|
+ "林夜是事务所的主检索员,擅长在受损记忆中建立临时路径。",
|
|
|
|
|
+ "他最大的弱点是不擅长拒绝任何一份“看起来还能救回来”的委托。"
|
|
|
|
|
+ ],
|
|
|
|
|
+ [
|
|
|
|
|
+ "资料四 深洲事务所",
|
|
|
|
|
+ "事务所位于深洲旧城区地下一层,常年由蓝色工作灯照明,主工作台正对一面由十五块屏幕拼成的监控墙。",
|
|
|
|
|
+ "多数外来委托都会先被收录为资料条目,再决定是否转入正式案件。"
|
|
|
|
|
+ ]
|
|
|
|
|
+ ]),
|
|
|
|
|
+ makeSection("mc-novel-volume-1", "正文 第一卷", "novel", 100, [
|
|
|
|
|
+ [
|
|
|
|
|
+ "第一章 数据废墟",
|
|
|
|
|
+ "深洲事务所的地下工作室被蓝色光芒覆盖,十五块屏幕全部亮起,数据流在每一个像素中涌动。",
|
|
|
|
|
+ "林夜坐在工作台中央,接口头环已经戴好,眼前是一份来自匿名客户的委托:在七十二小时内找回一段被人为删除的童年记忆。",
|
|
|
|
|
+ "这类工作本该只是技术活,可委托附件里多出了一段视频。视频结尾,有一只沾着雨水的手按住镜头,像是隔着时间朝他们打招呼。"
|
|
|
|
|
+ ],
|
|
|
|
|
+ [
|
|
|
|
|
+ "第二章 深网潜入",
|
|
|
|
|
+ "林夜坐在工作台中央,接口头环已经戴好,双手悬停在键盘上方,等待深网桥接程序完成最后一次校验。",
|
|
|
|
|
+ "任务目标是一段被藏进深层节点的私人记忆。它没有文件名,也没有索引,像一枚被扔进黑潮里的钉子,只能靠微弱的访问残响定位。",
|
|
|
|
|
+ "副屏上,系统给出了三条不太乐观的提示:来源匿名、时间戳错乱、回收通道不稳定。"
|
|
|
|
|
+ ],
|
|
|
|
|
+ [
|
|
|
|
|
+ "第三章 雨巷回声",
|
|
|
|
|
+ "连接建立后,第一段回收到的不是画面,而是一阵潮湿的雨声。",
|
|
|
|
|
+ "雨点顺着一条老旧的石板巷子落下,远处有人撑着黑伞停在路灯下,像在等谁,又像已经等了很久。",
|
|
|
|
|
+ "系统记录显示,这段记忆在过去七年里被人为删除过四次,但每次都会在不同的深夜重新出现。"
|
|
|
|
|
+ ],
|
|
|
|
|
+ [
|
|
|
|
|
+ "第四章 失真坐标",
|
|
|
|
|
+ "他们终于在失真层里找到了坐标,却发现坐标指向的是一座早已拆除的旧车站。",
|
|
|
|
|
+ "记忆里的广播还在播报过期的列车时刻,玻璃穹顶上方积着雨,候车厅里坐满了看不清脸的人。"
|
|
|
|
|
+ ],
|
|
|
|
|
+ [
|
|
|
|
|
+ "第五章 双重委托",
|
|
|
|
|
+ "清晨六点,他们刚从深层断开,门铃便响了。",
|
|
|
|
|
+ "来的人戴着深灰色帽子,把同样一份委托重新放在桌上,连措辞都和昨晚的一字不差,只在签名处多了一个新的名字。"
|
|
|
|
|
+ ],
|
|
|
|
|
+ [
|
|
|
|
|
+ "第六章 无名乘客",
|
|
|
|
|
+ "第二次进入时,他们看见候车厅角落多了一个孩子。",
|
|
|
|
|
+ "孩子穿着被雨打湿的校服,手里攥着半张车票,车票背面写着一行几乎被水泡开的字:不要相信站台上的广播。"
|
|
|
|
|
+ ],
|
|
|
|
|
+ [
|
|
|
|
|
+ "第七章 镜像证词",
|
|
|
|
|
+ "为了验证委托来源,他们调出了另一位委托人的证词记录。",
|
|
|
|
|
+ "两份证词在前半段完全一致,只在最后三分钟出现了分叉。"
|
|
|
|
|
+ ],
|
|
|
|
|
+ [
|
|
|
|
|
+ "第八章 灯箱之后",
|
|
|
|
|
+ "林夜在站台广告灯箱后找到了一扇隐藏维护门。",
|
|
|
|
|
+ "门后不是管道井,而是一间布满旧磁带和纸质档案的小房间。"
|
|
|
|
|
+ ],
|
|
|
|
|
+ [
|
|
|
|
|
+ "第九章 回收协议",
|
|
|
|
|
+ "事务所服务器在当晚收到一份未签名的回收协议。",
|
|
|
|
|
+ "协议条款极短,只要求他们在二十四小时内交出目标记忆的完整副本。"
|
|
|
|
|
+ ],
|
|
|
|
|
+ [
|
|
|
|
|
+ "第十章 七号出口",
|
|
|
|
|
+ "他们决定在现实中去找那座被封闭的七号出口。",
|
|
|
|
|
+ "清晨的围挡后满是积水和灰尘,可在围挡缝隙后,林夜看见了一盏仍旧亮着的引导灯。"
|
|
|
|
|
+ ]
|
|
|
|
|
+ ])
|
|
|
|
|
+ ]
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
id: "lan-archive",
|
|
id: "lan-archive",
|
|
|
title: "局域网夜航",
|
|
title: "局域网夜航",
|
|
|
author: "程未远",
|
|
author: "程未远",
|
|
|
category: "近未来",
|
|
category: "近未来",
|
|
|
- description:
|
|
|
|
|
- "一座封闭园区、几台常亮的旧电脑,以及深夜里不断跳出的陌生消息。故事从一个内部聊天室开始,也从那里逐渐偏离日常。",
|
|
|
|
|
|
|
+ description: "一座封闭园区、几台常亮的旧电脑,以及深夜里不断跳出的陌生消息。",
|
|
|
wordCount: "12.8 万字",
|
|
wordCount: "12.8 万字",
|
|
|
coverStyle: "linear-gradient(135deg, #b86143, #5c2d23)",
|
|
coverStyle: "linear-gradient(135deg, #b86143, #5c2d23)",
|
|
|
- chapters: [
|
|
|
|
|
- {
|
|
|
|
|
- id: "chapter-1",
|
|
|
|
|
- title: "第一章 机房尽头的灯",
|
|
|
|
|
- content: [
|
|
|
|
|
- "凌晨两点十三分,园区办公楼里只剩下二层最靠里的机房还亮着灯。陈泊把最后一台旧主机的风扇罩扣回去,抬头时,玻璃门上映出他略显疲惫的脸。",
|
|
|
|
|
- "楼道里很安静,安静得能听见交换机持续不断的细密电流声。那声音像潮水一样贴着墙面蔓延,穿过半开的门缝,也穿过他刚刚搭起来的局域网聊天页。",
|
|
|
|
|
- "页面很简单,甚至称得上粗糙。左边是在线设备,右边是聊天消息,底部一个输入框,可以发文字,也可以拖图片和文件进去。原本它只是为了方便他在几台电脑之间互传资料。",
|
|
|
|
|
- "可就在他准备关机的时候,聊天室里跳出了一条新消息。发送者是一台他从未见过的设备,名字显示为“Unknown-Edge-1.27-H3M2”。",
|
|
|
|
|
- "那条消息只有八个字:你终于把门打开了。",
|
|
|
|
|
- "陈泊盯着屏幕,手指停在键盘上方,迟迟没有落下。他确认过,这个局域网没有接外网,也没有其他人知道访问地址。可消息提示音仍旧在房间里轻轻回荡,像是谁站在走廊深处,耐心地敲了第二次门。"
|
|
|
|
|
- ]
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: "chapter-2",
|
|
|
|
|
- title: "第二章 没有登记的设备",
|
|
|
|
|
- content: [
|
|
|
|
|
- "他先检查 DHCP 记录,又翻了交换机最近一小时的地址分配表,结果一片空白。那台设备没有登记,没有接入记录,也没有任何真实存在的迹象。",
|
|
|
|
|
- "可聊天页里的头像气泡还停在那里,像一粒不合时宜的灰尘。陈泊尝试发出一句“你是谁”,对方却在三秒后回了一张图片。",
|
|
|
|
|
- "图片内容是这间机房。准确地说,是五分钟前的机房。画面里他正背对镜头,弯腰整理电源线,而取景角度来自房间最深处、那排早就废弃的机柜之间。",
|
|
|
|
|
- "他猛地转身,那里只有黑暗,和一排没有通电的指示灯。"
|
|
|
|
|
- ]
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ sections: [
|
|
|
|
|
+ makeSection("lan-lore", "设定资料", "lore", 1, [
|
|
|
|
|
+ ["资料一 园区网络", "园区网络与公网完全隔离,所有访问记录由本地交换系统统一收敛。"],
|
|
|
|
|
+ ["资料二 旧机房", "二层最靠里的旧机房仍保留着上一代局域网控制台与部分废弃机柜。"]
|
|
|
|
|
+ ]),
|
|
|
|
|
+ makeSection("lan-novel", "正文", "novel", 100, [
|
|
|
|
|
+ ["第一章 机房尽头的灯", "凌晨两点十三分,园区办公楼里只剩下二层最靠里的机房还亮着灯。"],
|
|
|
|
|
+ ["第二章 没有登记的设备", "他先检查 DHCP 记录,又翻了交换机最近一小时的地址分配表,结果一片空白。"],
|
|
|
|
|
+ ["第三章 反向截图", "对方没有回答,只发来一张刚刚拍下的机房照片。"]
|
|
|
|
|
+ ])
|
|
|
]
|
|
]
|
|
|
},
|
|
},
|
|
|
{
|
|
{
|
|
@@ -40,20 +143,16 @@ export const demoBooks: Book[] = [
|
|
|
title: "旧书铺茶事",
|
|
title: "旧书铺茶事",
|
|
|
author: "沈南絮",
|
|
author: "沈南絮",
|
|
|
category: "日常",
|
|
category: "日常",
|
|
|
- description:
|
|
|
|
|
- "一间开在老街口的旧书铺,白天卖书,傍晚煮茶。每位进门的客人都带来一本书的故事,也带走一点安静。",
|
|
|
|
|
|
|
+ description: "一间开在老街口的旧书铺,白天卖书,傍晚煮茶。",
|
|
|
wordCount: "8.4 万字",
|
|
wordCount: "8.4 万字",
|
|
|
coverStyle: "linear-gradient(135deg, #8f6a3d, #314438)",
|
|
coverStyle: "linear-gradient(135deg, #8f6a3d, #314438)",
|
|
|
- chapters: [
|
|
|
|
|
- {
|
|
|
|
|
- id: "chapter-1",
|
|
|
|
|
- title: "第一章 雨落在旧街口",
|
|
|
|
|
- content: [
|
|
|
|
|
- "傍晚五点,雨刚刚落下来,青石板路被洗得发亮。书铺门口挂着一盏老式铜灯,灯光穿过潮润的空气,把门前那块“今日新到旧书”的小黑板照得有些发暖。",
|
|
|
|
|
- "许青辞把最后一箱旧书搬进门,抬手拂去肩上的水珠。门口风铃轻轻一响,有位撑着深蓝长伞的姑娘走了进来,鞋尖落在木地板上,带来一点很轻的湿意。",
|
|
|
|
|
- "她没有立刻说话,只在靠窗的架子前停住,像在辨认一本已经很久没见过的旧书。"
|
|
|
|
|
- ]
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ sections: [
|
|
|
|
|
+ makeSection("tea-lore", "店铺札记", "lore", 1, [
|
|
|
|
|
+ ["资料一 书铺门铃", "门铃是一枚老铜铃,雨天响起来比晴天更轻一些。"]
|
|
|
|
|
+ ]),
|
|
|
|
|
+ makeSection("tea-novel", "正文", "novel", 100, [
|
|
|
|
|
+ ["第一章 雨落在旧街口", "傍晚五点,雨刚刚落下来,青石板路被洗得发亮。"]
|
|
|
|
|
+ ])
|
|
|
]
|
|
]
|
|
|
},
|
|
},
|
|
|
{
|
|
{
|
|
@@ -61,41 +160,33 @@ export const demoBooks: Book[] = [
|
|
|
title: "星港来信",
|
|
title: "星港来信",
|
|
|
author: "林观海",
|
|
author: "林观海",
|
|
|
category: "科幻",
|
|
category: "科幻",
|
|
|
- description:
|
|
|
|
|
- "远航舰队返程之前,地球收到一封延迟了十九年的星际邮件。它改变了一个港口城市,也改变了一群等待的人。",
|
|
|
|
|
|
|
+ description: "远航舰队返程之前,地球收到一封延迟了十九年的星际邮件。",
|
|
|
wordCount: "15.1 万字",
|
|
wordCount: "15.1 万字",
|
|
|
coverStyle: "linear-gradient(135deg, #355c7d, #121c2e)",
|
|
coverStyle: "linear-gradient(135deg, #355c7d, #121c2e)",
|
|
|
- chapters: [
|
|
|
|
|
- {
|
|
|
|
|
- id: "chapter-1",
|
|
|
|
|
- title: "第一章 邮件抵达前夜",
|
|
|
|
|
- content: [
|
|
|
|
|
- "海港城的夜总是比内陆亮一些。悬在码头上方的轨道灯像一排静止的流星,把泊位、塔吊和远处沉默的深空接收站一起照成银白色。",
|
|
|
|
|
- "路昭从监测塔的楼梯上走下来时,终端忽然震了一下。屏幕上只有一句系统提示:深空民用信道存在待解包数据,请立即确认。",
|
|
|
|
|
- "他看着那行字,脚步不由自主地慢了半拍。因为那条信道已经沉寂了十九年,久到所有人都默认它再也不会亮起。"
|
|
|
|
|
- ]
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ sections: [
|
|
|
|
|
+ makeSection("star-lore", "星港档案", "lore", 1, [
|
|
|
|
|
+ ["资料一 深空信道", "民用深空信道十九年未曾亮起,因此被默认彻底沉寂。"]
|
|
|
|
|
+ ]),
|
|
|
|
|
+ makeSection("star-novel", "正文", "novel", 100, [
|
|
|
|
|
+ ["第一章 邮件抵达前夜", "海港城的夜总是比内陆亮一些。"]
|
|
|
|
|
+ ])
|
|
|
]
|
|
]
|
|
|
},
|
|
},
|
|
|
{
|
|
{
|
|
|
id: "north-city",
|
|
id: "north-city",
|
|
|
- title: "北城旧事录",
|
|
|
|
|
|
|
+ title: "北城旧事簿",
|
|
|
author: "顾行舟",
|
|
author: "顾行舟",
|
|
|
category: "都市",
|
|
category: "都市",
|
|
|
- description:
|
|
|
|
|
- "一座旧城的黄昏、几条重复经过的街道、以及那些看似平常却慢慢累积出重量的日子。",
|
|
|
|
|
|
|
+ description: "一座旧城的黄昏、几条重复经过的街道,以及那些看似平常却慢慢累积出重量的日子。",
|
|
|
wordCount: "10.2 万字",
|
|
wordCount: "10.2 万字",
|
|
|
coverStyle: "linear-gradient(135deg, #7c5a43, #28384f)",
|
|
coverStyle: "linear-gradient(135deg, #7c5a43, #28384f)",
|
|
|
- chapters: [
|
|
|
|
|
- {
|
|
|
|
|
- id: "chapter-1",
|
|
|
|
|
- title: "第一章 天桥下的晚风",
|
|
|
|
|
- content: [
|
|
|
|
|
- "晚高峰刚过,天桥下的人群还没散完。霓虹广告在灰蓝色的天幕里逐渐亮起来,把路口照得像刚从雨里捞出来一样湿润。",
|
|
|
|
|
- "周临川站在报刊亭旁边,手里拿着一杯已经不热的豆浆,抬头看见远处那座旧商场外墙上的灯牌又坏了一角。",
|
|
|
|
|
- "北城从来不擅长把一切都修得整整齐齐,可也正因如此,很多细小的故事才有了藏身的缝隙。"
|
|
|
|
|
- ]
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ sections: [
|
|
|
|
|
+ makeSection("north-lore", "旧城资料", "lore", 1, [
|
|
|
|
|
+ ["资料一 北城地标", "天桥、报刊亭和旧商场灯牌,是北城许多故事共同的入口。"]
|
|
|
|
|
+ ]),
|
|
|
|
|
+ makeSection("north-novel", "正文", "novel", 100, [
|
|
|
|
|
+ ["第一章 天桥下的晚风", "晚高峰刚过,天桥下的人群还没散完。"]
|
|
|
|
|
+ ])
|
|
|
]
|
|
]
|
|
|
}
|
|
}
|
|
|
];
|
|
];
|
|
@@ -103,4 +194,3 @@ export const demoBooks: Book[] = [
|
|
|
export function getBookById(bookId: string) {
|
|
export function getBookById(bookId: string) {
|
|
|
return demoBooks.find((book) => book.id === bookId);
|
|
return demoBooks.find((book) => book.id === bookId);
|
|
|
}
|
|
}
|
|
|
-
|
|
|