v0.1.22: 灯下春秋(双 UI 修复)+ 文档同步

【速度暂停根因】onYearPaper 岁末族簿弹出时强制 speed:0——缓行一年整遇年报即'自动变暂停'
→ 修复:年报不打断自动速度(弹窗与时间流解耦;玩家随手翻页)

【弹框层级根因】MemberModal/EventModal 渲染于 .main-left(z-index:1) 内部,
层叠上下文被 tabs(z-index:2) 压制——'弹框出现在宗族/谱系菜单下面'
→ 修复:ModalShell 全量走 React Portal 到 document.body(免疫一切祖先层叠上下文)
+ .modal-outer z-index 50→100 双保险

【测试】1018 全绿(纯 UI 修复,引擎基线 0.1.21 不动);build 通过
This commit is contained in:
2026-08-23 15:40:29 +08:00
parent 8f9c3c9a72
commit 4a1a034f1e
7 changed files with 14 additions and 8 deletions
+2 -2
View File
@@ -1,7 +1,7 @@
# AGENTS.md # AGENTS.md
仙途家族志 · Chronicle of the Immortal Clan — Electron + React + TS 家族修仙模拟器。全部 UI 与文案为中文。 仙途家族志 · Chronicle of the Immortal Clan — Electron + React + TS 家族修仙模拟器。全部 UI 与文案为中文。
当前版本 **0.1.21**(《大势流转》:era↔景气双向闭环 + 世界史表 + 渲染管线修复)。 当前版本 **0.1.22**(《灯下春秋》:Modal 全走 body Portal(z 层越界修复)+ 年报不打断自动速度)。
## 命令 ## 命令
@@ -60,7 +60,7 @@ src/main/ Electron 主进程(app:// 协议 + IPC 存
- **特效/音效语义出口**`WorldEventBus.onFx?(em: FxEmit)` + `World.emitFx(kind, source?)`(零 rng 消耗);UI 的 `makeBus` 桥接 FxGate`onLog kind` 音效映射保留作兜底。 - **特效/音效语义出口**`WorldEventBus.onFx?(em: FxEmit)` + `World.emitFx(kind, source?)`(零 rng 消耗);UI 的 `makeBus` 桥接 FxGate`onLog kind` 音效映射保留作兜底。
- **插件架构**0.1.8 起,路径已迁 engine/runtime|kernel):`kernel/plugin.ts` 协议、`runtime/pluginManager.ts` 安装管线(依赖校验/异常回滚/追踪型上下文——注销时钩子全摘)、`plugin-bootstrap.ts` 三核心插件(core-systems/core-data/core-events protected)。事件多池 `world.eventPools`**findEvent 必须带 world 参数查池**。能力卡 12 张经 `viaCap` 注册;tournament/tribulation/apprentice/season 四卡各自内部检查 `w.sysEnabled`(无独立钩子)。 - **插件架构**0.1.8 起,路径已迁 engine/runtime|kernel):`kernel/plugin.ts` 协议、`runtime/pluginManager.ts` 安装管线(依赖校验/异常回滚/追踪型上下文——注销时钩子全摘)、`plugin-bootstrap.ts` 三核心插件(core-systems/core-data/core-events protected)。事件多池 `world.eventPools`**findEvent 必须带 world 参数查池**。能力卡 12 张经 `viaCap` 注册;tournament/tribulation/apprentice/season 四卡各自内部检查 `w.sysEnabled`(无独立钩子)。
- **门面**`runtime/ApiFacade.ts` GameFacadeact 24 项/query 6 类/subscribe 退订协议/about);**UI 面板事实走 world 直调**(act 为测试/自动化通道),`actDirect` 与 ACT_CATALOG 语义对齐(0.1.20 补齐全 24 项);store 的 `facade` 必须在 openState/startNewGame 赋值。 - **门面**`runtime/ApiFacade.ts` GameFacadeact 24 项/query 6 类/subscribe 退订协议/about);**UI 面板事实走 world 直调**(act 为测试/自动化通道),`actDirect` 与 ACT_CATALOG 语义对齐(0.1.20 补齐全 24 项);store 的 `facade` 必须在 openState/startNewGame 赋值。
- **金钟罩(双基线)**`tests/clock.test.ts``GOLDEN`(直调冻结世界)+ `GOLDEN_RESOLVED`(自动 resolve 长跑"现实"世界),各 3 seed × 三档月数(560/1200/2160)共 18 值。当前为 **0.1.21 基线**(见注释)。指纹 `tests/fingerprint.helper.ts` 含全世界轴(era/stance/prosperity/relationsWithOthers/calamity/pendingEvent/eventQueue/worldAnnals)。**有意变更时序/数值时**:指纹一并重算并在注释注明原因。 - **金钟罩(双基线)**`tests/clock.test.ts``GOLDEN`(直调冻结世界)+ `GOLDEN_RESOLVED`(自动 resolve 长跑"现实"世界),各 3 seed × 三档月数(560/1200/2160)共 18 值。当前为 **0.1.21 基线**0.1.22 纯 UI 修复未动引擎,基线不变;见注释)。指纹 `tests/fingerprint.helper.ts` 含全世界轴(era/stance/prosperity/relationsWithOthers/calamity/pendingEvent/eventQueue/worldAnnals)。**有意变更时序/数值时**:指纹一并重算并在注释注明原因。
## 世界自演进模型(0.1.14 sim/ 层,改数值勿动流程) ## 世界自演进模型(0.1.14 sim/ 层,改数值勿动流程)
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"name": "chronicle-of-the-immortal-clan", "name": "chronicle-of-the-immortal-clan",
"productName": "仙途家族志", "productName": "仙途家族志",
"version": "0.1.21", "version": "0.1.22",
"description": "修仙 · 家族 · 经营 · 战斗 模拟器", "description": "修仙 · 家族 · 经营 · 战斗 模拟器",
"main": "./out/main/index.js", "main": "./out/main/index.js",
"author": "MetonaTeam", "author": "MetonaTeam",
@@ -137,7 +137,7 @@ export class GameFacade {
about(): { title: string; version: string; modules: number; systems: number; plugins: number; packFingerprint: string } { about(): { title: string; version: string; modules: number; systems: number; plugins: number; packFingerprint: string } {
return { return {
title: '仙途家族志', title: '仙途家族志',
version: '0.1.21', version: '0.1.22',
modules: this.world.systemList().length, modules: this.world.systemList().length,
systems: this.world.systemList().filter((s) => s.enabled).length, systems: this.world.systemList().filter((s) => s.enabled).length,
plugins: this.world.pluginList().length, plugins: this.world.pluginList().length,
+6 -1
View File
@@ -1,4 +1,5 @@
import { useEffect, type ReactNode } from 'react' import { useEffect, type ReactNode } from 'react'
import { createPortal } from 'react-dom'
export interface ModalShellProps { export interface ModalShellProps {
title: string title: string
@@ -41,7 +42,9 @@ export function ModalShell({
return () => window.removeEventListener('keydown', onKey) return () => window.removeEventListener('keydown', onKey)
}, [onClose]) }, [onClose])
return ( // Portal 到 document.body:任何祖先(.main-left z1 / .app)的层叠上下文都无法压住弹框,
// 顶部菜单/主域均在其下(0.1.22 修复:弹框出现在宗族/谱系菜单下方的 z-index 越界)。
const shell = (
<div className="modal-outer" onClick={allowOuter ? onClose : undefined}> <div className="modal-outer" onClick={allowOuter ? onClose : undefined}>
<div className="modal" style={{ width: `min(92vw, ${width}px)` }} onClick={(e) => e.stopPropagation()} data-modal-kind="shell"> <div className="modal" style={{ width: `min(92vw, ${width}px)` }} onClick={(e) => e.stopPropagation()} data-modal-kind="shell">
<button className="modal-close" onClick={onClose} title={closeLabel} aria-label={closeLabel}> <button className="modal-close" onClick={onClose} title={closeLabel} aria-label={closeLabel}>
@@ -58,4 +61,6 @@ export function ModalShell({
</div> </div>
</div> </div>
) )
if (typeof document === 'undefined') return shell
return createPortal(shell, document.body)
} }
+1 -1
View File
@@ -210,7 +210,7 @@ export default function SettingsPanel() {
· <br /> · <br />
· ·
</div> </div>
<div className="dim2" style={{ marginTop: 8 }}> 0.1.21 · Chronicle of the Immortal Clan</div> <div className="dim2" style={{ marginTop: 8 }}> 0.1.22 · Chronicle of the Immortal Clan</div>
</div> </div>
</div> </div>
) )
+2 -1
View File
@@ -286,7 +286,8 @@ export const useGameStore = create<GameStore>((set, get) => ({
onYearPaper: (report) => { onYearPaper: (report) => {
if (report.year >= 2) { if (report.year >= 2) {
sPaper() sPaper()
set({ paperReport: report, speed: 0 }) // 0.1.22:年报不打断自动速度(旧:speed:0 导致「缓行过一月就变暂停」)
set({ paperReport: report })
} }
}, },
+1 -1
View File
@@ -1237,7 +1237,7 @@ html[data-blade] .battle-lines {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
z-index: 50; z-index: 100; /* 0.1.22 高于顶栏/菜单(2)与警讯(60)——配合 body Portal 双保险 */
} }
.modal { .modal {
position: relative; position: relative;