@musnows/scriverse 1.1.4 → 1.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/image-captcha.js +35 -9
- package/dist/image-captcha.js.map +1 -1
- package/dist/public/app.js +135 -50
- package/dist/public/index.html +12 -3
- package/dist/public/styles.css +13 -0
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/dist/image-captcha.js
CHANGED
|
@@ -2,8 +2,16 @@ import { createHash, randomBytes, timingSafeEqual } from "node:crypto";
|
|
|
2
2
|
import { AppError } from "./errors.js";
|
|
3
3
|
const alphabet = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
|
|
4
4
|
const captchaLength = 4;
|
|
5
|
-
|
|
5
|
+
/** 默认有效期 300 秒。任何配置或调用若短于下限,都会被抬到 180 秒。 */
|
|
6
|
+
export const CAPTCHA_LIFETIME_DEFAULT_MS = 300_000;
|
|
7
|
+
export const CAPTCHA_LIFETIME_MINIMUM_MS = 180_000;
|
|
6
8
|
const maximumChallenges = 5_000;
|
|
9
|
+
/** 把请求的有效期抬到下限;未提供或非法时使用默认 300 秒。 */
|
|
10
|
+
export function resolveCaptchaLifetimeMs(requestedMs) {
|
|
11
|
+
if (typeof requestedMs !== "number" || !Number.isFinite(requestedMs))
|
|
12
|
+
return CAPTCHA_LIFETIME_DEFAULT_MS;
|
|
13
|
+
return Math.max(CAPTCHA_LIFETIME_MINIMUM_MS, Math.trunc(requestedMs));
|
|
14
|
+
}
|
|
7
15
|
/**
|
|
8
16
|
* 5×7 点阵字形会被渲染为 path,而不是 SVG text:这样不会把答案以可直接读取的
|
|
9
17
|
* 文本节点放进 data URL。它不是对抗专业视觉模型的单独安全边界,但能阻止最基础的
|
|
@@ -44,8 +52,15 @@ const glyphPatterns = {
|
|
|
44
52
|
"9": ["01110", "10001", "10001", "01111", "00001", "00001", "01110"]
|
|
45
53
|
};
|
|
46
54
|
const fallbackGlyph = ["11111", "00001", "00010", "00100", "00100", "00000", "00100"];
|
|
55
|
+
/**
|
|
56
|
+
* 全角字母和数字与半角外观相同,但直接比较会失败。
|
|
57
|
+
* 先做 NFKC,再去掉空白和格式字符(含零宽空格),最后按 en-US 大写。
|
|
58
|
+
*/
|
|
59
|
+
export function normalizeCaptchaAnswer(answer) {
|
|
60
|
+
return answer.normalize("NFKC").replace(/[\p{Cf}\p{Z}\s]+/gu, "").toLocaleUpperCase("en-US");
|
|
61
|
+
}
|
|
47
62
|
function digestAnswer(answer) {
|
|
48
|
-
return createHash("sha256").update(answer
|
|
63
|
+
return createHash("sha256").update(normalizeCaptchaAnswer(answer)).digest();
|
|
49
64
|
}
|
|
50
65
|
function randomCode() {
|
|
51
66
|
const bytes = randomBytes(captchaLength);
|
|
@@ -131,8 +146,13 @@ export function renderCaptchaSvg(code, seed = randomBytes(8)) {
|
|
|
131
146
|
export class ImageCaptchaService {
|
|
132
147
|
options;
|
|
133
148
|
challenges = new Map();
|
|
149
|
+
lifetimeMs;
|
|
134
150
|
constructor(options = {}) {
|
|
135
151
|
this.options = options;
|
|
152
|
+
this.lifetimeMs = resolveCaptchaLifetimeMs(options.lifetimeMs);
|
|
153
|
+
}
|
|
154
|
+
currentTime() {
|
|
155
|
+
return this.options.now?.() ?? Date.now();
|
|
136
156
|
}
|
|
137
157
|
create() {
|
|
138
158
|
this.pruneExpired();
|
|
@@ -145,7 +165,7 @@ export class ImageCaptchaService {
|
|
|
145
165
|
const svg = renderCaptchaSvg(answer, seed);
|
|
146
166
|
this.challenges.set(captchaId, {
|
|
147
167
|
answerDigest: digestAnswer(answer),
|
|
148
|
-
expiresAt:
|
|
168
|
+
expiresAt: this.currentTime() + this.lifetimeMs
|
|
149
169
|
});
|
|
150
170
|
return {
|
|
151
171
|
captchaId,
|
|
@@ -153,20 +173,26 @@ export class ImageCaptchaService {
|
|
|
153
173
|
...(this.options.revealAnswer ? { answer } : {})
|
|
154
174
|
};
|
|
155
175
|
}
|
|
156
|
-
/**
|
|
176
|
+
/**
|
|
177
|
+
* 校验验证码。答案错误时保留挑战,允许用同一张图继续重试。
|
|
178
|
+
* 只有答案正确后才核销。过期,以及已核销或未知的挑战,返回已失效。
|
|
179
|
+
*/
|
|
157
180
|
consume(captchaId, answer) {
|
|
181
|
+
const currentTime = this.currentTime();
|
|
158
182
|
const challenge = this.challenges.get(captchaId);
|
|
159
|
-
|
|
160
|
-
|
|
183
|
+
if (!challenge || challenge.expiresAt <= currentTime) {
|
|
184
|
+
if (challenge)
|
|
185
|
+
this.challenges.delete(captchaId);
|
|
161
186
|
throw new AppError(400, "CAPTCHA_INVALID", "验证码已失效,请刷新后重试");
|
|
162
187
|
}
|
|
163
|
-
const provided = digestAnswer(answer
|
|
188
|
+
const provided = digestAnswer(answer);
|
|
164
189
|
if (provided.length !== challenge.answerDigest.length || !timingSafeEqual(provided, challenge.answerDigest)) {
|
|
165
|
-
throw new AppError(400, "
|
|
190
|
+
throw new AppError(400, "CAPTCHA_INCORRECT", "验证码不正确");
|
|
166
191
|
}
|
|
192
|
+
this.challenges.delete(captchaId);
|
|
167
193
|
}
|
|
168
194
|
pruneExpired() {
|
|
169
|
-
const currentTime =
|
|
195
|
+
const currentTime = this.currentTime();
|
|
170
196
|
for (const [captchaId, challenge] of this.challenges) {
|
|
171
197
|
if (challenge.expiresAt <= currentTime)
|
|
172
198
|
this.challenges.delete(captchaId);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"image-captcha.js","sourceRoot":"","sources":["../src/image-captcha.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACvE,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAcvC,MAAM,QAAQ,GAAG,kCAAkC,CAAC;AACpD,MAAM,aAAa,GAAG,CAAC,CAAC;AACxB,MAAM,iBAAiB,GAAG,CAAC,GAAG,MAAM,CAAC;AACrC,MAAM,iBAAiB,GAAG,KAAK,CAAC;AAEhC;;;;GAIG;AACH,MAAM,aAAa,GAAsC;IACvD,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;IAClE,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;IAClE,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;IAClE,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;IAClE,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;IAClE,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;IAClE,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;IAClE,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;IAClE,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;IAClE,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;IAClE,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;IAClE,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;IAClE,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;IAClE,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;IAClE,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;IAClE,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;IAClE,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;IAClE,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;IAClE,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;IAClE,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;IAClE,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;IAClE,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;IAClE,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;IAClE,CAAC,EAAE,CAAC,OAAO,EAAE,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"}
|
|
1
|
+
{"version":3,"file":"image-captcha.js","sourceRoot":"","sources":["../src/image-captcha.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACvE,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAcvC,MAAM,QAAQ,GAAG,kCAAkC,CAAC;AACpD,MAAM,aAAa,GAAG,CAAC,CAAC;AACxB,4CAA4C;AAC5C,MAAM,CAAC,MAAM,2BAA2B,GAAG,OAAO,CAAC;AACnD,MAAM,CAAC,MAAM,2BAA2B,GAAG,OAAO,CAAC;AACnD,MAAM,iBAAiB,GAAG,KAAK,CAAC;AAEhC,qCAAqC;AACrC,MAAM,UAAU,wBAAwB,CAAC,WAAoB;IAC3D,IAAI,OAAO,WAAW,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC;QAAE,OAAO,2BAA2B,CAAC;IACzG,OAAO,IAAI,CAAC,GAAG,CAAC,2BAA2B,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC;AACxE,CAAC;AAED;;;;GAIG;AACH,MAAM,aAAa,GAAsC;IACvD,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;IAClE,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;IAClE,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;IAClE,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;IAClE,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;IAClE,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;IAClE,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;IAClE,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;IAClE,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;IAClE,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;IAClE,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;IAClE,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;IAClE,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;IAClE,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;IAClE,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;IAClE,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;IAClE,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;IAClE,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;IAClE,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;IAClE,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;IAClE,CAAC,EAAE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"}
|
package/dist/public/app.js
CHANGED
|
@@ -1977,6 +1977,8 @@ let chapterDraftLineIdState = null;
|
|
|
1977
1977
|
let chapterBeforeInputState = null;
|
|
1978
1978
|
let chapterSearchMatchIndex = -1;
|
|
1979
1979
|
let chapterSelectionRequestId = 0;
|
|
1980
|
+
let chapterBodyAbort = null;
|
|
1981
|
+
let chapterContentReadyId = null;
|
|
1980
1982
|
let chapterForeshadowReminderRequestId = 0;
|
|
1981
1983
|
let chapterForeshadowReminders = [];
|
|
1982
1984
|
let chapterForeshadowReminderIndex = 0;
|
|
@@ -2082,9 +2084,12 @@ function applyChapterEditorMode() {
|
|
|
2082
2084
|
$("#chapter-content").readOnly = viewOnly;
|
|
2083
2085
|
$("#chapter-title").setAttribute("aria-readonly", String(viewOnly));
|
|
2084
2086
|
$("#chapter-content").setAttribute("aria-readonly", String(viewOnly));
|
|
2087
|
+
const waitingForChapter = chapterEditingLocked();
|
|
2085
2088
|
editButton.classList.toggle("hidden", permissionBlocked || !state.chapter);
|
|
2086
2089
|
editButton.classList.toggle("primary-button", chapterEditorReadOnly);
|
|
2087
2090
|
editButton.classList.toggle("ghost-button", !chapterEditorReadOnly);
|
|
2091
|
+
editButton.disabled = waitingForChapter;
|
|
2092
|
+
editButton.setAttribute("aria-disabled", String(waitingForChapter));
|
|
2088
2093
|
editButton.textContent = chapterEditorReadOnly ? "编辑" : "预览";
|
|
2089
2094
|
editButton.setAttribute("aria-pressed", String(!chapterEditorReadOnly));
|
|
2090
2095
|
editButton.setAttribute("aria-label", chapterEditorReadOnly ? "切换到编辑模式" : "切换到预览模式");
|
|
@@ -2095,6 +2100,8 @@ function applyChapterEditorMode() {
|
|
|
2095
2100
|
}
|
|
2096
2101
|
|
|
2097
2102
|
function enterChapterEditMode() {
|
|
2103
|
+
// 缓存或占位正文还没被本次请求确认前,编辑按钮不进入编辑。
|
|
2104
|
+
if (chapterEditingLocked()) return;
|
|
2098
2105
|
if (!state.chapter || !canEditProse()) return;
|
|
2099
2106
|
chapterEditorReadOnly = false;
|
|
2100
2107
|
applyChapterEditorMode();
|
|
@@ -2105,6 +2112,7 @@ function enterChapterEditMode() {
|
|
|
2105
2112
|
}
|
|
2106
2113
|
|
|
2107
2114
|
function toggleChapterEditPreviewMode() {
|
|
2115
|
+
if (chapterEditingLocked()) return;
|
|
2108
2116
|
if (!state.chapter || !canEditProse()) return;
|
|
2109
2117
|
if (chapterEditorReadOnly) {
|
|
2110
2118
|
enterChapterEditMode();
|
|
@@ -6535,6 +6543,7 @@ async function api(path, options = {}) {
|
|
|
6535
6543
|
body: body && typeof body !== "string" ? JSON.stringify(body) : body
|
|
6536
6544
|
});
|
|
6537
6545
|
} catch (error) {
|
|
6546
|
+
if (error?.name === "AbortError") throw error;
|
|
6538
6547
|
if (mobileOfflineRuntime.enabled) {
|
|
6539
6548
|
const offlineSession = await mobileOfflineRuntime.activateOffline();
|
|
6540
6549
|
if (offlineSession) return mobileOfflineRuntime.request(path, { method, body });
|
|
@@ -7660,6 +7669,7 @@ async function persistChapter({ automatic = false } = {}) {
|
|
|
7660
7669
|
const saved = await request;
|
|
7661
7670
|
if (state.work?.id !== workId || state.chapter?.id !== draft.chapterId) return saved.chapter;
|
|
7662
7671
|
state.chapter = saved.chapter;
|
|
7672
|
+
chapterContentReadyId = saved.chapter.id;
|
|
7663
7673
|
state.work = saved.work;
|
|
7664
7674
|
resetChapterDraftLineIds(state.chapter);
|
|
7665
7675
|
lastSavedChapterSnapshot = draft;
|
|
@@ -9374,6 +9384,9 @@ function renderShelf() {
|
|
|
9374
9384
|
|
|
9375
9385
|
function resetWorkScopedUiCaches() {
|
|
9376
9386
|
chapterSelectionRequestId += 1;
|
|
9387
|
+
chapterContentReadyId = null;
|
|
9388
|
+
chapterBodyAbort?.abort();
|
|
9389
|
+
chapterBodyAbort = null;
|
|
9377
9390
|
clearChapterForeshadowReminders({ invalidateRequest: true });
|
|
9378
9391
|
invalidateAiConversationNavigation("已切换作品");
|
|
9379
9392
|
stopBackgroundTaskCenter();
|
|
@@ -9861,7 +9874,10 @@ async function submitChapterBatch(event) {
|
|
|
9861
9874
|
state.work = await api(`/api/works/${encodeURIComponent(workId)}`);
|
|
9862
9875
|
const currentEditorVisible = state.module === "editor";
|
|
9863
9876
|
const currentStillExists = state.chapter && state.work.volumes.some((volume) => volume.chapters.some((chapter) => chapter.id === state.chapter.id));
|
|
9864
|
-
if (state.chapter && currentStillExists)
|
|
9877
|
+
if (state.chapter && currentStillExists) {
|
|
9878
|
+
state.chapter = await api(`/api/chapters/${encodeURIComponent(state.chapter.id)}`);
|
|
9879
|
+
chapterContentReadyId = state.chapter.id;
|
|
9880
|
+
}
|
|
9865
9881
|
if (state.chapter && !currentStillExists) {
|
|
9866
9882
|
state.chapter = null;
|
|
9867
9883
|
showWelcome(true);
|
|
@@ -9997,6 +10013,7 @@ async function deleteChapter(chapterId) {
|
|
|
9997
10013
|
const deletingSelectedChapter = state.chapter?.id === chapterId;
|
|
9998
10014
|
const expectedVersionNo = deletingSelectedChapter ? state.chapter.versionNo : chapter.versionNo;
|
|
9999
10015
|
await api(`/api/chapters/${chapterId}`, { method: "DELETE", body: { expectedVersionNo } });
|
|
10016
|
+
if (String(chapterContentReadyId ?? "") === String(chapterId)) chapterContentReadyId = null;
|
|
10000
10017
|
const workId = state.work.id;
|
|
10001
10018
|
state.work = await api(`/api/works/${workId}`);
|
|
10002
10019
|
if (deletingSelectedChapter) {
|
|
@@ -10215,33 +10232,47 @@ async function resolveCurrentChapterForeshadowReminder() {
|
|
|
10215
10232
|
}
|
|
10216
10233
|
}
|
|
10217
10234
|
|
|
10218
|
-
|
|
10219
|
-
|
|
10220
|
-
|
|
10221
|
-
|
|
10222
|
-
|
|
10223
|
-
|
|
10224
|
-
|
|
10225
|
-
|
|
10226
|
-
|
|
10227
|
-
|
|
10235
|
+
function setChapterContentSkeleton(visible) {
|
|
10236
|
+
const skeleton = $("#chapter-content-skeleton");
|
|
10237
|
+
skeleton.classList.toggle("hidden", !visible);
|
|
10238
|
+
skeleton.setAttribute("aria-busy", String(visible));
|
|
10239
|
+
$("#editor-view").setAttribute("aria-busy", String(visible));
|
|
10240
|
+
if (!visible) return;
|
|
10241
|
+
$("#chapter-line-numbers-inner").replaceChildren();
|
|
10242
|
+
$("#chapter-whitespace-inner").replaceChildren();
|
|
10243
|
+
}
|
|
10244
|
+
|
|
10245
|
+
function chapterEditingLocked() {
|
|
10246
|
+
return !state.chapter || String(chapterContentReadyId ?? "") !== String(state.chapter.id);
|
|
10247
|
+
}
|
|
10248
|
+
|
|
10249
|
+
function directoryChapterEntry(chapterId) {
|
|
10250
|
+
for (const volume of state.work?.volumes ?? []) {
|
|
10251
|
+
const chapter = volume.chapters?.find((item) => String(item.id) === String(chapterId));
|
|
10252
|
+
if (chapter) return chapter;
|
|
10228
10253
|
}
|
|
10229
|
-
|
|
10230
|
-
|
|
10231
|
-
|
|
10232
|
-
|
|
10233
|
-
|
|
10234
|
-
|
|
10235
|
-
|
|
10236
|
-
|
|
10237
|
-
|
|
10238
|
-
|
|
10239
|
-
|
|
10240
|
-
|
|
10241
|
-
|
|
10242
|
-
|
|
10243
|
-
|
|
10244
|
-
|
|
10254
|
+
return null;
|
|
10255
|
+
}
|
|
10256
|
+
|
|
10257
|
+
function chapterRequestStillCurrent(workId, selectionGeneration, selectionRequestId) {
|
|
10258
|
+
return selectionGeneration === chapterSelectionRequestGeneration
|
|
10259
|
+
&& selectionRequestId === chapterSelectionRequestId
|
|
10260
|
+
&& state.work?.id === workId;
|
|
10261
|
+
}
|
|
10262
|
+
|
|
10263
|
+
function presentChapter(chapter, { editMode = false, contentReady = false, syncRoute = true } = {}) {
|
|
10264
|
+
state.chapter = chapter;
|
|
10265
|
+
if (chapter?.volumeId && typeof chapter.content === "string" && (contentReady || chapter.content.length > 0)) {
|
|
10266
|
+
mergeChapterDirectoryEntry(state.chapter);
|
|
10267
|
+
}
|
|
10268
|
+
if (chapter?.volumeId) state.collapsedVolumeIds.delete(chapter.volumeId);
|
|
10269
|
+
lastSavedChapterSnapshot = {
|
|
10270
|
+
chapterId: state.chapter.id,
|
|
10271
|
+
title: state.chapter.title ?? "",
|
|
10272
|
+
content: state.chapter.content ?? ""
|
|
10273
|
+
};
|
|
10274
|
+
chapterContentReadyId = contentReady ? state.chapter.id : null;
|
|
10275
|
+
chapterEditorReadOnly = !contentReady || !editMode;
|
|
10245
10276
|
state.module = "editor";
|
|
10246
10277
|
applyWorkAccessMode();
|
|
10247
10278
|
markActiveModule("editor");
|
|
@@ -10249,22 +10280,77 @@ async function selectChapter(chapterId, { editMode = false } = {}) {
|
|
|
10249
10280
|
$("#module-view").classList.add("hidden");
|
|
10250
10281
|
$("#editor-view").classList.remove("hidden");
|
|
10251
10282
|
updateChapterPath();
|
|
10252
|
-
$("#chapter-title")
|
|
10253
|
-
$("#chapter-content")
|
|
10283
|
+
const titleInput = $("#chapter-title");
|
|
10284
|
+
const contentInput = $("#chapter-content");
|
|
10285
|
+
const nextTitle = state.chapter.title ?? "";
|
|
10286
|
+
const nextContent = state.chapter.content ?? "";
|
|
10287
|
+
if (titleInput.value !== nextTitle) titleInput.value = nextTitle;
|
|
10288
|
+
if (contentInput.value !== nextContent) contentInput.value = nextContent;
|
|
10254
10289
|
resetChapterDraftLineIds(state.chapter);
|
|
10255
10290
|
chapterAnnotationCounts = new Map();
|
|
10256
10291
|
clearChapterLineSelection();
|
|
10257
10292
|
scheduleChapterLineNumbers();
|
|
10258
|
-
void loadChapterAnnotationCounts(state.chapter.id).catch((error) => {
|
|
10259
|
-
if (String(state.chapter?.id ?? "") === String(chapterId)) toast("正文评论数量读取失败,请稍后重试", "error");
|
|
10260
|
-
});
|
|
10261
10293
|
dismissChapterInsightToast();
|
|
10262
10294
|
updateChapterStats();
|
|
10295
|
+
if (!contentReady) $("#chapter-stats").textContent = "正在载入";
|
|
10263
10296
|
if (!canEditProse()) setSaveState("正文只读");
|
|
10297
|
+
else if (!contentReady) setSaveState("正在同步正文");
|
|
10264
10298
|
else if (chapterEditorReadOnly) setSaveState("阅读模式");
|
|
10265
10299
|
else setSaveState("已保存");
|
|
10300
|
+
setChapterContentSkeleton(!contentReady);
|
|
10266
10301
|
syncChapterTreeSelection();
|
|
10267
|
-
replacePageRoute({ view: "editor", workId: state.work.id, chapterId: state.chapter.id });
|
|
10302
|
+
if (syncRoute) replacePageRoute({ view: "editor", workId: state.work.id, chapterId: state.chapter.id });
|
|
10303
|
+
}
|
|
10304
|
+
|
|
10305
|
+
async function selectChapter(chapterId, { editMode = false } = {}) {
|
|
10306
|
+
imWorkspace.close();
|
|
10307
|
+
const workId = state.work?.id;
|
|
10308
|
+
if (!workId) return false;
|
|
10309
|
+
const sameChapter = String(state.chapter?.id ?? "") === String(chapterId);
|
|
10310
|
+
if (sameChapter && chapterEditingLocked() && chapterBodyAbort && !chapterBodyAbort.signal.aborted) return true;
|
|
10311
|
+
const selectionGeneration = ++chapterSelectionRequestGeneration;
|
|
10312
|
+
const selectionRequestId = ++chapterSelectionRequestId;
|
|
10313
|
+
if (!sameChapter) clearChapterForeshadowReminders({ invalidateRequest: true });
|
|
10314
|
+
if (!sameChapter && !(await confirmDiscardChanges("当前章节有未保存修改,仍要切换吗?"))) {
|
|
10315
|
+
if (selectionRequestId === chapterSelectionRequestId) void loadChapterForeshadowReminders();
|
|
10316
|
+
return false;
|
|
10317
|
+
}
|
|
10318
|
+
resetChapterSearchPanel();
|
|
10319
|
+
dismissDeleteToasts();
|
|
10320
|
+
if (!chapterRequestStillCurrent(workId, selectionGeneration, selectionRequestId)) return false;
|
|
10321
|
+
cancelChapterAutoSave();
|
|
10322
|
+
if (sameChapter && String(chapterContentReadyId ?? "") === String(chapterId) && state.chapter) {
|
|
10323
|
+
presentChapter(state.chapter, { editMode, contentReady: true });
|
|
10324
|
+
syncChapterTreeSelection();
|
|
10325
|
+
return true;
|
|
10326
|
+
}
|
|
10327
|
+
const directoryEntry = directoryChapterEntry(chapterId);
|
|
10328
|
+
const previewChapter = directoryEntry
|
|
10329
|
+
? { ...directoryEntry, content: "", lineIds: [] }
|
|
10330
|
+
: { id: chapterId, workId, volumeId: "", title: "", content: "", wordCount: 0, versionNo: 0, chapterType: "正文", lineIds: [] };
|
|
10331
|
+
presentChapter(previewChapter, { editMode: false, contentReady: false });
|
|
10332
|
+
syncChapterTreeSelection();
|
|
10333
|
+
chapterBodyAbort?.abort();
|
|
10334
|
+
const chapterBodyController = new AbortController();
|
|
10335
|
+
chapterBodyAbort = chapterBodyController;
|
|
10336
|
+
let selectedChapter = null;
|
|
10337
|
+
try {
|
|
10338
|
+
selectedChapter = await api(`/api/chapters/${encodeURIComponent(chapterId)}`, { signal: chapterBodyController.signal });
|
|
10339
|
+
} catch (error) {
|
|
10340
|
+
if (chapterBodyAbort === chapterBodyController) chapterBodyAbort = null;
|
|
10341
|
+
if (error?.name === "AbortError" || !chapterRequestStillCurrent(workId, selectionGeneration, selectionRequestId)) return false;
|
|
10342
|
+
if (String(state.chapter?.id ?? "") === String(chapterId)) setSaveState("正文载入失败", true);
|
|
10343
|
+
toast(error.message || "章节读取失败", "error");
|
|
10344
|
+
return false;
|
|
10345
|
+
}
|
|
10346
|
+
if (chapterBodyAbort === chapterBodyController) chapterBodyAbort = null;
|
|
10347
|
+
if (!chapterRequestStillCurrent(workId, selectionGeneration, selectionRequestId)) return false;
|
|
10348
|
+
if (String(selectedChapter?.id ?? "") !== String(chapterId) || String(selectedChapter?.workId ?? "") !== String(workId)) return false;
|
|
10349
|
+
presentChapter(selectedChapter, { editMode, contentReady: true, syncRoute: false });
|
|
10350
|
+
syncChapterTreeSelection();
|
|
10351
|
+
void loadChapterAnnotationCounts(state.chapter.id).catch(() => {
|
|
10352
|
+
if (String(state.chapter?.id ?? "") === String(chapterId)) toast("正文评论数量读取失败,请稍后重试", "error");
|
|
10353
|
+
});
|
|
10268
10354
|
void loadChapterForeshadowReminders();
|
|
10269
10355
|
return true;
|
|
10270
10356
|
}
|
|
@@ -10836,6 +10922,8 @@ async function showModule(module) {
|
|
|
10836
10922
|
state.module = module;
|
|
10837
10923
|
if (module !== "editor") {
|
|
10838
10924
|
chapterSelectionRequestId += 1;
|
|
10925
|
+
chapterBodyAbort?.abort();
|
|
10926
|
+
chapterBodyAbort = null;
|
|
10839
10927
|
clearChapterForeshadowReminders({ invalidateRequest: true });
|
|
10840
10928
|
}
|
|
10841
10929
|
if (module !== "tasks") stopTaskProgressRefresh();
|
|
@@ -11897,12 +11985,13 @@ async function renderCharacters(page = characterListPage) {
|
|
|
11897
11985
|
|| characterFilters.genderValues.length > 0
|
|
11898
11986
|
|| characterFilters.deathState !== "all";
|
|
11899
11987
|
const pageSize = pageSizeFor("characters");
|
|
11988
|
+
const needsCharacterFilterCatalog = hasCharacterFilters || characterFiltersPanelOpen;
|
|
11900
11989
|
const [characterSource, races, organizations] = await Promise.all([
|
|
11901
11990
|
hasCharacterFilters
|
|
11902
11991
|
? moduleApiAllPages("characters", `/api/works/${state.work.id}/characters`)
|
|
11903
11992
|
: moduleApiPage("characters", `/api/works/${state.work.id}/characters`, page, pageSize),
|
|
11904
|
-
canReadModule("races") ? moduleApi("characters", `/api/works/${state.work.id}/races`) : Promise.resolve([]),
|
|
11905
|
-
canReadModule("organizations") ? moduleApiAllPages("characters", `/api/works/${state.work.id}/organizations`) : Promise.resolve([])
|
|
11993
|
+
needsCharacterFilterCatalog && canReadModule("races") ? moduleApi("characters", `/api/works/${state.work.id}/races`) : Promise.resolve([]),
|
|
11994
|
+
needsCharacterFilterCatalog && canReadModule("organizations") ? moduleApiAllPages("characters", `/api/works/${state.work.id}/organizations`) : Promise.resolve([])
|
|
11906
11995
|
]);
|
|
11907
11996
|
const characterPage = hasCharacterFilters
|
|
11908
11997
|
? paginateCharacters(filterCharacters(characterSource, characterFilters), page, pageSize)
|
|
@@ -11910,7 +11999,7 @@ async function renderCharacters(page = characterListPage) {
|
|
|
11910
11999
|
if (!characterPage.items.length && page > 1) return renderCharacters(page - 1);
|
|
11911
12000
|
characterListPage = characterPage.page;
|
|
11912
12001
|
const pageCharacters = characterPage.items;
|
|
11913
|
-
[state.races, state.organizations] = [races, organizations];
|
|
12002
|
+
if (needsCharacterFilterCatalog) [state.races, state.organizations] = [races, organizations];
|
|
11914
12003
|
mountModuleCount(characterPage.total);
|
|
11915
12004
|
const layout = readModuleLayout();
|
|
11916
12005
|
const characterActions = (item) => `${characterPinButton(item)}${characterFavoriteButton(item)}${recordCardEditButton("edit-character", item.id, `角色“${item.name}”`)}`;
|
|
@@ -14164,10 +14253,7 @@ function updateBackgroundTaskCenterVisibility() {
|
|
|
14164
14253
|
$("#background-task-count")?.classList.add("hidden");
|
|
14165
14254
|
return;
|
|
14166
14255
|
}
|
|
14167
|
-
const activityCount = backgroundTaskActivityCount(
|
|
14168
|
-
backgroundTaskCenterSnapshot.taskPage,
|
|
14169
|
-
backgroundTaskCenterSnapshot.relationshipIndex
|
|
14170
|
-
) + (productUpdateChecking ? 1 : 0);
|
|
14256
|
+
const activityCount = backgroundTaskActivityCount(backgroundTaskCenterSnapshot.taskPage) + (productUpdateChecking ? 1 : 0);
|
|
14171
14257
|
const badge = $("#background-task-count");
|
|
14172
14258
|
badge.textContent = activityCount > 99 ? "99+" : String(activityCount);
|
|
14173
14259
|
badge.classList.toggle("hidden", activityCount === 0);
|
|
@@ -14251,7 +14337,7 @@ function backgroundIndexMarkup(relationshipIndex, error) {
|
|
|
14251
14337
|
const editable = canEditModule("ai-settings");
|
|
14252
14338
|
return `<section class="background-task-section">
|
|
14253
14339
|
<div class="background-task-section-heading">
|
|
14254
|
-
<div><strong>人物关系拼音索引</strong><small
|
|
14340
|
+
<div><strong>人物关系拼音索引</strong><small>打开本窗口时显示当前索引状态</small></div>
|
|
14255
14341
|
<div class="background-index-actions ${editable ? "" : "hidden"}">
|
|
14256
14342
|
<button class="primary-button" type="button" data-background-index-action="sync">同步增量队列</button>
|
|
14257
14343
|
<button class="ghost-button" type="button" data-background-index-action="rebuild">完整重建</button>
|
|
@@ -14322,10 +14408,7 @@ function scheduleBackgroundTaskCenterRefresh() {
|
|
|
14322
14408
|
if (backgroundTaskCenterTimer !== null) window.clearTimeout(backgroundTaskCenterTimer);
|
|
14323
14409
|
backgroundTaskCenterTimer = null;
|
|
14324
14410
|
if (!backgroundTaskCenterWorkId) return;
|
|
14325
|
-
const activityCount = backgroundTaskActivityCount(
|
|
14326
|
-
backgroundTaskCenterSnapshot.taskPage,
|
|
14327
|
-
backgroundTaskCenterSnapshot.relationshipIndex
|
|
14328
|
-
);
|
|
14411
|
+
const activityCount = backgroundTaskActivityCount(backgroundTaskCenterSnapshot.taskPage);
|
|
14329
14412
|
const delay = backgroundTaskPollDelay(activityCount, Boolean($("#background-task-dialog")?.open));
|
|
14330
14413
|
backgroundTaskCenterTimer = window.setTimeout(() => {
|
|
14331
14414
|
backgroundTaskCenterTimer = null;
|
|
@@ -14339,8 +14422,9 @@ async function refreshBackgroundTaskCenter({ announce = true } = {}) {
|
|
|
14339
14422
|
if (backgroundTaskCenterTimer !== null) window.clearTimeout(backgroundTaskCenterTimer);
|
|
14340
14423
|
backgroundTaskCenterTimer = null;
|
|
14341
14424
|
const requestId = ++backgroundTaskCenterRequest;
|
|
14425
|
+
const dialogOpen = Boolean($("#background-task-dialog")?.open);
|
|
14342
14426
|
const readTasks = canReadModule("tasks");
|
|
14343
|
-
const readIndex = canReadModule("ai-settings");
|
|
14427
|
+
const readIndex = dialogOpen && canReadModule("ai-settings");
|
|
14344
14428
|
const [taskResult, indexResult] = await Promise.all([
|
|
14345
14429
|
readTasks
|
|
14346
14430
|
? api(`/api/works/${encodeURIComponent(workId)}/tasks?page=1&limit=30`)
|
|
@@ -20373,6 +20457,7 @@ async function showVersions() {
|
|
|
20373
20457
|
}
|
|
20374
20458
|
try {
|
|
20375
20459
|
state.chapter = await api(`/api/chapters/${state.chapter.id}/restore`, { method: "POST", body: { versionNo: Number(button.dataset.restoreVersion) } });
|
|
20460
|
+
chapterContentReadyId = state.chapter.id;
|
|
20376
20461
|
resetChapterDraftLineIds(state.chapter);
|
|
20377
20462
|
lastSavedChapterSnapshot = { chapterId: state.chapter.id, title: state.chapter.title, content: state.chapter.content };
|
|
20378
20463
|
$("#chapter-title").value = state.chapter.title;
|
|
@@ -21456,8 +21541,8 @@ $("#login-form").addEventListener("submit", async (event) => {
|
|
|
21456
21541
|
window.location.reload();
|
|
21457
21542
|
} catch (error) {
|
|
21458
21543
|
$("#auth-error").textContent = error.message;
|
|
21459
|
-
//
|
|
21460
|
-
if (!$("#login-captcha-image").hidden) refreshAuthCaptcha("login").catch(() => {});
|
|
21544
|
+
// 答案错误时保留同一张图;过期、已核销或其他失败才换一张
|
|
21545
|
+
if (error?.code !== "CAPTCHA_INCORRECT" && !$("#login-captcha-image").hidden) refreshAuthCaptcha("login").catch(() => {});
|
|
21461
21546
|
}
|
|
21462
21547
|
});
|
|
21463
21548
|
$("#register-form").addEventListener("submit", async (event) => {
|
|
@@ -21485,8 +21570,8 @@ $("#register-form").addEventListener("submit", async (event) => {
|
|
|
21485
21570
|
window.location.reload();
|
|
21486
21571
|
} catch (error) {
|
|
21487
21572
|
$("#auth-error").textContent = error.message;
|
|
21488
|
-
//
|
|
21489
|
-
if (!$("#register-captcha-image").hidden) refreshAuthCaptcha("register").catch(() => {});
|
|
21573
|
+
// 答案错误时保留同一张图;过期、已核销或其他失败才换一张
|
|
21574
|
+
if (error?.code !== "CAPTCHA_INCORRECT" && !$("#register-captcha-image").hidden) refreshAuthCaptcha("register").catch(() => {});
|
|
21490
21575
|
}
|
|
21491
21576
|
});
|
|
21492
21577
|
$("#settings-return").addEventListener("click", () => returnFromSettings().catch((error) => toast(error.message, "error")));
|
package/dist/public/index.html
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
<link rel="icon" href="/icon.svg?v=20260712" type="image/svg+xml">
|
|
11
11
|
<link rel="manifest" href="/site.webmanifest">
|
|
12
12
|
<link rel="stylesheet" href="/mobile-app.css?v=20260922-mobile-offline-v2">
|
|
13
|
-
<link rel="stylesheet" href="/styles.css?v=20260816-task-scope-volume-collapse-v2&feature=ai-tool-call-copy-feedback-v2&feature=ai-send-control-v3&feature=character-gender-v1&feature=character-filter-state-v1&feature=relationship-canvas-scale-v1&feature=relationship-table-scroll-v1&feature=galaxy-compact-controls-v2&feature=galaxy-motion-mode-v2&feature=chapter-search-replace-v3&feature=task-auto-run-ring-center-v3&feature=character-relationship-delete-v1&feature=ai-assistant-workspace-v2&feature=mobile-module-tab-position-v1&feature=volume-detail-icon-v1&feature=editor-actions-flow-v1&feature=reader-controls-subpanel-v1&feature=reader-focus-ring-v1&feature=ai-message-actions-v1&feature=assistant-responsive-navigation-v2&feature=ai-composer-square-controls-v2&feature=ai-composer-compact-controls-v1&feature=ai-context-meter-ring-only-v2&feature=ai-context-cache-hit-v1&feature=annotation-line-counts-v1&feature=chapter-comment-filters-v1&feature=line-number-gutter-fill-v1&feature=ai-relationship-roleplay-v1&feature=ai-model-picker-v1&feature=markdown-word-count-five-digit-v2&feature=ai-stream-character-count-stable-v1&feature=ai-stream-character-count-five-digit-v1&feature=annotation-marker-offset-v1&feature=mobile-ai-entry-hidden-v1&feature=phone-client-entry-v1&feature=ai-stream-idle-timeout-v1&feature=ai-user-message-width-v2&feature=ai-chat-image-attachments-v9&feature=ai-message-image-preview-v1&feature=ai-thinking-scroll-v2&feature=toast-click-dismiss-v3&feature=character-avatar-v6&feature=admin-ai-conversations-v1&feature=ai-usage-pricing-v1&feature=ai-usage-pricing-badge-v2&feature=ai-token-quota-positive-v5&feature=ai-token-usage-details-v1&feature=ai-token-usage-details-centered-v1&feature=ai-stream-connection-seconds-v1&feature=ai-token-usage-estimated-price-v1&feature=record-favorites-v1&feature=entity-detail-favorites-v1&feature=entity-pin-v1&feature=character-persona-summary-v1&feature=ai-roleplay-scene-turn-v1&feature=admin-account-identity-v2&feature=task-detail-failure-orange-v1&feature=character-card-header-alignment-v6&feature=character-card-title-fit-v2&feature=book-import-progress-v1&feature=editor-toolbar-compact-v2&feature=reader-first-frame-v1&feature=auth-compact-v2&feature=editor-preview-toggle-v2&feature=setting-title-chrome-v2&feature=entity-pin-icon-center-v1&feature=chapter-center-bottom-space-v1&feature=work-editor-preferences-v1&feature=work-editor-preference-checkbox-v1&feature=ai-roleplay-memory-v2&feature=ai-roleplay-memory-v3&feature=ai-roleplay-memory-v5&feature=character-editor-header-actions-v1&feature=roleplay-memory-header-actions-v1&feature=roleplay-memory-action-icons-v1&feature=roleplay-memory-action-colors-v1&feature=roleplay-memory-pin-border-v1&feature=ai-write-tools-v2&feature=ai-write-card-actions-compact-v1&feature=ai-write-plan-actions-footer-v1&feature=ai-question-actions-footer-v1&feature=ai-question-selection-highlight-v1&feature=ai-question-submit-guidance-v1&feature=ai-question-answer-limit-v1&feature=ai-question-batch-v1&feature=semantic-search-v6&feature=chapter-title-renumber-v1&feature=ai-writing-skills-v1&feature=remote-mcp-v1&feature=character-alias-chips-v2&feature=character-title-input-v1&feature=character-detail-value-wrap-v2&feature=ai-settings-textarea-font-v1&feature=ai-usage-stat-display-v1&feature=ai-usage-year-v1&feature=ai-skill-slash-menu-v1&feature=ai-message-citation-popover-v1&feature=line-citation-menu-separator-v1&feature=global-im-v106&feature=im-sidebar-compact-v1&feature=im-narration-contrast-v1&feature=im-member-add-plus-v2&feature=im-button-hierarchy-v1&feature=im-icon-button-size-v1&feature=compact-sidebar-directory-v5&feature=ai-model-config-dialog-v1&feature=system-prompt-override-v3&feature=entity-editor-back-icon-v1&feature=toast-stack-v1&feature=chapter-header-compact-v4&feature=ai-attachment-disabled-v1&feature=ai-prose-acceptance-removed-v1&feature=chapter-line-scroll-bind-v1&feature=writing-goal-module-navigation-v2&feature=invite-registration-v1&feature=ai-send-mode-v2&feature=character-attributes-prune-v1&feature=chapter-directory-click-priority-v1&feature=annotation-bubble-visibility-v1&feature=chapter-auto-title-menu-v1&feature=chapter-insert-menu-v1">
|
|
13
|
+
<link rel="stylesheet" href="/styles.css?v=20260816-task-scope-volume-collapse-v2&feature=ai-tool-call-copy-feedback-v2&feature=ai-send-control-v3&feature=character-gender-v1&feature=character-filter-state-v1&feature=relationship-canvas-scale-v1&feature=relationship-table-scroll-v1&feature=galaxy-compact-controls-v2&feature=galaxy-motion-mode-v2&feature=chapter-search-replace-v3&feature=task-auto-run-ring-center-v3&feature=character-relationship-delete-v1&feature=ai-assistant-workspace-v2&feature=mobile-module-tab-position-v1&feature=volume-detail-icon-v1&feature=editor-actions-flow-v1&feature=reader-controls-subpanel-v1&feature=reader-focus-ring-v1&feature=ai-message-actions-v1&feature=assistant-responsive-navigation-v2&feature=ai-composer-square-controls-v2&feature=ai-composer-compact-controls-v1&feature=ai-context-meter-ring-only-v2&feature=ai-context-cache-hit-v1&feature=annotation-line-counts-v1&feature=chapter-comment-filters-v1&feature=line-number-gutter-fill-v1&feature=ai-relationship-roleplay-v1&feature=ai-model-picker-v1&feature=markdown-word-count-five-digit-v2&feature=ai-stream-character-count-stable-v1&feature=ai-stream-character-count-five-digit-v1&feature=annotation-marker-offset-v1&feature=mobile-ai-entry-hidden-v1&feature=phone-client-entry-v1&feature=ai-stream-idle-timeout-v1&feature=ai-user-message-width-v2&feature=ai-chat-image-attachments-v9&feature=ai-message-image-preview-v1&feature=ai-thinking-scroll-v2&feature=toast-click-dismiss-v3&feature=character-avatar-v6&feature=admin-ai-conversations-v1&feature=ai-usage-pricing-v1&feature=ai-usage-pricing-badge-v2&feature=ai-token-quota-positive-v5&feature=ai-token-usage-details-v1&feature=ai-token-usage-details-centered-v1&feature=ai-stream-connection-seconds-v1&feature=ai-token-usage-estimated-price-v1&feature=record-favorites-v1&feature=entity-detail-favorites-v1&feature=entity-pin-v1&feature=character-persona-summary-v1&feature=ai-roleplay-scene-turn-v1&feature=admin-account-identity-v2&feature=task-detail-failure-orange-v1&feature=character-card-header-alignment-v6&feature=character-card-title-fit-v2&feature=book-import-progress-v1&feature=editor-toolbar-compact-v2&feature=reader-first-frame-v1&feature=auth-compact-v2&feature=editor-preview-toggle-v2&feature=setting-title-chrome-v2&feature=entity-pin-icon-center-v1&feature=chapter-center-bottom-space-v1&feature=work-editor-preferences-v1&feature=work-editor-preference-checkbox-v1&feature=ai-roleplay-memory-v2&feature=ai-roleplay-memory-v3&feature=ai-roleplay-memory-v5&feature=character-editor-header-actions-v1&feature=roleplay-memory-header-actions-v1&feature=roleplay-memory-action-icons-v1&feature=roleplay-memory-action-colors-v1&feature=roleplay-memory-pin-border-v1&feature=ai-write-tools-v2&feature=ai-write-card-actions-compact-v1&feature=ai-write-plan-actions-footer-v1&feature=ai-question-actions-footer-v1&feature=ai-question-selection-highlight-v1&feature=ai-question-submit-guidance-v1&feature=ai-question-answer-limit-v1&feature=ai-question-batch-v1&feature=semantic-search-v6&feature=chapter-title-renumber-v1&feature=ai-writing-skills-v1&feature=remote-mcp-v1&feature=character-alias-chips-v2&feature=character-title-input-v1&feature=character-detail-value-wrap-v2&feature=ai-settings-textarea-font-v1&feature=ai-usage-stat-display-v1&feature=ai-usage-year-v1&feature=ai-skill-slash-menu-v1&feature=ai-message-citation-popover-v1&feature=line-citation-menu-separator-v1&feature=global-im-v106&feature=im-sidebar-compact-v1&feature=im-narration-contrast-v1&feature=im-member-add-plus-v2&feature=im-button-hierarchy-v1&feature=im-icon-button-size-v1&feature=compact-sidebar-directory-v5&feature=ai-model-config-dialog-v1&feature=system-prompt-override-v3&feature=entity-editor-back-icon-v1&feature=toast-stack-v1&feature=chapter-header-compact-v4&feature=ai-attachment-disabled-v1&feature=ai-prose-acceptance-removed-v1&feature=chapter-line-scroll-bind-v1&feature=writing-goal-module-navigation-v2&feature=invite-registration-v1&feature=ai-send-mode-v2&feature=character-attributes-prune-v1&feature=chapter-directory-click-priority-v1&feature=annotation-bubble-visibility-v1&feature=chapter-auto-title-menu-v1&feature=chapter-insert-menu-v1&feature=chapter-switch-skeleton-v1">
|
|
14
14
|
</head>
|
|
15
15
|
<body class="auth-pending">
|
|
16
16
|
<section id="auth-view" class="auth-view hidden" aria-labelledby="auth-title">
|
|
@@ -330,6 +330,16 @@
|
|
|
330
330
|
<div id="chapter-editor-scroll" class="chapter-editor-scroll">
|
|
331
331
|
<aside id="chapter-line-numbers" class="chapter-line-numbers" aria-label="正文行号,可拖拽引用多行"><div id="chapter-line-numbers-inner"></div></aside>
|
|
332
332
|
<textarea id="chapter-content" class="chapter-content" aria-label="章节正文" placeholder="在这里开始你的故事……"></textarea>
|
|
333
|
+
<div id="chapter-content-skeleton" class="chapter-content-skeleton hidden" role="status" aria-live="polite" aria-busy="false" aria-label="正在载入正文">
|
|
334
|
+
<span class="chapter-content-skeleton-line"></span>
|
|
335
|
+
<span class="chapter-content-skeleton-line"></span>
|
|
336
|
+
<span class="chapter-content-skeleton-line"></span>
|
|
337
|
+
<span class="chapter-content-skeleton-line"></span>
|
|
338
|
+
<span class="chapter-content-skeleton-line"></span>
|
|
339
|
+
<span class="chapter-content-skeleton-line"></span>
|
|
340
|
+
<span class="chapter-content-skeleton-line"></span>
|
|
341
|
+
<span class="chapter-content-skeleton-line"></span>
|
|
342
|
+
</div>
|
|
333
343
|
<div id="chapter-whitespace-overlay" class="chapter-whitespace-overlay is-visible" aria-hidden="true"><div id="chapter-whitespace-inner"></div></div>
|
|
334
344
|
</div>
|
|
335
345
|
<div id="chapter-line-measure" class="chapter-line-measure" aria-hidden="true"></div>
|
|
@@ -1459,7 +1469,6 @@
|
|
|
1459
1469
|
</dialog>
|
|
1460
1470
|
|
|
1461
1471
|
<div id="auth-loading" class="auth-loading" role="status" aria-label="正在载入工作台"></div>
|
|
1462
|
-
<script type="module" src="/app.js?v=20260816-extended-thinking-effort-v1&feature=ai-history-rename-v1&feature=ai-tool-call-copy-feedback-v2&feature=ai-send-control-v2&feature=analysis-task-queue-refresh-v1&feature=character-gender-v1&feature=character-filter-state-v1&feature=relationship-canvas-scale-v1&feature=relationship-table-scroll-v1&feature=ai-session-id-copy-v2&feature=galaxy-motion-mode-v3&feature=galaxy-edge-label-threshold-v1&feature=calculate-time-tool-v2&feature=analysis-task-expired-toast-v1&feature=global-replace-volume-v1&feature=chapter-search-replace-v1&feature=chapter-save-toast-v1&feature=character-relationship-delete-v1&feature=character-relationship-group-v1&feature=analysis-task-stability-delay-v1&feature=ai-assistant-workspace-v2&feature=volume-detail-icon-v1&feature=volume-story-order-v1&feature=reader-manual-chapter-navigation-v1&feature=ai-message-reference-badges-v1&feature=ai-roleplay-message-reference-v1&feature=ai-message-actions-v1&feature=assistant-responsive-navigation-v3&feature=annotation-permissions-v1&feature=annotation-line-counts-v1&feature=ai-relationship-roleplay-v1&feature=ai-roleplay-user-character-visibility-v1&feature=ai-roleplay-story-recall-v1&feature=ai-model-picker-v1&feature=ai-fork-model-unlock-v1&feature=context-percent-format-v1&feature=annotation-precise-locate-v1&feature=markdown-word-count-stable-v1&feature=ai-stream-character-count-stable-v2&feature=ai-process-empty-intermediate-v1&feature=ai-feed-scroll-follow-v2&feature=ai-message-retry-v1&feature=ai-stream-idle-timeout-v2&feature=ai-config-delete-v1&feature=ai-provider-protocol-options-v1&feature=ai-provider-thinking-type-v1&feature=ai-chat-image-attachments-v8&feature=ai-message-image-preview-v1&feature=ai-thinking-scroll-v2&feature=ai-image-conversation-model-lock-v1&feature=toast-click-dismiss-v2&feature=system-restart-dialog-delay-v1&feature=character-avatar-v6&feature=character-death-position-v1&feature=admin-ai-conversations-v1&feature=ai-usage-pricing-v1&feature=ai-usage-pricing-badge-v2&feature=ai-usage-pricing-label-v1&feature=ai-usage-token-breakdown-v1&feature=ai-usage-pricing-cache-v2&feature=ai-usage-pricing-manual-refresh-v1&feature=ai-monthly-token-quota-v1&feature=ai-provider-token-quota-v1&feature=ai-token-quota-positive-v6&feature=ai-model-thinking-label-v1&feature=ai-model-picker-focus-v1&feature=ai-provider-model-import-v1&feature=ai-assistant-brain-icon-v1&feature=ai-token-usage-details-v1&feature=ai-token-usage-details-centered-v1&feature=ai-token-usage-raw-input-v1&feature=ai-stream-connection-seconds-v1&feature=phone-client-entry-v1&feature=ai-usage-pricing-cache-v1&feature=ai-model-thinking-label-v3&feature=ai-roleplay-speaker-label-v1&feature=toast-modal-host-v1&feature=api-key-copy-existing-v1&feature=character-favorite-v1&feature=record-favorites-v1&feature=ai-token-usage-estimated-price-v1&feature=entity-detail-favorites-v1&feature=entity-pin-v1&feature=entity-pin-icon-v1&feature=roleplay-favorite-label-v1&feature=ai-roleplay-knowledge-tools-v1&feature=character-persona-summary-v1&feature=ai-roleplay-scene-turn-v2&feature=admin-account-identity-v2&feature=ai-provider-analysis-timeout-v1&feature=task-detail-failure-orange-v1&feature=book-import-progress-v1&feature=presence-multiple-users-v1&feature=ai-context-input-output-v1&feature=editor-blank-lines-preserved-v1&feature=reader-first-frame-v1&feature=vditor-lazy-load-v1&feature=ui-module-preload-v1&feature=reader-initial-prefetch-v1&feature=editor-preview-toggle-v2&feature=vditor-fullscreen-disabled-v1&feature=chapter-auto-indent-v1&feature=chapter-centered-scroll-v1&feature=work-editor-preferences-v1&feature=ai-context-output-usage-v1&feature=ai-context-meter-ring-only-v1&feature=ai-context-cache-hit-v1&feature=ai-roleplay-memory-v4&feature=ai-roleplay-memory-v5&feature=roleplay-memory-header-actions-v1&feature=roleplay-memory-header-toolbar-v1&feature=roleplay-memory-action-icons-v1&feature=roleplay-memory-action-colors-v1&feature=annotation-line-anchor-v1&feature=stable-line-ids-v1&feature=live-annotation-anchors-v1&feature=chapter-comment-filters-v1&feature=ai-write-tools-v3&feature=ai-question-option-supplement-v1&feature=ai-question-selection-highlight-v1&feature=ai-question-continuation-ui-v3&feature=ai-background-stream-v1&feature=ai-question-tool-result-v1&feature=ai-question-tool-summary-v1&feature=ai-question-submit-guidance-v1&feature=ai-question-batch-v1&feature=ai-question-answer-limit-v1&feature=semantic-search-v6&feature=chapter-title-renumber-v1&feature=ai-writing-skills-v3&feature=ai-cancel-preserve-process-v2&feature=remote-mcp-v1&feature=character-alias-chips-v2&feature=character-title-input-v1&feature=character-detail-value-wrap-v2&feature=chapter-batch-editor-refresh-v1&feature=ai-usage-stat-display-v1&feature=ai-usage-year-v1&feature=semantic-search-rag-label-v1&feature=ai-skill-slash-menu-v1&feature=ai-roleplay-scene-bubble-v1&feature=ai-roleplay-scene-collapse-v1&feature=markdown-adjacent-blockquotes-v1&feature=chapter-save-shortcut-v2&feature=ai-message-citation-popover-v1&feature=line-citation-menu-separator-v1&feature=global-im-v106&feature=im-sidebar-compact-v1&feature=ai-fork-progress-toast-v1&feature=im-settings-gear-v1&feature=compact-sidebar-directory-v2&feature=chapter-word-count-consistency-v1&feature=ai-all-message-references-v2&feature=ai-question-render-recovery-v3&feature=setting-category-preservation-v1&feature=toast-stack-v1&feature=toast-stack-label-v2&feature=agent-tool-limits-300-v1&feature=server-dev-logo-v1&feature=chapter-directory-ai-reference-v3&feature=ai-error-origin-v1&feature=ai-stream-render-performance-v2&feature=ai-attachment-disabled-v1&feature=ai-prose-acceptance-removed-v1&feature=ai-inline-message-references-v1&feature=ai-write-plan-status-sync-v1&feature=writing-goal-module-navigation-v2&feature=chapter-line-scroll-bind-v1&feature=invite-registration-v1&feature=ai-send-mode-v2&feature=character-attributes-prune-v1&feature=annotation-note-limit-v1&feature=chapter-directory-performance-v2&feature=chapter-directory-click-priority-v1&feature=mobile-offline-runtime-v6&feature=ai-title-first-turn-v1&feature=ai-optimistic-send-v1&feature=chapter-auto-title-menu-v1&feature=chapter-insert-menu-v1"></script>
|
|
1463
|
-
|
|
1472
|
+
<script type="module" src="/app.js?v=20260816-extended-thinking-effort-v1&feature=ai-history-rename-v1&feature=ai-tool-call-copy-feedback-v2&feature=ai-send-control-v2&feature=analysis-task-queue-refresh-v1&feature=character-gender-v1&feature=character-filter-state-v1&feature=relationship-canvas-scale-v1&feature=relationship-table-scroll-v1&feature=ai-session-id-copy-v2&feature=galaxy-motion-mode-v3&feature=galaxy-edge-label-threshold-v1&feature=calculate-time-tool-v2&feature=analysis-task-expired-toast-v1&feature=global-replace-volume-v1&feature=chapter-search-replace-v1&feature=chapter-save-toast-v1&feature=character-relationship-delete-v1&feature=character-relationship-group-v1&feature=analysis-task-stability-delay-v1&feature=ai-assistant-workspace-v2&feature=volume-detail-icon-v1&feature=volume-story-order-v1&feature=reader-manual-chapter-navigation-v1&feature=ai-message-reference-badges-v1&feature=ai-roleplay-message-reference-v1&feature=ai-message-actions-v1&feature=assistant-responsive-navigation-v3&feature=annotation-permissions-v1&feature=annotation-line-counts-v1&feature=ai-relationship-roleplay-v1&feature=ai-roleplay-user-character-visibility-v1&feature=ai-roleplay-story-recall-v1&feature=ai-model-picker-v1&feature=ai-fork-model-unlock-v1&feature=context-percent-format-v1&feature=annotation-precise-locate-v1&feature=markdown-word-count-stable-v1&feature=ai-stream-character-count-stable-v2&feature=ai-process-empty-intermediate-v1&feature=ai-feed-scroll-follow-v2&feature=ai-message-retry-v1&feature=ai-stream-idle-timeout-v2&feature=ai-config-delete-v1&feature=ai-provider-protocol-options-v1&feature=ai-provider-thinking-type-v1&feature=ai-chat-image-attachments-v8&feature=ai-message-image-preview-v1&feature=ai-thinking-scroll-v2&feature=ai-image-conversation-model-lock-v1&feature=toast-click-dismiss-v2&feature=system-restart-dialog-delay-v1&feature=character-avatar-v6&feature=character-death-position-v1&feature=admin-ai-conversations-v1&feature=ai-usage-pricing-v1&feature=ai-usage-pricing-badge-v2&feature=ai-usage-pricing-label-v1&feature=ai-usage-token-breakdown-v1&feature=ai-usage-pricing-cache-v2&feature=ai-usage-pricing-manual-refresh-v1&feature=ai-monthly-token-quota-v1&feature=ai-provider-token-quota-v1&feature=ai-token-quota-positive-v6&feature=ai-model-thinking-label-v1&feature=ai-model-picker-focus-v1&feature=ai-provider-model-import-v1&feature=ai-assistant-brain-icon-v1&feature=ai-token-usage-details-v1&feature=ai-token-usage-details-centered-v1&feature=ai-token-usage-raw-input-v1&feature=ai-stream-connection-seconds-v1&feature=phone-client-entry-v1&feature=ai-usage-pricing-cache-v1&feature=ai-model-thinking-label-v3&feature=ai-roleplay-speaker-label-v1&feature=toast-modal-host-v1&feature=api-key-copy-existing-v1&feature=character-favorite-v1&feature=record-favorites-v1&feature=ai-token-usage-estimated-price-v1&feature=entity-detail-favorites-v1&feature=entity-pin-v1&feature=entity-pin-icon-v1&feature=roleplay-favorite-label-v1&feature=ai-roleplay-knowledge-tools-v1&feature=character-persona-summary-v1&feature=ai-roleplay-scene-turn-v2&feature=admin-account-identity-v2&feature=ai-provider-analysis-timeout-v1&feature=task-detail-failure-orange-v1&feature=book-import-progress-v1&feature=presence-multiple-users-v1&feature=ai-context-input-output-v1&feature=editor-blank-lines-preserved-v1&feature=reader-first-frame-v1&feature=vditor-lazy-load-v1&feature=ui-module-preload-v1&feature=reader-initial-prefetch-v1&feature=editor-preview-toggle-v2&feature=vditor-fullscreen-disabled-v1&feature=chapter-auto-indent-v1&feature=chapter-centered-scroll-v1&feature=work-editor-preferences-v1&feature=ai-context-output-usage-v1&feature=ai-context-meter-ring-only-v1&feature=ai-context-cache-hit-v1&feature=ai-roleplay-memory-v4&feature=ai-roleplay-memory-v5&feature=roleplay-memory-header-actions-v1&feature=roleplay-memory-header-toolbar-v1&feature=roleplay-memory-action-icons-v1&feature=roleplay-memory-action-colors-v1&feature=annotation-line-anchor-v1&feature=stable-line-ids-v1&feature=live-annotation-anchors-v1&feature=chapter-comment-filters-v1&feature=ai-write-tools-v3&feature=ai-question-option-supplement-v1&feature=ai-question-selection-highlight-v1&feature=ai-question-continuation-ui-v3&feature=ai-background-stream-v1&feature=ai-question-tool-result-v1&feature=ai-question-tool-summary-v1&feature=ai-question-submit-guidance-v1&feature=ai-question-batch-v1&feature=ai-question-answer-limit-v1&feature=semantic-search-v6&feature=chapter-title-renumber-v1&feature=ai-writing-skills-v3&feature=ai-cancel-preserve-process-v2&feature=remote-mcp-v1&feature=character-alias-chips-v2&feature=character-title-input-v1&feature=character-detail-value-wrap-v2&feature=chapter-batch-editor-refresh-v1&feature=ai-usage-stat-display-v1&feature=ai-usage-year-v1&feature=semantic-search-rag-label-v1&feature=ai-skill-slash-menu-v1&feature=ai-roleplay-scene-bubble-v1&feature=ai-roleplay-scene-collapse-v1&feature=markdown-adjacent-blockquotes-v1&feature=chapter-save-shortcut-v2&feature=ai-message-citation-popover-v1&feature=line-citation-menu-separator-v1&feature=global-im-v106&feature=im-sidebar-compact-v1&feature=ai-fork-progress-toast-v1&feature=im-settings-gear-v1&feature=compact-sidebar-directory-v2&feature=chapter-word-count-consistency-v1&feature=ai-all-message-references-v2&feature=ai-question-render-recovery-v3&feature=setting-category-preservation-v1&feature=toast-stack-v1&feature=toast-stack-label-v2&feature=agent-tool-limits-300-v1&feature=server-dev-logo-v1&feature=chapter-directory-ai-reference-v3&feature=ai-error-origin-v1&feature=ai-stream-render-performance-v2&feature=ai-attachment-disabled-v1&feature=ai-prose-acceptance-removed-v1&feature=ai-inline-message-references-v1&feature=ai-write-plan-status-sync-v1&feature=writing-goal-module-navigation-v2&feature=chapter-line-scroll-bind-v1&feature=invite-registration-v1&feature=ai-send-mode-v2&feature=character-attributes-prune-v1&feature=annotation-note-limit-v1&feature=chapter-directory-performance-v2&feature=chapter-directory-click-priority-v1&feature=chapter-switch-skeleton-v1&feature=mobile-offline-runtime-v6&feature=ai-title-first-turn-v1&feature=ai-optimistic-send-v1&feature=chapter-auto-title-menu-v1&feature=chapter-insert-menu-v1&feature=captcha-retry-same-image-v1&feature=relationship-index-dialog-poll-v1"></script>
|
|
1464
1473
|
</body>
|
|
1465
1474
|
</html>
|
package/dist/public/styles.css
CHANGED
|
@@ -1598,6 +1598,18 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
|
|
|
1598
1598
|
.chapter-content { position: relative; z-index: 1; grid-column: 2; grid-row: 1; resize: none; width: 100%; height: auto; min-height: 100%; margin: 0; padding: 32px 36px 72px; border: 0; background: transparent; border-radius: 0; font-size: var(--editor-font-size); line-height: var(--editor-line-height); letter-spacing: .01em; overflow-wrap: break-word; overflow: hidden; }
|
|
1599
1599
|
.app-shell.editor-typewriter-mode .chapter-content { padding-bottom: max(72px, 45dvh); }
|
|
1600
1600
|
.chapter-content:focus { box-shadow: none; }
|
|
1601
|
+
.chapter-content-skeleton { position: absolute; z-index: 3; grid-column: 2; grid-row: 1; display: grid; align-content: start; gap: 16px; width: 100%; min-height: 100%; margin: 0; padding: 36px 36px 72px; background: var(--paper); pointer-events: none; }
|
|
1602
|
+
.chapter-content-skeleton.hidden { display: none; }
|
|
1603
|
+
.chapter-content-skeleton-line { position: relative; display: block; height: 14px; overflow: hidden; border-radius: 4px; background: color-mix(in srgb, var(--line) 78%, var(--paper)); }
|
|
1604
|
+
.chapter-content-skeleton-line::after { position: absolute; inset: 0; background: linear-gradient(110deg, transparent 18%, color-mix(in srgb, var(--surface) 72%, transparent) 48%, transparent 78%); content: ""; transform: translateX(-110%); animation: image-upload-placeholder-shimmer 1.45s ease-in-out infinite; }
|
|
1605
|
+
.chapter-content-skeleton-line:nth-child(2) { width: 92%; }
|
|
1606
|
+
.chapter-content-skeleton-line:nth-child(3) { width: 84%; }
|
|
1607
|
+
.chapter-content-skeleton-line:nth-child(4) { width: 46%; }
|
|
1608
|
+
.chapter-content-skeleton-line:nth-child(5) { width: 96%; margin-top: 8px; }
|
|
1609
|
+
.chapter-content-skeleton-line:nth-child(6) { width: 88%; }
|
|
1610
|
+
.chapter-content-skeleton-line:nth-child(7) { width: 73%; }
|
|
1611
|
+
.chapter-content-skeleton-line:nth-child(8) { width: 38%; }
|
|
1612
|
+
@media (prefers-reduced-motion: reduce) { .chapter-content-skeleton-line::after { animation: none; } }
|
|
1601
1613
|
.chapter-whitespace-overlay { position: relative; z-index: 2; grid-column: 2; grid-row: 1; width: 100%; height: 100%; overflow: hidden; opacity: 0; pointer-events: none; }
|
|
1602
1614
|
.chapter-whitespace-overlay.is-visible { opacity: 1; }
|
|
1603
1615
|
#chapter-whitespace-inner { box-sizing: border-box; min-height: 100%; color: transparent; white-space: pre-wrap; }
|
|
@@ -4575,6 +4587,7 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
|
|
|
4575
4587
|
.editor-view .editor-actions > button { min-width: 0; min-height: 34px; padding-inline: 6px; font-size: 11px; }
|
|
4576
4588
|
.chapter-title { font-size: 18px; }
|
|
4577
4589
|
.chapter-content { padding: 22px 16px 64px 12px; font-size: max(16px, var(--editor-font-size)); }
|
|
4590
|
+
.chapter-content-skeleton { gap: 14px; padding: 26px 16px 64px 12px; }
|
|
4578
4591
|
.app-shell.editor-typewriter-mode .chapter-content { padding-bottom: max(64px, 45dvh); }
|
|
4579
4592
|
.chapter-line-numbers { width: 32px; font-size: 11px; }
|
|
4580
4593
|
.chapter-editor-scroll { grid-template-columns: 32px minmax(0, 1fr); }
|
package/dist/version.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const APP_VERSION = "1.1.
|
|
1
|
+
export const APP_VERSION = "1.1.5";
|
|
2
2
|
export const SCRIVERSE_BETA_COMMIT_ENV = "SCRIVERSE_BETA_COMMIT";
|
|
3
3
|
export function resolveBetaVersionLabel(environment) {
|
|
4
4
|
const commit = environment[SCRIVERSE_BETA_COMMIT_ENV]?.trim().toLocaleLowerCase() ?? "";
|