@waterwx/dsh-novel-forge 1.1.0 → 1.1.2

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
@@ -469,6 +469,8 @@ window.__ModuleLoader__.load({
469
469
  "settings.chapterChars": "每章目标字数",
470
470
  "settings.maxTokens": "单章最大输出 tokens",
471
471
  "settings.reviewPassScore": "审稿通过分数(0-100)",
472
+ "settings.editorFontSize": "编辑器字号(仅编辑页显示)",
473
+ "settings.editorFontSizeHint": "存于浏览器本地,不影响其他设备",
472
474
  "settings.autoReview": "生成后自动审稿",
473
475
  "settings.save": "保存设置",
474
476
  "settings.saved": "设置已保存",
@@ -600,6 +602,8 @@ window.__ModuleLoader__.load({
600
602
  "settings.chapterChars": "Chars per chapter",
601
603
  "settings.maxTokens": "Max output tokens",
602
604
  "settings.reviewPassScore": "Review pass score (0-100)",
605
+ "settings.editorFontSize": "Editor font size (workspace only)",
606
+ "settings.editorFontSizeHint": "Stored in browser localStorage; display-only",
603
607
  "settings.autoReview": "Auto-review after writing",
604
608
  "settings.save": "Save settings",
605
609
  "settings.saved": "Settings saved",
@@ -641,7 +645,7 @@ window.__ModuleLoader__.load({
641
645
  }
642
646
  //#endregion
643
647
  //#region \0dsh-css:C:\Users\Ryan\Desktop\111\novel-forge\src\client\panel\panel.module.css.mjs
644
- 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-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:#007aff;--nf-accent-hover:#0071e3;--nf-accent-soft:#007aff1f;--nf-accent-fg:#fff;--nf-hover:#0000000d;--nf-success:#34c759;--nf-error:#ff3b30;--nf-warn:#ff9500;--nf-info:#5856d6;--nf-shadow:0 1px 3px #0000000f, 0 12px 32px #00000014;--nf-shadow-lg:0 4px 12px #00000012, 0 20px 48px #0000001f;background:var(--nf-bg);backdrop-filter:blur(32px)saturate(180%);color:var(--nf-text);font-family:-apple-system,BlinkMacSystemFont,SF Pro Text,SF Pro SC,PingFang SC,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:#000000b8;--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:#0a84ff;--nf-accent-hover:#3a9bff;--nf-accent-soft:#0a84ff33;--nf-accent-fg:#fff;--nf-hover:#ffffff17;--nf-success:#30d158;--nf-error:#ff453a;--nf-warn:#ff9f0a;--nf-info:#bf5af2;--nf-shadow:0 1px 2px #00000059, 0 10px 30px #0006;--nf-shadow-lg:0 4px 12px #0006, 0 20px 48px #0000008c}html[data-dsh-novelforge-active]:not([data-dsh-taskboard-active]):not([data-dsh-ssh-active]) .CUIYUW_view{display:block}.CUIYUW_panel{flex-direction:column;min-width:0;height:100%;font-size:14px;line-height:1.6;display:flex;position:relative}.CUIYUW_panelHeader{border-bottom:1px solid var(--nf-border);background:var(--nf-bg-raise);backdrop-filter:blur(24px)saturate(180%);z-index:5;flex-shrink:0;justify-content:space-between;align-items:center;padding:12px 18px;display:flex;position:sticky;top:0}.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{flex-direction:column;flex:1;gap:14px;padding:16px 18px 20px;display:flex;overflow:auto}.CUIYUW_panelBody{flex:1;min-height:0;display:flex}.CUIYUW_panelNav{border-right:1px solid var(--nf-border);background:var(--nf-bg-raise);backdrop-filter:blur(24px)saturate(180%);flex-direction:column;flex:none;gap:2px;width:142px;padding:10px 8px;transition:width .18s;display:flex;overflow-y:auto}.CUIYUW_panelNavCollapsed{width:52px;padding:10px 6px}.CUIYUW_navGroup{flex-direction:column;gap:2px;display:flex}.CUIYUW_navGroupLabel{letter-spacing:.6px;text-transform:uppercase;color:var(--nf-text-3);user-select:none;padding:6px 10px 2px;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_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_headerProgress{color:var(--nf-text-2);white-space:nowrap;align-items:center;gap:6px;margin-left:4px;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-border);background:var(--nf-bg-raise);box-shadow:var(--nf-shadow);backdrop-filter:blur(24px)saturate(180%);border-radius:20px;flex-direction:column;gap:10px;padding:16px 18px;transition:border-color .2s,box-shadow .2s;display:flex}.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 8px color-mix(in srgb, var(--nf-accent) 35%, 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);background:var(--nf-bg-inset);border-radius:10px;padding:10px 14px;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:12px;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;gap:8px;max-height:460px;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_wsColumns{grid-template-columns:minmax(0,3fr) minmax(0,2fr);gap:14px;display:grid}.CUIYUW_wsColumn{flex-direction:column;gap:8px;min-width:0;display:flex}.CUIYUW_wsEditor{resize:vertical;white-space:pre-wrap;flex:1;min-height:340px;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;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;max-height:320px;color:var(--nf-text);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-border);background:var(--nf-bg-inset);border-radius:10px;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-border);background:radial-gradient(1200px 400px at 110% -60%, color-mix(in srgb, var(--nf-accent) 16%, transparent), transparent 60%), linear-gradient(135deg, var(--nf-bg-raise), color-mix(in srgb, var(--nf-accent) 5%, var(--nf-bg-raise)));box-shadow:var(--nf-shadow);border-radius:16px;flex-direction:column;gap:14px;padding:18px 20px;display:flex}.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-border);background:color-mix(in srgb, var(--nf-bg-base) 65%, transparent);border-radius:12px;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-bottom:1px solid var(--nf-border);background:var(--nf-bg-raise);flex-wrap:wrap;flex-shrink:0;align-items:center;gap:10px;padding:8px 18px;display:flex}.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}";
648
+ 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-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:#007aff;--nf-accent-hover:#0071e3;--nf-accent-soft:#007aff1f;--nf-accent-fg:#fff;--nf-hover:#0000000d;--nf-success:#34c759;--nf-error:#ff3b30;--nf-warn:#ff9500;--nf-info:#5856d6;--nf-shadow:0 1px 3px #0000000f, 0 12px 32px #00000014;--nf-shadow-lg:0 4px 12px #00000012, 0 20px 48px #0000001f;background:var(--nf-bg);backdrop-filter:blur(32px)saturate(180%);color:var(--nf-text);font-family:-apple-system,BlinkMacSystemFont,SF Pro Text,SF Pro SC,PingFang SC,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:#000000b8;--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:#0a84ff;--nf-accent-hover:#3a9bff;--nf-accent-soft:#0a84ff33;--nf-accent-fg:#fff;--nf-hover:#ffffff17;--nf-success:#30d158;--nf-error:#ff453a;--nf-warn:#ff9f0a;--nf-info:#bf5af2;--nf-shadow:0 1px 2px #00000059, 0 10px 30px #0006;--nf-shadow-lg:0 4px 12px #0006, 0 20px 48px #0000008c}html[data-dsh-novelforge-active]:not([data-dsh-taskboard-active]):not([data-dsh-ssh-active]) .CUIYUW_view{display:block}.CUIYUW_panel{flex-direction:column;min-width:0;height:100%;font-size:14px;line-height:1.6;display:flex;position:relative}.CUIYUW_panelHeader{border-bottom:1px solid var(--nf-border);background:var(--nf-bg-raise);backdrop-filter:blur(24px)saturate(180%);z-index:5;flex-shrink:0;justify-content:space-between;align-items:center;padding:12px 18px;display:flex;position:sticky;top:0}.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{flex-direction:column;flex:1;gap:14px;padding:16px 18px 20px;display:flex;overflow:auto}.CUIYUW_panelBody{flex:1;min-height:0;display:flex}.CUIYUW_panelNav{border-right:1px solid var(--nf-border);background:var(--nf-bg-raise);backdrop-filter:blur(24px)saturate(180%);flex-direction:column;flex:none;gap:2px;width:142px;padding:10px 8px;transition:width .18s;display:flex;overflow-y:auto}.CUIYUW_panelNavCollapsed{width:52px;padding:10px 6px}.CUIYUW_navGroup{flex-direction:column;gap:2px;display:flex}.CUIYUW_navGroupLabel{letter-spacing:.6px;text-transform:uppercase;color:var(--nf-text-3);user-select:none;padding:6px 10px 2px;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_headerProgress{color:var(--nf-text-2);white-space:nowrap;align-items:center;gap:6px;margin-left:4px;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-border);background:var(--nf-bg-raise);box-shadow:var(--nf-shadow);backdrop-filter:blur(24px)saturate(180%);border-radius:20px;flex-direction:column;gap:10px;padding:16px 18px;transition:border-color .2s,box-shadow .2s;display:flex}.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 8px color-mix(in srgb, var(--nf-accent) 35%, 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);background:var(--nf-bg-inset);border-radius:10px;padding:10px 14px;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:12px;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;gap:8px;max-height:70vh;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_wsColumns{grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:14px;display:grid}.CUIYUW_wsColumn{flex-direction:column;gap:8px;min-width:0;display:flex}.CUIYUW_wsEditor{resize:vertical;white-space:pre-wrap;flex:1;min-height:50vh;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;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;max-height:55vh;color:var(--nf-text);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-border);background:var(--nf-bg-inset);border-radius:10px;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-border);background:radial-gradient(1200px 400px at 110% -60%, color-mix(in srgb, var(--nf-accent) 16%, transparent), transparent 60%), linear-gradient(135deg, var(--nf-bg-raise), color-mix(in srgb, var(--nf-accent) 5%, var(--nf-bg-raise)));box-shadow:var(--nf-shadow);border-radius:16px;flex-direction:column;gap:14px;padding:18px 20px;display:flex}.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-border);background:color-mix(in srgb, var(--nf-bg-base) 65%, transparent);border-radius:12px;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-bottom:1px solid var(--nf-border);background:var(--nf-bg-raise);flex-wrap:wrap;flex-shrink:0;align-items:center;gap:10px;padding:8px 18px;display:flex}.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}";
645
649
  const tagId = "@waterwx/dsh-novel-forge/panel.module.css";
646
650
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
647
651
  const tag = document.createElement("style");
@@ -651,199 +655,202 @@ window.__ModuleLoader__.load({
651
655
  document.head.appendChild(tag);
652
656
  }
653
657
  var panel_module_css_default = {
654
- "bookAdd": "CUIYUW_bookAdd",
655
- "toolLive": "CUIYUW_toolLive",
656
- "wsColumn": "CUIYUW_wsColumn",
657
- "dashGrid": "CUIYUW_dashGrid",
658
- "coverPreview": "CUIYUW_coverPreview",
658
+ "diffNew": "CUIYUW_diffNew",
659
+ "dashHeroArrow": "CUIYUW_dashHeroArrow",
660
+ "workflowDotActive": "CUIYUW_workflowDotActive",
661
+ "bookCreateForm": "CUIYUW_bookCreateForm",
662
+ "progress": "CUIYUW_progress",
663
+ "fileList": "CUIYUW_fileList",
664
+ "toolStep": "CUIYUW_toolStep",
665
+ "workflowHint": "CUIYUW_workflowHint",
666
+ "panelNav": "CUIYUW_panelNav",
667
+ "assistantFloat": "CUIYUW_assistantFloat",
668
+ "diffColumn": "CUIYUW_diffColumn",
669
+ "buttonSmall": "CUIYUW_buttonSmall",
659
670
  "progressLineError": "CUIYUW_progressLineError",
660
- "toolStepIcon": "CUIYUW_toolStepIcon",
661
- "navTabBadgeDanger": "CUIYUW_navTabBadgeDanger",
662
- "chapterNum": "CUIYUW_chapterNum",
663
- "navGroupSep": "CUIYUW_navGroupSep",
664
- "chatRole": "CUIYUW_chatRole",
665
- "workflowDotDone": "CUIYUW_workflowDotDone",
671
+ "chapterBeats": "CUIYUW_chapterBeats",
672
+ "bookCardName": "CUIYUW_bookCardName",
673
+ "toolLive": "CUIYUW_toolLive",
674
+ "dropzone": "CUIYUW_dropzone",
675
+ "toolSteps": "CUIYUW_toolSteps",
676
+ "chapter": "CUIYUW_chapter",
666
677
  "diffList": "CUIYUW_diffList",
667
- "diffNew": "CUIYUW_diffNew",
668
- "fadeIn": "CUIYUW_fadeIn",
669
- "diffOld": "CUIYUW_diffOld",
670
- "headerProgress": "CUIYUW_headerProgress",
671
- "fieldLabel": "CUIYUW_fieldLabel",
672
- "bookChip": "CUIYUW_bookChip",
673
- "volumeGroup": "CUIYUW_volumeGroup",
674
- "diffTagOld": "CUIYUW_diffTagOld",
675
- "navTabLabel": "CUIYUW_navTabLabel",
676
- "dashHeroActionBody": "CUIYUW_dashHeroActionBody",
677
- "workflowDot": "CUIYUW_workflowDot",
678
- "bookChipActive": "CUIYUW_bookChipActive",
679
- "panelNavCollapsed": "CUIYUW_panelNavCollapsed",
680
- "badgeRejected": "CUIYUW_badgeRejected",
681
- "entry": "CUIYUW_entry",
682
- "wsSelected": "CUIYUW_wsSelected",
683
- "badgeGenerating": "CUIYUW_badgeGenerating",
684
- "onlyChanges": "CUIYUW_onlyChanges",
685
- "navTabBadge": "CUIYUW_navTabBadge",
686
- "bigProgressBar": "CUIYUW_bigProgressBar",
687
- "diffDel": "CUIYUW_diffDel",
688
- "busyRow": "CUIYUW_busyRow",
689
- "badgeWritten": "CUIYUW_badgeWritten",
690
- "badgePending": "CUIYUW_badgePending",
691
- "assetStatValue": "CUIYUW_assetStatValue",
692
- "assistantResize": "CUIYUW_assistantResize",
693
- "toolStepName": "CUIYUW_toolStepName",
694
- "bookCardProgressBar": "CUIYUW_bookCardProgressBar",
695
- "progressLineDone": "CUIYUW_progressLineDone",
696
- "pulse": "CUIYUW_pulse",
697
- "navSpacer": "CUIYUW_navSpacer",
698
- "buttonPrimary": "CUIYUW_buttonPrimary",
678
+ "assistantFloatHeader": "CUIYUW_assistantFloatHeader",
679
+ "cardTitle": "CUIYUW_cardTitle",
680
+ "dashJourneyBar": "CUIYUW_dashJourneyBar",
681
+ "bookCreateCard": "CUIYUW_bookCreateCard",
682
+ "assetStatLabel": "CUIYUW_assetStatLabel",
683
+ "dashHeroAction": "CUIYUW_dashHeroAction",
684
+ "navGroupLabel": "CUIYUW_navGroupLabel",
699
685
  "liveText": "CUIYUW_liveText",
686
+ "busyRow": "CUIYUW_busyRow",
687
+ "badgeRejected": "CUIYUW_badgeRejected",
688
+ "bookCardBlurb": "CUIYUW_bookCardBlurb",
700
689
  "createBookView": "CUIYUW_createBookView",
690
+ "dashGrid": "CUIYUW_dashGrid",
701
691
  "panelTitle": "CUIYUW_panelTitle",
702
- "wsPreview": "CUIYUW_wsPreview",
703
- "workflowRow": "CUIYUW_workflowRow",
704
- "entryLabel": "CUIYUW_entryLabel",
705
- "volumeGroupHeader": "CUIYUW_volumeGroupHeader",
706
- "buttonDanger": "CUIYUW_buttonDanger",
707
- "wsPreviewText": "CUIYUW_wsPreviewText",
708
- "dashHeroEyebrow": "CUIYUW_dashHeroEyebrow",
709
- "assetStatLabel": "CUIYUW_assetStatLabel",
710
- "progressBarFill": "CUIYUW_progressBarFill",
711
- "outlineReadonly": "CUIYUW_outlineReadonly",
712
- "button": "CUIYUW_button",
713
- "diffText": "CUIYUW_diffText",
714
- "workflowLabel": "CUIYUW_workflowLabel",
715
- "bookshelf": "CUIYUW_bookshelf",
692
+ "createBookIcon": "CUIYUW_createBookIcon",
693
+ "chapterMain": "CUIYUW_chapterMain",
694
+ "genreDesc": "CUIYUW_genreDesc",
716
695
  "dashJourneyFill": "CUIYUW_dashJourneyFill",
717
- "coverPlaceholder": "CUIYUW_coverPlaceholder",
718
- "bookshelfLabel": "CUIYUW_bookshelfLabel",
719
- "chapterPreview": "CUIYUW_chapterPreview",
720
- "bookCardTitleRow": "CUIYUW_bookCardTitleRow",
721
- "buttonSmall": "CUIYUW_buttonSmall",
722
- "bookChipRemove": "CUIYUW_bookChipRemove",
723
- "assetStatDetail": "CUIYUW_assetStatDetail",
696
+ "wsColumns": "CUIYUW_wsColumns",
697
+ "progressBarFill": "CUIYUW_progressBarFill",
724
698
  "dashHeroTitle": "CUIYUW_dashHeroTitle",
725
- "bookCreateOutline": "CUIYUW_bookCreateOutline",
726
- "bookCreateForm": "CUIYUW_bookCreateForm",
727
- "dropzoneIcon": "CUIYUW_dropzoneIcon",
728
- "diffSameBody": "CUIYUW_diffSameBody",
729
- "assistantFloatBody": "CUIYUW_assistantFloatBody",
730
- "createBookTitle": "CUIYUW_createBookTitle",
731
- "dropzone": "CUIYUW_dropzone",
732
- "input": "CUIYUW_input",
699
+ "bookCardActive": "CUIYUW_bookCardActive",
700
+ "badgePending": "CUIYUW_badgePending",
733
701
  "toolStepActive": "CUIYUW_toolStepActive",
734
- "wsSelectedText": "CUIYUW_wsSelectedText",
735
- "progressLine": "CUIYUW_progressLine",
736
- "headerProgressDot": "CUIYUW_headerProgressDot",
702
+ "toolStepIcon": "CUIYUW_toolStepIcon",
703
+ "navTabBadge": "CUIYUW_navTabBadge",
704
+ "workflowBody": "CUIYUW_workflowBody",
705
+ "bookshelfLabel": "CUIYUW_bookshelfLabel",
706
+ "assistantFloatBody": "CUIYUW_assistantFloatBody",
707
+ "tabBar": "CUIYUW_tabBar",
708
+ "progressLineLive": "CUIYUW_progressLineLive",
709
+ "navTabBadgeDanger": "CUIYUW_navTabBadgeDanger",
710
+ "dashJourney": "CUIYUW_dashJourney",
737
711
  "textarea": "CUIYUW_textarea",
738
- "dashStage": "CUIYUW_dashStage",
739
- "entryIcon": "CUIYUW_entryIcon",
740
- "shelfView": "CUIYUW_shelfView",
741
- "panelNav": "CUIYUW_panelNav",
742
- "dashHero": "CUIYUW_dashHero",
743
- "genreDesc": "CUIYUW_genreDesc",
712
+ "dashHeroActionTitle": "CUIYUW_dashHeroActionTitle",
713
+ "bookAddIcon": "CUIYUW_bookAddIcon",
714
+ "todoWarning": "CUIYUW_todoWarning",
715
+ "chatBubbleAssistant": "CUIYUW_chatBubbleAssistant",
716
+ "navAboutUpdate": "CUIYUW_navAboutUpdate",
717
+ "wsEditor": "CUIYUW_wsEditor",
744
718
  "navGroup": "CUIYUW_navGroup",
745
- "bookshelfList": "CUIYUW_bookshelfList",
746
- "field": "CUIYUW_field",
747
- "toolStep": "CUIYUW_toolStep",
748
- "diffLegend": "CUIYUW_diffLegend",
749
- "reviewBox": "CUIYUW_reviewBox",
750
- "dashHeroSparkle": "CUIYUW_dashHeroSparkle",
751
- "badgeDone": "CUIYUW_badgeDone",
752
- "chapterBeats": "CUIYUW_chapterBeats",
753
- "chapterMain": "CUIYUW_chapterMain",
719
+ "navGroupSep": "CUIYUW_navGroupSep",
720
+ "buttonDanger": "CUIYUW_buttonDanger",
721
+ "panelHeader": "CUIYUW_panelHeader",
722
+ "volumeGroup": "CUIYUW_volumeGroup",
723
+ "diffTagOld": "CUIYUW_diffTagOld",
724
+ "wsPreviewText": "CUIYUW_wsPreviewText",
725
+ "assetGrid": "CUIYUW_assetGrid",
726
+ "diffSame": "CUIYUW_diffSame",
754
727
  "assistantStatusBusy": "CUIYUW_assistantStatusBusy",
755
- "chatScroll": "CUIYUW_chatScroll",
756
- "assistantStatus": "CUIYUW_assistantStatus",
757
- "bookCardCover": "CUIYUW_bookCardCover",
758
- "assistantFloatHeader": "CUIYUW_assistantFloatHeader",
759
- "bookCardCoverFallback": "CUIYUW_bookCardCoverFallback",
760
- "tabBar": "CUIYUW_tabBar",
761
- "dashHeroAction": "CUIYUW_dashHeroAction",
762
- "chapter": "CUIYUW_chapter",
763
- "tab": "CUIYUW_tab",
764
- "assetStat": "CUIYUW_assetStat",
765
- "panelBody": "CUIYUW_panelBody",
766
- "toolStepDetail": "CUIYUW_toolStepDetail",
767
- "dashStageDot": "CUIYUW_dashStageDot",
768
- "chatBubbleUser": "CUIYUW_chatBubbleUser",
769
- "progress": "CUIYUW_progress",
770
- "dashFact": "CUIYUW_dashFact",
771
- "toolSteps": "CUIYUW_toolSteps",
772
- "dashJourneyStages": "CUIYUW_dashJourneyStages",
773
- "createBookTop": "CUIYUW_createBookTop",
774
- "fileList": "CUIYUW_fileList",
775
- "bookChipName": "CUIYUW_bookChipName",
776
- "bookCardName": "CUIYUW_bookCardName",
777
- "chapterList": "CUIYUW_chapterList",
778
- "legendNew": "CUIYUW_legendNew",
779
- "badge": "CUIYUW_badge",
780
- "diffColumn": "CUIYUW_diffColumn",
781
- "bookCardProgressFill": "CUIYUW_bookCardProgressFill",
782
- "chatBubbleAssistant": "CUIYUW_chatBubbleAssistant",
783
- "todoText": "CUIYUW_todoText",
784
728
  "bigProgressBarFill": "CUIYUW_bigProgressBarFill",
785
- "dashHeroBook": "CUIYUW_dashHeroBook",
729
+ "badgeDone": "CUIYUW_badgeDone",
730
+ "entry": "CUIYUW_entry",
731
+ "diffAdd": "CUIYUW_diffAdd",
786
732
  "dashStageCurrent": "CUIYUW_dashStageCurrent",
787
- "dashHeroActionTitle": "CUIYUW_dashHeroActionTitle",
788
733
  "meta": "CUIYUW_meta",
789
- "view": "CUIYUW_view",
734
+ "toolStepName": "CUIYUW_toolStepName",
735
+ "entryLabel": "CUIYUW_entryLabel",
736
+ "dashFacts": "CUIYUW_dashFacts",
790
737
  "bookChipMeta": "CUIYUW_bookChipMeta",
791
- "cardTitle": "CUIYUW_cardTitle",
792
- "navGroupLabel": "CUIYUW_navGroupLabel",
793
- "navTab": "CUIYUW_navTab",
794
- "wsColumns": "CUIYUW_wsColumns",
795
- "navTabBadgeWarn": "CUIYUW_navTabBadgeWarn",
738
+ "fieldLabel": "CUIYUW_fieldLabel",
739
+ "chatRole": "CUIYUW_chatRole",
740
+ "diffOld": "CUIYUW_diffOld",
741
+ "card": "CUIYUW_card",
742
+ "dashStage": "CUIYUW_dashStage",
743
+ "bookCardCoverTitle": "CUIYUW_bookCardCoverTitle",
744
+ "bookshelfList": "CUIYUW_bookshelfList",
745
+ "badgeWritten": "CUIYUW_badgeWritten",
746
+ "toolStepStatus": "CUIYUW_toolStepStatus",
747
+ "dashFact": "CUIYUW_dashFact",
748
+ "workflowLabel": "CUIYUW_workflowLabel",
796
749
  "navTabBadgeDone": "CUIYUW_navTabBadgeDone",
797
- "bookAddCard": "CUIYUW_bookAddCard",
798
- "bookCardBody": "CUIYUW_bookCardBody",
799
- "volumeGroupToggle": "CUIYUW_volumeGroupToggle",
800
- "bookCreateCard": "CUIYUW_bookCreateCard",
801
- "diffTagNew": "CUIYUW_diffTagNew",
750
+ "badgeGenerating": "CUIYUW_badgeGenerating",
751
+ "workflowDot": "CUIYUW_workflowDot",
752
+ "input": "CUIYUW_input",
753
+ "badge": "CUIYUW_badge",
754
+ "coverPreview": "CUIYUW_coverPreview",
755
+ "workflowRow": "CUIYUW_workflowRow",
756
+ "chapterList": "CUIYUW_chapterList",
757
+ "diffChange": "CUIYUW_diffChange",
758
+ "wsPreview": "CUIYUW_wsPreview",
759
+ "entryIcon": "CUIYUW_entryIcon",
760
+ "progressBar": "CUIYUW_progressBar",
761
+ "navAboutRow": "CUIYUW_navAboutRow",
762
+ "wsColumn": "CUIYUW_wsColumn",
763
+ "dashHero": "CUIYUW_dashHero",
764
+ "iconButton": "CUIYUW_iconButton",
765
+ "headerProgress": "CUIYUW_headerProgress",
766
+ "chapterNum": "CUIYUW_chapterNum",
767
+ "coverPlaceholder": "CUIYUW_coverPlaceholder",
768
+ "bookCardCover": "CUIYUW_bookCardCover",
769
+ "assetStatValue": "CUIYUW_assetStatValue",
770
+ "toolStepError": "CUIYUW_toolStepError",
771
+ "pulse": "CUIYUW_pulse",
772
+ "diffSameBody": "CUIYUW_diffSameBody",
773
+ "todoItem": "CUIYUW_todoItem",
774
+ "wsSelected": "CUIYUW_wsSelected",
775
+ "bookCardCoverFallback": "CUIYUW_bookCardCoverFallback",
802
776
  "navTabIcon": "CUIYUW_navTabIcon",
803
- "chapterTitle": "CUIYUW_chapterTitle",
804
777
  "badgeError": "CUIYUW_badgeError",
805
- "progressLineLive": "CUIYUW_progressLineLive",
806
- "progressBar": "CUIYUW_progressBar",
807
- "workflowHint": "CUIYUW_workflowHint",
778
+ "dropzoneActive": "CUIYUW_dropzoneActive",
779
+ "todoInfo": "CUIYUW_todoInfo",
780
+ "headerProgressDot": "CUIYUW_headerProgressDot",
781
+ "diffTagNew": "CUIYUW_diffTagNew",
808
782
  "createBookCard": "CUIYUW_createBookCard",
809
- "shelfGrid": "CUIYUW_shelfGrid",
810
- "bookCardActive": "CUIYUW_bookCardActive",
783
+ "dashHeroBook": "CUIYUW_dashHeroBook",
784
+ "navAbout": "CUIYUW_navAbout",
785
+ "bigProgressBar": "CUIYUW_bigProgressBar",
811
786
  "legendOld": "CUIYUW_legendOld",
812
- "panelHeader": "CUIYUW_panelHeader",
813
- "spaceBetween": "CUIYUW_spaceBetween",
814
- "diffChange": "CUIYUW_diffChange",
815
- "dashJourney": "CUIYUW_dashJourney",
787
+ "navSpacer": "CUIYUW_navSpacer",
788
+ "todoDanger": "CUIYUW_todoDanger",
789
+ "todoText": "CUIYUW_todoText",
790
+ "assistantResize": "CUIYUW_assistantResize",
791
+ "shelfGrid": "CUIYUW_shelfGrid",
816
792
  "panel": "CUIYUW_panel",
817
- "toolStepError": "CUIYUW_toolStepError",
818
- "chapterActions": "CUIYUW_chapterActions",
819
- "diffSame": "CUIYUW_diffSame",
820
- "wsEditor": "CUIYUW_wsEditor",
821
- "dashFacts": "CUIYUW_dashFacts",
822
- "assistantFloat": "CUIYUW_assistantFloat",
823
- "card": "CUIYUW_card",
824
- "panelContent": "CUIYUW_panelContent",
825
- "dashStageDone": "CUIYUW_dashStageDone",
826
- "todoWarning": "CUIYUW_todoWarning",
827
- "dashHeroArrow": "CUIYUW_dashHeroArrow",
828
- "dashJourneyBar": "CUIYUW_dashJourneyBar",
829
- "todoInfo": "CUIYUW_todoInfo",
830
- "bookCard": "CUIYUW_bookCard",
831
- "bookCardBlurb": "CUIYUW_bookCardBlurb",
832
- "iconButton": "CUIYUW_iconButton",
833
- "bookCardCoverTitle": "CUIYUW_bookCardCoverTitle",
834
- "createBookIcon": "CUIYUW_createBookIcon",
793
+ "onlyChanges": "CUIYUW_onlyChanges",
794
+ "createBookTop": "CUIYUW_createBookTop",
795
+ "spaceBetween": "CUIYUW_spaceBetween",
796
+ "dashHeroSparkle": "CUIYUW_dashHeroSparkle",
797
+ "navTabBadgeWarn": "CUIYUW_navTabBadgeWarn",
798
+ "navTab": "CUIYUW_navTab",
799
+ "diffDel": "CUIYUW_diffDel",
800
+ "bookChipName": "CUIYUW_bookChipName",
835
801
  "workflowList": "CUIYUW_workflowList",
836
- "workflowBody": "CUIYUW_workflowBody",
802
+ "buttonPrimary": "CUIYUW_buttonPrimary",
803
+ "legendNew": "CUIYUW_legendNew",
804
+ "assistantStatus": "CUIYUW_assistantStatus",
805
+ "outlineReadonly": "CUIYUW_outlineReadonly",
806
+ "reviewBox": "CUIYUW_reviewBox",
807
+ "diffText": "CUIYUW_diffText",
808
+ "dashStageDone": "CUIYUW_dashStageDone",
809
+ "tab": "CUIYUW_tab",
810
+ "bookAdd": "CUIYUW_bookAdd",
837
811
  "row": "CUIYUW_row",
838
- "bookAddIcon": "CUIYUW_bookAddIcon",
839
- "todoItem": "CUIYUW_todoItem",
840
- "assetGrid": "CUIYUW_assetGrid",
841
- "todoDanger": "CUIYUW_todoDanger",
842
- "diffAdd": "CUIYUW_diffAdd",
843
- "toolStepStatus": "CUIYUW_toolStepStatus",
812
+ "button": "CUIYUW_button",
813
+ "dashStageDot": "CUIYUW_dashStageDot",
814
+ "assetStatDetail": "CUIYUW_assetStatDetail",
815
+ "chatScroll": "CUIYUW_chatScroll",
816
+ "bookChip": "CUIYUW_bookChip",
817
+ "wsSelectedText": "CUIYUW_wsSelectedText",
818
+ "field": "CUIYUW_field",
819
+ "bookAddCard": "CUIYUW_bookAddCard",
820
+ "bookshelf": "CUIYUW_bookshelf",
821
+ "shelfView": "CUIYUW_shelfView",
822
+ "progressLine": "CUIYUW_progressLine",
823
+ "assetStat": "CUIYUW_assetStat",
824
+ "createBookTitle": "CUIYUW_createBookTitle",
825
+ "bookCreateOutline": "CUIYUW_bookCreateOutline",
826
+ "bookCardProgressBar": "CUIYUW_bookCardProgressBar",
827
+ "chatBubbleUser": "CUIYUW_chatBubbleUser",
828
+ "diffLegend": "CUIYUW_diffLegend",
829
+ "view": "CUIYUW_view",
830
+ "panelNavCollapsed": "CUIYUW_panelNavCollapsed",
831
+ "chapterTitle": "CUIYUW_chapterTitle",
832
+ "chapterPreview": "CUIYUW_chapterPreview",
833
+ "panelBody": "CUIYUW_panelBody",
834
+ "volumeGroupToggle": "CUIYUW_volumeGroupToggle",
835
+ "toolStepDetail": "CUIYUW_toolStepDetail",
836
+ "bookCard": "CUIYUW_bookCard",
837
+ "fadeIn": "CUIYUW_fadeIn",
838
+ "bookChipActive": "CUIYUW_bookChipActive",
839
+ "bookCardBody": "CUIYUW_bookCardBody",
840
+ "dropzoneIcon": "CUIYUW_dropzoneIcon",
841
+ "dashHeroActionBody": "CUIYUW_dashHeroActionBody",
844
842
  "shelfHeader": "CUIYUW_shelfHeader",
845
- "dropzoneActive": "CUIYUW_dropzoneActive",
846
- "workflowDotActive": "CUIYUW_workflowDotActive"
843
+ "bookChipRemove": "CUIYUW_bookChipRemove",
844
+ "panelContent": "CUIYUW_panelContent",
845
+ "bookCardTitleRow": "CUIYUW_bookCardTitleRow",
846
+ "navTabLabel": "CUIYUW_navTabLabel",
847
+ "chapterActions": "CUIYUW_chapterActions",
848
+ "dashHeroEyebrow": "CUIYUW_dashHeroEyebrow",
849
+ "dashJourneyStages": "CUIYUW_dashJourneyStages",
850
+ "bookCardProgressFill": "CUIYUW_bookCardProgressFill",
851
+ "volumeGroupHeader": "CUIYUW_volumeGroupHeader",
852
+ "progressLineDone": "CUIYUW_progressLineDone",
853
+ "workflowDotDone": "CUIYUW_workflowDotDone"
847
854
  };
848
855
  //#endregion
849
856
  //#region src/client/panel/AssistantTab.tsx
@@ -3344,6 +3351,9 @@ window.__ModuleLoader__.load({
3344
3351
  label: tt("tab.settings"),
3345
3352
  icon: "⚙️"
3346
3353
  };
3354
+ const PLUGIN_VERSION = "1.1.2";
3355
+ /** GitHub 仓库地址(关于区块点击跳转)。 */
3356
+ const REPO_URL = "https://github.com/watersxya/dsh-novel-forge";
3347
3357
  /** Whether any chapter is being generated right now. */
3348
3358
  function anyGenerating(chapters) {
3349
3359
  return (chapters ?? []).some((c) => c.status === "generating" || c.status === "reviewing");
@@ -3485,7 +3495,7 @@ window.__ModuleLoader__.load({
3485
3495
  });
3486
3496
  }
3487
3497
  /** The diff list of a draft-vs-original comparison (scrollable). */
3488
- function DiffList({ original, draft }) {
3498
+ function DiffList({ original, draft, fontSize }) {
3489
3499
  const rows = (0, react.useMemo)(() => paragraphDiff(original, draft), [original, draft]);
3490
3500
  const changed = rows.filter((r) => r.kind === "change").length;
3491
3501
  const added = rows.filter((r) => r.kind === "add").length;
@@ -3531,6 +3541,7 @@ window.__ModuleLoader__.load({
3531
3541
  ]
3532
3542
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3533
3543
  className: panel_module_css_default.diffList,
3544
+ style: fontSize !== void 0 ? { fontSize } : void 0,
3534
3545
  children: shown.map((row, idx) => {
3535
3546
  if (row.kind === "same") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
3536
3547
  className: panel_module_css_default.diffSame,
@@ -3629,6 +3640,24 @@ window.__ModuleLoader__.load({
3629
3640
  const wsEditorRef = (0, react.useRef)(null);
3630
3641
  /** 工作区:手动编辑后的 AI 审查结果(不落盘)。 */
3631
3642
  const [wsCheckReport, setWsCheckReport] = (0, react.useState)(null);
3643
+ /** 手动审查结果中作者勾选要修复的问题(issue 下标)。 */
3644
+ const [wsChecked, setWsChecked] = (0, react.useState)([]);
3645
+ /** 编辑页字号(localStorage 记忆,仅影响显示)。 */
3646
+ const [editorFontSize, setEditorFontSize] = (0, react.useState)(() => {
3647
+ try {
3648
+ const v = Number(window.localStorage.getItem("dsh-novel-forge.editor.fontSize"));
3649
+ return v >= 12 && v <= 24 ? v : 14;
3650
+ } catch {
3651
+ return 14;
3652
+ }
3653
+ });
3654
+ const changeEditorFontSize = (next) => {
3655
+ const v = Math.min(24, Math.max(12, next));
3656
+ setEditorFontSize(v);
3657
+ try {
3658
+ window.localStorage.setItem("dsh-novel-forge.editor.fontSize", String(v));
3659
+ } catch {}
3660
+ };
3632
3661
  /** 有未采纳草稿的章节号(refresh 后检测到遗留草稿时提示)。 */
3633
3662
  const [draftNo, setDraftNo] = (0, react.useState)(null);
3634
3663
  /** 大纲页「更新大纲」编辑区是否展开。 */
@@ -3649,6 +3678,18 @@ window.__ModuleLoader__.load({
3649
3678
  const coverFileRef = (0, react.useRef)(null);
3650
3679
  /** 章节列表按卷折叠(存已折叠的卷号)。 */
3651
3680
  const [collapsedVolumes, setCollapsedVolumes] = (0, react.useState)([]);
3681
+ /** npm 最新版本(更新检测;null = 未检测/检测失败)。 */
3682
+ const [npmLatest, setNpmLatest] = (0, react.useState)(null);
3683
+ /** 后台检测 npm 最新版本(失败静默,不打扰)。 */
3684
+ (0, react.useEffect)(() => {
3685
+ let cancelled = false;
3686
+ fetch("https://registry.npmjs.org/@waterwx%2Fdsh-novel-forge").then((response) => response.json()).then((data) => {
3687
+ if (!cancelled && data["dist-tags"]?.latest !== void 0) setNpmLatest(data["dist-tags"].latest);
3688
+ }).catch(() => {});
3689
+ return () => {
3690
+ cancelled = true;
3691
+ };
3692
+ }, []);
3652
3693
  /** AI 助手悬浮窗:是否打开。 */
3653
3694
  const [assistantOpen, setAssistantOpen] = (0, react.useState)(false);
3654
3695
  /** 悬浮窗位置(相对面板,localStorage 记忆)。 */
@@ -4036,6 +4077,15 @@ window.__ModuleLoader__.load({
4036
4077
  try {
4037
4078
  const result = await api.chapterCheck(workspace.no, workspace.original);
4038
4079
  setWsCheckReport(result.report);
4080
+ const highIdx = result.report.issues.map((it, i) => ({
4081
+ it,
4082
+ i
4083
+ })).filter((x) => x.it.severity === "high").map((x) => x.i);
4084
+ const mediumIdx = result.report.issues.map((it, i) => ({
4085
+ it,
4086
+ i
4087
+ })).filter((x) => x.it.severity === "medium").map((x) => x.i);
4088
+ setWsChecked(highIdx.length > 0 ? highIdx : mediumIdx);
4039
4089
  pushProgress(`审查完成:${result.report.score} 分 — ${result.report.verdict}`, result.report.passed ? "done" : "error");
4040
4090
  } catch (err) {
4041
4091
  setError(err.message);
@@ -4060,6 +4110,7 @@ window.__ModuleLoader__.load({
4060
4110
  setWorkspace(null);
4061
4111
  setDraftNo(null);
4062
4112
  setWsCheckReport(null);
4113
+ setWsChecked([]);
4063
4114
  if (report !== void 0) pushProgress(`已保存并审稿:${report.score} 分 — ${report.verdict}(${report.passed ? "通过" : "未通过"})`, report.passed ? "done" : "error");
4064
4115
  else pushProgress(`已保存第 ${workspace.no} 章编辑(${result.chars} 字,原稿已备份 .bak)`, "done");
4065
4116
  } catch (err) {
@@ -4158,6 +4209,7 @@ window.__ModuleLoader__.load({
4158
4209
  setError("");
4159
4210
  try {
4160
4211
  const result = await api.plan(outlineText || void 0, planCount);
4212
+ let freshCount = 0;
4161
4213
  setProject((prev) => {
4162
4214
  const base = prev ?? {
4163
4215
  bookName: "",
@@ -4167,13 +4219,18 @@ window.__ModuleLoader__.load({
4167
4219
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
4168
4220
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
4169
4221
  };
4222
+ const existingTitles = new Set(base.chapters.map((c) => c.title));
4223
+ const fresh = result.chapters.filter((c) => !existingTitles.has(c.title));
4224
+ freshCount = fresh.length;
4225
+ if (fresh.length === 0) return base;
4170
4226
  return {
4171
4227
  ...base,
4172
- chapters: [...base.chapters, ...result.chapters],
4228
+ chapters: [...base.chapters, ...fresh],
4173
4229
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
4174
4230
  };
4175
4231
  });
4176
- pushProgress(tt("workflow.planDone", { n: result.chapters.length }), "done");
4232
+ pushProgress(tt("workflow.planDone", { n: freshCount }), "done");
4233
+ if (freshCount < result.chapters.length) pushProgress(`已跳过 ${result.chapters.length - freshCount} 个与已有章节同名的重复章节`, "error");
4177
4234
  } catch (err) {
4178
4235
  setError(err.message);
4179
4236
  pushProgress(`生成章节计划失败:${err.message}`, "error");
@@ -4201,7 +4258,9 @@ window.__ModuleLoader__.load({
4201
4258
  draft: chapter.pendingDraft !== void 0 && chapter.pendingDraft !== "" ? chapter.pendingDraft : null
4202
4259
  });
4203
4260
  setWsSelected("");
4204
- setWsShowDiff(false);
4261
+ setWsShowDiff(true);
4262
+ setWsCheckReport(null);
4263
+ setWsChecked([]);
4205
4264
  } catch {}
4206
4265
  }, [api]);
4207
4266
  /** 捕获工作区原文 textarea 中选中的文字(局部修订目标)。 */
@@ -4233,14 +4292,15 @@ window.__ModuleLoader__.load({
4233
4292
  }
4234
4293
  };
4235
4294
  /** 工作区:按指令修订(whole=true 整章,false 仅修订选中片段)。 */
4236
- const handleWsRewrite = async (whole) => {
4295
+ const handleWsRewrite = async (whole, overrideInstruction) => {
4237
4296
  if (workspace === null) return;
4238
4297
  const target = whole ? "" : wsSelected;
4298
+ const instruction = overrideInstruction ?? workspace.instruction;
4239
4299
  setBusy(true);
4240
4300
  setBusyLabel(`${tt("plan.rewrite")} 第${workspace.no}章`);
4241
4301
  setError("");
4242
4302
  try {
4243
- await api.rewrite(workspace.no, workspace.instruction, target, (frame) => {
4303
+ await api.rewrite(workspace.no, instruction, target, (frame) => {
4244
4304
  applyJobFrame(frame, (n) => tt("progress.rewriting", { no: n }));
4245
4305
  });
4246
4306
  } catch (err) {
@@ -4252,6 +4312,18 @@ window.__ModuleLoader__.load({
4252
4312
  await refresh(false);
4253
4313
  }
4254
4314
  };
4315
+ /** 工作区:按审查报告中勾选的问题一键修订(预填指令 + 立即整章修订到草稿)。 */
4316
+ const handleWsReviseByReport = async () => {
4317
+ if (workspace === null || wsCheckReport === null) return;
4318
+ const picked = wsChecked.map((i) => wsCheckReport.issues[i]).filter((it) => it !== void 0).slice(0, 5);
4319
+ if (picked.length === 0) return;
4320
+ const instruction = "按审稿意见修订(优先处理):\n" + picked.map((i) => `[${i.severity}] ${i.item} → ${i.suggestion}`).join("\n");
4321
+ setWorkspace({
4322
+ ...workspace,
4323
+ instruction
4324
+ });
4325
+ await handleWsRewrite(true, instruction);
4326
+ };
4255
4327
  /** 采纳草稿:覆盖正文文件并刷新。 */
4256
4328
  const handleDraftApply = async (no) => {
4257
4329
  setBusy(true);
@@ -4993,6 +5065,29 @@ window.__ModuleLoader__.load({
4993
5065
  className: panel_module_css_default.navTabLabel,
4994
5066
  children: SETTINGS_TAB.label
4995
5067
  })]
5068
+ }),
5069
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5070
+ className: panel_module_css_default.navAbout,
5071
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
5072
+ type: "button",
5073
+ className: panel_module_css_default.navAboutRow,
5074
+ title: "打开 GitHub 仓库",
5075
+ onClick: () => {
5076
+ window.open(REPO_URL, "_blank", "noopener");
5077
+ },
5078
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: ["ℹ️ v", PLUGIN_VERSION] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5079
+ className: panel_module_css_default.meta,
5080
+ children: "GitHub ↗"
5081
+ })]
5082
+ }), npmLatest !== null && npmLatest !== PLUGIN_VERSION && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
5083
+ type: "button",
5084
+ className: panel_module_css_default.navAboutUpdate,
5085
+ title: "查看更新方法",
5086
+ onClick: () => {
5087
+ window.alert(`检测到新版本 v${npmLatest}(当前 v${PLUGIN_VERSION})\n\n更新方式:\n\n【npm 安装】\ncd ~/.dsh/profiles/web && pnpm add @waterwx/dsh-novel-forge@latest\n然后重启 dsh web\n\n【GitHub 安装】\ndsh plugin --profile web add github:watersxya/dsh-novel-forge\n\n【本地开发】\n拉取最新代码 → pnpm install && pnpm build → 重启 dsh web`);
5088
+ },
5089
+ children: ["📦 有新版本 v", npmLatest]
5090
+ })]
4996
5091
  })
4997
5092
  ]
4998
5093
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -5078,25 +5173,79 @@ window.__ModuleLoader__.load({
5078
5173
  style: { borderColor: "var(--nf-accent)" },
5079
5174
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5080
5175
  className: panel_module_css_default.busyRow,
5081
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
5082
- className: panel_module_css_default.cardTitle,
5083
- children: [
5084
- "第 ",
5085
- workspace.no,
5086
- " 章《",
5087
- workspace.title,
5088
- "》润色/修订"
5089
- ]
5090
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5091
- type: "button",
5092
- className: panel_module_css_default.iconButton,
5093
- title: "关闭工作区",
5094
- "aria-label": "关闭工作区",
5095
- onClick: () => {
5096
- setWorkspace(null);
5097
- },
5098
- children: "×"
5099
- })]
5176
+ style: {
5177
+ flexWrap: "wrap",
5178
+ gap: 8
5179
+ },
5180
+ children: [
5181
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5182
+ type: "button",
5183
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
5184
+ onClick: () => {
5185
+ setWorkspace(null);
5186
+ },
5187
+ title: "返回章节列表(草稿不丢失)",
5188
+ children: "← 返回"
5189
+ }),
5190
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
5191
+ className: panel_module_css_default.cardTitle,
5192
+ children: [
5193
+ "第 ",
5194
+ workspace.no,
5195
+ " 章《",
5196
+ workspace.title,
5197
+ "》"
5198
+ ]
5199
+ }),
5200
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
5201
+ className: panel_module_css_default.meta,
5202
+ children: [workspace.original.length, " 字"]
5203
+ }),
5204
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
5205
+ style: {
5206
+ display: "flex",
5207
+ gap: 4,
5208
+ alignItems: "center",
5209
+ marginLeft: "auto"
5210
+ },
5211
+ children: [
5212
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5213
+ type: "button",
5214
+ className: panel_module_css_default.iconButton,
5215
+ title: "减小字号",
5216
+ "aria-label": "减小字号",
5217
+ onClick: () => {
5218
+ changeEditorFontSize(editorFontSize - 1);
5219
+ },
5220
+ children: "A−"
5221
+ }),
5222
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
5223
+ className: panel_module_css_default.meta,
5224
+ children: [editorFontSize, "px"]
5225
+ }),
5226
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5227
+ type: "button",
5228
+ className: panel_module_css_default.iconButton,
5229
+ title: "增大字号",
5230
+ "aria-label": "增大字号",
5231
+ onClick: () => {
5232
+ changeEditorFontSize(editorFontSize + 1);
5233
+ },
5234
+ children: "A+"
5235
+ }),
5236
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5237
+ type: "button",
5238
+ className: panel_module_css_default.iconButton,
5239
+ title: "关闭工作区",
5240
+ "aria-label": "关闭工作区",
5241
+ onClick: () => {
5242
+ setWorkspace(null);
5243
+ },
5244
+ children: "×"
5245
+ })
5246
+ ]
5247
+ })
5248
+ ]
5100
5249
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5101
5250
  className: panel_module_css_default.wsColumns,
5102
5251
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -5111,6 +5260,7 @@ window.__ModuleLoader__.load({
5111
5260
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
5112
5261
  ref: wsEditorRef,
5113
5262
  className: `${panel_module_css_default.textarea} ${panel_module_css_default.wsEditor}`,
5263
+ style: { fontSize: editorFontSize },
5114
5264
  value: workspace.original,
5115
5265
  onChange: (e) => {
5116
5266
  setWorkspace({
@@ -5160,7 +5310,7 @@ window.__ModuleLoader__.load({
5160
5310
  className: panel_module_css_default.row,
5161
5311
  style: { flexWrap: "wrap" },
5162
5312
  children: [
5163
- workspace.instruction.startsWith("按审稿意见修订") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5313
+ workspace.instruction.includes("按审稿意见修订") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5164
5314
  type: "button",
5165
5315
  className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall} ${panel_module_css_default.buttonPrimary}`,
5166
5316
  disabled: busy,
@@ -5244,14 +5394,29 @@ window.__ModuleLoader__.load({
5244
5394
  style: {
5245
5395
  margin: 0,
5246
5396
  paddingLeft: 16,
5247
- fontSize: 12,
5248
5397
  display: "flex",
5249
5398
  flexDirection: "column",
5250
- gap: 3
5399
+ gap: 3,
5400
+ fontSize: editorFontSize - 1,
5401
+ maxHeight: "45vh",
5402
+ overflowY: "auto"
5251
5403
  },
5252
5404
  children: wsCheckReport.issues.map((issue, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
5253
- style: { color: severityColor(issue.severity) },
5254
- children: [
5405
+ style: {
5406
+ color: severityColor(issue.severity),
5407
+ display: "flex",
5408
+ gap: 6,
5409
+ alignItems: "flex-start"
5410
+ },
5411
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
5412
+ type: "checkbox",
5413
+ style: { marginTop: 1 },
5414
+ checked: wsChecked.includes(i),
5415
+ onChange: (e) => {
5416
+ setWsChecked((prev) => e.target.checked ? [...prev, i] : prev.filter((x) => x !== i));
5417
+ },
5418
+ title: "勾选后可由「修复所选问题」一起修订"
5419
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
5255
5420
  "[",
5256
5421
  issue.severity,
5257
5422
  "] ",
@@ -5260,12 +5425,29 @@ window.__ModuleLoader__.load({
5260
5425
  style: { color: "var(--nf-text-2)" },
5261
5426
  children: [" → ", issue.suggestion]
5262
5427
  })
5263
- ]
5428
+ ] })]
5264
5429
  }, i))
5265
5430
  }),
5266
5431
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5267
5432
  className: panel_module_css_default.meta,
5268
- children: "审查只读不落盘;改完点「💾 保存为正文」才写入文件(原稿自动备份 .bak)。"
5433
+ children: "审查只读不落盘;勾选要修的问题,点下方按钮一键修订;改完点「💾 保存为正文」才写入文件(原稿自动备份 .bak)。"
5434
+ }),
5435
+ wsCheckReport.issues.length > 0 && wsChecked.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5436
+ style: { marginTop: 8 },
5437
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
5438
+ type: "button",
5439
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall} ${panel_module_css_default.buttonPrimary}`,
5440
+ disabled: busy,
5441
+ onClick: () => {
5442
+ handleWsReviseByReport();
5443
+ },
5444
+ title: "自动按勾选的问题修订整章,产出草稿预览(不落盘),对比后应用或放弃",
5445
+ children: [
5446
+ "🔧 修复所选问题(",
5447
+ wsChecked.length,
5448
+ ")"
5449
+ ]
5450
+ })
5269
5451
  })
5270
5452
  ]
5271
5453
  }),
@@ -5316,9 +5498,11 @@ window.__ModuleLoader__.load({
5316
5498
  })]
5317
5499
  }), wsShowDiff ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DiffList, {
5318
5500
  original: workspace.original,
5319
- draft: workspace.draft
5501
+ draft: workspace.draft,
5502
+ fontSize: editorFontSize
5320
5503
  }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
5321
5504
  className: panel_module_css_default.wsPreviewText,
5505
+ style: { fontSize: editorFontSize },
5322
5506
  children: workspace.draft
5323
5507
  })]
5324
5508
  })
@@ -5326,1760 +5510,1800 @@ window.__ModuleLoader__.load({
5326
5510
  })]
5327
5511
  })]
5328
5512
  }),
5329
- activeTab === "workflow" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
5330
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5331
- className: panel_module_css_default.dashHero,
5332
- children: [
5333
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5334
- className: panel_module_css_default.dashHeroEyebrow,
5335
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5336
- className: panel_module_css_default.dashHeroSparkle,
5337
- children: "✨"
5338
- }), nextAction?.eyebrow ?? "开始"]
5339
- }),
5340
- project !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5341
- className: panel_module_css_default.dashHeroTitle,
5342
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5343
- className: panel_module_css_default.meta,
5344
- children: "正在创作"
5345
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("h3", {
5346
- className: panel_module_css_default.dashHeroBook,
5513
+ workspace === null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
5514
+ activeTab === "workflow" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
5515
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5516
+ className: panel_module_css_default.dashHero,
5517
+ children: [
5518
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5519
+ className: panel_module_css_default.dashHeroEyebrow,
5520
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5521
+ className: panel_module_css_default.dashHeroSparkle,
5522
+ children: "✨"
5523
+ }), nextAction?.eyebrow ?? "开始"]
5524
+ }),
5525
+ project !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5526
+ className: panel_module_css_default.dashHeroTitle,
5527
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5528
+ className: panel_module_css_default.meta,
5529
+ children: "正在创作"
5530
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("h3", {
5531
+ className: panel_module_css_default.dashHeroBook,
5532
+ children: [
5533
+ "《",
5534
+ project.bookName,
5535
+ "》"
5536
+ ]
5537
+ })]
5538
+ }),
5539
+ nextAction !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5540
+ className: panel_module_css_default.dashHeroAction,
5347
5541
  children: [
5348
- "《",
5349
- project.bookName,
5350
- "》"
5542
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5543
+ className: panel_module_css_default.dashHeroArrow,
5544
+ children: "→"
5545
+ }),
5546
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5547
+ className: panel_module_css_default.dashHeroActionBody,
5548
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5549
+ className: panel_module_css_default.dashHeroActionTitle,
5550
+ children: nextAction.title
5551
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5552
+ className: panel_module_css_default.meta,
5553
+ children: nextAction.reason
5554
+ })]
5555
+ }),
5556
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5557
+ type: "button",
5558
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonPrimary}`,
5559
+ disabled: busy,
5560
+ onClick: () => {
5561
+ nextAction.onClick();
5562
+ },
5563
+ children: nextAction.actionLabel
5564
+ })
5351
5565
  ]
5352
- })]
5353
- }),
5354
- nextAction !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5355
- className: panel_module_css_default.dashHeroAction,
5356
- children: [
5357
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5358
- className: panel_module_css_default.dashHeroArrow,
5359
- children: "→"
5360
- }),
5361
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5362
- className: panel_module_css_default.dashHeroActionBody,
5363
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5364
- className: panel_module_css_default.dashHeroActionTitle,
5365
- children: nextAction.title
5366
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5367
- className: panel_module_css_default.meta,
5368
- children: nextAction.reason
5369
- })]
5370
- }),
5371
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5372
- type: "button",
5373
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonPrimary}`,
5374
- disabled: busy,
5375
- onClick: () => {
5376
- nextAction.onClick();
5377
- },
5378
- children: nextAction.actionLabel
5379
- })
5380
- ]
5381
- }),
5382
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5383
- className: panel_module_css_default.dashJourney,
5384
- children: [
5385
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5386
- className: panel_module_css_default.busyRow,
5387
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5388
- className: panel_module_css_default.meta,
5389
- style: { fontWeight: 600 },
5390
- children: "创作旅程"
5391
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
5392
- className: panel_module_css_default.meta,
5393
- children: [
5394
- journeyPercent,
5395
- "% · 已完成 ",
5396
- journeyDoneCount,
5397
- "/",
5398
- journeyStages.length,
5399
- " 步"
5400
- ]
5401
- })]
5402
- }),
5403
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5404
- className: panel_module_css_default.dashJourneyBar,
5405
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5406
- className: panel_module_css_default.dashJourneyFill,
5407
- style: { width: `${journeyPercent}%` }
5566
+ }),
5567
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5568
+ className: panel_module_css_default.dashJourney,
5569
+ children: [
5570
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5571
+ className: panel_module_css_default.busyRow,
5572
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5573
+ className: panel_module_css_default.meta,
5574
+ style: { fontWeight: 600 },
5575
+ children: "创作旅程"
5576
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
5577
+ className: panel_module_css_default.meta,
5578
+ children: [
5579
+ journeyPercent,
5580
+ "% · 已完成 ",
5581
+ journeyDoneCount,
5582
+ "/",
5583
+ journeyStages.length,
5584
+ " 步"
5585
+ ]
5586
+ })]
5587
+ }),
5588
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5589
+ className: panel_module_css_default.dashJourneyBar,
5590
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5591
+ className: panel_module_css_default.dashJourneyFill,
5592
+ style: { width: `${journeyPercent}%` }
5593
+ })
5594
+ }),
5595
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5596
+ className: panel_module_css_default.dashJourneyStages,
5597
+ children: journeyStages.map((stage) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
5598
+ className: `${panel_module_css_default.dashStage} ${stage.done ? panel_module_css_default.dashStageDone : stage.id === currentStageId ? panel_module_css_default.dashStageCurrent : ""}`,
5599
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5600
+ className: panel_module_css_default.dashStageDot,
5601
+ children: stage.done ? "✓" : stage.id === currentStageId ? "●" : "○"
5602
+ }), stage.label]
5603
+ }, stage.id))
5408
5604
  })
5409
- }),
5410
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5411
- className: panel_module_css_default.dashJourneyStages,
5412
- children: journeyStages.map((stage) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
5413
- className: `${panel_module_css_default.dashStage} ${stage.done ? panel_module_css_default.dashStageDone : stage.id === currentStageId ? panel_module_css_default.dashStageCurrent : ""}`,
5605
+ ]
5606
+ }),
5607
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5608
+ className: panel_module_css_default.dashFacts,
5609
+ children: [
5610
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5611
+ className: panel_module_css_default.dashFact,
5414
5612
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5415
- className: panel_module_css_default.dashStageDot,
5416
- children: stage.done ? "✓" : stage.id === currentStageId ? "●" : "○"
5417
- }), stage.label]
5418
- }, stage.id))
5419
- })
5420
- ]
5421
- }),
5422
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5423
- className: panel_module_css_default.dashFacts,
5424
- children: [
5425
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5426
- className: panel_module_css_default.dashFact,
5427
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5428
- className: panel_module_css_default.meta,
5429
- children: "已沉淀章节"
5430
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("b", { children: [doneCount, " 章"] })]
5431
- }),
5432
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5433
- className: panel_module_css_default.dashFact,
5434
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5435
- className: panel_module_css_default.meta,
5436
- children: "累计字数"
5437
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("b", { children: [totalChars, " 字"] })]
5438
- }),
5439
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5440
- className: panel_module_css_default.dashFact,
5441
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5613
+ className: panel_module_css_default.meta,
5614
+ children: "已沉淀章节"
5615
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("b", { children: [doneCount, " 章"] })]
5616
+ }),
5617
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5618
+ className: panel_module_css_default.dashFact,
5619
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5620
+ className: panel_module_css_default.meta,
5621
+ children: "累计字数"
5622
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("b", { children: [totalChars, " 字"] })]
5623
+ }),
5624
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5625
+ className: panel_module_css_default.dashFact,
5626
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5627
+ className: panel_module_css_default.meta,
5628
+ children: "当前卷"
5629
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: currentVolumeName })]
5630
+ }),
5631
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5632
+ className: panel_module_css_default.dashFact,
5633
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5634
+ className: panel_module_css_default.meta,
5635
+ children: "最近创作"
5636
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: lastUpdated })]
5637
+ })
5638
+ ]
5639
+ })
5640
+ ]
5641
+ }),
5642
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5643
+ className: panel_module_css_default.assetGrid,
5644
+ children: [
5645
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5646
+ className: panel_module_css_default.assetStat,
5647
+ children: [
5648
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5649
+ className: panel_module_css_default.assetStatLabel,
5650
+ children: "已通过审稿"
5651
+ }),
5652
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5653
+ className: panel_module_css_default.assetStatValue,
5654
+ style: { color: approvedCount > 0 ? "var(--nf-success)" : void 0 },
5655
+ children: approvedCount
5656
+ }),
5657
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5658
+ className: panel_module_css_default.assetStatDetail,
5659
+ children: "章节已 approved"
5660
+ })
5661
+ ]
5662
+ }),
5663
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5664
+ className: panel_module_css_default.assetStat,
5665
+ children: [
5666
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5667
+ className: panel_module_css_default.assetStatLabel,
5668
+ children: "待生成"
5669
+ }),
5670
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5671
+ className: panel_module_css_default.assetStatValue,
5672
+ style: { color: pendingCount > 0 ? "var(--nf-warn)" : void 0 },
5673
+ children: pendingCount
5674
+ }),
5675
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5676
+ className: panel_module_css_default.assetStatDetail,
5677
+ children: "pending + error"
5678
+ })
5679
+ ]
5680
+ }),
5681
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5682
+ className: panel_module_css_default.assetStat,
5683
+ children: [
5684
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5685
+ className: panel_module_css_default.assetStatLabel,
5686
+ children: "待审稿"
5687
+ }),
5688
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5689
+ className: panel_module_css_default.assetStatValue,
5690
+ style: { color: reviewPendingCount > 0 ? "var(--nf-info)" : void 0 },
5691
+ children: reviewPendingCount
5692
+ }),
5693
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5694
+ className: panel_module_css_default.assetStatDetail,
5695
+ children: "written + rejected"
5696
+ })
5697
+ ]
5698
+ }),
5699
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5700
+ className: panel_module_css_default.assetStat,
5701
+ children: [
5702
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5703
+ className: panel_module_css_default.assetStatLabel,
5704
+ children: "总字数"
5705
+ }),
5706
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5707
+ className: panel_module_css_default.assetStatValue,
5708
+ children: totalChars
5709
+ }),
5710
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5711
+ className: panel_module_css_default.assetStatDetail,
5712
+ children: "已生成正文累计"
5713
+ })
5714
+ ]
5715
+ })
5716
+ ]
5717
+ }),
5718
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5719
+ className: panel_module_css_default.dashGrid,
5720
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5721
+ className: panel_module_css_default.card,
5722
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5723
+ className: panel_module_css_default.cardTitle,
5724
+ children: "待办队列"
5725
+ }), todos.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5726
+ className: panel_module_css_default.meta,
5727
+ children: "🎉 暂无待办,一切顺畅"
5728
+ }) : todos.map((todo, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5729
+ 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}`,
5730
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
5731
+ className: panel_module_css_default.todoText,
5732
+ children: [todo.title, todo.description !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
5442
5733
  className: panel_module_css_default.meta,
5443
- children: "当前卷"
5444
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: currentVolumeName })]
5445
- }),
5446
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5447
- className: panel_module_css_default.dashFact,
5448
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5734
+ children: [" — ", todo.description]
5735
+ })]
5736
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5737
+ type: "button",
5738
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
5739
+ disabled: busy,
5740
+ onClick: () => {
5741
+ todo.onClick();
5742
+ },
5743
+ children: todo.actionLabel
5744
+ })]
5745
+ }, i))]
5746
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5747
+ className: panel_module_css_default.card,
5748
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5749
+ className: panel_module_css_default.row,
5750
+ style: { justifyContent: "space-between" },
5751
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5752
+ className: panel_module_css_default.cardTitle,
5753
+ children: "资产健康"
5754
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5755
+ type: "button",
5756
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
5757
+ disabled: busy || doneCount === 0,
5758
+ onClick: () => {
5759
+ handleAudit();
5760
+ },
5761
+ title: "LLM 扫描全本已生成章节,检查人名/境界/资源/时间线矛盾",
5762
+ children: "🔍 全书质检"
5763
+ })]
5764
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5765
+ className: panel_module_css_default.assetGrid,
5766
+ children: [
5767
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5768
+ className: panel_module_css_default.assetStat,
5769
+ children: [
5770
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5771
+ className: panel_module_css_default.assetStatLabel,
5772
+ children: "道藏"
5773
+ }),
5774
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5775
+ className: panel_module_css_default.assetStatValue,
5776
+ style: { color: bible !== void 0 ? "var(--nf-success)" : "var(--nf-text-3)" },
5777
+ children: bible !== void 0 ? `✓ ${bible.worldRules.length} 条规则` : "未生成"
5778
+ }),
5779
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5780
+ className: panel_module_css_default.assetStatDetail,
5781
+ children: bible !== void 0 ? `${bible.characters.length} 人物 · ${bible.redLines.length} 红线` : "提炼人设 / 世界观 / 金手指"
5782
+ })
5783
+ ]
5784
+ }),
5785
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5786
+ className: panel_module_css_default.assetStat,
5787
+ children: [
5788
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5789
+ className: panel_module_css_default.assetStatLabel,
5790
+ children: "卷计划"
5791
+ }),
5792
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5793
+ className: panel_module_css_default.assetStatValue,
5794
+ style: { color: volumes !== void 0 ? "var(--nf-success)" : "var(--nf-text-3)" },
5795
+ children: volumes !== void 0 ? `${volumes.length} 卷` : "未生成"
5796
+ }),
5797
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5798
+ className: panel_module_css_default.assetStatDetail,
5799
+ title: volumes?.map((v) => v.title).join(" / "),
5800
+ children: volumes !== void 0 ? volumes.map((v) => v.title).join(" / ") : "按剧情弧线划分全书"
5801
+ })
5802
+ ]
5803
+ }),
5804
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5805
+ className: panel_module_css_default.assetStat,
5806
+ children: [
5807
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5808
+ className: panel_module_css_default.assetStatLabel,
5809
+ children: "写作资产"
5810
+ }),
5811
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
5812
+ className: panel_module_css_default.assetStatValue,
5813
+ style: { color: assetCount > 0 ? "var(--nf-success)" : "var(--nf-text-3)" },
5814
+ children: [assetCount, " 项"]
5815
+ }),
5816
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5817
+ className: panel_module_css_default.assetStatDetail,
5818
+ title: assetSummary,
5819
+ children: assetSummary
5820
+ })
5821
+ ]
5822
+ }),
5823
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5824
+ className: panel_module_css_default.assetStat,
5825
+ children: [
5826
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5827
+ className: panel_module_css_default.assetStatLabel,
5828
+ children: "伏笔"
5829
+ }),
5830
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
5831
+ className: panel_module_css_default.assetStatValue,
5832
+ children: [foreshadows.length, " 条"]
5833
+ }),
5834
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
5835
+ className: panel_module_css_default.assetStatDetail,
5836
+ children: [
5837
+ foreshadows.filter((f) => f.status === "planned").length,
5838
+ " 待埋 · ",
5839
+ foreshadows.filter((f) => f.status === "resolved").length,
5840
+ " 已回收"
5841
+ ]
5842
+ })
5843
+ ]
5844
+ })
5845
+ ]
5846
+ })]
5847
+ })]
5848
+ }),
5849
+ auditIssues !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5850
+ className: panel_module_css_default.card,
5851
+ style: { borderColor: auditIssues.length > 0 ? "var(--nf-error)" : "var(--nf-success)" },
5852
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5853
+ className: panel_module_css_default.row,
5854
+ style: { justifyContent: "space-between" },
5855
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
5856
+ className: panel_module_css_default.cardTitle,
5857
+ children: ["🔍 全书质检", auditIssues.length === 0 ? ":未发现矛盾 🎉" : `:${auditIssues.length} 处疑似矛盾`]
5858
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5859
+ type: "button",
5860
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
5861
+ onClick: () => {
5862
+ setAuditIssues(null);
5863
+ },
5864
+ children: "收起"
5865
+ })]
5866
+ }), auditIssues.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5867
+ style: {
5868
+ display: "flex",
5869
+ flexDirection: "column",
5870
+ gap: 6
5871
+ },
5872
+ children: auditIssues.map((issue, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5873
+ 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}`,
5874
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
5875
+ className: panel_module_css_default.todoText,
5876
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
5877
+ issue.chapterNo > 0 ? `第 ${issue.chapterNo} 章` : "未定位章节",
5878
+ " · [",
5879
+ issue.severity,
5880
+ "] ",
5881
+ issue.item
5882
+ ] }), issue.suggestion !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
5449
5883
  className: panel_module_css_default.meta,
5450
- children: "最近创作"
5451
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: lastUpdated })]
5452
- })
5453
- ]
5454
- })
5455
- ]
5456
- }),
5457
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5458
- className: panel_module_css_default.assetGrid,
5459
- children: [
5884
+ children: ["建议:", issue.suggestion]
5885
+ })]
5886
+ }), issue.chapterNo > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5887
+ type: "button",
5888
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
5889
+ disabled: busy,
5890
+ onClick: () => {
5891
+ openWorkspace(issue.chapterNo, `按质检意见修订:${issue.item}(建议:${issue.suggestion})`);
5892
+ },
5893
+ children: "去修订"
5894
+ })]
5895
+ }, i))
5896
+ })]
5897
+ })
5898
+ ] }),
5899
+ activeTab === "overview" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5900
+ className: panel_module_css_default.card,
5901
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5902
+ className: panel_module_css_default.row,
5903
+ style: { justifyContent: "space-between" },
5904
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5905
+ className: panel_module_css_default.cardTitle,
5906
+ children: tt("tab.overview")
5907
+ }), project !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5908
+ className: panel_module_css_default.row,
5909
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
5910
+ className: panel_module_css_default.meta,
5911
+ children: [
5912
+ tt("overview.bookName"),
5913
+ ": ",
5914
+ project.bookName,
5915
+ " · ",
5916
+ project.outline.length,
5917
+ " 字",
5918
+ project.outlinePath !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [" · ", project.outlinePath] })
5919
+ ]
5920
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5921
+ type: "button",
5922
+ className: panel_module_css_default.button,
5923
+ disabled: busy,
5924
+ onClick: () => {
5925
+ handleToggleUpdateOutline();
5926
+ },
5927
+ children: updatingOutline ? "收起" : "更新大纲"
5928
+ })]
5929
+ })]
5930
+ }), project === null ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
5460
5931
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5461
- className: panel_module_css_default.assetStat,
5932
+ className: `${panel_module_css_default.dropzone} ${dragActive ? panel_module_css_default.dropzoneActive : ""}`,
5933
+ onClick: () => {
5934
+ fileInputRef.current?.click();
5935
+ },
5936
+ onDragOver: (e) => {
5937
+ e.preventDefault();
5938
+ setDragActive(true);
5939
+ },
5940
+ onDragLeave: () => {
5941
+ setDragActive(false);
5942
+ },
5943
+ onDrop: (e) => {
5944
+ e.preventDefault();
5945
+ setDragActive(false);
5946
+ const file = e.dataTransfer.files?.[0];
5947
+ if (file !== void 0) handleDocxFile(file);
5948
+ },
5462
5949
  children: [
5463
5950
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5464
- className: panel_module_css_default.assetStatLabel,
5465
- children: "已通过审稿"
5951
+ className: panel_module_css_default.dropzoneIcon,
5952
+ children: "📄"
5466
5953
  }),
5954
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "点击选择本机 docx 大纲,或将文件拖到这里" }),
5467
5955
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5468
- className: panel_module_css_default.assetStatValue,
5469
- style: { color: approvedCount > 0 ? "var(--nf-success)" : void 0 },
5470
- children: approvedCount
5956
+ className: panel_module_css_default.meta,
5957
+ children: "也支持粘贴文本到下方编辑区"
5471
5958
  }),
5472
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5473
- className: panel_module_css_default.assetStatDetail,
5474
- children: "章节已 approved"
5959
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
5960
+ ref: fileInputRef,
5961
+ type: "file",
5962
+ accept: ".docx,application/vnd.openxmlformats-officedocument.wordprocessingml.document",
5963
+ style: { display: "none" },
5964
+ onChange: (e) => {
5965
+ const file = e.target.files?.[0];
5966
+ if (file !== void 0) handleDocxFile(file);
5967
+ e.target.value = "";
5968
+ }
5475
5969
  })
5476
5970
  ]
5477
5971
  }),
5478
5972
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5479
- className: panel_module_css_default.assetStat,
5480
- children: [
5481
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5482
- className: panel_module_css_default.assetStatLabel,
5483
- children: "待生成"
5484
- }),
5485
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5486
- className: panel_module_css_default.assetStatValue,
5487
- style: { color: pendingCount > 0 ? "var(--nf-warn)" : void 0 },
5488
- children: pendingCount
5489
- }),
5490
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5491
- className: panel_module_css_default.assetStatDetail,
5492
- children: "pending + error"
5493
- })
5494
- ]
5973
+ className: panel_module_css_default.row,
5974
+ style: { justifyContent: "space-between" },
5975
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
5976
+ className: panel_module_css_default.meta,
5977
+ children: [
5978
+ tt("overview.outlineChars"),
5979
+ ": ",
5980
+ outlineText.length
5981
+ ]
5982
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5983
+ type: "button",
5984
+ className: panel_module_css_default.button,
5985
+ disabled: busy || outlineText.length < 50,
5986
+ onClick: () => {
5987
+ handleSaveOutline();
5988
+ },
5989
+ children: tt("overview.saveOutline")
5990
+ })]
5495
5991
  }),
5992
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
5993
+ className: panel_module_css_default.textarea,
5994
+ value: outlineText,
5995
+ placeholder: tt("overview.outlineHint"),
5996
+ onChange: (e) => {
5997
+ setOutlineText(e.target.value);
5998
+ },
5999
+ spellCheck: false
6000
+ })
6001
+ ] }) : updatingOutline ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
5496
6002
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5497
- className: panel_module_css_default.assetStat,
6003
+ className: panel_module_css_default.meta,
5498
6004
  children: [
5499
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5500
- className: panel_module_css_default.assetStatLabel,
5501
- children: "待审稿"
5502
- }),
5503
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5504
- className: panel_module_css_default.assetStatValue,
5505
- style: { color: reviewPendingCount > 0 ? "var(--nf-info)" : void 0 },
5506
- children: reviewPendingCount
5507
- }),
5508
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5509
- className: panel_module_css_default.assetStatDetail,
5510
- children: "written + rejected"
5511
- })
6005
+ "大纲是本书的「出生证明」。更新时请二选一:",
6006
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: "仅更新文本" }),
6007
+ "(保留设定/章节/正文全部进度),或",
6008
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: "重置项目" }),
6009
+ "(从新总纲重新开始,清空道藏/卷/章节/正文/暗线/资产/编年录,不可恢复)。"
5512
6010
  ]
5513
6011
  }),
6012
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
6013
+ className: panel_module_css_default.textarea,
6014
+ value: outlineText,
6015
+ placeholder: "粘贴新版大纲文本…",
6016
+ onChange: (e) => {
6017
+ setOutlineText(e.target.value);
6018
+ },
6019
+ spellCheck: false
6020
+ }),
5514
6021
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5515
- className: panel_module_css_default.assetStat,
6022
+ className: panel_module_css_default.row,
5516
6023
  children: [
5517
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5518
- className: panel_module_css_default.assetStatLabel,
5519
- children: "总字数"
6024
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6025
+ type: "button",
6026
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonPrimary}`,
6027
+ disabled: busy || outlineText.length < 50,
6028
+ onClick: () => {
6029
+ handleSaveOutline();
6030
+ },
6031
+ children: "仅更新文本(保留进度)"
5520
6032
  }),
5521
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5522
- className: panel_module_css_default.assetStatValue,
5523
- children: totalChars
6033
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6034
+ type: "button",
6035
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonDanger}`,
6036
+ disabled: busy || outlineText.length < 50,
6037
+ onClick: () => {
6038
+ handleResetProject();
6039
+ },
6040
+ children: "重置项目并更新(清空进度)"
5524
6041
  }),
5525
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5526
- className: panel_module_css_default.assetStatDetail,
5527
- children: "已生成正文累计"
5528
- })
6042
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6043
+ className: panel_module_css_default.meta,
6044
+ children: [outlineText.length, " 字"]
6045
+ })
5529
6046
  ]
5530
6047
  })
5531
- ]
5532
- }),
5533
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5534
- className: panel_module_css_default.dashGrid,
5535
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5536
- className: panel_module_css_default.card,
5537
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5538
- className: panel_module_css_default.cardTitle,
5539
- children: "待办队列"
5540
- }), todos.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5541
- className: panel_module_css_default.meta,
5542
- children: "🎉 暂无待办,一切顺畅"
5543
- }) : todos.map((todo, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5544
- 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}`,
5545
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
5546
- className: panel_module_css_default.todoText,
5547
- children: [todo.title, todo.description !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6048
+ ] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
6049
+ className: panel_module_css_default.outlineReadonly,
6050
+ children: project.outline
6051
+ })]
6052
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6053
+ className: panel_module_css_default.card,
6054
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6055
+ className: panel_module_css_default.cardTitle,
6056
+ children: [
6057
+ tt("status.files"),
6058
+ "(",
6059
+ generatedFiles.length,
6060
+ ")"
6061
+ ]
6062
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6063
+ className: panel_module_css_default.fileList,
6064
+ children: [generatedFiles.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: tt("status.projectNone") }), generatedFiles.map((file) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: file }, file))]
6065
+ })]
6066
+ })] }),
6067
+ activeTab === "blurb" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6068
+ className: panel_module_css_default.card,
6069
+ children: [
6070
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6071
+ className: panel_module_css_default.row,
6072
+ style: { justifyContent: "space-between" },
6073
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6074
+ className: panel_module_css_default.cardTitle,
6075
+ children: "卷首语"
6076
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6077
+ className: panel_module_css_default.row,
6078
+ children: [
6079
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6080
+ type: "button",
6081
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall} ${panel_module_css_default.buttonPrimary}`,
6082
+ disabled: busy || project === null,
6083
+ onClick: () => {
6084
+ handleBlurbGenerate();
6085
+ },
6086
+ children: "✨ AI 生成"
6087
+ }),
6088
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6089
+ type: "button",
6090
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
6091
+ disabled: busy || project === null || blurbDraft.trim() === "",
6092
+ onClick: () => {
6093
+ handleBlurbComplete();
6094
+ },
6095
+ children: "✍️ AI 补全"
6096
+ }),
6097
+ project?.blurb !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6098
+ type: "button",
6099
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
6100
+ disabled: busy || project === null,
6101
+ onClick: () => {
6102
+ if (window.confirm("重新生成会覆盖当前简介(可先复制保存),确定?")) handleBlurbGenerate();
6103
+ },
6104
+ children: "🔄 重新生成"
6105
+ })
6106
+ ]
6107
+ })]
6108
+ }),
6109
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6110
+ className: panel_module_css_default.row,
6111
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
6112
+ className: panel_module_css_default.input,
6113
+ style: {
6114
+ flex: 1,
6115
+ maxWidth: 320
6116
+ },
6117
+ placeholder: "书名",
6118
+ value: bookNameDraft,
6119
+ onChange: (e) => {
6120
+ setBookNameDraft(e.target.value);
6121
+ },
6122
+ onKeyDown: (e) => {
6123
+ if (e.key === "Enter") handleRename();
6124
+ }
6125
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6126
+ type: "button",
6127
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
6128
+ disabled: busy || bookNameDraft.trim() === "" || bookNameDraft.trim() === project?.bookName,
6129
+ onClick: () => {
6130
+ handleRename();
6131
+ },
6132
+ children: "💾 改书名"
6133
+ })]
6134
+ }),
6135
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6136
+ className: panel_module_css_default.row,
6137
+ style: {
6138
+ alignItems: "flex-start",
6139
+ gap: 14
6140
+ },
6141
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6142
+ className: panel_module_css_default.coverPreview,
6143
+ children: coverDataUrl !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
6144
+ src: coverDataUrl,
6145
+ alt: "封面"
6146
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6147
+ className: panel_module_css_default.coverPlaceholder,
6148
+ children: "暂无封面"
6149
+ })
6150
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6151
+ style: {
6152
+ display: "flex",
6153
+ flexDirection: "column",
6154
+ gap: 8
6155
+ },
6156
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6157
+ className: panel_module_css_default.row,
6158
+ children: [
6159
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6160
+ type: "button",
6161
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
6162
+ disabled: busy || project === null,
6163
+ onClick: () => {
6164
+ coverFileRef.current?.click();
6165
+ },
6166
+ children: "📤 上传封面"
6167
+ }),
6168
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
6169
+ ref: coverFileRef,
6170
+ type: "file",
6171
+ accept: "image/png,image/jpeg,image/webp",
6172
+ style: { display: "none" },
6173
+ onChange: (e) => {
6174
+ handleCoverUpload(e.target.files?.[0]);
6175
+ e.target.value = "";
6176
+ }
6177
+ }),
6178
+ coverDataUrl !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6179
+ type: "button",
6180
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
6181
+ disabled: busy,
6182
+ onClick: () => {
6183
+ handleCoverRemove();
6184
+ },
6185
+ children: "🗑️ 移除"
6186
+ })
6187
+ ]
6188
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5548
6189
  className: panel_module_css_default.meta,
5549
- children: [" — ", todo.description]
6190
+ children: "支持 PNG / JPG / WebP,建议 3:4 竖版;保存于输出目录 cover.*。"
5550
6191
  })]
5551
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6192
+ })]
6193
+ }),
6194
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6195
+ className: panel_module_css_default.meta,
6196
+ children: "面向读者的作品门面(120-250 字):突出核心卖点与开局钩子,不剧透。点击 ✨AI 生成全量生成;或先写几句再点 ✍️AI 补全续写完整;不满意可 🔄 重新生成。"
6197
+ }),
6198
+ project === null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6199
+ className: panel_module_css_default.meta,
6200
+ children: "请先在大纲页导入大纲建立项目。"
6201
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
6202
+ className: panel_module_css_default.textarea,
6203
+ style: { minHeight: 140 },
6204
+ placeholder: "点击 ✨AI 生成,或先写下开头几句,再点 ✍️AI 补全…",
6205
+ value: blurbDraft,
6206
+ onChange: (e) => {
6207
+ setBlurbDraft(e.target.value);
6208
+ },
6209
+ spellCheck: false
6210
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6211
+ className: panel_module_css_default.row,
6212
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5552
6213
  type: "button",
5553
6214
  className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
5554
- disabled: busy,
6215
+ disabled: busy || blurbDraft.trim() === "",
5555
6216
  onClick: () => {
5556
- todo.onClick();
6217
+ handleBlurbSave();
5557
6218
  },
5558
- children: todo.actionLabel
6219
+ children: "💾 保存简介"
6220
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6221
+ className: panel_module_css_default.meta,
6222
+ children: [
6223
+ blurbDraft.length,
6224
+ " 字 · 已保存:",
6225
+ project.blurb !== void 0 ? `${project.blurb.length} 字` : "无"
6226
+ ]
5559
6227
  })]
5560
- }, i))]
5561
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6228
+ })] })
6229
+ ]
6230
+ }),
6231
+ activeTab === "plan" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
6232
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5562
6233
  className: panel_module_css_default.card,
5563
6234
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5564
6235
  className: panel_module_css_default.row,
5565
6236
  style: { justifyContent: "space-between" },
5566
6237
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5567
6238
  className: panel_module_css_default.cardTitle,
5568
- children: "资产健康"
5569
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6239
+ children: tt("tab.plan")
6240
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6241
+ className: panel_module_css_default.row,
6242
+ children: [
6243
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6244
+ className: panel_module_css_default.meta,
6245
+ children: tt("plan.generateHint")
6246
+ }),
6247
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
6248
+ className: panel_module_css_default.input,
6249
+ style: { width: 72 },
6250
+ type: "number",
6251
+ min: 1,
6252
+ max: 200,
6253
+ value: planCount,
6254
+ onChange: (e) => {
6255
+ const v = Number(e.target.value);
6256
+ if (Number.isInteger(v)) setPlanCount(v);
6257
+ }
6258
+ }),
6259
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6260
+ className: panel_module_css_default.meta,
6261
+ children: tt("plan.count")
6262
+ }),
6263
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6264
+ type: "button",
6265
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonPrimary}`,
6266
+ disabled: busy || outlineText.length < 50,
6267
+ onClick: () => {
6268
+ handlePlan();
6269
+ },
6270
+ children: tt("plan.generate")
6271
+ })
6272
+ ]
6273
+ })]
6274
+ }), volumes !== void 0 && volumes.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6275
+ className: panel_module_css_default.row,
6276
+ children: volumes.map((v) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6277
+ className: panel_module_css_default.badge,
6278
+ style: {
6279
+ borderColor: "var(--nf-accent)",
6280
+ color: "var(--nf-accent)"
6281
+ },
6282
+ children: [
6283
+ v.no,
6284
+ ". ",
6285
+ v.title,
6286
+ "(",
6287
+ v.chapterStart,
6288
+ "-",
6289
+ v.chapterEnd,
6290
+ ")"
6291
+ ]
6292
+ }, v.no))
6293
+ })]
6294
+ }),
6295
+ chapters.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6296
+ className: panel_module_css_default.card,
6297
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6298
+ className: panel_module_css_default.row,
6299
+ style: { justifyContent: "space-between" },
6300
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6301
+ className: panel_module_css_default.meta,
6302
+ children: [
6303
+ "共 ",
6304
+ chapters.length,
6305
+ " 章 · 已完成 ",
6306
+ doneCount,
6307
+ " · 待生成 ",
6308
+ pendingCount
6309
+ ]
6310
+ }), pendingCount > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
5570
6311
  type: "button",
5571
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
5572
- disabled: busy || doneCount === 0,
6312
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonPrimary}`,
6313
+ disabled: busy,
5573
6314
  onClick: () => {
5574
- handleAudit();
6315
+ handleWriteAll();
5575
6316
  },
5576
- title: "LLM 扫描全本已生成章节,检查人名/境界/资源/时间线矛盾",
5577
- children: "🔍 全书质检"
6317
+ children: [
6318
+ tt("plan.writeAllPending"),
6319
+ "(",
6320
+ pendingCount,
6321
+ ")"
6322
+ ]
5578
6323
  })]
5579
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5580
- className: panel_module_css_default.assetGrid,
5581
- children: [
5582
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5583
- className: panel_module_css_default.assetStat,
5584
- children: [
5585
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5586
- className: panel_module_css_default.assetStatLabel,
5587
- children: "道藏"
5588
- }),
5589
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5590
- className: panel_module_css_default.assetStatValue,
5591
- style: { color: bible !== void 0 ? "var(--nf-success)" : "var(--nf-text-3)" },
5592
- children: bible !== void 0 ? `✓ ${bible.worldRules.length} 条规则` : "未生成"
5593
- }),
5594
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5595
- className: panel_module_css_default.assetStatDetail,
5596
- children: bible !== void 0 ? `${bible.characters.length} 人物 · ${bible.redLines.length} 红线` : "提炼人设 / 世界观 / 金手指"
5597
- })
5598
- ]
5599
- }),
5600
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5601
- className: panel_module_css_default.assetStat,
5602
- children: [
5603
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5604
- className: panel_module_css_default.assetStatLabel,
5605
- children: "卷计划"
5606
- }),
5607
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5608
- className: panel_module_css_default.assetStatValue,
5609
- style: { color: volumes !== void 0 ? "var(--nf-success)" : "var(--nf-text-3)" },
5610
- children: volumes !== void 0 ? `${volumes.length} 卷` : "未生成"
5611
- }),
5612
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5613
- className: panel_module_css_default.assetStatDetail,
5614
- title: volumes?.map((v) => v.title).join(" / "),
5615
- children: volumes !== void 0 ? volumes.map((v) => v.title).join(" / ") : "按剧情弧线划分全书"
5616
- })
5617
- ]
5618
- }),
5619
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5620
- className: panel_module_css_default.assetStat,
5621
- children: [
5622
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5623
- className: panel_module_css_default.assetStatLabel,
5624
- children: "写作资产"
5625
- }),
5626
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
5627
- className: panel_module_css_default.assetStatValue,
5628
- style: { color: assetCount > 0 ? "var(--nf-success)" : "var(--nf-text-3)" },
5629
- children: [assetCount, " 项"]
5630
- }),
5631
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5632
- className: panel_module_css_default.assetStatDetail,
5633
- title: assetSummary,
5634
- children: assetSummary
5635
- })
5636
- ]
5637
- }),
5638
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5639
- className: panel_module_css_default.assetStat,
5640
- children: [
5641
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5642
- className: panel_module_css_default.assetStatLabel,
5643
- children: "伏笔"
5644
- }),
5645
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
5646
- className: panel_module_css_default.assetStatValue,
5647
- children: [foreshadows.length, " 条"]
5648
- }),
5649
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
5650
- className: panel_module_css_default.assetStatDetail,
6324
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6325
+ className: panel_module_css_default.chapterList,
6326
+ children: chapterGroups.map((group) => {
6327
+ const collapsed = group.no !== 0 && collapsedVolumes.includes(group.no);
6328
+ const groupDone = group.chapters.filter((c) => c.status === "approved" || c.status === "written" || c.status === "rejected").length;
6329
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6330
+ className: panel_module_css_default.volumeGroup,
6331
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6332
+ className: panel_module_css_default.volumeGroupHeader,
6333
+ onClick: () => {
6334
+ if (group.no !== 0) setCollapsedVolumes((prev) => prev.includes(group.no) ? prev.filter((x) => x !== group.no) : [...prev, group.no]);
6335
+ },
6336
+ children: [
6337
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6338
+ className: panel_module_css_default.volumeGroupToggle,
6339
+ children: group.no !== 0 ? collapsed ? "▸" : "▾" : "📖"
6340
+ }),
6341
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: group.title }),
6342
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6343
+ className: panel_module_css_default.meta,
6344
+ children: [
6345
+ "(",
6346
+ group.chapters.length,
6347
+ " 章 · 已完成 ",
6348
+ groupDone,
6349
+ ")"
6350
+ ]
6351
+ })
6352
+ ]
6353
+ }), !collapsed && group.chapters.map((chapter) => {
6354
+ const badge = statusBadge(chapter);
6355
+ const expanded = expandedChapter === chapter.no;
6356
+ const review = chapter.review;
6357
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6358
+ className: panel_module_css_default.chapter,
5651
6359
  children: [
5652
- foreshadows.filter((f) => f.status === "planned").length,
5653
- " 待埋 · ",
5654
- foreshadows.filter((f) => f.status === "resolved").length,
5655
- " 已回收"
6360
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6361
+ className: panel_module_css_default.chapterNum,
6362
+ children: chapter.no
6363
+ }),
6364
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6365
+ className: panel_module_css_default.chapterMain,
6366
+ children: [
6367
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6368
+ className: panel_module_css_default.chapterTitle,
6369
+ children: [
6370
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6371
+ type: "button",
6372
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
6373
+ style: { padding: "1px 6px" },
6374
+ onClick: () => {
6375
+ handleToggleChapter(chapter.no);
6376
+ },
6377
+ children: expanded ? "−" : "+"
6378
+ }),
6379
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: chapter.title }),
6380
+ chapter.status === "approved" && chapter.chars !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6381
+ className: panel_module_css_default.meta,
6382
+ children: [chapter.chars, tt("common.chars")]
6383
+ }),
6384
+ chapter.volume > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6385
+ className: panel_module_css_default.meta,
6386
+ children: [tt("plan.volumes"), chapter.volume]
6387
+ })
6388
+ ]
6389
+ }),
6390
+ !expanded && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6391
+ className: panel_module_css_default.chapterBeats,
6392
+ title: chapter.beats,
6393
+ children: chapter.beats
6394
+ }),
6395
+ expanded && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6396
+ style: {
6397
+ display: "flex",
6398
+ flexDirection: "column",
6399
+ gap: 6
6400
+ },
6401
+ children: [
6402
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6403
+ className: panel_module_css_default.meta,
6404
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("b", { children: [tt("plan.beats"), ":"] })
6405
+ }),
6406
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6407
+ className: panel_module_css_default.meta,
6408
+ children: renderBeats(chapter.beats)
6409
+ }),
6410
+ chapter.summary !== void 0 && chapter.summary !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6411
+ className: panel_module_css_default.meta,
6412
+ children: [
6413
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("b", { children: [tt("plan.summary"), ":"] }),
6414
+ " ",
6415
+ chapter.summary
6416
+ ]
6417
+ }),
6418
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
6419
+ className: panel_module_css_default.chapterPreview,
6420
+ children: chapterText || `(${tt("common.loading")})`
6421
+ }),
6422
+ review !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6423
+ className: panel_module_css_default.reviewBox,
6424
+ children: [
6425
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6426
+ className: panel_module_css_default.row,
6427
+ style: { justifyContent: "space-between" },
6428
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: tt("plan.reviewReport") }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6429
+ style: { color: review.passed ? "var(--nf-success)" : "var(--nf-error)" },
6430
+ children: [
6431
+ tt("plan.reviewScore"),
6432
+ ": ",
6433
+ review.score,
6434
+ " — ",
6435
+ review.passed ? tt("plan.reviewPass") : tt("plan.reviewFail")
6436
+ ]
6437
+ })]
6438
+ }),
6439
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6440
+ className: panel_module_css_default.meta,
6441
+ children: [
6442
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("b", { children: [tt("plan.reviewVerdict"), ":"] }),
6443
+ " ",
6444
+ review.verdict
6445
+ ]
6446
+ }),
6447
+ review.issues.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
6448
+ style: {
6449
+ margin: 0,
6450
+ paddingLeft: 18,
6451
+ fontSize: 12
6452
+ },
6453
+ children: review.issues.map((issue, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
6454
+ style: { color: severityColor(issue.severity) },
6455
+ children: [
6456
+ "[",
6457
+ issue.severity,
6458
+ "] ",
6459
+ issue.item,
6460
+ " → ",
6461
+ issue.suggestion
6462
+ ]
6463
+ }, i))
6464
+ })
6465
+ ]
6466
+ }),
6467
+ (chapter.status === "rejected" || chapter.status === "written" || chapter.status === "approved") && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6468
+ style: {
6469
+ display: "flex",
6470
+ flexDirection: "column",
6471
+ gap: 6
6472
+ },
6473
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6474
+ className: panel_module_css_default.meta,
6475
+ style: { fontWeight: 600 },
6476
+ children: "润色 / 修订 — 在右上角打开工作区:左栏原文可直接选中文字做局部修订,右栏输入指令后预览,确认后再应用(未应用不改动原稿)"
6477
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6478
+ className: panel_module_css_default.row,
6479
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
6480
+ type: "button",
6481
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonPrimary}`,
6482
+ disabled: busy || busyAny,
6483
+ onClick: () => {
6484
+ openWorkspace(chapter.no);
6485
+ },
6486
+ children: [
6487
+ tt("plan.rewrite"),
6488
+ " / ",
6489
+ tt("plan.polish")
6490
+ ]
6491
+ })
6492
+ })]
6493
+ })
6494
+ ]
6495
+ })
6496
+ ]
6497
+ }),
6498
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6499
+ className: `${panel_module_css_default.badge} ${badge.cls}`,
6500
+ children: badge.label
6501
+ }),
6502
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6503
+ className: panel_module_css_default.chapterActions,
6504
+ children: [
6505
+ (chapter.status === "pending" || chapter.status === "error") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6506
+ type: "button",
6507
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall} ${panel_module_css_default.buttonPrimary}`,
6508
+ disabled: busy || busyAny,
6509
+ onClick: () => {
6510
+ handleWriteChapter(chapter.no, true);
6511
+ },
6512
+ children: tt("plan.write")
6513
+ }),
6514
+ (chapter.status === "written" || chapter.status === "rejected") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6515
+ type: "button",
6516
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
6517
+ disabled: busy || busyAny,
6518
+ onClick: () => {
6519
+ handleReview(chapter.no);
6520
+ },
6521
+ children: tt("plan.review")
6522
+ }),
6523
+ chapter.status === "written" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6524
+ type: "button",
6525
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
6526
+ disabled: busy || busyAny,
6527
+ onClick: () => {
6528
+ handleApprove(chapter.no);
6529
+ },
6530
+ children: tt("plan.approve")
6531
+ }),
6532
+ (chapter.status === "written" || chapter.status === "rejected" || chapter.status === "approved") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6533
+ type: "button",
6534
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
6535
+ disabled: busy || busyAny,
6536
+ onClick: () => {
6537
+ openWorkspace(chapter.no);
6538
+ },
6539
+ title: "手动编辑正文 → AI 审查 → 保存",
6540
+ children: "✏️ 编辑"
6541
+ }),
6542
+ (chapter.status === "written" || chapter.status === "rejected" || chapter.status === "approved") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6543
+ type: "button",
6544
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
6545
+ disabled: busy || busyAny,
6546
+ onClick: () => {
6547
+ openWorkspace(chapter.no);
6548
+ },
6549
+ children: tt("plan.polish")
6550
+ }),
6551
+ chapter.status === "rejected" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6552
+ type: "button",
6553
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
6554
+ disabled: busy || busyAny,
6555
+ onClick: () => {
6556
+ openWorkspace(chapter.no);
6557
+ },
6558
+ title: "按审稿意见修订(自动带入意见)",
6559
+ children: "按意见修订"
6560
+ }),
6561
+ chapter.status === "rejected" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6562
+ type: "button",
6563
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
6564
+ disabled: busy || busyAny,
6565
+ onClick: () => {
6566
+ handleWriteChapter(chapter.no, true);
6567
+ },
6568
+ title: "整章重新生成",
6569
+ children: "重新生成"
6570
+ })
6571
+ ]
6572
+ })
5656
6573
  ]
5657
- })
5658
- ]
5659
- })
5660
- ]
6574
+ }, chapter.no);
6575
+ })]
6576
+ }, group.no);
6577
+ })
5661
6578
  })]
5662
- })]
5663
- }),
5664
- auditIssues !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6579
+ }),
6580
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6581
+ className: panel_module_css_default.card,
6582
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6583
+ className: panel_module_css_default.cardTitle,
6584
+ children: tt("plan.progress")
6585
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6586
+ className: panel_module_css_default.progress,
6587
+ children: [progress.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6588
+ className: panel_module_css_default.meta,
6589
+ children: tt("progress.empty")
6590
+ }), progress.map((line) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6591
+ className: line.kind === "done" ? panel_module_css_default.progressLineDone : line.kind === "error" ? panel_module_css_default.progressLineError : line.live === true ? panel_module_css_default.progressLineLive : panel_module_css_default.progressLine,
6592
+ children: [line.live === true && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6593
+ className: panel_module_css_default.progressBar,
6594
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6595
+ className: panel_module_css_default.progressBarFill,
6596
+ style: { width: `${Math.round((line.ratio ?? 0) * 100)}%` }
6597
+ })
6598
+ }), line.text]
6599
+ }, line.id))]
6600
+ })]
6601
+ })
6602
+ ] }),
6603
+ activeTab === "bible" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5665
6604
  className: panel_module_css_default.card,
5666
- style: { borderColor: auditIssues.length > 0 ? "var(--nf-error)" : "var(--nf-success)" },
5667
6605
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5668
6606
  className: panel_module_css_default.row,
5669
6607
  style: { justifyContent: "space-between" },
5670
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6608
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5671
6609
  className: panel_module_css_default.cardTitle,
5672
- children: ["🔍 全书质检", auditIssues.length === 0 ? ":未发现矛盾 🎉" : `:${auditIssues.length} 处疑似矛盾`]
6610
+ children: tt("bible.title")
5673
6611
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5674
6612
  type: "button",
5675
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
6613
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonPrimary}`,
6614
+ disabled: busy,
5676
6615
  onClick: () => {
5677
- setAuditIssues(null);
6616
+ handleBible();
5678
6617
  },
5679
- children: "收起"
6618
+ children: tt("bible.gen")
5680
6619
  })]
5681
- }), auditIssues.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6620
+ }), bible === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6621
+ className: panel_module_css_default.meta,
6622
+ children: tt("bible.none")
6623
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5682
6624
  style: {
5683
6625
  display: "flex",
5684
6626
  flexDirection: "column",
5685
- gap: 6
6627
+ gap: 10
5686
6628
  },
5687
- children: auditIssues.map((issue, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5688
- 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}`,
5689
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
5690
- className: panel_module_css_default.todoText,
5691
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
5692
- issue.chapterNo > 0 ? `第 ${issue.chapterNo} 章` : "未定位章节",
5693
- " · [",
5694
- issue.severity,
5695
- "] ",
5696
- issue.item
5697
- ] }), issue.suggestion !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6629
+ children: [
6630
+ bible.genre !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [
6631
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("b", { children: [tt("bible.genre"), ":"] }),
6632
+ " ",
6633
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5698
6634
  className: panel_module_css_default.meta,
5699
- children: ["建议:", issue.suggestion]
5700
- })]
5701
- }), issue.chapterNo > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5702
- type: "button",
5703
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
5704
- disabled: busy,
5705
- onClick: () => {
5706
- openWorkspace(issue.chapterNo, `按质检意见修订:${issue.item}(建议:${issue.suggestion})`);
6635
+ children: bible.genre
6636
+ })
6637
+ ] }),
6638
+ bible.worldRules.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6639
+ style: {
6640
+ border: "1px solid var(--nf-border)",
6641
+ borderRadius: 10,
6642
+ padding: "8px 10px"
5707
6643
  },
5708
- children: "去修订"
5709
- })]
5710
- }, i))
5711
- })]
5712
- })
5713
- ] }),
5714
- activeTab === "overview" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5715
- className: panel_module_css_default.card,
5716
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5717
- className: panel_module_css_default.row,
5718
- style: { justifyContent: "space-between" },
5719
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5720
- className: panel_module_css_default.cardTitle,
5721
- children: tt("tab.overview")
5722
- }), project !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5723
- className: panel_module_css_default.row,
5724
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
5725
- className: panel_module_css_default.meta,
5726
- children: [
5727
- tt("overview.bookName"),
5728
- ": ",
5729
- project.bookName,
5730
- " · ",
5731
- project.outline.length,
5732
- " 字",
5733
- project.outlinePath !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [" · ", project.outlinePath] })
5734
- ]
5735
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5736
- type: "button",
5737
- className: panel_module_css_default.button,
5738
- disabled: busy,
5739
- onClick: () => {
5740
- handleToggleUpdateOutline();
5741
- },
5742
- children: updatingOutline ? "收起" : "更新大纲"
5743
- })]
5744
- })]
5745
- }), project === null ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
5746
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5747
- className: `${panel_module_css_default.dropzone} ${dragActive ? panel_module_css_default.dropzoneActive : ""}`,
5748
- onClick: () => {
5749
- fileInputRef.current?.click();
5750
- },
5751
- onDragOver: (e) => {
5752
- e.preventDefault();
5753
- setDragActive(true);
5754
- },
5755
- onDragLeave: () => {
5756
- setDragActive(false);
5757
- },
5758
- onDrop: (e) => {
5759
- e.preventDefault();
5760
- setDragActive(false);
5761
- const file = e.dataTransfer.files?.[0];
5762
- if (file !== void 0) handleDocxFile(file);
5763
- },
5764
- children: [
5765
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5766
- className: panel_module_css_default.dropzoneIcon,
5767
- children: "📄"
5768
- }),
5769
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "点击选择本机 docx 大纲,或将文件拖到这里" }),
5770
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5771
- className: panel_module_css_default.meta,
5772
- children: "也支持粘贴文本到下方编辑区"
6644
+ children: [
6645
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6646
+ className: panel_module_css_default.row,
6647
+ style: { justifyContent: "space-between" },
6648
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("b", { children: [
6649
+ tt("bible.worldRules"),
6650
+ "(",
6651
+ bible.worldRules.length,
6652
+ ")"
6653
+ ] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6654
+ type: "button",
6655
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
6656
+ onClick: () => {
6657
+ setWorldRulesDraft(bible.worldRules.join("\n"));
6658
+ },
6659
+ children: "编辑"
6660
+ })]
6661
+ }),
6662
+ worldRulesDraft !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6663
+ style: {
6664
+ display: "flex",
6665
+ flexDirection: "column",
6666
+ gap: 6,
6667
+ marginTop: 6
6668
+ },
6669
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
6670
+ className: panel_module_css_default.textarea,
6671
+ style: { minHeight: 120 },
6672
+ value: worldRulesDraft,
6673
+ onChange: (e) => {
6674
+ setWorldRulesDraft(e.target.value);
6675
+ },
6676
+ placeholder: "每条规则一行…"
6677
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6678
+ className: panel_module_css_default.row,
6679
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6680
+ type: "button",
6681
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall} ${panel_module_css_default.buttonPrimary}`,
6682
+ disabled: busy,
6683
+ onClick: () => {
6684
+ handleSaveWorldRules();
6685
+ },
6686
+ children: "保存规则"
6687
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6688
+ type: "button",
6689
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
6690
+ onClick: () => {
6691
+ setWorldRulesDraft("");
6692
+ },
6693
+ children: "取消"
6694
+ })]
6695
+ })]
6696
+ }),
6697
+ worldRulesDraft === "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
6698
+ style: {
6699
+ margin: "4px 0 0",
6700
+ paddingLeft: 18,
6701
+ fontSize: 12
6702
+ },
6703
+ children: bible.worldRules.map((r, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: r }, i))
6704
+ })
6705
+ ]
5773
6706
  }),
5774
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
5775
- ref: fileInputRef,
5776
- type: "file",
5777
- accept: ".docx,application/vnd.openxmlformats-officedocument.wordprocessingml.document",
5778
- style: { display: "none" },
5779
- onChange: (e) => {
5780
- const file = e.target.files?.[0];
5781
- if (file !== void 0) handleDocxFile(file);
5782
- e.target.value = "";
5783
- }
5784
- })
5785
- ]
5786
- }),
5787
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5788
- className: panel_module_css_default.row,
5789
- style: { justifyContent: "space-between" },
5790
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
5791
- className: panel_module_css_default.meta,
5792
- children: [
5793
- tt("overview.outlineChars"),
5794
- ": ",
5795
- outlineText.length
5796
- ]
5797
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5798
- type: "button",
5799
- className: panel_module_css_default.button,
5800
- disabled: busy || outlineText.length < 50,
5801
- onClick: () => {
5802
- handleSaveOutline();
5803
- },
5804
- children: tt("overview.saveOutline")
5805
- })]
5806
- }),
5807
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
5808
- className: panel_module_css_default.textarea,
5809
- value: outlineText,
5810
- placeholder: tt("overview.outlineHint"),
5811
- onChange: (e) => {
5812
- setOutlineText(e.target.value);
5813
- },
5814
- spellCheck: false
5815
- })
5816
- ] }) : updatingOutline ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
5817
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5818
- className: panel_module_css_default.meta,
5819
- children: [
5820
- "大纲是本书的「出生证明」。更新时请二选一:",
5821
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: "仅更新文本" }),
5822
- "(保留设定/章节/正文全部进度),或",
5823
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: "重置项目" }),
5824
- "(从新总纲重新开始,清空道藏/卷/章节/正文/暗线/资产/编年录,不可恢复)。"
5825
- ]
5826
- }),
5827
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
5828
- className: panel_module_css_default.textarea,
5829
- value: outlineText,
5830
- placeholder: "粘贴新版大纲文本…",
5831
- onChange: (e) => {
5832
- setOutlineText(e.target.value);
5833
- },
5834
- spellCheck: false
5835
- }),
5836
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5837
- className: panel_module_css_default.row,
5838
- children: [
5839
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5840
- type: "button",
5841
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonPrimary}`,
5842
- disabled: busy || outlineText.length < 50,
5843
- onClick: () => {
5844
- handleSaveOutline();
6707
+ bible.characters.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("b", { children: [
6708
+ tt("bible.characters"),
6709
+ "(",
6710
+ bible.characters.length,
6711
+ ")"
6712
+ ] }), bible.characters.map((card) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6713
+ style: {
6714
+ marginTop: 4,
6715
+ fontSize: 12
5845
6716
  },
5846
- children: "仅更新文本(保留进度)"
5847
- }),
5848
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5849
- type: "button",
5850
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonDanger}`,
5851
- disabled: busy || outlineText.length < 50,
5852
- onClick: () => {
5853
- handleResetProject();
6717
+ children: [
6718
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: card.name }),
6719
+ " ",
6720
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6721
+ className: panel_module_css_default.meta,
6722
+ children: [
6723
+ "[",
6724
+ card.role,
6725
+ "] ",
6726
+ card.traits.join("、")
6727
+ ]
6728
+ }),
6729
+ card.goals !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6730
+ className: panel_module_css_default.meta,
6731
+ children: ["目标:", card.goals]
6732
+ }),
6733
+ card.relations !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6734
+ className: panel_module_css_default.meta,
6735
+ children: ["关系:", card.relations]
6736
+ })
6737
+ ]
6738
+ }, card.name))] }),
6739
+ bible.redLines.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("b", { children: [
6740
+ tt("bible.redLines"),
6741
+ "(",
6742
+ bible.redLines.length,
6743
+ ")"
6744
+ ] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
6745
+ style: {
6746
+ margin: 0,
6747
+ paddingLeft: 18,
6748
+ fontSize: 12,
6749
+ color: "var(--nf-error)"
5854
6750
  },
5855
- children: "重置项目并更新(清空进度)"
5856
- }),
5857
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
5858
- className: panel_module_css_default.meta,
5859
- children: [outlineText.length, " 字"]
5860
- })
6751
+ children: bible.redLines.map((r, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: r }, i))
6752
+ })] }),
6753
+ bible.style.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("b", { children: [
6754
+ tt("bible.style"),
6755
+ "(",
6756
+ bible.style.length,
6757
+ ")"
6758
+ ] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
6759
+ style: {
6760
+ margin: 0,
6761
+ paddingLeft: 18,
6762
+ fontSize: 12
6763
+ },
6764
+ children: bible.style.map((r, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: r }, i))
6765
+ })] })
5861
6766
  ]
5862
- })
5863
- ] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
5864
- className: panel_module_css_default.outlineReadonly,
5865
- children: project.outline
5866
- })]
5867
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5868
- className: panel_module_css_default.card,
5869
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
5870
- className: panel_module_css_default.cardTitle,
6767
+ })]
6768
+ }) }),
6769
+ activeTab === "world" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(WorldTab, {
6770
+ api,
6771
+ world: project?.world,
6772
+ onChanged: (w) => {
6773
+ setProject((prev) => prev === null ? prev : {
6774
+ ...prev,
6775
+ world: w,
6776
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
6777
+ });
6778
+ pushProgress(`大世界已保存:${w.realms.length} 境界 · ${w.regions.length} 区域 · ${w.factions.length} 势力`, "done");
6779
+ }
6780
+ }),
6781
+ activeTab === "characters" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6782
+ className: panel_module_css_default.card,
5871
6783
  children: [
5872
- tt("status.files"),
5873
- "(",
5874
- generatedFiles.length,
5875
- ")"
5876
- ]
5877
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5878
- className: panel_module_css_default.fileList,
5879
- children: [generatedFiles.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: tt("status.projectNone") }), generatedFiles.map((file) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: file }, file))]
5880
- })]
5881
- })] }),
5882
- activeTab === "blurb" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5883
- className: panel_module_css_default.card,
5884
- children: [
5885
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5886
- className: panel_module_css_default.row,
5887
- style: { justifyContent: "space-between" },
5888
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5889
- className: panel_module_css_default.cardTitle,
5890
- children: "卷首语"
5891
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6784
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5892
6785
  className: panel_module_css_default.row,
5893
- children: [
5894
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5895
- type: "button",
5896
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall} ${panel_module_css_default.buttonPrimary}`,
5897
- disabled: busy || project === null,
5898
- onClick: () => {
5899
- handleBlurbGenerate();
5900
- },
5901
- children: "✨ AI 生成"
5902
- }),
5903
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6786
+ style: { justifyContent: "space-between" },
6787
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6788
+ className: panel_module_css_default.cardTitle,
6789
+ children: "人物志(当前状态)"
6790
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6791
+ className: panel_module_css_default.row,
6792
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5904
6793
  type: "button",
5905
6794
  className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
5906
- disabled: busy || project === null || blurbDraft.trim() === "",
6795
+ disabled: busy || doneCount === 0,
5907
6796
  onClick: () => {
5908
- handleBlurbComplete();
6797
+ handleFactsBackfill();
5909
6798
  },
5910
- children: "✍️ AI 补全"
5911
- }),
5912
- project?.blurb !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6799
+ title: "历史章节(编年录功能上线前生成的)批量抽取事实",
6800
+ children: "📥 回填编年录"
6801
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5913
6802
  type: "button",
5914
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
5915
- disabled: busy || project === null,
6803
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall} ${panel_module_css_default.buttonPrimary}`,
6804
+ disabled: busy || (project?.facts ?? []).length === 0,
5916
6805
  onClick: () => {
5917
- if (window.confirm("重新生成会覆盖当前简介(可先复制保存),确定?")) handleBlurbGenerate();
6806
+ handleCharactersRefresh();
5918
6807
  },
5919
- children: "🔄 重新生成"
5920
- })
5921
- ]
5922
- })]
5923
- }),
5924
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5925
- className: panel_module_css_default.row,
5926
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
5927
- className: panel_module_css_default.input,
5928
- style: {
5929
- flex: 1,
5930
- maxWidth: 320
5931
- },
5932
- placeholder: "书名",
5933
- value: bookNameDraft,
5934
- onChange: (e) => {
5935
- setBookNameDraft(e.target.value);
5936
- },
5937
- onKeyDown: (e) => {
5938
- if (e.key === "Enter") handleRename();
5939
- }
5940
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5941
- type: "button",
5942
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
5943
- disabled: busy || bookNameDraft.trim() === "" || bookNameDraft.trim() === project?.bookName,
5944
- onClick: () => {
5945
- handleRename();
5946
- },
5947
- children: "💾 改书名"
5948
- })]
5949
- }),
5950
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5951
- className: panel_module_css_default.row,
5952
- style: {
5953
- alignItems: "flex-start",
5954
- gap: 14
5955
- },
5956
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5957
- className: panel_module_css_default.coverPreview,
5958
- children: coverDataUrl !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
5959
- src: coverDataUrl,
5960
- alt: "封面"
5961
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5962
- className: panel_module_css_default.coverPlaceholder,
5963
- children: "暂无封面"
5964
- })
5965
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6808
+ children: "↻ 从编年录刷新"
6809
+ })]
6810
+ })]
6811
+ }),
6812
+ charCards === null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6813
+ className: panel_module_css_default.meta,
6814
+ children: (project?.facts ?? []).length === 0 ? "暂无编年录(生成章节后自动积累人物状态/境界/资源/关系等事实),刷新按钮将在有事实后可用。" : "点击「从编年录刷新」聚合各人物当前状态(境界/资源/伤势/心境)。"
6815
+ }) : charCards.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6816
+ className: panel_module_css_default.meta,
6817
+ children: "未识别到人物信息。"
6818
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5966
6819
  style: {
5967
6820
  display: "flex",
5968
6821
  flexDirection: "column",
5969
- gap: 8
5970
- },
5971
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5972
- className: panel_module_css_default.row,
5973
- children: [
5974
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5975
- type: "button",
5976
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
5977
- disabled: busy || project === null,
5978
- onClick: () => {
5979
- coverFileRef.current?.click();
5980
- },
5981
- children: "📤 上传封面"
5982
- }),
5983
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
5984
- ref: coverFileRef,
5985
- type: "file",
5986
- accept: "image/png,image/jpeg,image/webp",
5987
- style: { display: "none" },
5988
- onChange: (e) => {
5989
- handleCoverUpload(e.target.files?.[0]);
5990
- e.target.value = "";
5991
- }
5992
- }),
5993
- coverDataUrl !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5994
- type: "button",
5995
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
5996
- disabled: busy,
5997
- onClick: () => {
5998
- handleCoverRemove();
5999
- },
6000
- children: "🗑️ 移除"
6001
- })
6002
- ]
6003
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6004
- className: panel_module_css_default.meta,
6005
- children: "支持 PNG / JPG / WebP,建议 3:4 竖版;保存于输出目录 cover.*。"
6006
- })]
6007
- })]
6008
- }),
6009
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6010
- className: panel_module_css_default.meta,
6011
- children: "面向读者的作品门面(120-250 字):突出核心卖点与开局钩子,不剧透。点击 ✨AI 生成全量生成;或先写几句再点 ✍️AI 补全续写完整;不满意可 🔄 重新生成。"
6012
- }),
6013
- project === null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6014
- className: panel_module_css_default.meta,
6015
- children: "请先在大纲页导入大纲建立项目。"
6016
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
6017
- className: panel_module_css_default.textarea,
6018
- style: { minHeight: 140 },
6019
- placeholder: "点击 ✨AI 生成,或先写下开头几句,再点 ✍️AI 补全…",
6020
- value: blurbDraft,
6021
- onChange: (e) => {
6022
- setBlurbDraft(e.target.value);
6023
- },
6024
- spellCheck: false
6025
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6026
- className: panel_module_css_default.row,
6027
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6028
- type: "button",
6029
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
6030
- disabled: busy || blurbDraft.trim() === "",
6031
- onClick: () => {
6032
- handleBlurbSave();
6822
+ gap: 6
6033
6823
  },
6034
- children: "💾 保存简介"
6035
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6824
+ children: charCards.map((card) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6825
+ style: {
6826
+ border: "1px solid var(--nf-border)",
6827
+ borderRadius: 8,
6828
+ padding: "6px 10px",
6829
+ fontSize: 12
6830
+ },
6831
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6832
+ className: panel_module_css_default.row,
6833
+ style: { justifyContent: "space-between" },
6834
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: card.name }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6835
+ className: panel_module_css_default.meta,
6836
+ children: [
6837
+ card.role === "protagonist" ? "主角" : card.role === "supporting" ? "配角" : card.role === "antagonist" ? "反派" : "其他",
6838
+ " · 出场 ",
6839
+ card.appearances,
6840
+ " 次 · 最近 第 ",
6841
+ card.lastChapter,
6842
+ " 章"
6843
+ ]
6844
+ })]
6845
+ }), card.status !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6846
+ className: panel_module_css_default.meta,
6847
+ children: ["状态:", card.status]
6848
+ })]
6849
+ }, card.name))
6850
+ }),
6851
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6036
6852
  className: panel_module_css_default.meta,
6037
- children: [
6038
- blurbDraft.length,
6039
- " 字 · 已保存:",
6040
- project.blurb !== void 0 ? `${project.blurb.length} 字` : "无"
6041
- ]
6042
- })]
6043
- })] })
6044
- ]
6045
- }),
6046
- activeTab === "plan" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
6047
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6853
+ children: "人物志由「道藏」人物名单 + 「编年录」聚合而来,随章节生成自动保持最新。"
6854
+ })
6855
+ ]
6856
+ }),
6857
+ activeTab === "assetsGenre" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AssetsTab, {
6858
+ api,
6859
+ initialTab: "genre"
6860
+ }),
6861
+ activeTab === "assetsProgression" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AssetsTab, {
6862
+ api,
6863
+ initialTab: "progression"
6864
+ }),
6865
+ activeTab === "assetsTemplates" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AssetsTab, {
6866
+ api,
6867
+ initialTab: "templates"
6868
+ }),
6869
+ activeTab === "assetsRules" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AssetsTab, {
6870
+ api,
6871
+ initialTab: "rules"
6872
+ }),
6873
+ activeTab === "assetsStyle" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AssetsTab, {
6874
+ api,
6875
+ initialTab: "style"
6876
+ }),
6877
+ activeTab === "foreshadow" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6048
6878
  className: panel_module_css_default.card,
6049
6879
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6050
6880
  className: panel_module_css_default.row,
6051
6881
  style: { justifyContent: "space-between" },
6052
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6882
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6053
6883
  className: panel_module_css_default.cardTitle,
6054
- children: tt("tab.plan")
6055
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6056
- className: panel_module_css_default.row,
6057
6884
  children: [
6058
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6059
- className: panel_module_css_default.meta,
6060
- children: tt("plan.generateHint")
6061
- }),
6062
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
6063
- className: panel_module_css_default.input,
6064
- style: { width: 72 },
6065
- type: "number",
6066
- min: 1,
6067
- max: 200,
6068
- value: planCount,
6069
- onChange: (e) => {
6070
- const v = Number(e.target.value);
6071
- if (Number.isInteger(v)) setPlanCount(v);
6072
- }
6073
- }),
6074
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6075
- className: panel_module_css_default.meta,
6076
- children: tt("plan.count")
6077
- }),
6078
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6079
- type: "button",
6080
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonPrimary}`,
6081
- disabled: busy || outlineText.length < 50,
6082
- onClick: () => {
6083
- handlePlan();
6084
- },
6085
- children: tt("plan.generate")
6086
- })
6087
- ]
6088
- })]
6089
- }), volumes !== void 0 && volumes.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6090
- className: panel_module_css_default.row,
6091
- children: volumes.map((v) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6092
- className: panel_module_css_default.badge,
6093
- style: {
6094
- borderColor: "var(--nf-accent)",
6095
- color: "var(--nf-accent)"
6096
- },
6097
- children: [
6098
- v.no,
6099
- ". ",
6100
- v.title,
6885
+ tt("foreshadow.title"),
6101
6886
  "(",
6102
- v.chapterStart,
6103
- "-",
6104
- v.chapterEnd,
6887
+ foreshadows.length,
6105
6888
  ")"
6106
6889
  ]
6107
- }, v.no))
6108
- })]
6109
- }),
6110
- chapters.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6111
- className: panel_module_css_default.card,
6112
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6113
- className: panel_module_css_default.row,
6114
- style: { justifyContent: "space-between" },
6115
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6116
- className: panel_module_css_default.meta,
6117
- children: [
6118
- "共 ",
6119
- chapters.length,
6120
- " 章 · 已完成 ",
6121
- doneCount,
6122
- " · 待生成 ",
6123
- pendingCount
6124
- ]
6125
- }), pendingCount > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
6890
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6126
6891
  type: "button",
6127
6892
  className: `${panel_module_css_default.button} ${panel_module_css_default.buttonPrimary}`,
6128
6893
  disabled: busy,
6129
6894
  onClick: () => {
6130
- handleWriteAll();
6131
- },
6132
- children: [
6133
- tt("plan.writeAllPending"),
6134
- "(",
6135
- pendingCount,
6136
- ")"
6137
- ]
6138
- })]
6139
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6140
- className: panel_module_css_default.chapterList,
6141
- children: chapterGroups.map((group) => {
6142
- const collapsed = group.no !== 0 && collapsedVolumes.includes(group.no);
6143
- const groupDone = group.chapters.filter((c) => c.status === "approved" || c.status === "written" || c.status === "rejected").length;
6144
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6145
- className: panel_module_css_default.volumeGroup,
6146
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6147
- className: panel_module_css_default.volumeGroupHeader,
6148
- onClick: () => {
6149
- if (group.no !== 0) setCollapsedVolumes((prev) => prev.includes(group.no) ? prev.filter((x) => x !== group.no) : [...prev, group.no]);
6150
- },
6151
- children: [
6152
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6153
- className: panel_module_css_default.volumeGroupToggle,
6154
- children: group.no !== 0 ? collapsed ? "▸" : "▾" : "📖"
6155
- }),
6156
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: group.title }),
6157
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6158
- className: panel_module_css_default.meta,
6159
- children: [
6160
- "(",
6161
- group.chapters.length,
6162
- " 章 · 已完成 ",
6163
- groupDone,
6164
- ")"
6165
- ]
6166
- })
6167
- ]
6168
- }), !collapsed && group.chapters.map((chapter) => {
6169
- const badge = statusBadge(chapter);
6170
- const expanded = expandedChapter === chapter.no;
6171
- const review = chapter.review;
6172
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6173
- className: panel_module_css_default.chapter,
6174
- children: [
6175
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6176
- className: panel_module_css_default.chapterNum,
6177
- children: chapter.no
6178
- }),
6179
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6180
- className: panel_module_css_default.chapterMain,
6181
- children: [
6182
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6183
- className: panel_module_css_default.chapterTitle,
6184
- children: [
6185
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6186
- type: "button",
6187
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
6188
- style: { padding: "1px 6px" },
6189
- onClick: () => {
6190
- handleToggleChapter(chapter.no);
6191
- },
6192
- children: expanded ? "−" : "+"
6193
- }),
6194
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: chapter.title }),
6195
- chapter.status === "approved" && chapter.chars !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6196
- className: panel_module_css_default.meta,
6197
- children: [chapter.chars, tt("common.chars")]
6198
- }),
6199
- chapter.volume > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6200
- className: panel_module_css_default.meta,
6201
- children: [tt("plan.volumes"), chapter.volume]
6202
- })
6203
- ]
6204
- }),
6205
- !expanded && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6206
- className: panel_module_css_default.chapterBeats,
6207
- title: chapter.beats,
6208
- children: chapter.beats
6209
- }),
6210
- expanded && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6211
- style: {
6212
- display: "flex",
6213
- flexDirection: "column",
6214
- gap: 6
6215
- },
6216
- children: [
6217
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6218
- className: panel_module_css_default.meta,
6219
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("b", { children: [tt("plan.beats"), ":"] })
6220
- }),
6221
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6222
- className: panel_module_css_default.meta,
6223
- children: renderBeats(chapter.beats)
6224
- }),
6225
- chapter.summary !== void 0 && chapter.summary !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6226
- className: panel_module_css_default.meta,
6227
- children: [
6228
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("b", { children: [tt("plan.summary"), ":"] }),
6229
- " ",
6230
- chapter.summary
6231
- ]
6232
- }),
6233
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
6234
- className: panel_module_css_default.chapterPreview,
6235
- children: chapterText || `(${tt("common.loading")})`
6236
- }),
6237
- review !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6238
- className: panel_module_css_default.reviewBox,
6239
- children: [
6240
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6241
- className: panel_module_css_default.row,
6242
- style: { justifyContent: "space-between" },
6243
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: tt("plan.reviewReport") }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6244
- style: { color: review.passed ? "var(--nf-success)" : "var(--nf-error)" },
6245
- children: [
6246
- tt("plan.reviewScore"),
6247
- ": ",
6248
- review.score,
6249
- " — ",
6250
- review.passed ? tt("plan.reviewPass") : tt("plan.reviewFail")
6251
- ]
6252
- })]
6253
- }),
6254
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6255
- className: panel_module_css_default.meta,
6256
- children: [
6257
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("b", { children: [tt("plan.reviewVerdict"), ":"] }),
6258
- " ",
6259
- review.verdict
6260
- ]
6261
- }),
6262
- review.issues.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
6263
- style: {
6264
- margin: 0,
6265
- paddingLeft: 18,
6266
- fontSize: 12
6267
- },
6268
- children: review.issues.map((issue, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
6269
- style: { color: severityColor(issue.severity) },
6270
- children: [
6271
- "[",
6272
- issue.severity,
6273
- "] ",
6274
- issue.item,
6275
- " → ",
6276
- issue.suggestion
6277
- ]
6278
- }, i))
6279
- })
6280
- ]
6281
- }),
6282
- (chapter.status === "rejected" || chapter.status === "written" || chapter.status === "approved") && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6283
- style: {
6284
- display: "flex",
6285
- flexDirection: "column",
6286
- gap: 6
6287
- },
6288
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6289
- className: panel_module_css_default.meta,
6290
- style: { fontWeight: 600 },
6291
- children: "润色 / 修订 — 在右上角打开工作区:左栏原文可直接选中文字做局部修订,右栏输入指令后预览,确认后再应用(未应用不改动原稿)"
6292
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6293
- className: panel_module_css_default.row,
6294
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
6295
- type: "button",
6296
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonPrimary}`,
6297
- disabled: busy || busyAny,
6298
- onClick: () => {
6299
- openWorkspace(chapter.no);
6300
- },
6301
- children: [
6302
- tt("plan.rewrite"),
6303
- " / ",
6304
- tt("plan.polish")
6305
- ]
6306
- })
6307
- })]
6308
- })
6309
- ]
6310
- })
6311
- ]
6312
- }),
6313
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6314
- className: `${panel_module_css_default.badge} ${badge.cls}`,
6315
- children: badge.label
6316
- }),
6317
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6318
- className: panel_module_css_default.chapterActions,
6319
- children: [
6320
- (chapter.status === "pending" || chapter.status === "error") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6321
- type: "button",
6322
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall} ${panel_module_css_default.buttonPrimary}`,
6323
- disabled: busy || busyAny,
6324
- onClick: () => {
6325
- handleWriteChapter(chapter.no, true);
6326
- },
6327
- children: tt("plan.write")
6328
- }),
6329
- (chapter.status === "written" || chapter.status === "rejected") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6330
- type: "button",
6331
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
6332
- disabled: busy || busyAny,
6333
- onClick: () => {
6334
- handleReview(chapter.no);
6335
- },
6336
- children: tt("plan.review")
6337
- }),
6338
- chapter.status === "written" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6339
- type: "button",
6340
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
6341
- disabled: busy || busyAny,
6342
- onClick: () => {
6343
- handleApprove(chapter.no);
6344
- },
6345
- children: tt("plan.approve")
6346
- }),
6347
- (chapter.status === "written" || chapter.status === "rejected" || chapter.status === "approved") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6348
- type: "button",
6349
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
6350
- disabled: busy || busyAny,
6351
- onClick: () => {
6352
- openWorkspace(chapter.no);
6353
- },
6354
- title: "手动编辑正文 → AI 审查 → 保存",
6355
- children: "✏️ 编辑"
6356
- }),
6357
- (chapter.status === "written" || chapter.status === "rejected" || chapter.status === "approved") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6358
- type: "button",
6359
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
6360
- disabled: busy || busyAny,
6361
- onClick: () => {
6362
- openWorkspace(chapter.no);
6363
- },
6364
- children: tt("plan.polish")
6365
- }),
6366
- chapter.status === "rejected" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6367
- type: "button",
6368
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
6369
- disabled: busy || busyAny,
6370
- onClick: () => {
6371
- openWorkspace(chapter.no);
6372
- },
6373
- title: "按审稿意见修订(自动带入意见)",
6374
- children: "按意见修订"
6375
- }),
6376
- chapter.status === "rejected" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6377
- type: "button",
6378
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
6379
- disabled: busy || busyAny,
6380
- onClick: () => {
6381
- handleWriteChapter(chapter.no, true);
6382
- },
6383
- title: "整章重新生成",
6384
- children: "重新生成"
6385
- })
6386
- ]
6387
- })
6388
- ]
6389
- }, chapter.no);
6390
- })]
6391
- }, group.no);
6392
- })
6393
- })]
6394
- }),
6395
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6396
- className: panel_module_css_default.card,
6397
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6398
- className: panel_module_css_default.cardTitle,
6399
- children: tt("plan.progress")
6400
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6401
- className: panel_module_css_default.progress,
6402
- children: [progress.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6403
- className: panel_module_css_default.meta,
6404
- children: tt("progress.empty")
6405
- }), progress.map((line) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6406
- className: line.kind === "done" ? panel_module_css_default.progressLineDone : line.kind === "error" ? panel_module_css_default.progressLineError : line.live === true ? panel_module_css_default.progressLineLive : panel_module_css_default.progressLine,
6407
- children: [line.live === true && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6408
- className: panel_module_css_default.progressBar,
6409
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6410
- className: panel_module_css_default.progressBarFill,
6411
- style: { width: `${Math.round((line.ratio ?? 0) * 100)}%` }
6412
- })
6413
- }), line.text]
6414
- }, line.id))]
6415
- })]
6416
- })
6417
- ] }),
6418
- activeTab === "bible" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6419
- className: panel_module_css_default.card,
6420
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6421
- className: panel_module_css_default.row,
6422
- style: { justifyContent: "space-between" },
6423
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6424
- className: panel_module_css_default.cardTitle,
6425
- children: tt("bible.title")
6426
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6427
- type: "button",
6428
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonPrimary}`,
6429
- disabled: busy,
6430
- onClick: () => {
6431
- handleBible();
6432
- },
6433
- children: tt("bible.gen")
6434
- })]
6435
- }), bible === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6436
- className: panel_module_css_default.meta,
6437
- children: tt("bible.none")
6438
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6439
- style: {
6440
- display: "flex",
6441
- flexDirection: "column",
6442
- gap: 10
6443
- },
6444
- children: [
6445
- bible.genre !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [
6446
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("b", { children: [tt("bible.genre"), ":"] }),
6447
- " ",
6448
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6449
- className: panel_module_css_default.meta,
6450
- children: bible.genre
6451
- })
6452
- ] }),
6453
- bible.worldRules.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6454
- style: {
6455
- border: "1px solid var(--nf-border)",
6456
- borderRadius: 10,
6457
- padding: "8px 10px"
6458
- },
6459
- children: [
6460
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6461
- className: panel_module_css_default.row,
6462
- style: { justifyContent: "space-between" },
6463
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("b", { children: [
6464
- tt("bible.worldRules"),
6465
- "(",
6466
- bible.worldRules.length,
6467
- ")"
6468
- ] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6469
- type: "button",
6470
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
6471
- onClick: () => {
6472
- setWorldRulesDraft(bible.worldRules.join("\n"));
6473
- },
6474
- children: "编辑"
6475
- })]
6476
- }),
6477
- worldRulesDraft !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6478
- style: {
6479
- display: "flex",
6480
- flexDirection: "column",
6481
- gap: 6,
6482
- marginTop: 6
6483
- },
6484
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
6485
- className: panel_module_css_default.textarea,
6486
- style: { minHeight: 120 },
6487
- value: worldRulesDraft,
6488
- onChange: (e) => {
6489
- setWorldRulesDraft(e.target.value);
6490
- },
6491
- placeholder: "每条规则一行…"
6492
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6493
- className: panel_module_css_default.row,
6494
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6495
- type: "button",
6496
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall} ${panel_module_css_default.buttonPrimary}`,
6497
- disabled: busy,
6498
- onClick: () => {
6499
- handleSaveWorldRules();
6500
- },
6501
- children: "保存规则"
6502
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6503
- type: "button",
6504
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
6505
- onClick: () => {
6506
- setWorldRulesDraft("");
6507
- },
6508
- children: "取消"
6509
- })]
6510
- })]
6511
- }),
6512
- worldRulesDraft === "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
6513
- style: {
6514
- margin: "4px 0 0",
6515
- paddingLeft: 18,
6516
- fontSize: 12
6517
- },
6518
- children: bible.worldRules.map((r, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: r }, i))
6519
- })
6520
- ]
6521
- }),
6522
- bible.characters.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("b", { children: [
6523
- tt("bible.characters"),
6524
- "(",
6525
- bible.characters.length,
6526
- ")"
6527
- ] }), bible.characters.map((card) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6528
- style: {
6529
- marginTop: 4,
6530
- fontSize: 12
6531
- },
6532
- children: [
6533
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: card.name }),
6534
- " ",
6535
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6536
- className: panel_module_css_default.meta,
6537
- children: [
6538
- "[",
6539
- card.role,
6540
- "] ",
6541
- card.traits.join("、")
6542
- ]
6543
- }),
6544
- card.goals !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6545
- className: panel_module_css_default.meta,
6546
- children: ["目标:", card.goals]
6547
- }),
6548
- card.relations !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6549
- className: panel_module_css_default.meta,
6550
- children: ["关系:", card.relations]
6551
- })
6552
- ]
6553
- }, card.name))] }),
6554
- bible.redLines.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("b", { children: [
6555
- tt("bible.redLines"),
6556
- "(",
6557
- bible.redLines.length,
6558
- ")"
6559
- ] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
6560
- style: {
6561
- margin: 0,
6562
- paddingLeft: 18,
6563
- fontSize: 12,
6564
- color: "var(--nf-error)"
6565
- },
6566
- children: bible.redLines.map((r, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: r }, i))
6567
- })] }),
6568
- bible.style.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("b", { children: [
6569
- tt("bible.style"),
6570
- "(",
6571
- bible.style.length,
6572
- ")"
6573
- ] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
6574
- style: {
6575
- margin: 0,
6576
- paddingLeft: 18,
6577
- fontSize: 12
6578
- },
6579
- children: bible.style.map((r, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: r }, i))
6580
- })] })
6581
- ]
6582
- })]
6583
- }) }),
6584
- activeTab === "world" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(WorldTab, {
6585
- api,
6586
- world: project?.world,
6587
- onChanged: (w) => {
6588
- setProject((prev) => prev === null ? prev : {
6589
- ...prev,
6590
- world: w,
6591
- updatedAt: (/* @__PURE__ */ new Date()).toISOString()
6592
- });
6593
- pushProgress(`大世界已保存:${w.realms.length} 境界 · ${w.regions.length} 区域 · ${w.factions.length} 势力`, "done");
6594
- }
6595
- }),
6596
- activeTab === "characters" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6597
- className: panel_module_css_default.card,
6598
- children: [
6599
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6600
- className: panel_module_css_default.row,
6601
- style: { justifyContent: "space-between" },
6602
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6603
- className: panel_module_css_default.cardTitle,
6604
- children: "人物志(当前状态)"
6605
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6606
- className: panel_module_css_default.row,
6607
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6608
- type: "button",
6609
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
6610
- disabled: busy || doneCount === 0,
6611
- onClick: () => {
6612
- handleFactsBackfill();
6613
- },
6614
- title: "历史章节(编年录功能上线前生成的)批量抽取事实",
6615
- children: "📥 回填编年录"
6616
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6617
- type: "button",
6618
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall} ${panel_module_css_default.buttonPrimary}`,
6619
- disabled: busy || (project?.facts ?? []).length === 0,
6620
- onClick: () => {
6621
- handleCharactersRefresh();
6622
- },
6623
- children: "↻ 从编年录刷新"
6624
- })]
6625
- })]
6626
- }),
6627
- charCards === null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6628
- className: panel_module_css_default.meta,
6629
- children: (project?.facts ?? []).length === 0 ? "暂无编年录(生成章节后自动积累人物状态/境界/资源/关系等事实),刷新按钮将在有事实后可用。" : "点击「从编年录刷新」聚合各人物当前状态(境界/资源/伤势/心境)。"
6630
- }) : charCards.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6631
- className: panel_module_css_default.meta,
6632
- children: "未识别到人物信息。"
6633
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6634
- style: {
6635
- display: "flex",
6636
- flexDirection: "column",
6637
- gap: 6
6638
- },
6639
- children: charCards.map((card) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6640
- style: {
6641
- border: "1px solid var(--nf-border)",
6642
- borderRadius: 8,
6643
- padding: "6px 10px",
6644
- fontSize: 12
6645
- },
6646
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6647
- className: panel_module_css_default.row,
6648
- style: { justifyContent: "space-between" },
6649
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: card.name }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6650
- className: panel_module_css_default.meta,
6651
- children: [
6652
- card.role === "protagonist" ? "主角" : card.role === "supporting" ? "配角" : card.role === "antagonist" ? "反派" : "其他",
6653
- " · 出场 ",
6654
- card.appearances,
6655
- " 次 · 最近 第 ",
6656
- card.lastChapter,
6657
- " 章"
6658
- ]
6659
- })]
6660
- }), card.status !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6661
- className: panel_module_css_default.meta,
6662
- children: ["状态:", card.status]
6663
- })]
6664
- }, card.name))
6665
- }),
6666
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6667
- className: panel_module_css_default.meta,
6668
- children: "人物志由「道藏」人物名单 + 「编年录」聚合而来,随章节生成自动保持最新。"
6669
- })
6670
- ]
6671
- }),
6672
- activeTab === "assetsGenre" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AssetsTab, {
6673
- api,
6674
- initialTab: "genre"
6675
- }),
6676
- activeTab === "assetsProgression" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AssetsTab, {
6677
- api,
6678
- initialTab: "progression"
6679
- }),
6680
- activeTab === "assetsTemplates" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AssetsTab, {
6681
- api,
6682
- initialTab: "templates"
6683
- }),
6684
- activeTab === "assetsRules" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AssetsTab, {
6685
- api,
6686
- initialTab: "rules"
6687
- }),
6688
- activeTab === "assetsStyle" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AssetsTab, {
6689
- api,
6690
- initialTab: "style"
6691
- }),
6692
- activeTab === "foreshadow" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6693
- className: panel_module_css_default.card,
6694
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6695
- className: panel_module_css_default.row,
6696
- style: { justifyContent: "space-between" },
6697
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6698
- className: panel_module_css_default.cardTitle,
6699
- children: [
6700
- tt("foreshadow.title"),
6701
- "(",
6702
- foreshadows.length,
6703
- ")"
6704
- ]
6705
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6706
- type: "button",
6707
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonPrimary}`,
6708
- disabled: busy,
6709
- onClick: () => {
6710
- handleSuggestForeshadows();
6711
- },
6712
- children: tt("foreshadow.suggest")
6713
- })]
6714
- }), foreshadows.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6715
- className: panel_module_css_default.meta,
6716
- children: tt("foreshadow.none")
6717
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6718
- className: panel_module_css_default.chapterList,
6719
- children: foreshadows.map((f) => {
6720
- const statusLabel = {
6721
- planned: tt("foreshadow.planned"),
6722
- planted: tt("foreshadow.planted"),
6723
- progressing: tt("foreshadow.progressing"),
6724
- resolved: tt("foreshadow.resolved"),
6725
- abandoned: tt("foreshadow.abandoned")
6726
- }[f.status];
6727
- const statusColor = f.status === "resolved" ? "var(--nf-success)" : f.status === "planted" || f.status === "progressing" ? "var(--nf-accent)" : f.status === "abandoned" ? "var(--nf-text-3)" : "var(--nf-info)";
6728
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6729
- className: panel_module_css_default.chapter,
6730
- children: [
6731
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6732
- className: panel_module_css_default.chapterMain,
6733
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6734
- className: panel_module_css_default.chapterTitle,
6735
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: f.description })
6736
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6737
- className: panel_module_css_default.meta,
6738
- children: [
6739
- f.plantedChapter !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
6740
- tt("foreshadow.plantedAt"),
6741
- " 第",
6742
- f.plantedChapter,
6743
- "章 · "
6744
- ] }),
6745
- f.targetChapter !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
6746
- tt("foreshadow.target"),
6747
- " 第",
6748
- f.targetChapter,
6749
- "章 · "
6750
- ] }),
6751
- f.resolvedNote !== void 0 && f.resolvedNote !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
6752
- "回收:",
6753
- f.resolvedNote,
6754
- " · "
6755
- ] })
6756
- ]
6757
- })]
6758
- }),
6759
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6760
- className: panel_module_css_default.badge,
6761
- style: {
6762
- borderColor: statusColor,
6763
- color: statusColor
6764
- },
6765
- children: statusLabel
6766
- }),
6767
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6768
- className: panel_module_css_default.row,
6769
- style: { gap: 4 },
6770
- children: [f.status === "planned" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6771
- type: "button",
6772
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
6773
- disabled: busy,
6774
- onClick: () => {
6775
- api.foreshadow({
6776
- id: f.id,
6777
- status: "planted",
6778
- plantedChapter: doneCount + 1
6779
- }).then((r) => setProject((prev) => prev === null ? prev : {
6780
- ...prev,
6781
- foreshadows: r.foreshadows
6782
- }));
6783
- },
6784
- children: tt("foreshadow.setPlanted")
6785
- }), (f.status === "planted" || f.status === "progressing") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6786
- type: "button",
6787
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
6788
- disabled: busy,
6789
- onClick: () => {
6790
- api.foreshadow({
6791
- id: f.id,
6792
- status: "resolved",
6793
- resolvedNote: `第${doneCount}章回收`
6794
- }).then((r) => setProject((prev) => prev === null ? prev : {
6795
- ...prev,
6796
- foreshadows: r.foreshadows
6797
- }));
6798
- },
6799
- children: tt("foreshadow.setResolved")
6800
- })]
6801
- })
6802
- ]
6803
- }, f.id);
6804
- })
6805
- })]
6806
- }),
6807
- activeTab === "settings" && configDraft !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6808
- className: panel_module_css_default.card,
6809
- children: [
6810
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6811
- className: panel_module_css_default.cardTitle,
6812
- children: tt("settings.title")
6813
- }),
6814
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6815
- className: panel_module_css_default.field,
6816
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
6817
- className: panel_module_css_default.fieldLabel,
6818
- children: tt("settings.outlinePath")
6819
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
6820
- className: panel_module_css_default.input,
6821
- value: configDraft.outlinePath,
6822
- onChange: (e) => {
6823
- setConfigDraft({
6824
- ...configDraft,
6825
- outlinePath: e.target.value
6826
- });
6827
- }
6828
- })]
6829
- }),
6830
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6831
- className: panel_module_css_default.field,
6832
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
6833
- className: panel_module_css_default.fieldLabel,
6834
- children: tt("settings.outputDir")
6835
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
6836
- className: panel_module_css_default.input,
6837
- value: configDraft.outputDir,
6838
- onChange: (e) => {
6839
- setConfigDraft({
6840
- ...configDraft,
6841
- outputDir: e.target.value
6842
- });
6843
- }
6844
- })]
6845
- }),
6846
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6847
- className: panel_module_css_default.row,
6848
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6849
- className: panel_module_css_default.field,
6850
- style: { flex: 1 },
6851
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
6852
- className: panel_module_css_default.fieldLabel,
6853
- children: tt("settings.provider")
6854
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
6855
- className: panel_module_css_default.input,
6856
- value: configDraft.provider,
6857
- onChange: (e) => {
6858
- setConfigDraft({
6859
- ...configDraft,
6860
- provider: e.target.value
6861
- });
6862
- }
6863
- })]
6864
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6865
- className: panel_module_css_default.field,
6866
- style: { flex: 1 },
6867
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
6868
- className: panel_module_css_default.fieldLabel,
6869
- children: tt("settings.model")
6870
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
6871
- className: panel_module_css_default.input,
6872
- value: configDraft.model,
6873
- onChange: (e) => {
6874
- setConfigDraft({
6875
- ...configDraft,
6876
- model: e.target.value
6877
- });
6878
- }
6879
- })]
6895
+ handleSuggestForeshadows();
6896
+ },
6897
+ children: tt("foreshadow.suggest")
6880
6898
  })]
6881
- }),
6882
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6883
- className: panel_module_css_default.row,
6884
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6899
+ }), foreshadows.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6900
+ className: panel_module_css_default.meta,
6901
+ children: tt("foreshadow.none")
6902
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6903
+ className: panel_module_css_default.chapterList,
6904
+ children: foreshadows.map((f) => {
6905
+ const statusLabel = {
6906
+ planned: tt("foreshadow.planned"),
6907
+ planted: tt("foreshadow.planted"),
6908
+ progressing: tt("foreshadow.progressing"),
6909
+ resolved: tt("foreshadow.resolved"),
6910
+ abandoned: tt("foreshadow.abandoned")
6911
+ }[f.status];
6912
+ const statusColor = f.status === "resolved" ? "var(--nf-success)" : f.status === "planted" || f.status === "progressing" ? "var(--nf-accent)" : f.status === "abandoned" ? "var(--nf-text-3)" : "var(--nf-info)";
6913
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6914
+ className: panel_module_css_default.chapter,
6915
+ children: [
6916
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6917
+ className: panel_module_css_default.chapterMain,
6918
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6919
+ className: panel_module_css_default.chapterTitle,
6920
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: f.description })
6921
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6922
+ className: panel_module_css_default.meta,
6923
+ children: [
6924
+ f.plantedChapter !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
6925
+ tt("foreshadow.plantedAt"),
6926
+ " 第",
6927
+ f.plantedChapter,
6928
+ "章 · "
6929
+ ] }),
6930
+ f.targetChapter !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
6931
+ tt("foreshadow.target"),
6932
+ " 第",
6933
+ f.targetChapter,
6934
+ "章 · "
6935
+ ] }),
6936
+ f.resolvedNote !== void 0 && f.resolvedNote !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
6937
+ "回收:",
6938
+ f.resolvedNote,
6939
+ " · "
6940
+ ] })
6941
+ ]
6942
+ })]
6943
+ }),
6944
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6945
+ className: panel_module_css_default.badge,
6946
+ style: {
6947
+ borderColor: statusColor,
6948
+ color: statusColor
6949
+ },
6950
+ children: statusLabel
6951
+ }),
6952
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6953
+ className: panel_module_css_default.row,
6954
+ style: { gap: 4 },
6955
+ children: [f.status === "planned" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6956
+ type: "button",
6957
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
6958
+ disabled: busy,
6959
+ onClick: () => {
6960
+ api.foreshadow({
6961
+ id: f.id,
6962
+ status: "planted",
6963
+ plantedChapter: doneCount + 1
6964
+ }).then((r) => setProject((prev) => prev === null ? prev : {
6965
+ ...prev,
6966
+ foreshadows: r.foreshadows
6967
+ }));
6968
+ },
6969
+ children: tt("foreshadow.setPlanted")
6970
+ }), (f.status === "planted" || f.status === "progressing") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6971
+ type: "button",
6972
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
6973
+ disabled: busy,
6974
+ onClick: () => {
6975
+ api.foreshadow({
6976
+ id: f.id,
6977
+ status: "resolved",
6978
+ resolvedNote: `第${doneCount}章回收`
6979
+ }).then((r) => setProject((prev) => prev === null ? prev : {
6980
+ ...prev,
6981
+ foreshadows: r.foreshadows
6982
+ }));
6983
+ },
6984
+ children: tt("foreshadow.setResolved")
6985
+ })]
6986
+ })
6987
+ ]
6988
+ }, f.id);
6989
+ })
6990
+ })]
6991
+ }),
6992
+ activeTab === "settings" && configDraft !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6993
+ className: panel_module_css_default.card,
6994
+ children: [
6995
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6996
+ className: panel_module_css_default.cardTitle,
6997
+ children: tt("settings.title")
6998
+ }),
6999
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6885
7000
  className: panel_module_css_default.field,
6886
- style: { flex: 1 },
6887
7001
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
6888
7002
  className: panel_module_css_default.fieldLabel,
6889
- children: tt("settings.chapterChars")
7003
+ children: tt("settings.outlinePath")
6890
7004
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
6891
7005
  className: panel_module_css_default.input,
6892
- type: "number",
6893
- min: 1e3,
6894
- max: 2e4,
6895
- value: configDraft.chapterChars,
7006
+ value: configDraft.outlinePath,
6896
7007
  onChange: (e) => {
6897
7008
  setConfigDraft({
6898
7009
  ...configDraft,
6899
- chapterChars: Number(e.target.value)
7010
+ outlinePath: e.target.value
6900
7011
  });
6901
7012
  }
6902
7013
  })]
6903
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7014
+ }),
7015
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6904
7016
  className: panel_module_css_default.field,
6905
- style: { flex: 1 },
6906
7017
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
6907
7018
  className: panel_module_css_default.fieldLabel,
6908
- children: tt("settings.maxTokens")
7019
+ children: tt("settings.outputDir")
6909
7020
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
6910
7021
  className: panel_module_css_default.input,
6911
- type: "number",
6912
- min: 2e3,
6913
- max: 64e3,
6914
- value: configDraft.maxTokens,
7022
+ value: configDraft.outputDir,
6915
7023
  onChange: (e) => {
6916
7024
  setConfigDraft({
6917
7025
  ...configDraft,
6918
- maxTokens: Number(e.target.value)
7026
+ outputDir: e.target.value
6919
7027
  });
6920
7028
  }
6921
7029
  })]
6922
- })]
6923
- }),
6924
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6925
- className: panel_module_css_default.row,
6926
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6927
- className: panel_module_css_default.field,
6928
- style: { flex: 1 },
6929
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
6930
- className: panel_module_css_default.fieldLabel,
6931
- children: tt("settings.reviewPassScore")
6932
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
6933
- className: panel_module_css_default.input,
6934
- type: "number",
6935
- min: 0,
6936
- max: 100,
6937
- value: configDraft.reviewPassScore,
6938
- onChange: (e) => {
6939
- setConfigDraft({
6940
- ...configDraft,
6941
- reviewPassScore: Number(e.target.value)
6942
- });
6943
- }
7030
+ }),
7031
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7032
+ className: panel_module_css_default.row,
7033
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7034
+ className: panel_module_css_default.field,
7035
+ style: { flex: 1 },
7036
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
7037
+ className: panel_module_css_default.fieldLabel,
7038
+ children: tt("settings.provider")
7039
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
7040
+ className: panel_module_css_default.input,
7041
+ value: configDraft.provider,
7042
+ onChange: (e) => {
7043
+ setConfigDraft({
7044
+ ...configDraft,
7045
+ provider: e.target.value
7046
+ });
7047
+ }
7048
+ })]
7049
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7050
+ className: panel_module_css_default.field,
7051
+ style: { flex: 1 },
7052
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
7053
+ className: panel_module_css_default.fieldLabel,
7054
+ children: tt("settings.model")
7055
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
7056
+ className: panel_module_css_default.input,
7057
+ value: configDraft.model,
7058
+ onChange: (e) => {
7059
+ setConfigDraft({
7060
+ ...configDraft,
7061
+ model: e.target.value
7062
+ });
7063
+ }
7064
+ })]
6944
7065
  })]
6945
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6946
- className: panel_module_css_default.field,
6947
- style: { flex: 1 },
6948
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
6949
- className: panel_module_css_default.fieldLabel,
6950
- children: tt("settings.autoReview")
6951
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
6952
- className: panel_module_css_default.input,
6953
- value: configDraft.autoReview ? "1" : "0",
6954
- onChange: (e) => {
6955
- setConfigDraft({
6956
- ...configDraft,
6957
- autoReview: e.target.value === "1"
6958
- });
6959
- },
6960
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
6961
- value: "1",
6962
- children: "✓ 是"
6963
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
6964
- value: "0",
6965
- children: "✗ 否"
7066
+ }),
7067
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7068
+ className: panel_module_css_default.row,
7069
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7070
+ className: panel_module_css_default.field,
7071
+ style: { flex: 1 },
7072
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
7073
+ className: panel_module_css_default.fieldLabel,
7074
+ children: tt("settings.chapterChars")
7075
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
7076
+ className: panel_module_css_default.input,
7077
+ type: "number",
7078
+ min: 1e3,
7079
+ max: 2e4,
7080
+ value: configDraft.chapterChars,
7081
+ onChange: (e) => {
7082
+ setConfigDraft({
7083
+ ...configDraft,
7084
+ chapterChars: Number(e.target.value)
7085
+ });
7086
+ }
7087
+ })]
7088
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7089
+ className: panel_module_css_default.field,
7090
+ style: { flex: 1 },
7091
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
7092
+ className: panel_module_css_default.fieldLabel,
7093
+ children: tt("settings.maxTokens")
7094
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
7095
+ className: panel_module_css_default.input,
7096
+ type: "number",
7097
+ min: 2e3,
7098
+ max: 64e3,
7099
+ value: configDraft.maxTokens,
7100
+ onChange: (e) => {
7101
+ setConfigDraft({
7102
+ ...configDraft,
7103
+ maxTokens: Number(e.target.value)
7104
+ });
7105
+ }
6966
7106
  })]
6967
7107
  })]
6968
- })]
6969
- }),
6970
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6971
- className: panel_module_css_default.row,
6972
- children: [
6973
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6974
- type: "button",
6975
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonPrimary}`,
6976
- disabled: busy,
6977
- onClick: () => {
6978
- handleSaveConfig();
6979
- },
6980
- children: tt("settings.save")
6981
- }),
6982
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6983
- type: "button",
6984
- className: panel_module_css_default.button,
6985
- onClick: () => {
6986
- api.openFolder();
6987
- },
6988
- children: tt("settings.openFolder")
6989
- }),
6990
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6991
- className: panel_module_css_default.meta,
6992
- children: [
6993
- "当前:",
6994
- config?.provider,
6995
- " / ",
6996
- config?.model,
6997
- " · ",
6998
- config?.outputDir
6999
- ]
7000
- })
7001
- ]
7002
- }),
7003
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7004
- className: panel_module_css_default.row,
7005
- children: [
7006
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7007
- className: panel_module_css_default.cardTitle,
7008
- children: tt("settings.export")
7009
- }),
7010
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7011
- type: "button",
7012
- className: panel_module_css_default.button,
7013
- disabled: busy || chapters.length === 0,
7014
- onClick: () => {
7015
- handleExport("txt");
7016
- },
7017
- children: tt("settings.exportTxt")
7018
- }),
7019
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7020
- type: "button",
7021
- className: panel_module_css_default.button,
7022
- disabled: busy || chapters.length === 0,
7023
- onClick: () => {
7024
- handleExport("md");
7025
- },
7026
- children: tt("settings.exportMd")
7027
- })
7028
- ]
7029
- }),
7030
- (project?.facts ?? []).length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7031
- className: panel_module_css_default.card,
7032
- children: [
7033
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
7034
- className: panel_module_css_default.cardTitle,
7035
- children: [
7036
- "编年录 / 时间线(",
7037
- (project?.facts ?? []).length,
7038
- " 条)"
7039
- ]
7040
- }),
7041
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7042
- className: panel_module_css_default.meta,
7043
- children: "每章生成后自动抽取「已确立事实」(人物状态/境界资源/关系变化/伏笔落地),最近 20 条注入后续章节生成,保证长期一致。"
7044
- }),
7045
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7046
- style: {
7047
- display: "flex",
7048
- flexDirection: "column",
7049
- gap: 4,
7050
- maxHeight: 300,
7051
- overflowY: "auto",
7052
- fontSize: 12
7053
- },
7054
- children: [...project?.facts ?? []].reverse().slice(0, 60).map((fact, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7108
+ }),
7109
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7110
+ className: panel_module_css_default.row,
7111
+ children: [
7112
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7113
+ className: panel_module_css_default.field,
7114
+ style: { flex: 1 },
7115
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
7116
+ className: panel_module_css_default.fieldLabel,
7117
+ children: tt("settings.reviewPassScore")
7118
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
7119
+ className: panel_module_css_default.input,
7120
+ type: "number",
7121
+ min: 0,
7122
+ max: 100,
7123
+ value: configDraft.reviewPassScore,
7124
+ onChange: (e) => {
7125
+ setConfigDraft({
7126
+ ...configDraft,
7127
+ reviewPassScore: Number(e.target.value)
7128
+ });
7129
+ }
7130
+ })]
7131
+ }),
7132
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7133
+ className: panel_module_css_default.field,
7134
+ style: { flex: 1 },
7135
+ children: [
7136
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
7137
+ className: panel_module_css_default.fieldLabel,
7138
+ children: tt("settings.editorFontSize")
7139
+ }),
7140
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("select", {
7141
+ className: panel_module_css_default.input,
7142
+ value: editorFontSize,
7143
+ onChange: (e) => {
7144
+ changeEditorFontSize(Number(e.target.value));
7145
+ },
7146
+ children: [
7147
+ 12,
7148
+ 13,
7149
+ 14,
7150
+ 15,
7151
+ 16,
7152
+ 18,
7153
+ 20,
7154
+ 22,
7155
+ 24
7156
+ ].map((v) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("option", {
7157
+ value: v,
7158
+ children: [v, "px"]
7159
+ }, v))
7160
+ }),
7161
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7162
+ className: panel_module_css_default.meta,
7163
+ children: tt("settings.editorFontSizeHint")
7164
+ })
7165
+ ]
7166
+ }),
7167
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7168
+ className: panel_module_css_default.field,
7169
+ style: { flex: 1 },
7170
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
7171
+ className: panel_module_css_default.fieldLabel,
7172
+ children: tt("settings.autoReview")
7173
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
7174
+ className: panel_module_css_default.input,
7175
+ value: configDraft.autoReview ? "1" : "0",
7176
+ onChange: (e) => {
7177
+ setConfigDraft({
7178
+ ...configDraft,
7179
+ autoReview: e.target.value === "1"
7180
+ });
7181
+ },
7182
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
7183
+ value: "1",
7184
+ children: "✓ 是"
7185
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
7186
+ value: "0",
7187
+ children: "✗ 否"
7188
+ })]
7189
+ })]
7190
+ })
7191
+ ]
7192
+ }),
7193
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7194
+ className: panel_module_css_default.row,
7195
+ children: [
7196
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7197
+ type: "button",
7198
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonPrimary}`,
7199
+ disabled: busy,
7200
+ onClick: () => {
7201
+ handleSaveConfig();
7202
+ },
7203
+ children: tt("settings.save")
7204
+ }),
7205
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7206
+ type: "button",
7207
+ className: panel_module_css_default.button,
7208
+ onClick: () => {
7209
+ api.openFolder();
7210
+ },
7211
+ children: tt("settings.openFolder")
7212
+ }),
7213
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
7214
+ className: panel_module_css_default.meta,
7215
+ children: [
7216
+ "当前:",
7217
+ config?.provider,
7218
+ " / ",
7219
+ config?.model,
7220
+ " · ",
7221
+ config?.outputDir
7222
+ ]
7223
+ })
7224
+ ]
7225
+ }),
7226
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7227
+ className: panel_module_css_default.row,
7228
+ children: [
7229
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7230
+ className: panel_module_css_default.cardTitle,
7231
+ children: tt("settings.export")
7232
+ }),
7233
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7234
+ type: "button",
7235
+ className: panel_module_css_default.button,
7236
+ disabled: busy || chapters.length === 0,
7237
+ onClick: () => {
7238
+ handleExport("txt");
7239
+ },
7240
+ children: tt("settings.exportTxt")
7241
+ }),
7242
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7243
+ type: "button",
7244
+ className: panel_module_css_default.button,
7245
+ disabled: busy || chapters.length === 0,
7246
+ onClick: () => {
7247
+ handleExport("md");
7248
+ },
7249
+ children: tt("settings.exportMd")
7250
+ })
7251
+ ]
7252
+ }),
7253
+ (project?.facts ?? []).length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7254
+ className: panel_module_css_default.card,
7255
+ children: [
7256
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
7257
+ className: panel_module_css_default.cardTitle,
7258
+ children: [
7259
+ "编年录 / 时间线(",
7260
+ (project?.facts ?? []).length,
7261
+ " 条)"
7262
+ ]
7263
+ }),
7264
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7265
+ className: panel_module_css_default.meta,
7266
+ children: "每章生成后自动抽取「已确立事实」(人物状态/境界资源/关系变化/伏笔落地),最近 20 条注入后续章节生成,保证长期一致。"
7267
+ }),
7268
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7055
7269
  style: {
7056
7270
  display: "flex",
7057
- gap: 8,
7058
- alignItems: "flex-start"
7271
+ flexDirection: "column",
7272
+ gap: 4,
7273
+ maxHeight: 300,
7274
+ overflowY: "auto",
7275
+ fontSize: 12
7059
7276
  },
7060
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
7061
- className: panel_module_css_default.badge,
7277
+ children: [...project?.facts ?? []].reverse().slice(0, 60).map((fact, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7062
7278
  style: {
7063
- borderColor: "var(--nf-text-3)",
7064
- color: "var(--nf-text-3)",
7065
- flex: "none",
7066
- marginTop: 1
7279
+ display: "flex",
7280
+ gap: 8,
7281
+ alignItems: "flex-start"
7067
7282
  },
7068
- children: [
7069
- "第 ",
7070
- fact.chapterNo,
7071
- " 章"
7072
- ]
7073
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7074
- className: panel_module_css_default.meta,
7075
- children: fact.text
7076
- })]
7077
- }, i))
7078
- })
7079
- ]
7080
- })
7081
- ]
7082
- })
7283
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
7284
+ className: panel_module_css_default.badge,
7285
+ style: {
7286
+ borderColor: "var(--nf-text-3)",
7287
+ color: "var(--nf-text-3)",
7288
+ flex: "none",
7289
+ marginTop: 1
7290
+ },
7291
+ children: [
7292
+ "第 ",
7293
+ fact.chapterNo,
7294
+ " 章"
7295
+ ]
7296
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7297
+ className: panel_module_css_default.meta,
7298
+ children: fact.text
7299
+ })]
7300
+ }, i))
7301
+ })
7302
+ ]
7303
+ })
7304
+ ]
7305
+ })
7306
+ ] })
7083
7307
  ]
7084
7308
  })]
7085
7309
  })] }), assistantOpen && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {