@waterwx/dsh-novel-forge 1.1.5 → 1.1.7

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/lib/client.js CHANGED
@@ -71,6 +71,8 @@ window.__ModuleLoader__.load({
71
71
  reviewBackfill: "/api/dsh-novel-forge/review/backfill",
72
72
  /** 章节复位:generating 卡死 → pending(可重新生成)。 */
73
73
  chapterReset: "/api/dsh-novel-forge/chapter/reset",
74
+ /** 章节直接通过:作者对 rejected/written 章节行使最终决定权。 */
75
+ chapterApprove: "/api/dsh-novel-forge/chapter/approve",
74
76
  /** 敏感词检查:全书已写章节或指定文本。 */
75
77
  sensitiveCheck: "/api/dsh-novel-forge/sensitive-check",
76
78
  config: "/api/dsh-novel-forge/config",
@@ -228,6 +230,10 @@ window.__ModuleLoader__.load({
228
230
  async chapterReset(no) {
229
231
  return postJson(NOVEL_API.chapterReset, { chapterNo: no });
230
232
  }
233
+ /** 章节直接通过(作者行使最终决定权)。 */
234
+ async chapterApprove(no) {
235
+ return postJson(NOVEL_API.chapterApprove, { chapterNo: no });
236
+ }
231
237
  /** 角色库:AI 提炼 / 采纳 / 更新 / 删除。 */
232
238
  async roles(req) {
233
239
  return postJson(NOVEL_API.roles, req);
@@ -765,6 +771,49 @@ window.__ModuleLoader__.load({
765
771
  if (params !== void 0) for (const [name, value] of Object.entries(params)) text = text.replaceAll(`{${name}}`, String(value));
766
772
  return text;
767
773
  }
774
+ /** 角色定位中文名(角色库/提炼候选共用,收敛自多份复制)。 */
775
+ const ROLE_LABELS = {
776
+ protagonist: "主角",
777
+ female_lead: "女主",
778
+ female_support: "女配",
779
+ support: "配角",
780
+ antagonist: "反派",
781
+ extra: "路人"
782
+ };
783
+ /** 角色定位徽章颜色。 */
784
+ function roleColor(label) {
785
+ if (label === "protagonist") return "var(--nf-success)";
786
+ if (label === "female_lead") return "var(--nf-accent)";
787
+ if (label === "antagonist") return "var(--nf-error)";
788
+ return "var(--nf-text-3)";
789
+ }
790
+ /** 剧情线类型中文名(与 locale 对齐)。 */
791
+ function kindLabel(kind) {
792
+ switch (kind) {
793
+ case "main": return tt("plotlines.kindMain");
794
+ case "branch": return tt("plotlines.kindBranch");
795
+ case "character": return tt("plotlines.kindCharacter");
796
+ case "mystery": return tt("plotlines.kindMystery");
797
+ default: return kind;
798
+ }
799
+ }
800
+ /** 剧情线状态中文名。 */
801
+ function plotlineStatusLabel(status) {
802
+ switch (status) {
803
+ case "active": return tt("plotlines.statusActive");
804
+ case "paused": return tt("plotlines.statusPaused");
805
+ case "resolved": return tt("plotlines.statusResolved");
806
+ case "abandoned": return tt("plotlines.statusAbandoned");
807
+ default: return status;
808
+ }
809
+ }
810
+ /** 剧情线状态颜色。 */
811
+ function plotlineStatusColor(status) {
812
+ if (status === "resolved") return "var(--nf-success)";
813
+ if (status === "abandoned") return "var(--nf-text-3)";
814
+ if (status === "paused") return "var(--nf-warn)";
815
+ return "var(--nf-accent)";
816
+ }
768
817
  //#endregion
769
818
  //#region \0dsh-css:C:\Users\Ryan\Desktop\111\novel-forge\src\client\panel\panel.module.css.mjs
770
819
  const css = ".CUIYUW_entry{width:100%;color:var(--dsw-alias-label-primary,#1f1f23);cursor:pointer;text-align:left;background:0 0;border:none;border-radius:6px;align-items:center;gap:8px;padding:8px 12px;font-size:13px;transition:background .15s;display:flex}body[data-ds-dark-theme] .CUIYUW_entry{color:var(--dsw-alias-label-primary,#ececf1)}.CUIYUW_entry:hover{background:var(--dsw-alias-interactive-bg-hover,#7f7f7f1f)}.CUIYUW_entry[data-active]{background:var(--dsw-alias-interactive-bg-active,#7f7f7f33)}.CUIYUW_entryIcon{flex-shrink:0;justify-content:center;align-items:center;display:inline-flex}.CUIYUW_entryLabel{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}[data-pane=conversation]{position:relative}.CUIYUW_view{z-index:60;color-scheme:light;--nf-font:-apple-system, BlinkMacSystemFont, \"SF Pro Display\", \"SF Pro Text\", \"PingFang SC\", \"Hiragino Sans GB\", \"Microsoft YaHei\", \"Segoe UI\", Roboto, \"Helvetica Neue\", sans-serif;--nf-font-mono:ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;--nf-bg:#f2f2f7db;--nf-bg-raise:#ffffffb8;--nf-bg-inset:#7676801f;--nf-border:#3c3c4329;--nf-border-strong:#3c3c4352;--nf-text:#1c1c1e;--nf-text-2:#3c3c43;--nf-text-2-alpha:#3c3c43ad;--nf-text-3:#8e8e93;--nf-accent:#00b85c;--nf-accent-hover:#00a04e;--nf-accent-soft:#00b85c1f;--nf-accent-fg:#fff;--nf-hover:#0000000d;--nf-success:#34c759;--nf-error:#ff3b30;--nf-warn:#ff9500;--nf-info:#00b85c;--nf-shadow:0 1px 3px #0000000f, 0 12px 32px #00000014;--nf-shadow-lg:0 4px 12px #00000012, 0 20px 48px #0000001f;--nf-card-shadow:0 2px 6px #0000000f, 0 14px 38px #00000024;--nf-card-shadow-hover:0 4px 10px #00000014, 0 22px 52px #0003;--nf-glass-face:linear-gradient(180deg, #f6f7f9 0%, #f0f2f5 26%, #e9ebef 52%, #e0e3e8 78%, #d6d9df 100%);--nf-glass-core:radial-gradient(30% 24% at 36% 28%, #ffffff80 0%, #ffffff38 45%, #fff0 78%);--nf-glass-sheen:#ffffff8c;--nf-glass-border:#ffffffa6;--nf-glass-inset:#ffffff8c;--nf-glass-orb-a:#00b85c24;--nf-glass-orb-b:#78a0ff1a;--nf-glass-noise:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)'/%3E%3C/svg%3E\");background:var(--nf-bg);backdrop-filter:blur(32px)saturate(180%);color:var(--nf-text);font-family:-apple-system,BlinkMacSystemFont,SF Pro Display,SF Pro Text,PingFang SC,Hiragino Sans GB,Microsoft YaHei,Segoe UI,Roboto,Helvetica Neue,sans-serif;display:none;position:absolute;inset:0;overflow:auto}body[data-ds-dark-theme] .CUIYUW_view{color-scheme:dark;--nf-bg:#0a0b0ddb;--nf-bg-raise:#1c1c1ec7;--nf-bg-inset:#7676802e;--nf-border:#ffffff1f;--nf-border-strong:#ffffff47;--nf-text:#f2f2f7;--nf-text-2:#d1d1d6;--nf-text-2-alpha:#d1d1d6b8;--nf-text-3:#8e8e93;--nf-accent:#35d07a;--nf-accent-hover:#5ce695;--nf-accent-soft:#35d07a33;--nf-accent-fg:#062b18;--nf-hover:#ffffff17;--nf-success:#30d158;--nf-error:#ff453a;--nf-warn:#ff9f0a;--nf-info:#35d07a;--nf-shadow:0 1px 2px #00000059, 0 10px 30px #0006;--nf-shadow-lg:0 4px 12px #0006, 0 20px 48px #0000008c;--nf-card-shadow:0 2px 6px #00000059, 0 14px 38px #00000073;--nf-card-shadow-hover:0 4px 10px #0006, 0 22px 52px #0000008c;--nf-glass-face:linear-gradient(180deg, #70747a6b 0%, #60646a6b 26%, #52555a6b 52%, #44474c6b 78%, #383a3f6b 100%);--nf-glass-core:radial-gradient(30% 24% at 36% 28%, #ffffff42 0%, #ffffff1a 45%, #fff0 78%);--nf-glass-sheen:#ffffff42;--nf-glass-border:#ffffff24;--nf-glass-inset:#ffffff12;--nf-glass-orb-a:#00ca5233;--nf-glass-orb-b:#bec8d712;--nf-glass-noise:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)'/%3E%3C/svg%3E\")}html[data-dsh-novelforge-active]:not([data-dsh-taskboard-active]):not([data-dsh-ssh-active]) .CUIYUW_view{display:block}.CUIYUW_panel[data-nf-theme=classic]{--nf-accent:#007aff;--nf-accent-hover:#0071e3;--nf-accent-soft:#007aff1f;--nf-accent-fg:#fff;--nf-info:#5856d6;--nf-glass-face:var(--nf-bg-raise);--nf-glass-core:transparent;--nf-glass-sheen:#fff0;--nf-glass-border:var(--nf-border);--nf-glass-inset:var(--nf-bg-inset);--nf-glass-orb-a:transparent;--nf-glass-orb-b:transparent;--nf-glass-noise:none}body[data-ds-dark-theme] .CUIYUW_panel[data-nf-theme=classic]{--nf-accent:#0a84ff;--nf-accent-hover:#3a9bff;--nf-accent-soft:#0a84ff33;--nf-accent-fg:#fff;--nf-info:#bf5af2;--nf-glass-face:var(--nf-bg-raise);--nf-glass-core:transparent;--nf-glass-sheen:#fff0;--nf-glass-border:var(--nf-border);--nf-glass-inset:var(--nf-bg-inset);--nf-glass-orb-a:transparent;--nf-glass-orb-b:transparent;--nf-glass-noise:none}body:not([data-ds-dark-theme]) .CUIYUW_panel[data-nf-theme=neumorph]{--nf-bg:#e4e9f2;--nf-bg-raise:#e4e9f2;--nf-bg-inset:#d9dfe8;--nf-border:#8c9baf59;--nf-border-strong:#78879e80;--nf-text:#3a4250;--nf-text-2:#5b6472;--nf-text-2-alpha:#465060b3;--nf-text-3:#8b94a3;--nf-hover:#5a697d14;--nf-shadow:4px 4px 10px #a3b1c68c, -4px -4px 10px #ffffffd9;--nf-shadow-lg:6px 6px 14px #a3b1c699, -6px -6px 14px #ffffffe6;--nf-card-shadow:9px 9px 18px #a3b1c68c, -9px -9px 18px #ffffffd9;--nf-card-shadow-hover:12px 12px 24px #a3b1c6a6, -12px -12px 24px #fffffff2;--nf-glass-face:#e4e9f2;--nf-glass-core:transparent;--nf-glass-sheen:#fff0;--nf-glass-border:#a3b1c666;--nf-glass-inset:#d9dfe8;--nf-glass-orb-a:transparent;--nf-glass-orb-b:transparent;--nf-glass-noise:none}body[data-ds-dark-theme] .CUIYUW_panel[data-nf-theme=neumorph]{--nf-bg:#2b2f36;--nf-bg-raise:#2b2f36;--nf-bg-inset:#25292f;--nf-border:#0a0c1080;--nf-border-strong:#080a0e99;--nf-text:#d6dae1;--nf-text-2:#a8aeb8;--nf-text-2-alpha:#a8aeb8b3;--nf-text-3:#757c88;--nf-hover:#ffffff0d;--nf-shadow:4px 4px 10px #00000080, -4px -4px 10px #6068763d;--nf-shadow-lg:6px 6px 14px #0000008c, -6px -6px 14px #60687642;--nf-card-shadow:9px 9px 18px #00000080, -9px -9px 18px #6068763d;--nf-card-shadow-hover:12px 12px 24px #0009, -12px -12px 24px #60687647;--nf-glass-face:#2b2f36;--nf-glass-core:transparent;--nf-glass-sheen:#fff0;--nf-glass-border:#0c0e1273;--nf-glass-inset:#25292f;--nf-glass-orb-a:transparent;--nf-glass-orb-b:transparent;--nf-glass-noise:none}body:not([data-ds-dark-theme]) .CUIYUW_panel[data-nf-theme=neumorph] .CUIYUW_input,body:not([data-ds-dark-theme]) .CUIYUW_panel[data-nf-theme=neumorph] .CUIYUW_textarea{background:var(--nf-bg-inset);border-color:#0000;box-shadow:inset 3px 3px 7px #a3b1c68c,inset -3px -3px 7px #ffffffe6}body:not([data-ds-dark-theme]) .CUIYUW_panel[data-nf-theme=neumorph] .CUIYUW_input:focus,body:not([data-ds-dark-theme]) .CUIYUW_panel[data-nf-theme=neumorph] .CUIYUW_textarea:focus{border-color:var(--nf-accent);box-shadow:inset 2px 2px 6px #a3b1c680, inset -2px -2px 6px #ffffffd9, 0 0 0 3px var(--nf-accent-soft)}body[data-ds-dark-theme] .CUIYUW_panel[data-nf-theme=neumorph] .CUIYUW_input,body[data-ds-dark-theme] .CUIYUW_panel[data-nf-theme=neumorph] .CUIYUW_textarea{background:var(--nf-bg-inset);border-color:#0000;box-shadow:inset 3px 3px 7px #0000008c,inset -3px -3px 7px #6068763d}body[data-ds-dark-theme] .CUIYUW_panel[data-nf-theme=neumorph] .CUIYUW_input:focus,body[data-ds-dark-theme] .CUIYUW_panel[data-nf-theme=neumorph] .CUIYUW_textarea:focus{border-color:var(--nf-accent);box-shadow:inset 2px 2px 6px #00000080, inset -2px -2px 6px #60687638, 0 0 0 3px var(--nf-accent-soft)}body:not([data-ds-dark-theme]) .CUIYUW_panel[data-nf-theme=neumorph] .CUIYUW_button{background:var(--nf-bg-raise);border-color:#0000;box-shadow:5px 5px 10px #a3b1c68c,-5px -5px 10px #ffffffe6}body:not([data-ds-dark-theme]) .CUIYUW_panel[data-nf-theme=neumorph] .CUIYUW_button:hover:not([disabled]){background:var(--nf-bg-raise);border-color:#0000;box-shadow:7px 7px 14px #a3b1c699,-7px -7px 14px #fffffff2}body:not([data-ds-dark-theme]) .CUIYUW_panel[data-nf-theme=neumorph] .CUIYUW_button:active:not([disabled]){box-shadow:inset 3px 3px 7px #a3b1c68c,inset -3px -3px 7px #ffffffe6}body:not([data-ds-dark-theme]) .CUIYUW_panel[data-nf-theme=neumorph] .CUIYUW_buttonPrimary{background:linear-gradient(#00c563,#00a952);box-shadow:5px 5px 10px #a3b1c699,-5px -5px 10px #ffffffd9}body[data-ds-dark-theme] .CUIYUW_panel[data-nf-theme=neumorph] .CUIYUW_button{background:var(--nf-bg-raise);border-color:#0000;box-shadow:5px 5px 10px #00000080,-5px -5px 10px #6068763d}body[data-ds-dark-theme] .CUIYUW_panel[data-nf-theme=neumorph] .CUIYUW_button:hover:not([disabled]){background:var(--nf-bg-raise);border-color:#0000;box-shadow:7px 7px 14px #0000008c,-7px -7px 14px #60687642}body[data-ds-dark-theme] .CUIYUW_panel[data-nf-theme=neumorph] .CUIYUW_button:active:not([disabled]){box-shadow:inset 3px 3px 7px #0000008c,inset -3px -3px 7px #6068763d}body[data-ds-dark-theme] .CUIYUW_panel[data-nf-theme=neumorph] .CUIYUW_buttonPrimary{background:linear-gradient(#3ddc86,#27b96a);box-shadow:5px 5px 10px #00000080,-5px -5px 10px #6068763d}.CUIYUW_panel{flex-direction:column;min-width:0;height:100%;font-size:14px;line-height:1.6;display:flex;position:relative;overflow:hidden}.CUIYUW_panel:before{content:\"\";z-index:0;pointer-events:none;background:radial-gradient(46% 36% at 18% 12%, var(--nf-glass-orb-a), transparent 70%), radial-gradient(52% 42% at 88% 22%, var(--nf-glass-orb-b), transparent 72%), radial-gradient(120% 95% at 50% 42%, transparent 55%, #0202031a 100%);position:absolute;inset:0}.CUIYUW_panelHeader{border:1px solid var(--nf-glass-border);background:var(--nf-glass-face);box-shadow:var(--nf-shadow), inset 0 1px 0 var(--nf-glass-sheen);backdrop-filter:blur(28px)saturate(175%);z-index:5;border-radius:18px;flex-shrink:0;justify-content:space-between;align-items:center;margin:10px 12px 0;padding:10px 16px;display:flex;position:sticky;top:10px}.CUIYUW_panelTitle{letter-spacing:.2px;align-items:center;gap:8px;margin:0;font-size:16px;font-weight:700;display:flex}.CUIYUW_panelTitle:before{content:\"\";background:linear-gradient(180deg, var(--nf-accent), var(--nf-info));border-radius:2px;width:4px;height:16px}.CUIYUW_iconButton{cursor:pointer;color:var(--nf-text-2);background:0 0;border:none;border-radius:8px;padding:4px 9px;font-size:16px;transition:background .15s,color .15s}.CUIYUW_iconButton:hover{background:var(--nf-hover);color:var(--nf-text)}.CUIYUW_tabBar{border-bottom:1px solid var(--nf-border);background:var(--nf-bg-raise);z-index:4;flex-shrink:0;gap:2px;padding:8px 14px 0;display:flex;position:sticky;top:45px}.CUIYUW_tab{cursor:pointer;color:var(--nf-text-2);background:0 0;border:none;border-radius:8px 8px 0 0;padding:7px 13px;font-size:13.5px;font-weight:500;transition:color .15s,background .15s;position:relative}.CUIYUW_tab:hover{color:var(--nf-text);background:var(--nf-hover)}.CUIYUW_tab[data-active]{color:var(--nf-accent);font-weight:600}.CUIYUW_tab[data-active]:after{content:\"\";background:var(--nf-accent);border-radius:2px 2px 0 0;height:2.5px;position:absolute;bottom:-1px;left:10px;right:10px}.CUIYUW_panelContent{z-index:1;flex-direction:column;flex:1;gap:14px;padding:16px 18px 20px;display:flex;position:relative;overflow:auto}.CUIYUW_panelBody{z-index:1;flex:1;min-height:0;display:flex;position:relative}.CUIYUW_panelNav{border:1px solid var(--nf-glass-border);background:var(--nf-glass-face);width:142px;box-shadow:var(--nf-shadow), inset 0 1px 0 var(--nf-glass-sheen);backdrop-filter:blur(28px)saturate(175%);border-radius:16px;flex-direction:column;flex:none;align-self:flex-start;gap:4px;margin:10px 0 10px 12px;padding:10px 8px;transition:width .18s;display:flex;overflow-y:auto}.CUIYUW_panelNavCollapsed{width:52px;padding:10px 6px}.CUIYUW_navGroup{flex-direction:column;gap:4px;display:flex}.CUIYUW_navGroupLabel{letter-spacing:.6px;text-transform:uppercase;color:var(--nf-text-3);user-select:none;padding:8px 10px 3px;font-size:10.5px;font-weight:600}.CUIYUW_navGroupSep{background:var(--nf-border);height:1px;margin:6px 8px 4px}.CUIYUW_navSpacer{flex:1;min-height:8px}.CUIYUW_navAbout{border-top:1px solid var(--nf-border);flex-direction:column;flex:none;gap:4px;margin-top:4px;padding:8px 6px 4px;display:flex}.CUIYUW_navAboutRow{cursor:pointer;color:var(--nf-text-3);text-align:left;white-space:nowrap;background:0 0;border:none;border-radius:8px;justify-content:space-between;align-items:center;gap:4px;padding:4px 6px;font-size:11px;transition:color .15s,background .15s;display:flex}.CUIYUW_navAboutRow:hover{color:var(--nf-text);background:var(--nf-hover)}.CUIYUW_navAboutUpdate{background:var(--nf-accent-soft);color:var(--nf-accent);cursor:pointer;text-align:left;white-space:nowrap;border:none;border-radius:8px;padding:4px 6px;font-size:10.5px;font-weight:600}.CUIYUW_navAboutUpdate:hover{color:var(--nf-accent-hover)}.CUIYUW_panelNavCollapsed .CUIYUW_navAbout{align-items:center;padding:6px 2px 2px}.CUIYUW_panelNavCollapsed .CUIYUW_navAboutRow{justify-content:center;width:100%;padding:4px 0}.CUIYUW_navTabBadge{background:var(--nf-accent);color:#fff;text-align:center;border-radius:999px;flex:none;min-width:18px;height:18px;margin-left:auto;padding:0 5px;font-size:10.5px;font-weight:700;line-height:18px;display:inline-block}.CUIYUW_panelNavCollapsed .CUIYUW_navTabBadge{min-width:14px;height:14px;padding:0 3px;font-size:9px;line-height:14px;position:absolute;top:2px;right:2px}.CUIYUW_navTabBadgeDanger{background:var(--nf-error)}.CUIYUW_navTabBadgeWarn{background:var(--nf-warn)}.CUIYUW_navTabBadgeDone{background:var(--nf-success)}.CUIYUW_navTab{cursor:pointer;width:100%;color:var(--nf-text-2-alpha,var(--nf-text-2));text-align:left;white-space:nowrap;background:0 0;border:none;border-radius:12px;align-items:center;gap:8px;padding:8px 10px;font-size:13px;font-weight:500;transition:color .15s,background .15s;display:flex;position:relative}.CUIYUW_panelNavCollapsed .CUIYUW_navTab{justify-content:center;padding:8px 0}.CUIYUW_navTab:hover{color:var(--nf-text);background:var(--nf-hover)}.CUIYUW_navTab[data-active]{color:var(--nf-accent);background:var(--nf-accent-soft);font-weight:600}.CUIYUW_navTab[data-active]:before{content:\"\";background:var(--nf-accent);border-radius:999px;width:3px;position:absolute;top:20%;bottom:20%;left:-8px}.CUIYUW_panelNavCollapsed .CUIYUW_navTab[data-active]:before{left:-6px}.CUIYUW_navTabIcon{flex:none;font-size:15px;line-height:1}.CUIYUW_navTabLabel{text-overflow:ellipsis;overflow:hidden}.CUIYUW_panelSubtitle{color:var(--nf-text-2);white-space:nowrap;flex-wrap:wrap;align-items:center;gap:8px;min-width:0;padding:0 4px 2px;font-size:12px;display:flex}.CUIYUW_headerProgress{color:var(--nf-text-2);white-space:nowrap;align-items:center;gap:6px;margin-left:0;font-size:12px;font-weight:400;display:inline-flex}.CUIYUW_headerProgress b{color:var(--nf-accent);font-weight:700}.CUIYUW_headerProgressDot{background:var(--nf-border-strong,var(--nf-text-3));border-radius:50%;width:3px;height:3px;display:inline-block}.CUIYUW_card{border:1px solid var(--nf-glass-border);background:var(--nf-glass-face);box-shadow:var(--nf-card-shadow), inset 0 1.5px 0 var(--nf-glass-sheen), inset 0 -1px 0 #ffffff40;backdrop-filter:blur(30px)saturate(180%);border-radius:22px;flex-direction:column;gap:10px;padding:16px 18px;transition:transform .22s,box-shadow .22s;display:flex;position:relative}.CUIYUW_card:before{content:\"\";border-radius:inherit;pointer-events:none;background:var(--nf-glass-core), linear-gradient(90deg, transparent, var(--nf-glass-sheen), transparent) no-repeat 10% 0 / 80% 1px, linear-gradient(156deg, #ffffff42 0%, #fff0 55%);z-index:0;position:absolute;inset:0}.CUIYUW_card:after{content:\"\";border-radius:inherit;pointer-events:none;background:var(--nf-glass-noise);opacity:.06;z-index:0;position:absolute;inset:0}.CUIYUW_card:hover{box-shadow:var(--nf-card-shadow-hover), inset 0 1.5px 0 var(--nf-glass-sheen), inset 0 -1px 0 #ffffff40;transform:translateY(-3px)}.CUIYUW_card>*{z-index:1;position:relative}.CUIYUW_cardTitle{color:var(--nf-text);align-items:center;gap:8px;margin:0;font-size:14px;font-weight:650;display:flex}.CUIYUW_button{border:1px solid var(--nf-border-strong);background:var(--nf-bg-inset);color:var(--nf-text);cursor:pointer;white-space:nowrap;border-radius:12px;padding:6px 14px;font-size:13px;font-weight:500;transition:background .15s,border-color .15s,transform .1s,box-shadow .15s}.CUIYUW_button:hover:not([disabled]){background:var(--nf-hover);border-color:var(--nf-border-strong)}.CUIYUW_button:active:not([disabled]){transform:scale(.96)}.CUIYUW_button[disabled]{opacity:.45;cursor:not-allowed}.CUIYUW_buttonPrimary{background:linear-gradient(180deg, color-mix(in srgb, var(--nf-accent) 88%, #fff), var(--nf-accent));color:var(--nf-accent-fg);box-shadow:0 2px 10px color-mix(in srgb, var(--nf-accent) 45%, transparent), 0 0 0 .5px color-mix(in srgb, var(--nf-accent) 30%, transparent);border-color:#0000}.CUIYUW_buttonPrimary:hover:not([disabled]){background:linear-gradient(180deg, var(--nf-accent-hover), color-mix(in srgb, var(--nf-accent-hover) 85%, #000));border-color:#0000}.CUIYUW_buttonDanger{border-color:var(--nf-error);color:var(--nf-error)}.CUIYUW_buttonDanger:hover:not([disabled]){background:#ff3b301a}.CUIYUW_buttonSmall{border-radius:9px;padding:3px 10px;font-size:12px}.CUIYUW_field{flex-direction:column;gap:5px;display:flex}.CUIYUW_fieldLabel{color:var(--nf-text-2);font-size:12px;font-weight:500}.CUIYUW_input{border:1px solid var(--nf-border-strong);background:var(--nf-bg-inset);color:var(--nf-text);box-sizing:border-box;border-radius:12px;width:100%;padding:7px 11px;font-size:13px;transition:border-color .15s,box-shadow .15s}.CUIYUW_input:focus,.CUIYUW_textarea:focus{border-color:var(--nf-accent);box-shadow:0 0 0 3px var(--nf-accent-soft);outline:none}.CUIYUW_input::placeholder,.CUIYUW_textarea::placeholder{color:var(--nf-text-3)}.CUIYUW_textarea{border:1px solid var(--nf-border-strong);background:var(--nf-bg-inset);color:var(--nf-text);box-sizing:border-box;resize:vertical;border-radius:12px;width:100%;min-height:200px;padding:9px 11px;font-family:inherit;font-size:13px;line-height:1.7;transition:border-color .15s,box-shadow .15s}.CUIYUW_row{flex-wrap:wrap;align-items:center;gap:8px;display:flex}.CUIYUW_spaceBetween{justify-content:space-between}.CUIYUW_chapterList{flex-direction:column;gap:8px;display:flex}.CUIYUW_volumeGroup{flex-direction:column;gap:6px;display:flex}.CUIYUW_volumeGroupHeader{background:var(--nf-bg-inset);border:1px solid var(--nf-border);cursor:pointer;user-select:none;border-radius:10px;align-items:center;gap:8px;padding:6px 10px;font-size:13px;transition:border-color .15s;display:flex}.CUIYUW_volumeGroupHeader:hover{border-color:var(--nf-accent)}.CUIYUW_volumeGroupToggle{color:var(--nf-text-2);flex:none;font-size:11px}.CUIYUW_chapter{border:1px solid var(--nf-border);background:var(--nf-bg);border-radius:10px;align-items:center;gap:10px;padding:9px 12px;transition:border-color .15s,box-shadow .15s,transform .1s;display:flex}.CUIYUW_chapter:hover{border-color:var(--nf-border-strong);box-shadow:var(--nf-shadow)}.CUIYUW_chapterNum{background:var(--nf-bg-inset);border:1px solid var(--nf-border);min-width:28px;height:28px;color:var(--nf-text-2);border-radius:8px;flex-shrink:0;justify-content:center;align-items:center;padding:0 8px;font-size:12px;font-weight:700;display:inline-flex}.CUIYUW_chapterMain{flex:1;min-width:0}.CUIYUW_chapterTitle{color:var(--nf-text);align-items:center;gap:8px;font-size:13px;font-weight:600;display:flex}.CUIYUW_chapterBeats{color:var(--nf-text-2);opacity:.85;text-overflow:ellipsis;white-space:nowrap;font-size:12px;overflow:hidden}.CUIYUW_chapterActions{opacity:.85;flex-shrink:0;gap:4px;transition:opacity .15s;display:flex}.CUIYUW_chapter:hover .CUIYUW_chapterActions{opacity:1}.CUIYUW_badge{white-space:nowrap;letter-spacing:.2px;border:1px solid;border-radius:999px;padding:2px 9px;font-size:11px;font-weight:600}.CUIYUW_badgePending{color:var(--nf-info);border-color:var(--nf-info);background:color-mix(in srgb, var(--nf-info) 10%, transparent)}.CUIYUW_badgeGenerating{color:var(--nf-accent);border-color:var(--nf-accent);background:color-mix(in srgb, var(--nf-accent) 12%, transparent);animation:1.2s ease-in-out infinite CUIYUW_pulse}.CUIYUW_badgeWritten{color:var(--nf-warn);border-color:var(--nf-warn);background:color-mix(in srgb, var(--nf-warn) 10%, transparent)}.CUIYUW_badgeRejected{color:var(--nf-error);border-color:var(--nf-error);background:color-mix(in srgb, var(--nf-error) 10%, transparent)}.CUIYUW_badgeDone{color:var(--nf-success);border-color:var(--nf-success);background:color-mix(in srgb, var(--nf-success) 10%, transparent)}.CUIYUW_badgeError{color:var(--nf-error);border-color:var(--nf-error);background:color-mix(in srgb, var(--nf-error) 10%, transparent)}.CUIYUW_reviewBox{border:1px solid var(--nf-border);background:var(--nf-bg-inset);border-radius:10px;flex-direction:column;gap:6px;padding:10px 12px;font-size:12.5px;display:flex}.CUIYUW_chapterPreview{white-space:pre-wrap;word-break:break-all;max-height:320px;color:var(--nf-text);background:var(--nf-bg-inset);border:1px solid var(--nf-border);border-radius:10px;margin:0;padding:10px 12px;font-family:inherit;font-size:12.5px;line-height:1.8;overflow:auto}.CUIYUW_chatScroll{border:1px solid var(--nf-border);background:var(--nf-bg-inset);border-radius:12px;flex-direction:column;flex:1;gap:10px;min-height:240px;max-height:480px;padding:14px;display:flex;overflow-y:auto}.CUIYUW_chatBubbleUser{background:linear-gradient(180deg, var(--nf-accent), var(--nf-accent-hover));max-width:90%;color:var(--nf-accent-fg);border-radius:14px 14px 4px;align-self:flex-end;padding:9px 14px;font-size:13px;box-shadow:0 2px 6px #4d6bfe33}.CUIYUW_chatBubbleAssistant{background:var(--nf-bg-raise);max-width:92%;color:var(--nf-text);border:1px solid var(--nf-border);box-shadow:var(--nf-shadow);border-radius:14px 14px 14px 4px;align-self:flex-start;padding:9px 14px;font-size:13px}.CUIYUW_chatRole{color:var(--nf-text-3);margin-bottom:3px;font-size:11px;font-weight:600}.CUIYUW_toolLive{background:var(--nf-bg-inset);border:1px dashed var(--nf-border-strong);white-space:pre-wrap;word-break:break-all;color:var(--nf-text-2);border-radius:8px;max-height:180px;margin-top:6px;padding:8px 10px;font-size:12px;line-height:1.7;overflow-y:auto}.CUIYUW_assistantStatus{color:var(--nf-text-2);background:var(--nf-bg-inset);border:1px solid var(--nf-border);border-radius:999px;flex:none;align-items:center;gap:6px;margin-top:6px;padding:6px 12px;font-size:12px;display:flex}.CUIYUW_assistantStatusBusy{color:var(--nf-accent);border-color:var(--nf-accent);background:var(--nf-accent-soft);font-weight:600}.CUIYUW_toolSteps{flex-direction:column;gap:4px;margin-top:6px;display:flex}.CUIYUW_toolStep{background:var(--nf-bg-inset);border:1px solid var(--nf-border);border-radius:8px;align-items:center;gap:8px;padding:5px 10px;font-size:12px;display:flex}.CUIYUW_toolStepActive{border-color:var(--nf-accent);background:var(--nf-accent-soft)}.CUIYUW_toolStepError{border-color:var(--nf-error);background:color-mix(in srgb, var(--nf-error) 8%, transparent)}.CUIYUW_toolStepIcon{flex:none;font-size:13px}.CUIYUW_toolStepName{text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;font-weight:600;overflow:hidden}.CUIYUW_toolStepStatus{color:var(--nf-text-2);flex:none;font-size:11px}.CUIYUW_toolStepActive .CUIYUW_toolStepStatus{color:var(--nf-accent)}.CUIYUW_toolStepError .CUIYUW_toolStepStatus{color:var(--nf-error)}.CUIYUW_toolStepDetail{width:100%;color:var(--nf-error);word-break:break-all;font-size:11px}.CUIYUW_progress{border:1px solid var(--nf-border);white-space:pre-wrap;word-break:break-all;min-height:60px;max-height:220px;color:var(--nf-text-2);font-size:12px;font-family:var(--nf-font-mono);background:var(--nf-bg-inset);border-radius:10px;padding:10px 14px;line-height:1.8;overflow:auto}.CUIYUW_progressLine{color:var(--nf-text-2);opacity:.9}.CUIYUW_progressLineLive{color:var(--nf-accent);align-items:center;gap:8px;font-weight:600;display:flex}.CUIYUW_progressBar{background:var(--nf-border);border-radius:999px;flex:none;width:110px;height:6px;display:inline-block;overflow:hidden}.CUIYUW_progressBarFill{background:var(--nf-accent);border-radius:3px;height:100%;transition:width .3s;display:block}.CUIYUW_busyRow{flex-wrap:wrap;justify-content:space-between;align-items:center;gap:12px;display:flex}.CUIYUW_liveText{font-variant-numeric:tabular-nums;color:var(--nf-text-2);font-size:12px}.CUIYUW_bigProgressBar{background:var(--nf-border);border-radius:999px;height:8px;margin-top:10px;overflow:hidden}.CUIYUW_bigProgressBarFill{background:linear-gradient(90deg, var(--nf-accent), var(--nf-accent-2,var(--nf-accent)));border-radius:999px;height:100%;transition:width .3s;display:block}.CUIYUW_diffLegend{flex-wrap:wrap;align-items:center;gap:14px;margin:6px 0 8px;font-size:12px;display:flex}.CUIYUW_legendOld{color:var(--nf-error);font-weight:700}.CUIYUW_legendNew{color:var(--nf-success);font-weight:700}.CUIYUW_onlyChanges{color:var(--nf-text-2);cursor:pointer;align-items:center;gap:4px;margin-left:auto;display:inline-flex}.CUIYUW_diffList{border:1px solid var(--nf-border);background:var(--nf-bg-inset);border-radius:8px;flex-direction:column;flex:1;gap:8px;min-height:0;padding:10px 12px;font-size:13px;line-height:1.7;display:flex;overflow-y:auto}.CUIYUW_diffSame{border:1px dashed var(--nf-border);color:var(--nf-text-2);opacity:.85;border-radius:6px;padding:6px 10px}.CUIYUW_diffSame summary{cursor:pointer;user-select:none;font-size:12px}.CUIYUW_diffSameBody{white-space:pre-wrap;margin-top:6px}.CUIYUW_diffChange{border:1px solid var(--nf-border);border-radius:8px;grid-template-columns:1fr 1fr;display:grid;overflow:hidden}.CUIYUW_diffColumn{flex-direction:column;gap:6px;min-width:0;padding:8px 10px;display:flex}.CUIYUW_diffColumn:first-child{border-right:1px solid var(--nf-border)}.CUIYUW_diffTagOld,.CUIYUW_diffTagNew{letter-spacing:.5px;border-radius:4px;flex:none;align-self:flex-start;padding:1px 7px;font-size:11px;font-weight:700}.CUIYUW_diffTagOld{color:var(--nf-error);background:color-mix(in srgb, var(--nf-error) 16%, transparent);border:1px solid color-mix(in srgb, var(--nf-error) 45%, transparent)}.CUIYUW_diffTagNew{color:var(--nf-success);background:color-mix(in srgb, var(--nf-success) 16%, transparent);border:1px solid color-mix(in srgb, var(--nf-success) 45%, transparent)}.CUIYUW_diffOld{color:var(--nf-error);white-space:pre-wrap;text-decoration:line-through;text-decoration-color:color-mix(in srgb, var(--nf-error) 55%, transparent)}.CUIYUW_diffNew{color:var(--nf-success);white-space:pre-wrap;font-weight:500}.CUIYUW_diffDel{border:1px solid color-mix(in srgb, var(--nf-error) 35%, transparent);background:color-mix(in srgb, var(--nf-error) 7%, transparent);border-radius:6px;flex-direction:column;gap:4px;padding:6px 10px;display:flex}.CUIYUW_diffAdd{border:1px solid color-mix(in srgb, var(--nf-success) 35%, transparent);background:color-mix(in srgb, var(--nf-success) 7%, transparent);border-radius:6px;flex-direction:column;gap:4px;padding:6px 10px;display:flex}.CUIYUW_diffText{white-space:pre-wrap}.CUIYUW_diffDel .CUIYUW_diffText{color:var(--nf-error);text-decoration:line-through;text-decoration-color:color-mix(in srgb, var(--nf-error) 50%, transparent)}.CUIYUW_diffAdd .CUIYUW_diffText{color:var(--nf-success)}.CUIYUW_wsPage{flex-direction:column;flex:1;gap:10px;min-height:0;display:flex}.CUIYUW_wsPageHeader{flex-wrap:wrap;flex:none;align-items:center;gap:8px;display:flex}.CUIYUW_wsColumns{flex:1;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:14px;min-height:0;display:grid}.CUIYUW_wsColumn{flex-direction:column;gap:8px;min-width:0;min-height:0;display:flex}.CUIYUW_wsEditor{resize:vertical;min-height:0;font-family:var(--nf-font);white-space:pre-wrap;flex:1;font-size:13px;line-height:1.75}.CUIYUW_wsSelected{border:1px solid var(--nf-accent);background:color-mix(in srgb, var(--nf-accent) 8%, transparent);border-radius:6px;max-height:120px;padding:6px 10px;overflow:auto}.CUIYUW_wsSelectedText{color:var(--nf-text-2);white-space:pre-wrap;margin-top:4px;font-size:12px}.CUIYUW_wsPreview{border:1px solid var(--nf-border);background:var(--nf-bg-inset);border-radius:8px;flex-direction:column;gap:8px;padding:8px 10px;display:flex}.CUIYUW_wsPreviewText{white-space:pre-wrap;min-height:0;color:var(--nf-text);flex:1;margin:0;font-size:13px;line-height:1.7;overflow:auto}.CUIYUW_assetGrid{grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:10px;display:grid}.CUIYUW_assetStat{border:1px solid var(--nf-glass-border);background:var(--nf-glass-inset);box-shadow:inset 0 1px 0 var(--nf-glass-sheen);border-radius:14px;flex-direction:column;gap:4px;padding:10px 12px;display:flex}.CUIYUW_assetStatLabel{color:var(--nf-text-2);opacity:.9;font-size:11px}.CUIYUW_assetStatValue{color:var(--nf-text);font-size:15px;font-weight:700;line-height:1.2}.CUIYUW_assetStatDetail{color:var(--nf-text-2);opacity:.85;text-overflow:ellipsis;white-space:nowrap;font-size:11px;overflow:hidden}.CUIYUW_dashHero{border:1px solid var(--nf-glass-border);background:var(--nf-glass-face);box-shadow:var(--nf-card-shadow), inset 0 1.5px 0 var(--nf-glass-sheen), inset 0 -1px 0 #ffffff40;backdrop-filter:blur(30px)saturate(180%);border-radius:22px;flex-direction:column;gap:14px;padding:18px 20px;transition:transform .22s,box-shadow .22s;display:flex;position:relative}.CUIYUW_dashHero:before{content:\"\";border-radius:inherit;pointer-events:none;background:radial-gradient(46% 40% at 92% -10%, color-mix(in srgb, var(--nf-accent) 13%, transparent), transparent 62%), var(--nf-glass-core), linear-gradient(90deg, transparent, var(--nf-glass-sheen), transparent) no-repeat 10% 0 / 80% 1px, linear-gradient(156deg, #ffffff42 0%, #fff0 55%);z-index:0;position:absolute;inset:0}.CUIYUW_dashHero:after{content:\"\";border-radius:inherit;pointer-events:none;background:var(--nf-glass-noise);opacity:.06;z-index:0;position:absolute;inset:0}.CUIYUW_dashHero:hover{box-shadow:var(--nf-card-shadow-hover), inset 0 1.5px 0 var(--nf-glass-sheen), inset 0 -1px 0 #ffffff40;transform:translateY(-3px)}.CUIYUW_dashHero>*{z-index:1;position:relative}.CUIYUW_dashHeroEyebrow{color:var(--nf-accent);align-items:center;gap:6px;font-size:13px;font-weight:600;display:inline-flex}.CUIYUW_dashHeroSparkle{font-size:14px}.CUIYUW_dashHeroTitle{flex-direction:column;gap:2px;display:flex}.CUIYUW_dashHeroBook{letter-spacing:-.3px;margin:0;font-size:24px;font-weight:700;line-height:1.25}.CUIYUW_dashHeroAction{border:1px solid var(--nf-glass-border);background:var(--nf-glass-inset);box-shadow:inset 0 1px 0 var(--nf-glass-sheen);border-radius:14px;align-items:center;gap:12px;padding:10px 14px;display:flex}.CUIYUW_dashHeroArrow{background:var(--nf-accent);color:#fff;border-radius:50%;flex:none;justify-content:center;align-items:center;width:28px;height:28px;font-size:14px;display:inline-flex}.CUIYUW_dashHeroActionBody{flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}.CUIYUW_dashHeroActionTitle{font-size:14px;font-weight:600}.CUIYUW_dashJourney{flex-direction:column;gap:6px;display:flex}.CUIYUW_dashJourneyBar{background:var(--nf-border);border-radius:999px;height:6px;overflow:hidden}.CUIYUW_dashJourneyFill{background:linear-gradient(90deg, var(--nf-info), var(--nf-accent));border-radius:999px;height:100%;transition:width .4s;display:block}.CUIYUW_dashJourneyStages{grid-template-columns:repeat(6,minmax(0,1fr));gap:4px;display:grid}.CUIYUW_dashStage{color:var(--nf-text-3);text-align:center;white-space:nowrap;flex-direction:column;align-items:center;gap:3px;font-size:11px;display:flex}.CUIYUW_dashStageDot{border:1px solid var(--nf-border-strong,var(--nf-text-3));background:var(--nf-bg-base);border-radius:50%;justify-content:center;align-items:center;width:18px;height:18px;font-size:10px;display:inline-flex}.CUIYUW_dashStageDone{color:var(--nf-text-2)}.CUIYUW_dashStageDone .CUIYUW_dashStageDot{background:var(--nf-success);border-color:var(--nf-success);color:#fff}.CUIYUW_dashStageCurrent{color:var(--nf-accent);font-weight:600}.CUIYUW_dashStageCurrent .CUIYUW_dashStageDot{border-color:var(--nf-accent);color:var(--nf-accent);box-shadow:0 0 0 3px color-mix(in srgb, var(--nf-accent) 18%, transparent)}.CUIYUW_dashFacts{border-top:1px solid var(--nf-border);grid-template-columns:repeat(4,minmax(0,1fr));gap:8px;padding-top:12px;display:grid}.CUIYUW_dashFact{flex-direction:column;gap:2px;min-width:0;display:flex}.CUIYUW_dashFact b{white-space:nowrap;text-overflow:ellipsis;font-size:13px;overflow:hidden}.CUIYUW_dashGrid{grid-template-columns:minmax(0,3fr) minmax(0,2fr);align-items:start;gap:14px;display:grid}.CUIYUW_todoItem{border:1px solid var(--nf-border);border-radius:8px;align-items:center;gap:10px;padding:8px 12px;font-size:12.5px;display:flex}.CUIYUW_todoDanger{border-color:color-mix(in srgb, var(--nf-error) 40%, transparent);background:color-mix(in srgb, var(--nf-error) 8%, transparent)}.CUIYUW_todoWarning{border-color:color-mix(in srgb, var(--nf-warn) 40%, transparent);background:color-mix(in srgb, var(--nf-warn) 8%, transparent)}.CUIYUW_todoInfo{border-color:color-mix(in srgb, var(--nf-info) 40%, transparent);background:color-mix(in srgb, var(--nf-info) 7%, transparent)}.CUIYUW_todoText{flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}.CUIYUW_outlineReadonly{border:1px solid var(--nf-border);background:var(--nf-bg-inset);white-space:pre-wrap;user-select:text;border-radius:12px;max-height:480px;margin:0;padding:12px 14px;font-size:12.5px;line-height:1.8;overflow:auto}.CUIYUW_bookCreateOutline{flex-direction:column;align-items:flex-start;gap:6px;display:flex}.CUIYUW_assistantFloat{z-index:80;border:1px solid var(--nf-border);background:var(--nf-bg-raise);backdrop-filter:blur(24px)saturate(180%);box-shadow:var(--nf-shadow-lg);border-radius:16px;flex-direction:column;min-width:320px;min-height:220px;display:flex;position:absolute;overflow:hidden}.CUIYUW_assistantFloatHeader{cursor:grab;user-select:none;border-bottom:1px solid var(--nf-border);background:var(--nf-bg-inset);flex:none;justify-content:space-between;align-items:center;gap:8px;padding:8px 10px 8px 14px;font-size:13px;font-weight:600;display:flex}.CUIYUW_assistantFloatHeader:active{cursor:grabbing}.CUIYUW_assistantFloatBody{flex:1;min-height:0;padding:10px;display:flex;overflow:hidden}.CUIYUW_assistantFloatBody>*{flex:1;min-width:0}.CUIYUW_assistantResize{cursor:nwse-resize;background:linear-gradient(135deg, transparent 0 55%, var(--nf-border-strong) 55% 62%, transparent 62%) no-repeat 4px 4px / 12px 12px;width:20px;height:20px;position:absolute;bottom:0;right:0}.CUIYUW_coverPreview{border:1px solid var(--nf-border);background:var(--nf-bg-inset);border-radius:12px;flex:none;justify-content:center;align-items:center;width:150px;height:200px;display:flex;overflow:hidden}.CUIYUW_coverPreview img{object-fit:contain;width:100%;height:100%;display:block}.CUIYUW_coverPlaceholder{color:var(--nf-text-3);font-size:12px}.CUIYUW_shelfView{flex-direction:column;flex:1;gap:16px;min-height:0;padding:18px;display:flex;overflow:auto}.CUIYUW_shelfHeader{flex-direction:column;gap:2px;display:flex}.CUIYUW_shelfGrid{grid-template-columns:repeat(auto-fill,minmax(190px,1fr));align-content:start;gap:14px;display:grid}.CUIYUW_bookCard{border:1px solid var(--nf-border);background:var(--nf-bg-raise);backdrop-filter:blur(24px)saturate(180%);box-shadow:var(--nf-shadow);cursor:pointer;border-radius:16px;flex-direction:column;gap:8px;padding:12px;transition:border-color .15s,transform .1s,box-shadow .15s;display:flex}.CUIYUW_bookCard:hover{border-color:var(--nf-accent);box-shadow:var(--nf-shadow-lg);transform:translateY(-2px)}.CUIYUW_bookCardActive{border-color:var(--nf-accent);box-shadow:0 0 0 3px var(--nf-accent-soft)}.CUIYUW_bookCardCover{aspect-ratio:3/4;background:var(--nf-bg-inset);border:1px solid var(--nf-border);border-radius:12px;flex:none;justify-content:center;align-items:center;display:flex;overflow:hidden}.CUIYUW_bookCardCover img{object-fit:contain;width:100%;height:100%;display:block}.CUIYUW_bookCardCoverFallback{background:radial-gradient(400px 200px at 80% -20%, color-mix(in srgb, var(--nf-accent) 25%, transparent), transparent 70%), linear-gradient(155deg, var(--nf-bg-inset), color-mix(in srgb, var(--nf-accent) 10%, var(--nf-bg-inset)));flex-direction:column;justify-content:center;align-items:center;gap:6px;width:100%;height:100%;display:flex}.CUIYUW_bookCardCoverTitle{color:var(--nf-accent);letter-spacing:2px;font-size:22px;font-weight:800}.CUIYUW_bookCardBody{flex-direction:column;gap:5px;min-width:0;display:flex}.CUIYUW_bookCardTitleRow{justify-content:space-between;align-items:center;gap:6px;display:flex}.CUIYUW_bookCardName{text-overflow:ellipsis;white-space:nowrap;font-size:13.5px;font-weight:700;overflow:hidden}.CUIYUW_bookCardBlurb{-webkit-line-clamp:2;-webkit-box-orient:vertical;min-height:34px;display:-webkit-box;overflow:hidden}.CUIYUW_bookCardProgressBar{background:var(--nf-border);border-radius:999px;height:5px;overflow:hidden}.CUIYUW_bookCardProgressFill{background:linear-gradient(90deg, var(--nf-info), var(--nf-accent));border-radius:999px;height:100%;transition:width .3s;display:block}.CUIYUW_bookAddCard{text-align:center;color:var(--nf-text-2);border-style:dashed;justify-content:center;align-items:center;gap:8px;min-height:260px}.CUIYUW_bookAddCard:hover{color:var(--nf-accent)}.CUIYUW_bookAddIcon{color:var(--nf-accent);font-size:34px;line-height:1}.CUIYUW_bookCreateCard{border-color:var(--nf-accent);min-height:260px}.CUIYUW_createBookView{flex-direction:column;flex:1;gap:14px;min-height:0;padding:14px 18px 24px;display:flex;overflow:auto}.CUIYUW_createBookTop{align-items:center;display:flex}.CUIYUW_createBookCard{border:1px solid var(--nf-border);background:var(--nf-bg-raise);backdrop-filter:blur(24px)saturate(180%);width:min(520px,100%);box-shadow:var(--nf-shadow-lg);border-radius:20px;flex-direction:column;align-self:center;gap:12px;padding:26px 28px;display:flex}.CUIYUW_createBookIcon{font-size:34px;line-height:1}.CUIYUW_createBookTitle{letter-spacing:-.3px;margin:0;font-size:22px;font-weight:800}.CUIYUW_progressLineDone{color:var(--nf-success);font-weight:600}.CUIYUW_progressLineError{color:var(--nf-error);font-weight:600}.CUIYUW_meta{color:var(--nf-text-2);opacity:.9;font-size:12px}.CUIYUW_genreDesc{-webkit-line-clamp:2;-webkit-box-orient:vertical;max-width:560px;display:-webkit-box;overflow:hidden}.CUIYUW_fileList{color:var(--nf-text-2);opacity:.9;word-break:break-all;flex-direction:column;gap:3px;font-size:12px;display:flex}.CUIYUW_panelContent::-webkit-scrollbar,.CUIYUW_chatScroll::-webkit-scrollbar,.CUIYUW_chapterPreview::-webkit-scrollbar,.CUIYUW_progress::-webkit-scrollbar,.CUIYUW_toolLive::-webkit-scrollbar{width:8px;height:8px}.CUIYUW_panelContent::-webkit-scrollbar-thumb,.CUIYUW_chatScroll::-webkit-scrollbar-thumb,.CUIYUW_chapterPreview::-webkit-scrollbar-thumb,.CUIYUW_progress::-webkit-scrollbar-thumb,.CUIYUW_toolLive::-webkit-scrollbar-thumb{background:var(--nf-border-strong);border-radius:4px}.CUIYUW_panelContent::-webkit-scrollbar-thumb:hover,.CUIYUW_chatScroll::-webkit-scrollbar-thumb:hover,.CUIYUW_chapterPreview::-webkit-scrollbar-thumb:hover,.CUIYUW_progress::-webkit-scrollbar-thumb:hover,.CUIYUW_toolLive::-webkit-scrollbar-thumb:hover{background:var(--nf-text-3)}.CUIYUW_workflowList{flex-direction:column;gap:0;display:flex}.CUIYUW_workflowRow{align-items:flex-start;gap:12px;padding:8px 4px;display:flex;position:relative}.CUIYUW_workflowRow:before{content:\"\";background:var(--nf-border);width:2px;position:absolute;top:34px;bottom:-8px;left:13px}.CUIYUW_workflowRow:last-child:before{display:none}.CUIYUW_workflowDot{border:2px solid var(--nf-border-strong);background:var(--nf-bg-raise);width:28px;height:28px;color:var(--nf-text-2);z-index:1;border-radius:50%;flex-shrink:0;justify-content:center;align-items:center;font-size:12px;font-weight:700;display:inline-flex}.CUIYUW_workflowDotDone{border-color:var(--nf-success);background:color-mix(in srgb, var(--nf-success) 15%, var(--nf-bg-raise));color:var(--nf-success)}.CUIYUW_workflowDotActive{border-color:var(--nf-accent);background:var(--nf-accent);color:var(--nf-accent-fg);box-shadow:0 0 0 4px var(--nf-accent-soft)}.CUIYUW_workflowBody{flex-direction:column;flex:1;gap:4px;min-width:0;padding-top:2px;display:flex}.CUIYUW_workflowLabel{color:var(--nf-text);font-size:13px;font-weight:600}.CUIYUW_workflowHint{color:var(--nf-text-2);font-size:12px}@keyframes CUIYUW_pulse{0%,to{opacity:1}50%{opacity:.45}}@keyframes CUIYUW_fadeIn{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}.CUIYUW_card{animation:.2s CUIYUW_fadeIn}.CUIYUW_bookshelf{border:1px solid var(--nf-glass-border);background:var(--nf-glass-face);box-shadow:var(--nf-shadow), inset 0 1px 0 var(--nf-glass-sheen);backdrop-filter:blur(26px)saturate(175%);z-index:1;border-radius:16px;flex-wrap:wrap;flex-shrink:0;align-items:center;gap:10px;margin:10px 12px 0;padding:8px 14px;display:flex;position:relative}.CUIYUW_bookshelfLabel{color:var(--nf-text-3);letter-spacing:1px;flex-shrink:0;font-size:12px;font-weight:700}.CUIYUW_bookshelfList{flex-wrap:wrap;flex:1;align-items:center;gap:6px;min-width:0;display:flex}.CUIYUW_bookChip{border:1px solid var(--nf-border);background:var(--nf-bg-inset);cursor:pointer;border-radius:999px;align-items:center;gap:6px;max-width:220px;padding:4px 8px 4px 10px;font-size:12px;transition:border-color .15s,background .15s;display:flex}.CUIYUW_bookChip:hover{border-color:var(--nf-border-strong)}.CUIYUW_bookChipActive{border-color:var(--nf-accent);background:var(--nf-accent-soft);color:var(--nf-accent)}.CUIYUW_bookChipName{text-overflow:ellipsis;white-space:nowrap;font-weight:600;overflow:hidden}.CUIYUW_bookChipMeta{opacity:.7;white-space:nowrap;font-size:11px}.CUIYUW_bookChipRemove{color:var(--nf-text-3);cursor:pointer;background:0 0;border:none;border-radius:4px;padding:0 2px;font-size:13px;line-height:1}.CUIYUW_bookChipRemove:hover{color:var(--nf-error)}.CUIYUW_bookAdd{border:1px dashed var(--nf-border-strong);color:var(--nf-text-2);cursor:pointer;background:0 0;border-radius:999px;padding:4px 12px;font-size:12px;transition:border-color .15s,color .15s}.CUIYUW_bookAdd:hover{border-color:var(--nf-accent);color:var(--nf-accent)}.CUIYUW_bookCreateForm{align-items:center;gap:6px;display:flex}.CUIYUW_dropzone{border:2px dashed var(--nf-border-strong);text-align:center;color:var(--nf-text-2);cursor:pointer;border-radius:10px;flex-direction:column;align-items:center;gap:6px;padding:18px 14px;font-size:13px;transition:border-color .15s,background .15s;display:flex}.CUIYUW_dropzone:hover,.CUIYUW_dropzoneActive{border-color:var(--nf-accent);background:var(--nf-accent-soft);color:var(--nf-accent)}.CUIYUW_dropzoneIcon{font-size:22px;line-height:1}";
@@ -777,205 +826,205 @@ window.__ModuleLoader__.load({
777
826
  document.head.appendChild(tag);
778
827
  }
779
828
  var panel_module_css_default = {
780
- "headerProgress": "CUIYUW_headerProgress",
781
- "assetGrid": "CUIYUW_assetGrid",
782
- "textarea": "CUIYUW_textarea",
783
- "entryIcon": "CUIYUW_entryIcon",
784
- "assistantStatus": "CUIYUW_assistantStatus",
785
- "assistantResize": "CUIYUW_assistantResize",
786
- "navTabIcon": "CUIYUW_navTabIcon",
787
- "workflowHint": "CUIYUW_workflowHint",
788
- "chapter": "CUIYUW_chapter",
789
- "bookCardBody": "CUIYUW_bookCardBody",
790
- "navGroupLabel": "CUIYUW_navGroupLabel",
791
- "bookshelf": "CUIYUW_bookshelf",
792
- "navAbout": "CUIYUW_navAbout",
793
- "dashHeroSparkle": "CUIYUW_dashHeroSparkle",
794
- "dashJourneyStages": "CUIYUW_dashJourneyStages",
795
- "panelNavCollapsed": "CUIYUW_panelNavCollapsed",
796
- "fieldLabel": "CUIYUW_fieldLabel",
829
+ "createBookView": "CUIYUW_createBookView",
830
+ "tabBar": "CUIYUW_tabBar",
831
+ "badgeGenerating": "CUIYUW_badgeGenerating",
832
+ "workflowDotDone": "CUIYUW_workflowDotDone",
833
+ "bookAdd": "CUIYUW_bookAdd",
834
+ "toolStepName": "CUIYUW_toolStepName",
835
+ "volumeGroupToggle": "CUIYUW_volumeGroupToggle",
797
836
  "dashHeroActionBody": "CUIYUW_dashHeroActionBody",
798
- "todoItem": "CUIYUW_todoItem",
799
- "toolLive": "CUIYUW_toolLive",
837
+ "wsSelected": "CUIYUW_wsSelected",
838
+ "navAboutUpdate": "CUIYUW_navAboutUpdate",
839
+ "chapterList": "CUIYUW_chapterList",
840
+ "dashGrid": "CUIYUW_dashGrid",
841
+ "dashJourney": "CUIYUW_dashJourney",
800
842
  "assistantFloatHeader": "CUIYUW_assistantFloatHeader",
801
- "createBookView": "CUIYUW_createBookView",
802
- "row": "CUIYUW_row",
803
- "wsColumns": "CUIYUW_wsColumns",
804
- "workflowRow": "CUIYUW_workflowRow",
805
- "fadeIn": "CUIYUW_fadeIn",
806
- "bookChipMeta": "CUIYUW_bookChipMeta",
807
- "assetStatValue": "CUIYUW_assetStatValue",
808
- "progressLineError": "CUIYUW_progressLineError",
809
- "bookChipName": "CUIYUW_bookChipName",
810
- "toolSteps": "CUIYUW_toolSteps",
811
- "dashHeroEyebrow": "CUIYUW_dashHeroEyebrow",
812
- "todoText": "CUIYUW_todoText",
843
+ "assistantFloat": "CUIYUW_assistantFloat",
844
+ "bookCardCover": "CUIYUW_bookCardCover",
845
+ "dashStageCurrent": "CUIYUW_dashStageCurrent",
846
+ "progressLineLive": "CUIYUW_progressLineLive",
847
+ "diffDel": "CUIYUW_diffDel",
848
+ "dashHeroTitle": "CUIYUW_dashHeroTitle",
849
+ "createBookCard": "CUIYUW_createBookCard",
850
+ "shelfView": "CUIYUW_shelfView",
813
851
  "createBookIcon": "CUIYUW_createBookIcon",
814
- "dropzoneActive": "CUIYUW_dropzoneActive",
815
- "iconButton": "CUIYUW_iconButton",
816
- "fileList": "CUIYUW_fileList",
817
- "badge": "CUIYUW_badge",
818
- "chatScroll": "CUIYUW_chatScroll",
819
- "workflowList": "CUIYUW_workflowList",
820
- "wsPage": "CUIYUW_wsPage",
852
+ "createBookTitle": "CUIYUW_createBookTitle",
853
+ "navGroupLabel": "CUIYUW_navGroupLabel",
854
+ "textarea": "CUIYUW_textarea",
855
+ "row": "CUIYUW_row",
856
+ "headerProgressDot": "CUIYUW_headerProgressDot",
857
+ "buttonDanger": "CUIYUW_buttonDanger",
821
858
  "assetStatDetail": "CUIYUW_assetStatDetail",
822
- "diffAdd": "CUIYUW_diffAdd",
859
+ "assistantStatus": "CUIYUW_assistantStatus",
860
+ "badgeDone": "CUIYUW_badgeDone",
861
+ "navTabBadgeWarn": "CUIYUW_navTabBadgeWarn",
862
+ "wsEditor": "CUIYUW_wsEditor",
863
+ "chapterMain": "CUIYUW_chapterMain",
864
+ "progressBar": "CUIYUW_progressBar",
865
+ "chapter": "CUIYUW_chapter",
866
+ "navTabBadgeDone": "CUIYUW_navTabBadgeDone",
867
+ "diffLegend": "CUIYUW_diffLegend",
868
+ "diffSameBody": "CUIYUW_diffSameBody",
869
+ "diffList": "CUIYUW_diffList",
870
+ "wsSelectedText": "CUIYUW_wsSelectedText",
871
+ "dashStage": "CUIYUW_dashStage",
872
+ "shelfHeader": "CUIYUW_shelfHeader",
873
+ "bookCardCoverTitle": "CUIYUW_bookCardCoverTitle",
874
+ "progressLineDone": "CUIYUW_progressLineDone",
875
+ "bookshelfList": "CUIYUW_bookshelfList",
876
+ "dropzone": "CUIYUW_dropzone",
877
+ "entryIcon": "CUIYUW_entryIcon",
878
+ "chapterBeats": "CUIYUW_chapterBeats",
823
879
  "dashStageDot": "CUIYUW_dashStageDot",
824
- "chatRole": "CUIYUW_chatRole",
825
- "todoDanger": "CUIYUW_todoDanger",
880
+ "bookCard": "CUIYUW_bookCard",
881
+ "chapterTitle": "CUIYUW_chapterTitle",
882
+ "view": "CUIYUW_view",
883
+ "navSpacer": "CUIYUW_navSpacer",
884
+ "panelBody": "CUIYUW_panelBody",
885
+ "panelNavCollapsed": "CUIYUW_panelNavCollapsed",
826
886
  "navTabBadgeDanger": "CUIYUW_navTabBadgeDanger",
827
- "bookCreateOutline": "CUIYUW_bookCreateOutline",
828
- "dashHeroAction": "CUIYUW_dashHeroAction",
829
- "diffOld": "CUIYUW_diffOld",
830
- "badgeError": "CUIYUW_badgeError",
831
- "progress": "CUIYUW_progress",
832
- "dashJourneyBar": "CUIYUW_dashJourneyBar",
833
- "wsSelected": "CUIYUW_wsSelected",
834
- "badgeDone": "CUIYUW_badgeDone",
835
- "headerProgressDot": "CUIYUW_headerProgressDot",
887
+ "toolStepDetail": "CUIYUW_toolStepDetail",
888
+ "diffColumn": "CUIYUW_diffColumn",
889
+ "wsColumns": "CUIYUW_wsColumns",
890
+ "bookCardActive": "CUIYUW_bookCardActive",
891
+ "wsPreviewText": "CUIYUW_wsPreviewText",
892
+ "bookAddIcon": "CUIYUW_bookAddIcon",
893
+ "panelTitle": "CUIYUW_panelTitle",
894
+ "busyRow": "CUIYUW_busyRow",
895
+ "bookCardCoverFallback": "CUIYUW_bookCardCoverFallback",
836
896
  "reviewBox": "CUIYUW_reviewBox",
837
- "toolStepActive": "CUIYUW_toolStepActive",
838
- "button": "CUIYUW_button",
839
- "volumeGroup": "CUIYUW_volumeGroup",
840
- "assetStatLabel": "CUIYUW_assetStatLabel",
841
- "bookCreateCard": "CUIYUW_bookCreateCard",
842
- "createBookTop": "CUIYUW_createBookTop",
843
- "dashStageDone": "CUIYUW_dashStageDone",
844
- "genreDesc": "CUIYUW_genreDesc",
845
- "dashJourneyFill": "CUIYUW_dashJourneyFill",
846
- "wsPreview": "CUIYUW_wsPreview",
847
- "onlyChanges": "CUIYUW_onlyChanges",
848
- "toolStepError": "CUIYUW_toolStepError",
897
+ "meta": "CUIYUW_meta",
898
+ "workflowBody": "CUIYUW_workflowBody",
899
+ "assistantFloatBody": "CUIYUW_assistantFloatBody",
900
+ "workflowList": "CUIYUW_workflowList",
901
+ "bookshelfLabel": "CUIYUW_bookshelfLabel",
902
+ "bookChipActive": "CUIYUW_bookChipActive",
903
+ "assistantResize": "CUIYUW_assistantResize",
904
+ "chatRole": "CUIYUW_chatRole",
849
905
  "wsPageHeader": "CUIYUW_wsPageHeader",
850
- "view": "CUIYUW_view",
851
- "todoWarning": "CUIYUW_todoWarning",
852
- "diffTagNew": "CUIYUW_diffTagNew",
853
- "dashFacts": "CUIYUW_dashFacts",
854
- "input": "CUIYUW_input",
906
+ "legendOld": "CUIYUW_legendOld",
907
+ "bookCardProgressBar": "CUIYUW_bookCardProgressBar",
855
908
  "tab": "CUIYUW_tab",
856
- "pulse": "CUIYUW_pulse",
857
- "progressLineLive": "CUIYUW_progressLineLive",
858
- "assistantFloat": "CUIYUW_assistantFloat",
859
- "bookCardTitleRow": "CUIYUW_bookCardTitleRow",
909
+ "button": "CUIYUW_button",
910
+ "volumeGroup": "CUIYUW_volumeGroup",
911
+ "entryLabel": "CUIYUW_entryLabel",
860
912
  "dashHeroBook": "CUIYUW_dashHeroBook",
861
- "bookCardProgressBar": "CUIYUW_bookCardProgressBar",
862
- "diffLegend": "CUIYUW_diffLegend",
863
- "buttonDanger": "CUIYUW_buttonDanger",
864
- "bookCardProgressFill": "CUIYUW_bookCardProgressFill",
865
- "bigProgressBar": "CUIYUW_bigProgressBar",
866
- "shelfHeader": "CUIYUW_shelfHeader",
867
- "workflowDotDone": "CUIYUW_workflowDotDone",
868
- "bigProgressBarFill": "CUIYUW_bigProgressBarFill",
869
- "bookCreateForm": "CUIYUW_bookCreateForm",
870
- "diffList": "CUIYUW_diffList",
871
- "chapterMain": "CUIYUW_chapterMain",
872
913
  "badgeRejected": "CUIYUW_badgeRejected",
873
- "legendNew": "CUIYUW_legendNew",
874
- "diffText": "CUIYUW_diffText",
875
- "diffTagOld": "CUIYUW_diffTagOld",
876
- "panelBody": "CUIYUW_panelBody",
877
- "shelfView": "CUIYUW_shelfView",
878
- "bookCard": "CUIYUW_bookCard",
879
- "panelSubtitle": "CUIYUW_panelSubtitle",
880
- "dashStageCurrent": "CUIYUW_dashStageCurrent",
881
- "panelContent": "CUIYUW_panelContent",
882
- "buttonSmall": "CUIYUW_buttonSmall",
883
- "badgeGenerating": "CUIYUW_badgeGenerating",
884
- "wsPreviewText": "CUIYUW_wsPreviewText",
885
- "dashGrid": "CUIYUW_dashGrid",
886
- "entryLabel": "CUIYUW_entryLabel",
887
- "assistantFloatBody": "CUIYUW_assistantFloatBody",
888
- "chapterPreview": "CUIYUW_chapterPreview",
914
+ "workflowDot": "CUIYUW_workflowDot",
915
+ "panel": "CUIYUW_panel",
889
916
  "navGroup": "CUIYUW_navGroup",
890
- "createBookTitle": "CUIYUW_createBookTitle",
891
- "bookChip": "CUIYUW_bookChip",
892
- "panelHeader": "CUIYUW_panelHeader",
893
- "progressBar": "CUIYUW_progressBar",
894
- "toolStep": "CUIYUW_toolStep",
895
- "buttonPrimary": "CUIYUW_buttonPrimary",
896
- "busyRow": "CUIYUW_busyRow",
897
- "bookCardActive": "CUIYUW_bookCardActive",
898
- "tabBar": "CUIYUW_tabBar",
917
+ "navAbout": "CUIYUW_navAbout",
918
+ "navTabBadge": "CUIYUW_navTabBadge",
899
919
  "field": "CUIYUW_field",
900
- "card": "CUIYUW_card",
901
- "badgePending": "CUIYUW_badgePending",
902
- "volumeGroupToggle": "CUIYUW_volumeGroupToggle",
903
- "chapterActions": "CUIYUW_chapterActions",
904
- "dashFact": "CUIYUW_dashFact",
905
- "diffSame": "CUIYUW_diffSame",
906
- "bookAddIcon": "CUIYUW_bookAddIcon",
907
- "diffNew": "CUIYUW_diffNew",
908
- "navTabBadgeWarn": "CUIYUW_navTabBadgeWarn",
909
- "navTabLabel": "CUIYUW_navTabLabel",
910
- "chapterList": "CUIYUW_chapterList",
911
- "progressLine": "CUIYUW_progressLine",
912
- "bookCardBlurb": "CUIYUW_bookCardBlurb",
913
- "spaceBetween": "CUIYUW_spaceBetween",
914
- "coverPlaceholder": "CUIYUW_coverPlaceholder",
915
- "bookCardCover": "CUIYUW_bookCardCover",
916
- "badgeWritten": "CUIYUW_badgeWritten",
917
- "toolStepIcon": "CUIYUW_toolStepIcon",
918
- "dropzoneIcon": "CUIYUW_dropzoneIcon",
920
+ "volumeGroupHeader": "CUIYUW_volumeGroupHeader",
921
+ "toolLive": "CUIYUW_toolLive",
922
+ "toolSteps": "CUIYUW_toolSteps",
923
+ "bigProgressBar": "CUIYUW_bigProgressBar",
924
+ "diffTagNew": "CUIYUW_diffTagNew",
919
925
  "outlineReadonly": "CUIYUW_outlineReadonly",
920
- "coverPreview": "CUIYUW_coverPreview",
926
+ "bookCardBody": "CUIYUW_bookCardBody",
927
+ "bookCardTitleRow": "CUIYUW_bookCardTitleRow",
928
+ "diffNew": "CUIYUW_diffNew",
929
+ "bookCardProgressFill": "CUIYUW_bookCardProgressFill",
930
+ "headerProgress": "CUIYUW_headerProgress",
931
+ "progressLineError": "CUIYUW_progressLineError",
932
+ "diffAdd": "CUIYUW_diffAdd",
933
+ "assetStatValue": "CUIYUW_assetStatValue",
934
+ "workflowRow": "CUIYUW_workflowRow",
935
+ "fadeIn": "CUIYUW_fadeIn",
921
936
  "chatBubbleUser": "CUIYUW_chatBubbleUser",
922
- "panel": "CUIYUW_panel",
937
+ "bookChipName": "CUIYUW_bookChipName",
938
+ "dropzoneIcon": "CUIYUW_dropzoneIcon",
939
+ "panelSubtitle": "CUIYUW_panelSubtitle",
940
+ "entry": "CUIYUW_entry",
941
+ "panelContent": "CUIYUW_panelContent",
942
+ "buttonSmall": "CUIYUW_buttonSmall",
943
+ "fieldLabel": "CUIYUW_fieldLabel",
944
+ "todoDanger": "CUIYUW_todoDanger",
945
+ "dropzoneActive": "CUIYUW_dropzoneActive",
923
946
  "cardTitle": "CUIYUW_cardTitle",
924
947
  "chatBubbleAssistant": "CUIYUW_chatBubbleAssistant",
925
- "navTab": "CUIYUW_navTab",
926
- "dashHeroArrow": "CUIYUW_dashHeroArrow",
948
+ "spaceBetween": "CUIYUW_spaceBetween",
949
+ "badgeError": "CUIYUW_badgeError",
950
+ "toolStepActive": "CUIYUW_toolStepActive",
951
+ "dashJourneyBar": "CUIYUW_dashJourneyBar",
952
+ "progress": "CUIYUW_progress",
953
+ "dashJourneyStages": "CUIYUW_dashJourneyStages",
954
+ "navTabIcon": "CUIYUW_navTabIcon",
955
+ "diffTagOld": "CUIYUW_diffTagOld",
956
+ "navAboutRow": "CUIYUW_navAboutRow",
957
+ "bookCreateForm": "CUIYUW_bookCreateForm",
958
+ "bookCardName": "CUIYUW_bookCardName",
959
+ "chapterPreview": "CUIYUW_chapterPreview",
960
+ "assetStat": "CUIYUW_assetStat",
961
+ "pulse": "CUIYUW_pulse",
962
+ "bookCardBlurb": "CUIYUW_bookCardBlurb",
963
+ "workflowDotActive": "CUIYUW_workflowDotActive",
964
+ "bookshelf": "CUIYUW_bookshelf",
927
965
  "dashHeroActionTitle": "CUIYUW_dashHeroActionTitle",
928
- "bookChipActive": "CUIYUW_bookChipActive",
929
- "panelNav": "CUIYUW_panelNav",
930
- "diffDel": "CUIYUW_diffDel",
931
- "bookCardCoverFallback": "CUIYUW_bookCardCoverFallback",
932
- "dashHeroTitle": "CUIYUW_dashHeroTitle",
933
- "workflowBody": "CUIYUW_workflowBody",
934
- "bookChipRemove": "CUIYUW_bookChipRemove",
935
- "wsSelectedText": "CUIYUW_wsSelectedText",
936
- "navSpacer": "CUIYUW_navSpacer",
937
- "navTabBadge": "CUIYUW_navTabBadge",
938
- "navGroupSep": "CUIYUW_navGroupSep",
939
- "progressBarFill": "CUIYUW_progressBarFill",
940
- "toolStepStatus": "CUIYUW_toolStepStatus",
941
- "diffSameBody": "CUIYUW_diffSameBody",
942
- "volumeGroupHeader": "CUIYUW_volumeGroupHeader",
943
- "legendOld": "CUIYUW_legendOld",
944
- "navTabBadgeDone": "CUIYUW_navTabBadgeDone",
966
+ "diffOld": "CUIYUW_diffOld",
967
+ "bookAddCard": "CUIYUW_bookAddCard",
968
+ "fileList": "CUIYUW_fileList",
945
969
  "dashHero": "CUIYUW_dashHero",
946
- "panelTitle": "CUIYUW_panelTitle",
947
- "chapterTitle": "CUIYUW_chapterTitle",
948
- "wsEditor": "CUIYUW_wsEditor",
949
- "chapterBeats": "CUIYUW_chapterBeats",
950
- "bookCardName": "CUIYUW_bookCardName",
951
- "navAboutRow": "CUIYUW_navAboutRow",
952
- "bookshelfList": "CUIYUW_bookshelfList",
953
- "bookAdd": "CUIYUW_bookAdd",
954
- "dropzone": "CUIYUW_dropzone",
955
- "toolStepName": "CUIYUW_toolStepName",
956
- "workflowLabel": "CUIYUW_workflowLabel",
957
- "bookshelfLabel": "CUIYUW_bookshelfLabel",
958
- "navAboutUpdate": "CUIYUW_navAboutUpdate",
959
- "todoInfo": "CUIYUW_todoInfo",
960
- "shelfGrid": "CUIYUW_shelfGrid",
961
- "assistantStatusBusy": "CUIYUW_assistantStatusBusy",
962
- "createBookCard": "CUIYUW_createBookCard",
963
- "workflowDotActive": "CUIYUW_workflowDotActive",
970
+ "workflowHint": "CUIYUW_workflowHint",
971
+ "wsColumn": "CUIYUW_wsColumn",
972
+ "bookCreateOutline": "CUIYUW_bookCreateOutline",
964
973
  "diffChange": "CUIYUW_diffChange",
974
+ "progressBarFill": "CUIYUW_progressBarFill",
965
975
  "liveText": "CUIYUW_liveText",
966
- "assetStat": "CUIYUW_assetStat",
967
- "progressLineDone": "CUIYUW_progressLineDone",
968
- "entry": "CUIYUW_entry",
969
- "workflowDot": "CUIYUW_workflowDot",
970
- "bookAddCard": "CUIYUW_bookAddCard",
971
- "wsColumn": "CUIYUW_wsColumn",
972
- "dashStage": "CUIYUW_dashStage",
973
- "bookCardCoverTitle": "CUIYUW_bookCardCoverTitle",
976
+ "shelfGrid": "CUIYUW_shelfGrid",
977
+ "iconButton": "CUIYUW_iconButton",
978
+ "todoItem": "CUIYUW_todoItem",
979
+ "badgePending": "CUIYUW_badgePending",
980
+ "assetStatLabel": "CUIYUW_assetStatLabel",
981
+ "card": "CUIYUW_card",
974
982
  "chapterNum": "CUIYUW_chapterNum",
975
- "meta": "CUIYUW_meta",
976
- "toolStepDetail": "CUIYUW_toolStepDetail",
977
- "dashJourney": "CUIYUW_dashJourney",
978
- "diffColumn": "CUIYUW_diffColumn"
983
+ "diffText": "CUIYUW_diffText",
984
+ "dashFact": "CUIYUW_dashFact",
985
+ "assetGrid": "CUIYUW_assetGrid",
986
+ "assistantStatusBusy": "CUIYUW_assistantStatusBusy",
987
+ "toolStep": "CUIYUW_toolStep",
988
+ "badge": "CUIYUW_badge",
989
+ "buttonPrimary": "CUIYUW_buttonPrimary",
990
+ "toolStepStatus": "CUIYUW_toolStepStatus",
991
+ "panelHeader": "CUIYUW_panelHeader",
992
+ "bigProgressBarFill": "CUIYUW_bigProgressBarFill",
993
+ "onlyChanges": "CUIYUW_onlyChanges",
994
+ "wsPreview": "CUIYUW_wsPreview",
995
+ "dashHeroEyebrow": "CUIYUW_dashHeroEyebrow",
996
+ "toolStepError": "CUIYUW_toolStepError",
997
+ "dashHeroArrow": "CUIYUW_dashHeroArrow",
998
+ "chapterActions": "CUIYUW_chapterActions",
999
+ "todoWarning": "CUIYUW_todoWarning",
1000
+ "navGroupSep": "CUIYUW_navGroupSep",
1001
+ "todoInfo": "CUIYUW_todoInfo",
1002
+ "wsPage": "CUIYUW_wsPage",
1003
+ "coverPreview": "CUIYUW_coverPreview",
1004
+ "badgeWritten": "CUIYUW_badgeWritten",
1005
+ "dashHeroAction": "CUIYUW_dashHeroAction",
1006
+ "bookCreateCard": "CUIYUW_bookCreateCard",
1007
+ "dashStageDone": "CUIYUW_dashStageDone",
1008
+ "dashHeroSparkle": "CUIYUW_dashHeroSparkle",
1009
+ "dashFacts": "CUIYUW_dashFacts",
1010
+ "toolStepIcon": "CUIYUW_toolStepIcon",
1011
+ "createBookTop": "CUIYUW_createBookTop",
1012
+ "genreDesc": "CUIYUW_genreDesc",
1013
+ "bookChip": "CUIYUW_bookChip",
1014
+ "navTab": "CUIYUW_navTab",
1015
+ "bookChipMeta": "CUIYUW_bookChipMeta",
1016
+ "progressLine": "CUIYUW_progressLine",
1017
+ "panelNav": "CUIYUW_panelNav",
1018
+ "dashJourneyFill": "CUIYUW_dashJourneyFill",
1019
+ "diffSame": "CUIYUW_diffSame",
1020
+ "workflowLabel": "CUIYUW_workflowLabel",
1021
+ "bookChipRemove": "CUIYUW_bookChipRemove",
1022
+ "input": "CUIYUW_input",
1023
+ "navTabLabel": "CUIYUW_navTabLabel",
1024
+ "todoText": "CUIYUW_todoText",
1025
+ "chatScroll": "CUIYUW_chatScroll",
1026
+ "legendNew": "CUIYUW_legendNew",
1027
+ "coverPlaceholder": "CUIYUW_coverPlaceholder"
979
1028
  };
980
1029
  //#endregion
981
1030
  //#region src/client/panel/AssistantTab.tsx
@@ -3163,230 +3212,834 @@ window.__ModuleLoader__.load({
3163
3212
  style: {
3164
3213
  display: "flex",
3165
3214
  flexDirection: "column",
3166
- gap: 12
3215
+ gap: 12
3216
+ },
3217
+ children: [
3218
+ error !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3219
+ className: panel_module_css_default.card,
3220
+ style: { borderColor: "var(--nf-error)" },
3221
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3222
+ style: { color: "var(--nf-error)" },
3223
+ children: error
3224
+ })
3225
+ }),
3226
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3227
+ className: panel_module_css_default.card,
3228
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3229
+ className: panel_module_css_default.row,
3230
+ style: { justifyContent: "space-between" },
3231
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3232
+ className: panel_module_css_default.cardTitle,
3233
+ children: "大世界"
3234
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3235
+ className: panel_module_css_default.row,
3236
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3237
+ type: "button",
3238
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall} ${panel_module_css_default.buttonPrimary}`,
3239
+ disabled: busy,
3240
+ onClick: () => {
3241
+ handleGenerate();
3242
+ },
3243
+ children: "✨ AI 提炼"
3244
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3245
+ type: "button",
3246
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
3247
+ disabled: busy,
3248
+ onClick: () => {
3249
+ handleSave();
3250
+ },
3251
+ children: "💾 保存"
3252
+ })]
3253
+ })]
3254
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3255
+ className: panel_module_css_default.meta,
3256
+ children: "境界体系按由低到高排序注入章节生成提示词,模型不得随意跳级或自创境界;区域与势力约束地理/势力设定。AI 提炼不满意可逐条编辑后保存。"
3257
+ })]
3258
+ }),
3259
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3260
+ className: panel_module_css_default.card,
3261
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3262
+ className: panel_module_css_default.row,
3263
+ style: { justifyContent: "space-between" },
3264
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3265
+ className: panel_module_css_default.cardTitle,
3266
+ children: [
3267
+ "境界体系(",
3268
+ draft.realms.length,
3269
+ ")"
3270
+ ]
3271
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3272
+ type: "button",
3273
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
3274
+ onClick: () => {
3275
+ setRealms([...draft.realms, {
3276
+ name: "",
3277
+ description: ""
3278
+ }]);
3279
+ },
3280
+ children: "+ 新增境界"
3281
+ })]
3282
+ }), draft.realms.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3283
+ className: panel_module_css_default.meta,
3284
+ children: "暂无境界体系 — 点击 ✨AI 提炼 或手动添加(由低到高)。"
3285
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3286
+ style: {
3287
+ display: "flex",
3288
+ flexDirection: "column",
3289
+ gap: 6
3290
+ },
3291
+ children: draft.realms.map((realm, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EditableRow, {
3292
+ name: realm.name,
3293
+ detail: realm.description,
3294
+ onName: (v) => {
3295
+ const next = [...draft.realms];
3296
+ next[i] = {
3297
+ ...next[i],
3298
+ name: v
3299
+ };
3300
+ setRealms(next);
3301
+ },
3302
+ onDetail: (v) => {
3303
+ const next = [...draft.realms];
3304
+ next[i] = {
3305
+ ...next[i],
3306
+ description: v
3307
+ };
3308
+ setRealms(next);
3309
+ },
3310
+ onRemove: () => {
3311
+ setRealms(draft.realms.filter((_, idx) => idx !== i));
3312
+ },
3313
+ namePlaceholder: `第 ${i + 1} 阶境界名`,
3314
+ detailPlaceholder: "突破条件 / 寿命 / 标志…"
3315
+ }, i))
3316
+ })]
3317
+ }),
3318
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3319
+ className: panel_module_css_default.card,
3320
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3321
+ className: panel_module_css_default.row,
3322
+ style: { justifyContent: "space-between" },
3323
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3324
+ className: panel_module_css_default.cardTitle,
3325
+ children: [
3326
+ "地理区域(",
3327
+ draft.regions.length,
3328
+ ")"
3329
+ ]
3330
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3331
+ type: "button",
3332
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
3333
+ onClick: () => {
3334
+ setRegions([...draft.regions, {
3335
+ name: "",
3336
+ description: ""
3337
+ }]);
3338
+ },
3339
+ children: "+ 新增区域"
3340
+ })]
3341
+ }), draft.regions.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3342
+ className: panel_module_css_default.meta,
3343
+ children: "暂无地理区域 — 大陆 / 海域 / 秘境 / 遗迹…"
3344
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3345
+ style: {
3346
+ display: "flex",
3347
+ flexDirection: "column",
3348
+ gap: 6
3349
+ },
3350
+ children: draft.regions.map((region, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EditableRow, {
3351
+ name: region.name,
3352
+ detail: region.description,
3353
+ onName: (v) => {
3354
+ const next = [...draft.regions];
3355
+ next[i] = {
3356
+ ...next[i],
3357
+ name: v
3358
+ };
3359
+ setRegions(next);
3360
+ },
3361
+ onDetail: (v) => {
3362
+ const next = [...draft.regions];
3363
+ next[i] = {
3364
+ ...next[i],
3365
+ description: v
3366
+ };
3367
+ setRegions(next);
3368
+ },
3369
+ onRemove: () => {
3370
+ setRegions(draft.regions.filter((_, idx) => idx !== i));
3371
+ },
3372
+ namePlaceholder: "区域名(如大荒 / 青云山脉)",
3373
+ detailPlaceholder: "描述…"
3374
+ }, i))
3375
+ })]
3376
+ }),
3377
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3378
+ className: panel_module_css_default.card,
3379
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3380
+ className: panel_module_css_default.row,
3381
+ style: { justifyContent: "space-between" },
3382
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3383
+ className: panel_module_css_default.cardTitle,
3384
+ children: [
3385
+ "势力分布(",
3386
+ draft.factions.length,
3387
+ ")"
3388
+ ]
3389
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3390
+ type: "button",
3391
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
3392
+ onClick: () => {
3393
+ setFactions([...draft.factions, {
3394
+ name: "",
3395
+ kind: "宗门",
3396
+ description: ""
3397
+ }]);
3398
+ },
3399
+ children: "+ 新增势力"
3400
+ })]
3401
+ }), draft.factions.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3402
+ className: panel_module_css_default.meta,
3403
+ children: "暂无势力 — 宗门 / 家族 / 王朝 / 组织…"
3404
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3405
+ style: {
3406
+ display: "flex",
3407
+ flexDirection: "column",
3408
+ gap: 6
3409
+ },
3410
+ children: draft.factions.map((faction, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EditableRow, {
3411
+ name: `${faction.name}(${faction.kind})`,
3412
+ detail: faction.description,
3413
+ onName: (v) => {
3414
+ const next = [...draft.factions];
3415
+ const match = /^(.*)((.*))$/.exec(v);
3416
+ next[i] = {
3417
+ ...next[i],
3418
+ name: (match?.[1] ?? v).trim(),
3419
+ kind: (match?.[2] ?? next[i].kind).trim() || "宗门"
3420
+ };
3421
+ setFactions(next);
3422
+ },
3423
+ onDetail: (v) => {
3424
+ const next = [...draft.factions];
3425
+ next[i] = {
3426
+ ...next[i],
3427
+ description: v
3428
+ };
3429
+ setFactions(next);
3430
+ },
3431
+ onRemove: () => {
3432
+ setFactions(draft.factions.filter((_, idx) => idx !== i));
3433
+ },
3434
+ namePlaceholder: "势力名(类型)如:青云宗(宗门)",
3435
+ detailPlaceholder: "描述…"
3436
+ }, i))
3437
+ })]
3438
+ })
3439
+ ]
3440
+ });
3441
+ }
3442
+ //#endregion
3443
+ //#region src/client/panel/views.tsx
3444
+ /** 统计格:状态摘要条 / 资产健康通用。 */
3445
+ function StatCell(props) {
3446
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3447
+ className: panel_module_css_default.assetStat,
3448
+ children: [
3449
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3450
+ className: panel_module_css_default.assetStatLabel,
3451
+ children: props.label
3452
+ }),
3453
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3454
+ className: panel_module_css_default.assetStatValue,
3455
+ style: {
3456
+ color: props.valueColor,
3457
+ fontSize: props.valueFontSize
3458
+ },
3459
+ children: props.value
3460
+ }),
3461
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3462
+ className: panel_module_css_default.assetStatDetail,
3463
+ title: props.detailTitle,
3464
+ children: props.detail
3465
+ })
3466
+ ]
3467
+ });
3468
+ }
3469
+ /** 待办队列行。 */
3470
+ function TodoRow(props) {
3471
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3472
+ className: `${panel_module_css_default.todoItem} ${props.tone === "danger" ? panel_module_css_default.todoDanger : props.tone === "warning" ? panel_module_css_default.todoWarning : panel_module_css_default.todoInfo}`,
3473
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3474
+ className: panel_module_css_default.todoText,
3475
+ children: [props.title, props.description !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3476
+ className: panel_module_css_default.meta,
3477
+ children: [" — ", props.description]
3478
+ })]
3479
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3480
+ type: "button",
3481
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
3482
+ disabled: props.disabled,
3483
+ onClick: props.onAction,
3484
+ children: props.actionLabel
3485
+ })]
3486
+ });
3487
+ }
3488
+ /** 全书质检问题行。 */
3489
+ function AuditIssueRow(props) {
3490
+ const { issue } = props;
3491
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3492
+ className: `${panel_module_css_default.todoItem} ${issue.severity === "high" ? panel_module_css_default.todoDanger : issue.severity === "medium" ? panel_module_css_default.todoWarning : panel_module_css_default.todoInfo}`,
3493
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3494
+ className: panel_module_css_default.todoText,
3495
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
3496
+ issue.chapterNo > 0 ? `第 ${issue.chapterNo} 章` : "未定位章节",
3497
+ " · [",
3498
+ issue.severity,
3499
+ "] ",
3500
+ issue.item
3501
+ ] }), issue.suggestion !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3502
+ className: panel_module_css_default.meta,
3503
+ children: ["建议:", issue.suggestion]
3504
+ })]
3505
+ }), issue.chapterNo > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3506
+ type: "button",
3507
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
3508
+ disabled: props.disabled,
3509
+ onClick: props.onFix,
3510
+ children: "去修订"
3511
+ })]
3512
+ });
3513
+ }
3514
+ /** 剧情线卡片(列表主体)。 */
3515
+ function PlotlineCard(props) {
3516
+ const { line } = props;
3517
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3518
+ style: {
3519
+ border: "1px solid var(--nf-border)",
3520
+ borderRadius: 10,
3521
+ padding: "8px 12px",
3522
+ fontSize: 12,
3523
+ display: "flex",
3524
+ flexDirection: "column",
3525
+ gap: 4
3526
+ },
3527
+ children: [
3528
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3529
+ className: panel_module_css_default.row,
3530
+ style: {
3531
+ justifyContent: "space-between",
3532
+ flexWrap: "wrap"
3533
+ },
3534
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3535
+ style: {
3536
+ display: "flex",
3537
+ alignItems: "center",
3538
+ gap: 6,
3539
+ flexWrap: "wrap"
3540
+ },
3541
+ children: [
3542
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: line.name }),
3543
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3544
+ className: panel_module_css_default.badge,
3545
+ style: {
3546
+ borderColor: "var(--nf-accent)",
3547
+ color: "var(--nf-accent)"
3548
+ },
3549
+ children: kindLabel(line.kind)
3550
+ }),
3551
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3552
+ className: panel_module_css_default.badge,
3553
+ style: {
3554
+ borderColor: plotlineStatusColor(line.status),
3555
+ color: plotlineStatusColor(line.status)
3556
+ },
3557
+ children: plotlineStatusLabel(line.status)
3558
+ })
3559
+ ]
3560
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3561
+ style: {
3562
+ display: "flex",
3563
+ gap: 6
3564
+ },
3565
+ children: [
3566
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3567
+ type: "button",
3568
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
3569
+ disabled: props.disabled,
3570
+ onClick: props.onRefresh,
3571
+ title: "AI 结合编年录与章节摘要,自动更新这条线的当前进度",
3572
+ children: "↻ AI 刷新进度"
3573
+ }),
3574
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3575
+ type: "button",
3576
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
3577
+ disabled: props.disabled,
3578
+ onClick: props.onEdit,
3579
+ children: tt("plotlines.edit")
3580
+ }),
3581
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3582
+ type: "button",
3583
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
3584
+ disabled: props.disabled,
3585
+ onClick: props.onRemove,
3586
+ children: tt("plotlines.remove")
3587
+ })
3588
+ ]
3589
+ })]
3590
+ }),
3591
+ line.goal !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3592
+ className: panel_module_css_default.meta,
3593
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("b", { children: [tt("plotlines.goal"), ":"] }), line.goal]
3594
+ }),
3595
+ line.progress !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3596
+ className: panel_module_css_default.meta,
3597
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("b", { children: [tt("plotlines.progress"), ":"] }), line.progress]
3598
+ }),
3599
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3600
+ className: panel_module_css_default.meta,
3601
+ children: [
3602
+ tt("plotlines.chapters"),
3603
+ ":",
3604
+ line.chapters.length > 0 ? line.chapters.map((n) => `第${n}章`).join("、") : "—"
3605
+ ]
3606
+ })
3607
+ ]
3608
+ }, line.id);
3609
+ }
3610
+ /** AI 候选角色行(提炼结果,可采纳/修改后采纳)。 */
3611
+ function RoleCandidateRow(props) {
3612
+ const { candidate: r } = props;
3613
+ const label = ROLE_LABELS[r.roleLabel] ?? r.roleLabel;
3614
+ const color = roleColor(r.roleLabel);
3615
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3616
+ style: {
3617
+ border: "1px solid var(--nf-border)",
3618
+ borderRadius: 8,
3619
+ padding: "6px 10px",
3620
+ fontSize: 12
3621
+ },
3622
+ children: [
3623
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3624
+ className: panel_module_css_default.row,
3625
+ style: {
3626
+ justifyContent: "space-between",
3627
+ flexWrap: "wrap"
3628
+ },
3629
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3630
+ style: {
3631
+ display: "flex",
3632
+ alignItems: "center",
3633
+ gap: 6,
3634
+ flexWrap: "wrap"
3635
+ },
3636
+ children: [
3637
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: r.name }),
3638
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3639
+ className: panel_module_css_default.badge,
3640
+ style: {
3641
+ borderColor: color,
3642
+ color
3643
+ },
3644
+ children: label
3645
+ }),
3646
+ r.identity !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3647
+ className: panel_module_css_default.meta,
3648
+ children: r.identity
3649
+ })
3650
+ ]
3651
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3652
+ style: {
3653
+ display: "flex",
3654
+ gap: 6
3655
+ },
3656
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3657
+ type: "button",
3658
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall} ${panel_module_css_default.buttonPrimary}`,
3659
+ disabled: props.disabled,
3660
+ onClick: props.onAdopt,
3661
+ children: "+ 采纳"
3662
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3663
+ type: "button",
3664
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
3665
+ disabled: props.disabled,
3666
+ onClick: props.onEdit,
3667
+ title: "修改后再采纳(候选列表保留)",
3668
+ children: "✏️ 修改后采纳"
3669
+ })]
3670
+ })]
3671
+ }),
3672
+ r.goals !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3673
+ className: panel_module_css_default.meta,
3674
+ children: ["目标:", r.goals]
3675
+ }),
3676
+ r.relations.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3677
+ className: panel_module_css_default.meta,
3678
+ children: ["关系:", r.relations.join("、")]
3679
+ })
3680
+ ]
3681
+ }, r.name);
3682
+ }
3683
+ /** 已收录角色卡(含从编年录刷新的当前状态行)。 */
3684
+ function RoleCard(props) {
3685
+ const { role: r, status: st } = props;
3686
+ const label = ROLE_LABELS[r.roleLabel] ?? r.roleLabel;
3687
+ const color = roleColor(r.roleLabel);
3688
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3689
+ style: {
3690
+ border: "1px solid var(--nf-border)",
3691
+ borderRadius: 8,
3692
+ padding: "6px 10px",
3693
+ fontSize: 12
3694
+ },
3695
+ children: [
3696
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3697
+ className: panel_module_css_default.row,
3698
+ style: {
3699
+ justifyContent: "space-between",
3700
+ flexWrap: "wrap"
3701
+ },
3702
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3703
+ style: {
3704
+ display: "flex",
3705
+ alignItems: "center",
3706
+ gap: 6,
3707
+ flexWrap: "wrap"
3708
+ },
3709
+ children: [
3710
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: r.name }),
3711
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3712
+ className: panel_module_css_default.badge,
3713
+ style: {
3714
+ borderColor: color,
3715
+ color
3716
+ },
3717
+ children: label
3718
+ }),
3719
+ r.identity !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3720
+ className: panel_module_css_default.meta,
3721
+ children: r.identity
3722
+ })
3723
+ ]
3724
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3725
+ style: {
3726
+ display: "flex",
3727
+ gap: 6
3728
+ },
3729
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3730
+ type: "button",
3731
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
3732
+ disabled: props.disabled,
3733
+ onClick: props.onEdit,
3734
+ children: "编辑"
3735
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3736
+ type: "button",
3737
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
3738
+ disabled: props.disabled,
3739
+ onClick: props.onRemove,
3740
+ children: "删除"
3741
+ })]
3742
+ })]
3743
+ }),
3744
+ r.goals !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3745
+ className: panel_module_css_default.meta,
3746
+ children: ["目标:", r.goals]
3747
+ }),
3748
+ st !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3749
+ className: panel_module_css_default.meta,
3750
+ style: { color: "var(--nf-accent)" },
3751
+ children: [
3752
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: "当前状态:" }),
3753
+ st.status !== "" ? st.status : "(编年录暂无该角色记录)",
3754
+ " · 出场 ",
3755
+ st.appearances,
3756
+ " 次 · 最近 第 ",
3757
+ st.lastChapter,
3758
+ " 章"
3759
+ ]
3760
+ }),
3761
+ r.relations.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3762
+ className: panel_module_css_default.meta,
3763
+ children: ["关系:", r.relations.join("、")]
3764
+ }),
3765
+ r.arc.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3766
+ className: panel_module_css_default.meta,
3767
+ children: ["成长线:", r.arc.join(" → ")]
3768
+ }),
3769
+ r.knowledge.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3770
+ className: panel_module_css_default.meta,
3771
+ children: ["知情度:", r.knowledge.join(";")]
3772
+ })
3773
+ ]
3774
+ }, r.name);
3775
+ }
3776
+ /** 🩺 剧情健康检查报告面板。 */
3777
+ function PlotlineHealthPanel(props) {
3778
+ const { report } = props;
3779
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3780
+ style: {
3781
+ display: "flex",
3782
+ flexDirection: "column",
3783
+ gap: 6,
3784
+ border: "1px solid var(--nf-info)",
3785
+ borderRadius: 12,
3786
+ padding: 10
3787
+ },
3788
+ children: [
3789
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3790
+ className: panel_module_css_default.row,
3791
+ style: {
3792
+ justifyContent: "space-between",
3793
+ flexWrap: "wrap"
3794
+ },
3795
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: "🩺 剧情健康检查" }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3796
+ style: {
3797
+ display: "flex",
3798
+ gap: 8
3799
+ },
3800
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3801
+ type: "button",
3802
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
3803
+ disabled: props.disabled,
3804
+ onClick: props.onPlan,
3805
+ title: "基于本次诊断生成下一阶段剧情方案",
3806
+ children: "✨ 基于此设计方案"
3807
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3808
+ type: "button",
3809
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
3810
+ onClick: props.onClose,
3811
+ children: "收起"
3812
+ })]
3813
+ })]
3814
+ }),
3815
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3816
+ style: {
3817
+ fontSize: 12,
3818
+ fontWeight: 700,
3819
+ color: "var(--nf-accent)"
3820
+ },
3821
+ children: ["判定:", report.verdict]
3822
+ }),
3823
+ report.timing !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3824
+ className: panel_module_css_default.meta,
3825
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: "建议时机:" }), report.timing]
3826
+ }),
3827
+ report.reasons.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3828
+ style: {
3829
+ display: "flex",
3830
+ flexDirection: "column",
3831
+ gap: 2,
3832
+ fontSize: 12
3833
+ },
3834
+ children: report.reasons.map((r, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3835
+ className: panel_module_css_default.meta,
3836
+ children: ["· ", r]
3837
+ }, i))
3838
+ }),
3839
+ report.lines.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3840
+ style: {
3841
+ display: "flex",
3842
+ flexDirection: "column",
3843
+ gap: 4,
3844
+ fontSize: 12
3845
+ },
3846
+ children: report.lines.map((l, i) => {
3847
+ const color = l.health === "ok" ? "var(--nf-success)" : l.health === "warning" ? "var(--nf-warn)" : "var(--nf-error)";
3848
+ const label = l.health === "ok" ? "健康" : l.health === "warning" ? "预警" : "搁置过久";
3849
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3850
+ style: {
3851
+ display: "flex",
3852
+ gap: 8,
3853
+ alignItems: "flex-start"
3854
+ },
3855
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3856
+ className: panel_module_css_default.badge,
3857
+ style: {
3858
+ borderColor: color,
3859
+ color,
3860
+ flex: "none",
3861
+ marginTop: 1
3862
+ },
3863
+ children: label
3864
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3865
+ className: panel_module_css_default.meta,
3866
+ children: [
3867
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: l.name }),
3868
+ ":",
3869
+ l.note
3870
+ ]
3871
+ })]
3872
+ }, i);
3873
+ })
3874
+ })
3875
+ ]
3876
+ });
3877
+ }
3878
+ /** ✨ AI 剧情方案面板。 */
3879
+ function PlotlinePlanPanel(props) {
3880
+ const { plan } = props;
3881
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3882
+ style: {
3883
+ display: "flex",
3884
+ flexDirection: "column",
3885
+ gap: 6,
3886
+ border: "1px solid var(--nf-accent)",
3887
+ borderRadius: 12,
3888
+ padding: 10
3889
+ },
3890
+ children: [
3891
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3892
+ className: panel_module_css_default.row,
3893
+ style: {
3894
+ justifyContent: "space-between",
3895
+ flexWrap: "wrap"
3896
+ },
3897
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: "✨ AI 剧情方案" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3898
+ type: "button",
3899
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
3900
+ onClick: props.onClose,
3901
+ children: "收起"
3902
+ })]
3903
+ }),
3904
+ plan.direction !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3905
+ className: panel_module_css_default.meta,
3906
+ style: { fontSize: 12 },
3907
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: "下一阶段方向:" }), plan.direction]
3908
+ }),
3909
+ plan.suggestions.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3910
+ style: {
3911
+ display: "flex",
3912
+ flexDirection: "column",
3913
+ gap: 4,
3914
+ fontSize: 12
3915
+ },
3916
+ children: plan.suggestions.map((s, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3917
+ style: {
3918
+ border: "1px solid var(--nf-border)",
3919
+ borderRadius: 8,
3920
+ padding: "6px 10px"
3921
+ },
3922
+ children: [
3923
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3924
+ className: panel_module_css_default.row,
3925
+ style: {
3926
+ justifyContent: "space-between",
3927
+ flexWrap: "wrap"
3928
+ },
3929
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3930
+ style: {
3931
+ display: "flex",
3932
+ alignItems: "center",
3933
+ gap: 6,
3934
+ flexWrap: "wrap"
3935
+ },
3936
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: s.name }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3937
+ className: panel_module_css_default.badge,
3938
+ style: {
3939
+ borderColor: "var(--nf-accent)",
3940
+ color: "var(--nf-accent)"
3941
+ },
3942
+ children: kindLabel(s.kind)
3943
+ })]
3944
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3945
+ type: "button",
3946
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall} ${panel_module_css_default.buttonPrimary}`,
3947
+ disabled: props.disabled,
3948
+ onClick: () => {
3949
+ props.onAdopt(s);
3950
+ },
3951
+ children: "+ 采纳"
3952
+ })]
3953
+ }),
3954
+ s.goal !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3955
+ className: panel_module_css_default.meta,
3956
+ children: s.goal
3957
+ }),
3958
+ s.progress !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3959
+ className: panel_module_css_default.meta,
3960
+ children: ["初始进度:", s.progress]
3961
+ })
3962
+ ]
3963
+ }, i))
3964
+ })
3965
+ ]
3966
+ });
3967
+ }
3968
+ /** ✨ AI 建议剧情线面板。 */
3969
+ function PlotlineSuggestionPanel(props) {
3970
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3971
+ style: {
3972
+ display: "flex",
3973
+ flexDirection: "column",
3974
+ gap: 6,
3975
+ border: "1px solid var(--nf-info)",
3976
+ borderRadius: 12,
3977
+ padding: 10
3167
3978
  },
3168
3979
  children: [
3169
- error !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3170
- className: panel_module_css_default.card,
3171
- style: { borderColor: "var(--nf-error)" },
3172
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3173
- style: { color: "var(--nf-error)" },
3174
- children: error
3175
- })
3176
- }),
3177
3980
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3178
- className: panel_module_css_default.card,
3179
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3180
- className: panel_module_css_default.row,
3181
- style: { justifyContent: "space-between" },
3182
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3183
- className: panel_module_css_default.cardTitle,
3184
- children: "大世界"
3185
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3186
- className: panel_module_css_default.row,
3187
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3188
- type: "button",
3189
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall} ${panel_module_css_default.buttonPrimary}`,
3190
- disabled: busy,
3191
- onClick: () => {
3192
- handleGenerate();
3193
- },
3194
- children: "✨ AI 提炼"
3195
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3196
- type: "button",
3197
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
3198
- disabled: busy,
3199
- onClick: () => {
3200
- handleSave();
3201
- },
3202
- children: "💾 保存"
3203
- })]
3204
- })]
3205
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3206
- className: panel_module_css_default.meta,
3207
- children: "境界体系按由低到高排序注入章节生成提示词,模型不得随意跳级或自创境界;区域与势力约束地理/势力设定。AI 提炼不满意可逐条编辑后保存。"
3981
+ className: panel_module_css_default.row,
3982
+ style: {
3983
+ justifyContent: "space-between",
3984
+ flexWrap: "wrap"
3985
+ },
3986
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("b", { children: [
3987
+ "✨ AI 建议(",
3988
+ props.suggestions.length,
3989
+ " 条)"
3990
+ ] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3991
+ type: "button",
3992
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
3993
+ onClick: props.onClose,
3994
+ children: "收起"
3208
3995
  })]
3209
3996
  }),
3210
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3211
- className: panel_module_css_default.card,
3212
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3213
- className: panel_module_css_default.row,
3214
- style: { justifyContent: "space-between" },
3215
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3216
- className: panel_module_css_default.cardTitle,
3217
- children: [
3218
- "境界体系(",
3219
- draft.realms.length,
3220
- ")"
3221
- ]
3222
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3223
- type: "button",
3224
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
3225
- onClick: () => {
3226
- setRealms([...draft.realms, {
3227
- name: "",
3228
- description: ""
3229
- }]);
3230
- },
3231
- children: "+ 新增境界"
3232
- })]
3233
- }), draft.realms.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3234
- className: panel_module_css_default.meta,
3235
- children: "暂无境界体系 — 点击 ✨AI 提炼 或手动添加(由低到高)。"
3236
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3237
- style: {
3238
- display: "flex",
3239
- flexDirection: "column",
3240
- gap: 6
3241
- },
3242
- children: draft.realms.map((realm, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EditableRow, {
3243
- name: realm.name,
3244
- detail: realm.description,
3245
- onName: (v) => {
3246
- const next = [...draft.realms];
3247
- next[i] = {
3248
- ...next[i],
3249
- name: v
3250
- };
3251
- setRealms(next);
3252
- },
3253
- onDetail: (v) => {
3254
- const next = [...draft.realms];
3255
- next[i] = {
3256
- ...next[i],
3257
- description: v
3258
- };
3259
- setRealms(next);
3260
- },
3261
- onRemove: () => {
3262
- setRealms(draft.realms.filter((_, idx) => idx !== i));
3263
- },
3264
- namePlaceholder: `第 ${i + 1} 阶境界名`,
3265
- detailPlaceholder: "突破条件 / 寿命 / 标志…"
3266
- }, i))
3267
- })]
3997
+ props.suggestions.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3998
+ className: panel_module_css_default.meta,
3999
+ children: "没有候选线。"
3268
4000
  }),
3269
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3270
- className: panel_module_css_default.card,
4001
+ props.suggestions.map((s, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4002
+ style: {
4003
+ border: "1px solid var(--nf-border)",
4004
+ borderRadius: 8,
4005
+ padding: "6px 10px",
4006
+ fontSize: 12
4007
+ },
3271
4008
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3272
4009
  className: panel_module_css_default.row,
3273
- style: { justifyContent: "space-between" },
3274
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3275
- className: panel_module_css_default.cardTitle,
3276
- children: [
3277
- "地理区域(",
3278
- draft.regions.length,
3279
- ")"
3280
- ]
3281
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3282
- type: "button",
3283
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
3284
- onClick: () => {
3285
- setRegions([...draft.regions, {
3286
- name: "",
3287
- description: ""
3288
- }]);
3289
- },
3290
- children: "+ 新增区域"
3291
- })]
3292
- }), draft.regions.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3293
- className: panel_module_css_default.meta,
3294
- children: "暂无地理区域 — 大陆 / 海域 / 秘境 / 遗迹…"
3295
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3296
4010
  style: {
3297
- display: "flex",
3298
- flexDirection: "column",
3299
- gap: 6
4011
+ justifyContent: "space-between",
4012
+ flexWrap: "wrap"
3300
4013
  },
3301
- children: draft.regions.map((region, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EditableRow, {
3302
- name: region.name,
3303
- detail: region.description,
3304
- onName: (v) => {
3305
- const next = [...draft.regions];
3306
- next[i] = {
3307
- ...next[i],
3308
- name: v
3309
- };
3310
- setRegions(next);
3311
- },
3312
- onDetail: (v) => {
3313
- const next = [...draft.regions];
3314
- next[i] = {
3315
- ...next[i],
3316
- description: v
3317
- };
3318
- setRegions(next);
3319
- },
3320
- onRemove: () => {
3321
- setRegions(draft.regions.filter((_, idx) => idx !== i));
3322
- },
3323
- namePlaceholder: "区域名(如大荒 / 青云山脉)",
3324
- detailPlaceholder: "描述…"
3325
- }, i))
3326
- })]
3327
- }),
3328
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3329
- className: panel_module_css_default.card,
3330
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3331
- className: panel_module_css_default.row,
3332
- style: { justifyContent: "space-between" },
3333
4014
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3334
- className: panel_module_css_default.cardTitle,
3335
- children: [
3336
- "势力分布(",
3337
- draft.factions.length,
3338
- ")"
3339
- ]
4015
+ style: {
4016
+ display: "flex",
4017
+ alignItems: "center",
4018
+ gap: 6,
4019
+ flexWrap: "wrap"
4020
+ },
4021
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: s.name }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4022
+ className: panel_module_css_default.badge,
4023
+ style: {
4024
+ borderColor: "var(--nf-accent)",
4025
+ color: "var(--nf-accent)"
4026
+ },
4027
+ children: kindLabel(s.kind)
4028
+ })]
3340
4029
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3341
4030
  type: "button",
3342
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
4031
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall} ${panel_module_css_default.buttonPrimary}`,
4032
+ disabled: props.disabled,
3343
4033
  onClick: () => {
3344
- setFactions([...draft.factions, {
3345
- name: "",
3346
- kind: "宗门",
3347
- description: ""
3348
- }]);
4034
+ props.onAdopt(s);
3349
4035
  },
3350
- children: "+ 新增势力"
4036
+ children: "+ 采纳"
3351
4037
  })]
3352
- }), draft.factions.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4038
+ }), s.goal !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3353
4039
  className: panel_module_css_default.meta,
3354
- children: "暂无势力 — 宗门 / 家族 / 王朝 / 组织…"
3355
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3356
- style: {
3357
- display: "flex",
3358
- flexDirection: "column",
3359
- gap: 6
3360
- },
3361
- children: draft.factions.map((faction, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EditableRow, {
3362
- name: `${faction.name}(${faction.kind})`,
3363
- detail: faction.description,
3364
- onName: (v) => {
3365
- const next = [...draft.factions];
3366
- const match = /^(.*)((.*))$/.exec(v);
3367
- next[i] = {
3368
- ...next[i],
3369
- name: (match?.[1] ?? v).trim(),
3370
- kind: (match?.[2] ?? next[i].kind).trim() || "宗门"
3371
- };
3372
- setFactions(next);
3373
- },
3374
- onDetail: (v) => {
3375
- const next = [...draft.factions];
3376
- next[i] = {
3377
- ...next[i],
3378
- description: v
3379
- };
3380
- setFactions(next);
3381
- },
3382
- onRemove: () => {
3383
- setFactions(draft.factions.filter((_, idx) => idx !== i));
3384
- },
3385
- namePlaceholder: "势力名(类型)如:青云宗(宗门)",
3386
- detailPlaceholder: "描述…"
3387
- }, i))
4040
+ children: s.goal
3388
4041
  })]
3389
- })
4042
+ }, i))
3390
4043
  ]
3391
4044
  });
3392
4045
  }
@@ -3463,11 +4116,6 @@ window.__ModuleLoader__.load({
3463
4116
  label: "角色库",
3464
4117
  icon: "👥"
3465
4118
  },
3466
- {
3467
- id: "characters",
3468
- label: "人物志",
3469
- icon: "🧾"
3470
- },
3471
4119
  {
3472
4120
  id: "foreshadow",
3473
4121
  label: tt("tab.foreshadow"),
@@ -3517,7 +4165,7 @@ window.__ModuleLoader__.load({
3517
4165
  label: tt("tab.settings"),
3518
4166
  icon: "⚙️"
3519
4167
  };
3520
- const PLUGIN_VERSION = "1.1.5";
4168
+ const PLUGIN_VERSION = "1.1.7";
3521
4169
  /** GitHub 仓库地址(关于区块点击跳转)。 */
3522
4170
  const REPO_URL = "https://github.com/watersxya/dsh-novel-forge";
3523
4171
  /** Whether any chapter is being generated right now. */
@@ -4203,15 +4851,20 @@ window.__ModuleLoader__.load({
4203
4851
  /** 角色卡刷新。 */
4204
4852
  const handleCharactersRefresh = async () => {
4205
4853
  setBusy(true);
4206
- setBusyLabel("聚合角色卡中…");
4854
+ setBusyLabel("聚合角色状态中…");
4207
4855
  setError("");
4208
4856
  try {
4209
4857
  const result = await api.charactersRefresh();
4210
4858
  setCharCards(result.cards);
4211
- pushProgress(`角色卡已刷新:${result.cards.length} 个角色`, "done");
4859
+ setProject((prev) => prev === null ? prev : {
4860
+ ...prev,
4861
+ roleStatus: result.cards,
4862
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
4863
+ });
4864
+ pushProgress(`角色状态已刷新:${result.cards.length} 个角色`, "done");
4212
4865
  } catch (err) {
4213
4866
  setError(err.message);
4214
- pushProgress(`角色卡刷新失败:${err.message}`, "error");
4867
+ pushProgress(`角色状态刷新失败:${err.message}`, "error");
4215
4868
  } finally {
4216
4869
  setBusy(false);
4217
4870
  setBusyLabel("");
@@ -4245,14 +4898,36 @@ window.__ModuleLoader__.load({
4245
4898
  ...prev,
4246
4899
  chapters: prev.chapters.map((c) => c.no === no ? {
4247
4900
  ...c,
4248
- status: "pending",
4249
- error: void 0
4901
+ status: "pending",
4902
+ error: void 0
4903
+ } : c)
4904
+ });
4905
+ pushProgress(`第 ${no} 章已复位为待生成,可重新生成`, "info");
4906
+ } catch (err) {
4907
+ setError(err.message);
4908
+ pushProgress(`复位失败:${err.message}`, "error");
4909
+ } finally {
4910
+ setBusy(false);
4911
+ }
4912
+ };
4913
+ /** 章节直接通过(作者行使最终决定权)。 */
4914
+ const handleChapterApprove = async (no) => {
4915
+ if (!window.confirm(`确定直接通过第 ${no} 章?(跳过审稿判定,保留审稿记录)`)) return;
4916
+ setBusy(true);
4917
+ setError("");
4918
+ try {
4919
+ await api.chapterApprove(no);
4920
+ setProject((prev) => prev === null ? prev : {
4921
+ ...prev,
4922
+ chapters: prev.chapters.map((c) => c.no === no ? {
4923
+ ...c,
4924
+ status: "approved"
4250
4925
  } : c)
4251
4926
  });
4252
- pushProgress(`第 ${no} 章已复位为待生成,可重新生成`, "info");
4927
+ pushProgress(`第 ${no} 章已直接通过`, "done");
4253
4928
  } catch (err) {
4254
4929
  setError(err.message);
4255
- pushProgress(`复位失败:${err.message}`, "error");
4930
+ pushProgress(`操作失败:${err.message}`, "error");
4256
4931
  } finally {
4257
4932
  setBusy(false);
4258
4933
  }
@@ -5208,17 +5883,6 @@ window.__ModuleLoader__.load({
5208
5883
  setBusyLabel("");
5209
5884
  }
5210
5885
  };
5211
- /** Approve a chapter manually. */
5212
- const handleApprove = (no) => {
5213
- setProject((prev) => prev === null ? prev : {
5214
- ...prev,
5215
- chapters: prev.chapters.map((c) => c.no === no ? {
5216
- ...c,
5217
- status: "approved"
5218
- } : c),
5219
- updatedAt: (/* @__PURE__ */ new Date()).toISOString()
5220
- });
5221
- };
5222
5886
  /** Toggle chapter preview. */
5223
5887
  const handleToggleChapter = async (no) => {
5224
5888
  if (expandedChapter === no) {
@@ -6248,135 +6912,46 @@ window.__ModuleLoader__.load({
6248
6912
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6249
6913
  className: panel_module_css_default.assetGrid,
6250
6914
  children: [
6251
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6252
- className: panel_module_css_default.assetStat,
6253
- children: [
6254
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6255
- className: panel_module_css_default.assetStatLabel,
6256
- children: "全书进度"
6257
- }),
6258
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6259
- className: panel_module_css_default.assetStatValue,
6260
- style: { color: "var(--nf-accent)" },
6261
- children: [
6262
- doneCount,
6263
- "/",
6264
- chapters.length,
6265
- " 章"
6266
- ]
6267
- }),
6268
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6269
- className: panel_module_css_default.assetStatDetail,
6270
- children: [chapters.length > 0 ? Math.round(doneCount / chapters.length * 100) : 0, "%"]
6271
- })
6272
- ]
6915
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StatCell, {
6916
+ label: "全书进度",
6917
+ value: `${doneCount}/${chapters.length} 章`,
6918
+ valueColor: "var(--nf-accent)",
6919
+ detail: `${chapters.length > 0 ? Math.round(doneCount / chapters.length * 100) : 0}%`
6273
6920
  }),
6274
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6275
- className: panel_module_css_default.assetStat,
6276
- children: [
6277
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6278
- className: panel_module_css_default.assetStatLabel,
6279
- children: "已通过审稿"
6280
- }),
6281
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6282
- className: panel_module_css_default.assetStatValue,
6283
- style: { color: approvedCount > 0 ? "var(--nf-success)" : void 0 },
6284
- children: approvedCount
6285
- }),
6286
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6287
- className: panel_module_css_default.assetStatDetail,
6288
- children: "章节已 approved"
6289
- })
6290
- ]
6921
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StatCell, {
6922
+ label: "已通过审稿",
6923
+ value: String(approvedCount),
6924
+ valueColor: approvedCount > 0 ? "var(--nf-success)" : void 0,
6925
+ detail: "章节已 approved"
6291
6926
  }),
6292
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6293
- className: panel_module_css_default.assetStat,
6294
- children: [
6295
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6296
- className: panel_module_css_default.assetStatLabel,
6297
- children: "待生成"
6298
- }),
6299
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6300
- className: panel_module_css_default.assetStatValue,
6301
- style: { color: pendingCount > 0 ? "var(--nf-warn)" : void 0 },
6302
- children: pendingCount
6303
- }),
6304
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6305
- className: panel_module_css_default.assetStatDetail,
6306
- children: "pending + error"
6307
- })
6308
- ]
6927
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StatCell, {
6928
+ label: "待生成",
6929
+ value: String(pendingCount),
6930
+ valueColor: pendingCount > 0 ? "var(--nf-warn)" : void 0,
6931
+ detail: "pending + error"
6309
6932
  }),
6310
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6311
- className: panel_module_css_default.assetStat,
6312
- children: [
6313
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6314
- className: panel_module_css_default.assetStatLabel,
6315
- children: "待审稿"
6316
- }),
6317
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6318
- className: panel_module_css_default.assetStatValue,
6319
- style: { color: reviewPendingCount > 0 ? "var(--nf-info)" : void 0 },
6320
- children: reviewPendingCount
6321
- }),
6322
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6323
- className: panel_module_css_default.assetStatDetail,
6324
- children: "written + rejected"
6325
- })
6326
- ]
6933
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StatCell, {
6934
+ label: "待审稿",
6935
+ value: String(reviewPendingCount),
6936
+ valueColor: reviewPendingCount > 0 ? "var(--nf-info)" : void 0,
6937
+ detail: "written + rejected"
6327
6938
  }),
6328
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6329
- className: panel_module_css_default.assetStat,
6330
- children: [
6331
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6332
- className: panel_module_css_default.assetStatLabel,
6333
- children: "总字数"
6334
- }),
6335
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6336
- className: panel_module_css_default.assetStatValue,
6337
- children: totalChars
6338
- }),
6339
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6340
- className: panel_module_css_default.assetStatDetail,
6341
- children: "已生成正文累计"
6342
- })
6343
- ]
6939
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StatCell, {
6940
+ label: "总字数",
6941
+ value: String(totalChars),
6942
+ detail: "已生成正文累计"
6344
6943
  }),
6345
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6346
- className: panel_module_css_default.assetStat,
6347
- children: [
6348
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6349
- className: panel_module_css_default.assetStatLabel,
6350
- children: "当前卷"
6351
- }),
6352
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6353
- className: panel_module_css_default.assetStatValue,
6354
- style: { fontSize: 13 },
6355
- children: currentVolumeName
6356
- }),
6357
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6358
- className: panel_module_css_default.assetStatDetail,
6359
- children: "正在推进的卷"
6360
- })
6361
- ]
6944
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StatCell, {
6945
+ label: "当前卷",
6946
+ value: currentVolumeName,
6947
+ valueFontSize: 13,
6948
+ detail: "正在推进的卷"
6362
6949
  }),
6363
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6364
- className: panel_module_css_default.assetStat,
6365
- children: [
6366
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6367
- className: panel_module_css_default.assetStatLabel,
6368
- children: "最近创作"
6369
- }),
6370
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6371
- className: panel_module_css_default.assetStatValue,
6372
- style: { fontSize: 13 },
6373
- children: lastUpdated
6374
- }),
6375
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6376
- className: panel_module_css_default.assetStatDetail,
6377
- children: "最近生成/编辑时间"
6378
- })
6379
- ]
6950
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StatCell, {
6951
+ label: "最近创作",
6952
+ value: lastUpdated,
6953
+ valueFontSize: 13,
6954
+ detail: "最近生成/编辑时间"
6380
6955
  })
6381
6956
  ]
6382
6957
  }),
@@ -6401,83 +6976,30 @@ window.__ModuleLoader__.load({
6401
6976
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6402
6977
  className: panel_module_css_default.assetGrid,
6403
6978
  children: [
6404
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6405
- className: panel_module_css_default.assetStat,
6406
- children: [
6407
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6408
- className: panel_module_css_default.assetStatLabel,
6409
- children: "道藏"
6410
- }),
6411
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6412
- className: panel_module_css_default.assetStatValue,
6413
- style: { color: bible !== void 0 ? "var(--nf-success)" : "var(--nf-text-3)" },
6414
- children: bible !== void 0 ? `✓ ${bible.worldRules.length} 条规则` : "未生成"
6415
- }),
6416
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6417
- className: panel_module_css_default.assetStatDetail,
6418
- children: bible !== void 0 ? `${bible.characters.length} 人物 · ${bible.redLines.length} 红线` : "提炼人设 / 世界观 / 金手指"
6419
- })
6420
- ]
6979
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StatCell, {
6980
+ label: "道藏",
6981
+ value: bible !== void 0 ? `✓ ${bible.worldRules.length} 条规则` : "未生成",
6982
+ valueColor: bible !== void 0 ? "var(--nf-success)" : "var(--nf-text-3)",
6983
+ detail: bible !== void 0 ? `${bible.characters.length} 人物 · ${bible.redLines.length} 红线` : "提炼人设 / 世界观 / 金手指"
6421
6984
  }),
6422
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6423
- className: panel_module_css_default.assetStat,
6424
- children: [
6425
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6426
- className: panel_module_css_default.assetStatLabel,
6427
- children: "卷计划"
6428
- }),
6429
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6430
- className: panel_module_css_default.assetStatValue,
6431
- style: { color: volumes !== void 0 ? "var(--nf-success)" : "var(--nf-text-3)" },
6432
- children: volumes !== void 0 ? `${volumes.length} 卷` : "未生成"
6433
- }),
6434
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6435
- className: panel_module_css_default.assetStatDetail,
6436
- title: volumes?.map((v) => v.title).join(" / "),
6437
- children: volumes !== void 0 ? volumes.map((v) => v.title).join(" / ") : "按剧情弧线划分全书"
6438
- })
6439
- ]
6985
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StatCell, {
6986
+ label: "卷计划",
6987
+ value: volumes !== void 0 ? `${volumes.length} 卷` : "未生成",
6988
+ valueColor: volumes !== void 0 ? "var(--nf-success)" : "var(--nf-text-3)",
6989
+ detail: volumes !== void 0 ? volumes.map((v) => v.title).join(" / ") : "按剧情弧线划分全书",
6990
+ detailTitle: volumes?.map((v) => v.title).join(" / ")
6440
6991
  }),
6441
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6442
- className: panel_module_css_default.assetStat,
6443
- children: [
6444
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6445
- className: panel_module_css_default.assetStatLabel,
6446
- children: "写作资产"
6447
- }),
6448
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6449
- className: panel_module_css_default.assetStatValue,
6450
- style: { color: assetCount > 0 ? "var(--nf-success)" : "var(--nf-text-3)" },
6451
- children: [assetCount, " 项"]
6452
- }),
6453
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6454
- className: panel_module_css_default.assetStatDetail,
6455
- title: assetSummary,
6456
- children: assetSummary
6457
- })
6458
- ]
6992
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StatCell, {
6993
+ label: "写作资产",
6994
+ value: `${assetCount} 项`,
6995
+ valueColor: assetCount > 0 ? "var(--nf-success)" : "var(--nf-text-3)",
6996
+ detail: assetSummary,
6997
+ detailTitle: assetSummary
6459
6998
  }),
6460
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6461
- className: panel_module_css_default.assetStat,
6462
- children: [
6463
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6464
- className: panel_module_css_default.assetStatLabel,
6465
- children: "伏笔"
6466
- }),
6467
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6468
- className: panel_module_css_default.assetStatValue,
6469
- children: [foreshadows.length, " 条"]
6470
- }),
6471
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6472
- className: panel_module_css_default.assetStatDetail,
6473
- children: [
6474
- foreshadows.filter((f) => f.status === "planned").length,
6475
- " 待埋 · ",
6476
- foreshadows.filter((f) => f.status === "resolved").length,
6477
- " 已回收"
6478
- ]
6479
- })
6480
- ]
6999
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StatCell, {
7000
+ label: "伏笔",
7001
+ value: `${foreshadows.length} 条`,
7002
+ detail: `${foreshadows.filter((f) => f.status === "planned").length} 待埋 · ${foreshadows.filter((f) => f.status === "resolved").length} 已回收`
6481
7003
  })
6482
7004
  ]
6483
7005
  })]
@@ -6642,29 +7164,12 @@ window.__ModuleLoader__.load({
6642
7164
  flexDirection: "column",
6643
7165
  gap: 6
6644
7166
  },
6645
- children: auditIssues.map((issue, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6646
- className: `${panel_module_css_default.todoItem} ${issue.severity === "high" ? panel_module_css_default.todoDanger : issue.severity === "medium" ? panel_module_css_default.todoWarning : panel_module_css_default.todoInfo}`,
6647
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6648
- className: panel_module_css_default.todoText,
6649
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
6650
- issue.chapterNo > 0 ? `第 ${issue.chapterNo} 章` : "未定位章节",
6651
- " · [",
6652
- issue.severity,
6653
- "] ",
6654
- issue.item
6655
- ] }), issue.suggestion !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6656
- className: panel_module_css_default.meta,
6657
- children: ["建议:", issue.suggestion]
6658
- })]
6659
- }), issue.chapterNo > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6660
- type: "button",
6661
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
6662
- disabled: busy,
6663
- onClick: () => {
6664
- openWorkspace(issue.chapterNo, `按质检意见修订:${issue.item}(建议:${issue.suggestion})`);
6665
- },
6666
- children: "去修订"
6667
- })]
7167
+ children: auditIssues.map((issue, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AuditIssueRow, {
7168
+ issue,
7169
+ disabled: busy,
7170
+ onFix: () => {
7171
+ openWorkspace(issue.chapterNo, `按质检意见修订:${issue.item}(建议:${issue.suggestion})`);
7172
+ }
6668
7173
  }, i))
6669
7174
  })]
6670
7175
  }),
@@ -6676,23 +7181,13 @@ window.__ModuleLoader__.load({
6676
7181
  }), todos.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6677
7182
  className: panel_module_css_default.meta,
6678
7183
  children: "🎉 暂无待办,一切顺畅"
6679
- }) : todos.map((todo, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6680
- className: `${panel_module_css_default.todoItem} ${todo.tone === "danger" ? panel_module_css_default.todoDanger : todo.tone === "warning" ? panel_module_css_default.todoWarning : panel_module_css_default.todoInfo}`,
6681
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6682
- className: panel_module_css_default.todoText,
6683
- children: [todo.title, todo.description !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6684
- className: panel_module_css_default.meta,
6685
- children: [" — ", todo.description]
6686
- })]
6687
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6688
- type: "button",
6689
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
6690
- disabled: busy,
6691
- onClick: () => {
6692
- todo.onClick();
6693
- },
6694
- children: todo.actionLabel
6695
- })]
7184
+ }) : todos.map((todo, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TodoRow, {
7185
+ tone: todo.tone,
7186
+ title: todo.title,
7187
+ description: todo.description,
7188
+ actionLabel: todo.actionLabel,
7189
+ disabled: busy,
7190
+ onAction: todo.onClick
6696
7191
  }, i))]
6697
7192
  })
6698
7193
  ] }),
@@ -7487,14 +7982,15 @@ window.__ModuleLoader__.load({
7487
7982
  },
7488
7983
  children: tt("plan.review")
7489
7984
  }),
7490
- chapter.status === "written" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7985
+ (chapter.status === "written" || chapter.status === "rejected") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7491
7986
  type: "button",
7492
7987
  className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
7493
7988
  disabled: busy || busyAny,
7494
7989
  onClick: () => {
7495
- handleApprove(chapter.no);
7990
+ handleChapterApprove(chapter.no);
7496
7991
  },
7497
- children: tt("plan.approve")
7992
+ title: "作者行使最终决定权:直接通过(不重审,保留审稿记录,落盘保存)",
7993
+ children: "✔ 直接通过"
7498
7994
  }),
7499
7995
  (chapter.status === "written" || chapter.status === "rejected" || chapter.status === "approved") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7500
7996
  type: "button",
@@ -7935,9 +8431,18 @@ window.__ModuleLoader__.load({
7935
8431
  (project?.roles ?? []).length,
7936
8432
  " 个)"
7937
8433
  ]
7938
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8434
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7939
8435
  className: panel_module_css_default.row,
7940
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8436
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8437
+ type: "button",
8438
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
8439
+ disabled: busy || (project?.facts ?? []).length === 0,
8440
+ onClick: () => {
8441
+ handleCharactersRefresh();
8442
+ },
8443
+ title: "从编年录聚合各角色当前状态(境界/伤势/心境/出场统计),显示在每张卡上",
8444
+ children: "↻ 从编年录刷新状态"
8445
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7941
8446
  type: "button",
7942
8447
  className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall} ${panel_module_css_default.buttonPrimary}`,
7943
8448
  disabled: busy || doneCount === 0,
@@ -7946,12 +8451,12 @@ window.__ModuleLoader__.load({
7946
8451
  },
7947
8452
  title: "AI 扫描大纲/编年录/已写章节,提炼完整角色库(含女主/女配/反派定位)",
7948
8453
  children: "✨ 从全书提炼角色"
7949
- })
8454
+ })]
7950
8455
  })]
7951
8456
  }),
7952
8457
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7953
8458
  className: panel_module_css_default.meta,
7954
- children: "角色库是全书角色主表:定位(女主/女配/配角/反派)、身份、关系网、成长线、知情度——生成与审稿都会按定位规格刻画互动。"
8459
+ children: "角色库是全书角色主表:定位(女主/女配/配角/反派)、身份、关系网、成长线、知情度——生成与审稿都会按定位规格刻画互动。点「从编年录刷新状态」可在每张卡上显示角色当前状态。"
7955
8460
  }),
7956
8461
  roleCandidates !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7957
8462
  style: {
@@ -7986,88 +8491,16 @@ window.__ModuleLoader__.load({
7986
8491
  className: panel_module_css_default.meta,
7987
8492
  children: "未提炼到角色。"
7988
8493
  }),
7989
- roleCandidates.map((r, i) => {
7990
- const label = {
7991
- protagonist: "主角",
7992
- female_lead: "女主",
7993
- female_support: "女配",
7994
- support: "配角",
7995
- antagonist: "反派",
7996
- extra: "路人"
7997
- }[r.roleLabel];
7998
- const color = r.roleLabel === "protagonist" ? "var(--nf-success)" : r.roleLabel === "female_lead" ? "var(--nf-accent)" : r.roleLabel === "antagonist" ? "var(--nf-error)" : "var(--nf-text-3)";
7999
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8000
- style: {
8001
- border: "1px solid var(--nf-border)",
8002
- borderRadius: 8,
8003
- padding: "6px 10px",
8004
- fontSize: 12
8005
- },
8006
- children: [
8007
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8008
- className: panel_module_css_default.row,
8009
- style: {
8010
- justifyContent: "space-between",
8011
- flexWrap: "wrap"
8012
- },
8013
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
8014
- style: {
8015
- display: "flex",
8016
- alignItems: "center",
8017
- gap: 6,
8018
- flexWrap: "wrap"
8019
- },
8020
- children: [
8021
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: r.name }),
8022
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8023
- className: panel_module_css_default.badge,
8024
- style: {
8025
- borderColor: color,
8026
- color
8027
- },
8028
- children: label
8029
- }),
8030
- r.identity !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8031
- className: panel_module_css_default.meta,
8032
- children: r.identity
8033
- })
8034
- ]
8035
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
8036
- style: {
8037
- display: "flex",
8038
- gap: 6
8039
- },
8040
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8041
- type: "button",
8042
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall} ${panel_module_css_default.buttonPrimary}`,
8043
- disabled: busy,
8044
- onClick: () => {
8045
- handleRoleAdopt(r);
8046
- },
8047
- children: "+ 采纳"
8048
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8049
- type: "button",
8050
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
8051
- disabled: busy,
8052
- onClick: () => {
8053
- setRoleDraft(r);
8054
- },
8055
- title: "修改后再采纳(候选列表保留)",
8056
- children: "✏️ 修改后采纳"
8057
- })]
8058
- })]
8059
- }),
8060
- r.goals !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8061
- className: panel_module_css_default.meta,
8062
- children: ["目标:", r.goals]
8063
- }),
8064
- r.relations.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8065
- className: panel_module_css_default.meta,
8066
- children: ["关系:", r.relations.join("、")]
8067
- })
8068
- ]
8069
- }, i);
8070
- })
8494
+ roleCandidates.map((r, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RoleCandidateRow, {
8495
+ candidate: r,
8496
+ disabled: busy,
8497
+ onAdopt: () => {
8498
+ handleRoleAdopt(r);
8499
+ },
8500
+ onEdit: () => {
8501
+ setRoleDraft(r);
8502
+ }
8503
+ }, i))
8071
8504
  ]
8072
8505
  }),
8073
8506
  roleDraft !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -8239,212 +8672,42 @@ window.__ModuleLoader__.load({
8239
8672
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8240
8673
  type: "button",
8241
8674
  className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall} ${panel_module_css_default.buttonPrimary}`,
8242
- disabled: busy,
8243
- onClick: () => {
8244
- handleRoleSave();
8245
- },
8246
- children: "保存"
8247
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8248
- type: "button",
8249
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
8250
- onClick: () => {
8251
- setRoleDraft(null);
8252
- },
8253
- children: "取消"
8254
- })]
8255
- })
8256
- ]
8257
- }),
8258
- (project?.roles ?? []).length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8259
- className: panel_module_css_default.meta,
8260
- children: "角色库为空——点「✨ 从全书提炼角色」自动建立,或手动新增。"
8261
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8262
- style: {
8263
- display: "flex",
8264
- flexDirection: "column",
8265
- gap: 6
8266
- },
8267
- children: (project?.roles ?? []).map((r) => {
8268
- const label = {
8269
- protagonist: "主角",
8270
- female_lead: "女主",
8271
- female_support: "女配",
8272
- support: "配角",
8273
- antagonist: "反派",
8274
- extra: "路人"
8275
- }[r.roleLabel];
8276
- const color = r.roleLabel === "protagonist" ? "var(--nf-success)" : r.roleLabel === "female_lead" ? "var(--nf-accent)" : r.roleLabel === "antagonist" ? "var(--nf-error)" : "var(--nf-text-3)";
8277
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8278
- style: {
8279
- border: "1px solid var(--nf-border)",
8280
- borderRadius: 8,
8281
- padding: "6px 10px",
8282
- fontSize: 12
8283
- },
8284
- children: [
8285
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8286
- className: panel_module_css_default.row,
8287
- style: {
8288
- justifyContent: "space-between",
8289
- flexWrap: "wrap"
8290
- },
8291
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
8292
- style: {
8293
- display: "flex",
8294
- alignItems: "center",
8295
- gap: 6,
8296
- flexWrap: "wrap"
8297
- },
8298
- children: [
8299
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: r.name }),
8300
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8301
- className: panel_module_css_default.badge,
8302
- style: {
8303
- borderColor: color,
8304
- color
8305
- },
8306
- children: label
8307
- }),
8308
- r.identity !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8309
- className: panel_module_css_default.meta,
8310
- children: r.identity
8311
- })
8312
- ]
8313
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
8314
- style: {
8315
- display: "flex",
8316
- gap: 6
8317
- },
8318
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8319
- type: "button",
8320
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
8321
- disabled: busy,
8322
- onClick: () => {
8323
- setRoleDraft(r);
8324
- },
8325
- children: "编辑"
8326
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8327
- type: "button",
8328
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
8329
- disabled: busy,
8330
- onClick: () => {
8331
- handleRoleRemove(r.name);
8332
- },
8333
- children: "删除"
8334
- })]
8335
- })]
8336
- }),
8337
- r.goals !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8338
- className: panel_module_css_default.meta,
8339
- children: ["目标:", r.goals]
8340
- }),
8341
- r.relations.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8342
- className: panel_module_css_default.meta,
8343
- children: ["关系:", r.relations.join("、")]
8344
- }),
8345
- r.arc.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8346
- className: panel_module_css_default.meta,
8347
- children: ["成长线:", r.arc.join(" → ")]
8348
- }),
8349
- r.knowledge.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8350
- className: panel_module_css_default.meta,
8351
- children: ["知情度:", r.knowledge.join(";")]
8352
- })
8353
- ]
8354
- }, r.name);
8355
- })
8356
- })
8357
- ]
8358
- }),
8359
- activeTab === "characters" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8360
- className: panel_module_css_default.card,
8361
- children: [
8362
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8363
- className: panel_module_css_default.row,
8364
- style: { justifyContent: "space-between" },
8365
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8366
- className: panel_module_css_default.cardTitle,
8367
- children: "人物志(当前状态)"
8368
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8369
- className: panel_module_css_default.row,
8370
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8371
- type: "button",
8372
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
8373
- disabled: busy || doneCount === 0,
8374
- onClick: () => {
8375
- handleFactsBackfill();
8376
- },
8377
- title: "历史章节(编年录功能上线前生成的)批量抽取事实",
8378
- children: "📥 回填编年录"
8379
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8380
- type: "button",
8381
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall} ${panel_module_css_default.buttonPrimary}`,
8382
- disabled: busy || (project?.facts ?? []).length === 0,
8383
- onClick: () => {
8384
- handleCharactersRefresh();
8385
- },
8386
- children: "↻ 从编年录刷新"
8387
- })]
8388
- })]
8675
+ disabled: busy,
8676
+ onClick: () => {
8677
+ handleRoleSave();
8678
+ },
8679
+ children: "保存"
8680
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8681
+ type: "button",
8682
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
8683
+ onClick: () => {
8684
+ setRoleDraft(null);
8685
+ },
8686
+ children: "取消"
8687
+ })]
8688
+ })
8689
+ ]
8389
8690
  }),
8390
- charCards === null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8391
- className: panel_module_css_default.meta,
8392
- children: (project?.facts ?? []).length === 0 ? "暂无编年录(生成章节后自动积累人物状态/境界/资源/关系等事实),刷新按钮将在有事实后可用。" : "点击「从编年录刷新」聚合各人物当前状态(境界/资源/伤势/心境)。"
8393
- }) : charCards.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8691
+ (project?.roles ?? []).length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8394
8692
  className: panel_module_css_default.meta,
8395
- children: "未识别到人物信息。"
8693
+ children: "角色库为空——点「✨ 从全书提炼角色」自动建立,或手动新增。"
8396
8694
  }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8397
8695
  style: {
8398
8696
  display: "flex",
8399
8697
  flexDirection: "column",
8400
8698
  gap: 6
8401
8699
  },
8402
- children: charCards.map((card) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8403
- style: {
8404
- border: "1px solid var(--nf-border)",
8405
- borderRadius: 8,
8406
- padding: "6px 10px",
8407
- fontSize: 12
8700
+ children: (project?.roles ?? []).map((r) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RoleCard, {
8701
+ role: r,
8702
+ status: (project?.roleStatus ?? []).find((s) => s.name === r.name),
8703
+ disabled: busy,
8704
+ onEdit: () => {
8705
+ setRoleDraft(r);
8408
8706
  },
8409
- children: [
8410
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8411
- className: panel_module_css_default.row,
8412
- style: { justifyContent: "space-between" },
8413
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: card.name }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
8414
- className: panel_module_css_default.meta,
8415
- children: [
8416
- card.role === "protagonist" ? "主角" : card.role === "supporting" ? "配角" : card.role === "antagonist" ? "反派" : "其他",
8417
- " · 出场 ",
8418
- card.appearances,
8419
- " 次 · 最近 第 ",
8420
- card.lastChapter,
8421
- " 章"
8422
- ]
8423
- })]
8424
- }),
8425
- card.status !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8426
- className: panel_module_css_default.meta,
8427
- children: ["状态:", card.status]
8428
- }),
8429
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8430
- className: panel_module_css_default.row,
8431
- style: { marginTop: 4 },
8432
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8433
- type: "button",
8434
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
8435
- onClick: () => {
8436
- setActiveTab("roles");
8437
- },
8438
- title: "在角色库中查看/编辑该角色档案",
8439
- children: "📖 查看档案"
8440
- })
8441
- })
8442
- ]
8443
- }, card.name))
8444
- }),
8445
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8446
- className: panel_module_css_default.meta,
8447
- children: "人物志由「道藏」人物名单 + 「编年录」聚合而来,随章节生成自动保持最新。"
8707
+ onRemove: () => {
8708
+ handleRoleRemove(r.name);
8709
+ }
8710
+ }, r.name))
8448
8711
  })
8449
8712
  ]
8450
8713
  }),
@@ -9063,288 +9326,35 @@ window.__ModuleLoader__.load({
9063
9326
  className: panel_module_css_default.meta,
9064
9327
  children: tt("plotlines.hint")
9065
9328
  }),
9066
- plotlineHealth !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9067
- style: {
9068
- display: "flex",
9069
- flexDirection: "column",
9070
- gap: 6,
9071
- border: "1px solid var(--nf-info)",
9072
- borderRadius: 12,
9073
- padding: 10
9329
+ plotlineHealth !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PlotlineHealthPanel, {
9330
+ report: plotlineHealth,
9331
+ disabled: busy,
9332
+ onPlan: () => {
9333
+ handlePlotlinePlan();
9074
9334
  },
9075
- children: [
9076
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9077
- className: panel_module_css_default.row,
9078
- style: {
9079
- justifyContent: "space-between",
9080
- flexWrap: "wrap"
9081
- },
9082
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: "🩺 剧情健康检查" }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
9083
- style: {
9084
- display: "flex",
9085
- gap: 8
9086
- },
9087
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
9088
- type: "button",
9089
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
9090
- disabled: busy,
9091
- onClick: () => {
9092
- handlePlotlinePlan();
9093
- },
9094
- title: "基于本次诊断生成下一阶段剧情方案",
9095
- children: "✨ 基于此设计方案"
9096
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
9097
- type: "button",
9098
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
9099
- onClick: () => {
9100
- setPlotlineHealth(null);
9101
- },
9102
- children: "收起"
9103
- })]
9104
- })]
9105
- }),
9106
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9107
- style: {
9108
- fontSize: 12,
9109
- fontWeight: 700,
9110
- color: "var(--nf-accent)"
9111
- },
9112
- children: ["判定:", plotlineHealth.verdict]
9113
- }),
9114
- plotlineHealth.timing !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9115
- className: panel_module_css_default.meta,
9116
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: "建议时机:" }), plotlineHealth.timing]
9117
- }),
9118
- plotlineHealth.reasons.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9119
- style: {
9120
- display: "flex",
9121
- flexDirection: "column",
9122
- gap: 2,
9123
- fontSize: 12
9124
- },
9125
- children: plotlineHealth.reasons.map((r, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9126
- className: panel_module_css_default.meta,
9127
- children: ["· ", r]
9128
- }, i))
9129
- }),
9130
- plotlineHealth.lines.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9131
- style: {
9132
- display: "flex",
9133
- flexDirection: "column",
9134
- gap: 4,
9135
- fontSize: 12
9136
- },
9137
- children: plotlineHealth.lines.map((l, i) => {
9138
- const color = l.health === "ok" ? "var(--nf-success)" : l.health === "warning" ? "var(--nf-warn)" : "var(--nf-error)";
9139
- const label = l.health === "ok" ? "健康" : l.health === "warning" ? "预警" : "搁置过久";
9140
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9141
- style: {
9142
- display: "flex",
9143
- gap: 8,
9144
- alignItems: "flex-start"
9145
- },
9146
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9147
- className: panel_module_css_default.badge,
9148
- style: {
9149
- borderColor: color,
9150
- color,
9151
- flex: "none",
9152
- marginTop: 1
9153
- },
9154
- children: label
9155
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
9156
- className: panel_module_css_default.meta,
9157
- children: [
9158
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: l.name }),
9159
- ":",
9160
- l.note
9161
- ]
9162
- })]
9163
- }, i);
9164
- })
9165
- })
9166
- ]
9335
+ onClose: () => {
9336
+ setPlotlineHealth(null);
9337
+ }
9167
9338
  }),
9168
- plotlinePlan !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9169
- style: {
9170
- display: "flex",
9171
- flexDirection: "column",
9172
- gap: 6,
9173
- border: "1px solid var(--nf-accent)",
9174
- borderRadius: 12,
9175
- padding: 10
9339
+ plotlinePlan !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PlotlinePlanPanel, {
9340
+ plan: plotlinePlan,
9341
+ disabled: busy,
9342
+ onAdopt: (s) => {
9343
+ handlePlanAdopt(s);
9176
9344
  },
9177
- children: [
9178
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9179
- className: panel_module_css_default.row,
9180
- style: {
9181
- justifyContent: "space-between",
9182
- flexWrap: "wrap"
9183
- },
9184
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: "✨ AI 剧情方案" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
9185
- type: "button",
9186
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
9187
- onClick: () => {
9188
- setPlotlinePlan(null);
9189
- },
9190
- children: "收起"
9191
- })]
9192
- }),
9193
- plotlinePlan.direction !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9194
- className: panel_module_css_default.meta,
9195
- style: { fontSize: 12 },
9196
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: "下一阶段方向:" }), plotlinePlan.direction]
9197
- }),
9198
- plotlinePlan.suggestions.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9199
- style: {
9200
- display: "flex",
9201
- flexDirection: "column",
9202
- gap: 4,
9203
- fontSize: 12
9204
- },
9205
- children: plotlinePlan.suggestions.map((s, i) => {
9206
- const kindLabel = {
9207
- main: tt("plotlines.kindMain"),
9208
- branch: tt("plotlines.kindBranch"),
9209
- character: tt("plotlines.kindCharacter"),
9210
- mystery: tt("plotlines.kindMystery")
9211
- }[s.kind];
9212
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9213
- style: {
9214
- border: "1px solid var(--nf-border)",
9215
- borderRadius: 8,
9216
- padding: "6px 10px"
9217
- },
9218
- children: [
9219
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9220
- className: panel_module_css_default.row,
9221
- style: {
9222
- justifyContent: "space-between",
9223
- flexWrap: "wrap"
9224
- },
9225
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
9226
- style: {
9227
- display: "flex",
9228
- alignItems: "center",
9229
- gap: 6,
9230
- flexWrap: "wrap"
9231
- },
9232
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: s.name }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9233
- className: panel_module_css_default.badge,
9234
- style: {
9235
- borderColor: "var(--nf-accent)",
9236
- color: "var(--nf-accent)"
9237
- },
9238
- children: kindLabel
9239
- })]
9240
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
9241
- type: "button",
9242
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall} ${panel_module_css_default.buttonPrimary}`,
9243
- disabled: busy,
9244
- onClick: () => {
9245
- handlePlanAdopt(s);
9246
- },
9247
- children: "+ 采纳"
9248
- })]
9249
- }),
9250
- s.goal !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9251
- className: panel_module_css_default.meta,
9252
- children: s.goal
9253
- }),
9254
- s.progress !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9255
- className: panel_module_css_default.meta,
9256
- children: ["初始进度:", s.progress]
9257
- })
9258
- ]
9259
- }, i);
9260
- })
9261
- })
9262
- ]
9345
+ onClose: () => {
9346
+ setPlotlinePlan(null);
9347
+ }
9263
9348
  }),
9264
- plotlineSuggestions !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9265
- style: {
9266
- display: "flex",
9267
- flexDirection: "column",
9268
- gap: 6,
9269
- border: "1px solid var(--nf-info)",
9270
- borderRadius: 12,
9271
- padding: 10
9349
+ plotlineSuggestions !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PlotlineSuggestionPanel, {
9350
+ suggestions: plotlineSuggestions,
9351
+ disabled: busy,
9352
+ onAdopt: (s) => {
9353
+ handlePlotlineAdopt(s);
9272
9354
  },
9273
- children: [
9274
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9275
- className: panel_module_css_default.row,
9276
- style: {
9277
- justifyContent: "space-between",
9278
- flexWrap: "wrap"
9279
- },
9280
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("b", { children: [
9281
- "✨ AI 建议(",
9282
- plotlineSuggestions.length,
9283
- " 条)"
9284
- ] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
9285
- type: "button",
9286
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
9287
- onClick: () => {
9288
- setPlotlineSuggestions(null);
9289
- },
9290
- children: "收起"
9291
- })]
9292
- }),
9293
- plotlineSuggestions.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9294
- className: panel_module_css_default.meta,
9295
- children: "没有候选线。"
9296
- }),
9297
- plotlineSuggestions.map((s, i) => {
9298
- const kindLabel = {
9299
- main: tt("plotlines.kindMain"),
9300
- branch: tt("plotlines.kindBranch"),
9301
- character: tt("plotlines.kindCharacter"),
9302
- mystery: tt("plotlines.kindMystery")
9303
- }[s.kind];
9304
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9305
- style: {
9306
- border: "1px solid var(--nf-border)",
9307
- borderRadius: 8,
9308
- padding: "6px 10px",
9309
- fontSize: 12
9310
- },
9311
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9312
- className: panel_module_css_default.row,
9313
- style: {
9314
- justifyContent: "space-between",
9315
- flexWrap: "wrap"
9316
- },
9317
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
9318
- style: {
9319
- display: "flex",
9320
- alignItems: "center",
9321
- gap: 6,
9322
- flexWrap: "wrap"
9323
- },
9324
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: s.name }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9325
- className: panel_module_css_default.badge,
9326
- style: {
9327
- borderColor: "var(--nf-accent)",
9328
- color: "var(--nf-accent)"
9329
- },
9330
- children: kindLabel
9331
- })]
9332
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
9333
- type: "button",
9334
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall} ${panel_module_css_default.buttonPrimary}`,
9335
- disabled: busy,
9336
- onClick: () => {
9337
- handlePlotlineAdopt(s);
9338
- },
9339
- children: "+ 采纳"
9340
- })]
9341
- }), s.goal !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9342
- className: panel_module_css_default.meta,
9343
- children: s.goal
9344
- })]
9345
- }, i);
9346
- })
9347
- ]
9355
+ onClose: () => {
9356
+ setPlotlineSuggestions(null);
9357
+ }
9348
9358
  }),
9349
9359
  plotlineDraft !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9350
9360
  style: {
@@ -9521,126 +9531,26 @@ window.__ModuleLoader__.load({
9521
9531
  flex: 1,
9522
9532
  minHeight: 0
9523
9533
  },
9524
- children: (project?.plotlines ?? []).map((line) => {
9525
- const kindLabel = {
9526
- main: tt("plotlines.kindMain"),
9527
- branch: tt("plotlines.kindBranch"),
9528
- character: tt("plotlines.kindCharacter"),
9529
- mystery: tt("plotlines.kindMystery")
9530
- }[line.kind];
9531
- const statusLabel = {
9532
- active: tt("plotlines.statusActive"),
9533
- paused: tt("plotlines.statusPaused"),
9534
- resolved: tt("plotlines.statusResolved"),
9535
- abandoned: tt("plotlines.statusAbandoned")
9536
- }[line.status];
9537
- const statusColor = line.status === "resolved" ? "var(--nf-success)" : line.status === "abandoned" ? "var(--nf-text-3)" : line.status === "paused" ? "var(--nf-warn)" : "var(--nf-accent)";
9538
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9539
- style: {
9540
- border: "1px solid var(--nf-border)",
9541
- borderRadius: 10,
9542
- padding: "8px 12px",
9543
- fontSize: 12,
9544
- display: "flex",
9545
- flexDirection: "column",
9546
- gap: 4
9547
- },
9548
- children: [
9549
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9550
- className: panel_module_css_default.row,
9551
- style: {
9552
- justifyContent: "space-between",
9553
- flexWrap: "wrap"
9554
- },
9555
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
9556
- style: {
9557
- display: "flex",
9558
- alignItems: "center",
9559
- gap: 6,
9560
- flexWrap: "wrap"
9561
- },
9562
- children: [
9563
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: line.name }),
9564
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9565
- className: panel_module_css_default.badge,
9566
- style: {
9567
- borderColor: "var(--nf-accent)",
9568
- color: "var(--nf-accent)"
9569
- },
9570
- children: kindLabel
9571
- }),
9572
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9573
- className: panel_module_css_default.badge,
9574
- style: {
9575
- borderColor: statusColor,
9576
- color: statusColor
9577
- },
9578
- children: statusLabel
9579
- })
9580
- ]
9581
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
9582
- style: {
9583
- display: "flex",
9584
- gap: 6
9585
- },
9586
- children: [
9587
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
9588
- type: "button",
9589
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
9590
- disabled: busy,
9591
- onClick: () => {
9592
- handlePlotlineRefresh(line.id);
9593
- },
9594
- title: "AI 结合编年录与章节摘要,自动更新这条线的当前进度",
9595
- children: "↻ AI 刷新进度"
9596
- }),
9597
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
9598
- type: "button",
9599
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
9600
- disabled: busy,
9601
- onClick: () => {
9602
- setPlotlineDraft({
9603
- id: line.id,
9604
- name: line.name,
9605
- kind: line.kind,
9606
- goal: line.goal,
9607
- progress: line.progress,
9608
- status: line.status
9609
- });
9610
- },
9611
- children: tt("plotlines.edit")
9612
- }),
9613
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
9614
- type: "button",
9615
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
9616
- disabled: busy,
9617
- onClick: () => {
9618
- handlePlotlineRemove(line.id);
9619
- },
9620
- children: tt("plotlines.remove")
9621
- })
9622
- ]
9623
- })]
9624
- }),
9625
- line.goal !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9626
- className: panel_module_css_default.meta,
9627
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("b", { children: [tt("plotlines.goal"), ":"] }), line.goal]
9628
- }),
9629
- line.progress !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9630
- className: panel_module_css_default.meta,
9631
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("b", { children: [tt("plotlines.progress"), ":"] }), line.progress]
9632
- }),
9633
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9634
- className: panel_module_css_default.meta,
9635
- children: [
9636
- tt("plotlines.chapters"),
9637
- ":",
9638
- line.chapters.length > 0 ? line.chapters.map((n) => `第${n}章`).join("、") : "—"
9639
- ]
9640
- })
9641
- ]
9642
- }, line.id);
9643
- })
9534
+ children: (project?.plotlines ?? []).map((line) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PlotlineCard, {
9535
+ line,
9536
+ disabled: busy,
9537
+ onRefresh: () => {
9538
+ handlePlotlineRefresh(line.id);
9539
+ },
9540
+ onEdit: () => {
9541
+ setPlotlineDraft({
9542
+ id: line.id,
9543
+ name: line.name,
9544
+ kind: line.kind,
9545
+ goal: line.goal,
9546
+ progress: line.progress,
9547
+ status: line.status
9548
+ });
9549
+ },
9550
+ onRemove: () => {
9551
+ handlePlotlineRemove(line.id);
9552
+ }
9553
+ }, line.id))
9644
9554
  })
9645
9555
  ]
9646
9556
  })