@waterwx/dsh-novel-forge 1.6.0 → 1.7.0
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 +35487 -745
- package/lib/client.js.map +1 -1
- package/lib/index.js +111 -12
- package/lib/index.js.map +1 -1
- package/lib/types/client/api.d.ts +1 -0
- package/lib/types/client/panel/MangaWorkspace.d.ts +6 -4
- package/lib/types/client/panel/RoleVisualPanel.d.ts +5 -3
- package/lib/types/client/panel/SceneLibrary.d.ts +1 -1
- package/lib/types/client/panel/StoryboardTab.d.ts +1 -1
- package/lib/types/engine.d.ts +8 -1
- package/lib/types/index.d.ts +6 -4
- package/lib/types/protocol.d.ts +47 -3
- package/package.json +99 -98
- package/src/client/api.ts +4 -0
- package/src/client/panel/MangaWorkspace.tsx +7 -3
- package/src/client/panel/NovelPanel.tsx +389 -231
- package/src/client/panel/RoleVisualPanel.tsx +23 -6
- package/src/client/panel/RunPanel.tsx +1 -1
- package/src/client/panel/SceneLibrary.tsx +1 -1
- package/src/client/panel/ShelfView.tsx +28 -35
- package/src/client/panel/StoryboardTab.tsx +1 -1
- package/src/client/panel/panel.module.css +407 -23
- package/src/engine.ts +48 -8
- package/src/index.ts +37 -6
- package/src/protocol.ts +50 -3
- package/src/routes.ts +26 -1
|
@@ -359,13 +359,14 @@ body[data-ds-dark-theme] .panel[data-nf-theme='neumorph'] .buttonPrimary {
|
|
|
359
359
|
font-size: 16px;
|
|
360
360
|
color: var(--nf-text-2);
|
|
361
361
|
padding: 4px 9px;
|
|
362
|
-
border-radius:
|
|
363
|
-
transition: background 0.15s ease, color 0.15s ease;
|
|
362
|
+
border-radius: 9px;
|
|
363
|
+
transition: background 0.15s ease, color 0.15s ease, transform 0.1s ease;
|
|
364
364
|
}
|
|
365
365
|
|
|
366
366
|
.iconButton:hover {
|
|
367
367
|
background: var(--nf-hover);
|
|
368
368
|
color: var(--nf-text);
|
|
369
|
+
transform: translateY(-1px);
|
|
369
370
|
}
|
|
370
371
|
|
|
371
372
|
/* ------------------------------------------------------------ tab bar */
|
|
@@ -419,10 +420,10 @@ body[data-ds-dark-theme] .panel[data-nf-theme='neumorph'] .buttonPrimary {
|
|
|
419
420
|
.panelContent {
|
|
420
421
|
flex: 1;
|
|
421
422
|
overflow: auto;
|
|
422
|
-
padding: 16px 18px 20px;
|
|
423
|
+
padding: var(--nf-density-pad, 16px 18px 20px);
|
|
423
424
|
display: flex;
|
|
424
425
|
flex-direction: column;
|
|
425
|
-
gap: 14px;
|
|
426
|
+
gap: var(--nf-density-gap, 14px);
|
|
426
427
|
position: relative;
|
|
427
428
|
z-index: 1;
|
|
428
429
|
}
|
|
@@ -445,7 +446,7 @@ body[data-ds-dark-theme] .panel[data-nf-theme='neumorph'] .buttonPrimary {
|
|
|
445
446
|
flex-direction: column;
|
|
446
447
|
gap: 6px;
|
|
447
448
|
margin: 10px 0 10px 12px;
|
|
448
|
-
padding: 16px 12px 14px;
|
|
449
|
+
padding: var(--nf-density-nav, 16px 12px 14px);
|
|
449
450
|
border: 1px solid var(--nf-glass-border);
|
|
450
451
|
border-radius: 18px;
|
|
451
452
|
background: var(--nf-glass-face);
|
|
@@ -589,7 +590,7 @@ body[data-ds-dark-theme] .panel[data-nf-theme='neumorph'] .buttonPrimary {
|
|
|
589
590
|
background: var(--nf-success);
|
|
590
591
|
}
|
|
591
592
|
|
|
592
|
-
/*
|
|
593
|
+
/* 任务进行中:AI进度导航呼吸绿点(不自动弹窗,点击导航查看悬浮窗) */
|
|
593
594
|
.navTabBadgeLive {
|
|
594
595
|
background: var(--nf-success);
|
|
595
596
|
animation: navBadgePulse 1.2s ease-in-out infinite;
|
|
@@ -837,7 +838,7 @@ body[data-ds-dark-theme] .panel[data-nf-theme='neumorph'] .buttonPrimary {
|
|
|
837
838
|
position: relative;
|
|
838
839
|
border: 1px solid var(--nf-glass-border);
|
|
839
840
|
border-radius: 22px;
|
|
840
|
-
padding: 16px 18px;
|
|
841
|
+
padding: var(--nf-density-card, 16px 18px);
|
|
841
842
|
display: flex;
|
|
842
843
|
flex-direction: column;
|
|
843
844
|
gap: 10px;
|
|
@@ -906,11 +907,12 @@ body[data-ds-dark-theme] .panel[data-nf-theme='neumorph'] .buttonPrimary {
|
|
|
906
907
|
border: 1px solid var(--nf-border-strong);
|
|
907
908
|
background: var(--nf-bg-inset);
|
|
908
909
|
color: var(--nf-text);
|
|
909
|
-
padding:
|
|
910
|
-
border-radius:
|
|
910
|
+
padding: 7px 15px;
|
|
911
|
+
border-radius: 9px;
|
|
911
912
|
cursor: pointer;
|
|
912
913
|
font-size: 13px;
|
|
913
914
|
font-weight: 500;
|
|
915
|
+
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.09);
|
|
914
916
|
transition: background 0.15s ease, border-color 0.15s ease, transform 0.1s ease, box-shadow 0.15s ease;
|
|
915
917
|
white-space: nowrap;
|
|
916
918
|
}
|
|
@@ -918,10 +920,11 @@ body[data-ds-dark-theme] .panel[data-nf-theme='neumorph'] .buttonPrimary {
|
|
|
918
920
|
.button:hover:not([disabled]) {
|
|
919
921
|
background: var(--nf-hover);
|
|
920
922
|
border-color: var(--nf-border-strong);
|
|
923
|
+
transform: translateY(-1px);
|
|
921
924
|
}
|
|
922
925
|
|
|
923
926
|
.button:active:not([disabled]) {
|
|
924
|
-
transform: scale(0.
|
|
927
|
+
transform: translateY(0) scale(0.97);
|
|
925
928
|
}
|
|
926
929
|
|
|
927
930
|
.button[disabled] {
|
|
@@ -933,12 +936,15 @@ body[data-ds-dark-theme] .panel[data-nf-theme='neumorph'] .buttonPrimary {
|
|
|
933
936
|
border-color: transparent;
|
|
934
937
|
background: linear-gradient(180deg, color-mix(in srgb, var(--nf-accent) 88%, #ffffff), var(--nf-accent));
|
|
935
938
|
color: var(--nf-accent-fg);
|
|
936
|
-
|
|
939
|
+
border-radius: 10px;
|
|
940
|
+
box-shadow: 0 2px 10px color-mix(in srgb, var(--nf-accent) 45%, transparent), 0 0 0 0.5px color-mix(in srgb, var(--nf-accent) 30%, transparent), inset 0 1px 0 rgba(255, 255, 255, 0.45);
|
|
937
941
|
}
|
|
938
942
|
|
|
939
943
|
.buttonPrimary:hover:not([disabled]) {
|
|
940
944
|
background: linear-gradient(180deg, var(--nf-accent-hover), color-mix(in srgb, var(--nf-accent-hover) 85%, #000000));
|
|
941
945
|
border-color: transparent;
|
|
946
|
+
transform: translateY(-1px);
|
|
947
|
+
box-shadow: 0 12px 30px color-mix(in srgb, var(--nf-accent) 50%, transparent), 0 0 0 0.5px color-mix(in srgb, var(--nf-accent) 30%, transparent), inset 0 1px 0 rgba(255, 255, 255, 0.45);
|
|
942
948
|
}
|
|
943
949
|
|
|
944
950
|
.buttonDanger {
|
|
@@ -951,9 +957,9 @@ body[data-ds-dark-theme] .panel[data-nf-theme='neumorph'] .buttonPrimary {
|
|
|
951
957
|
}
|
|
952
958
|
|
|
953
959
|
.buttonSmall {
|
|
954
|
-
padding:
|
|
960
|
+
padding: 4px 10px;
|
|
955
961
|
font-size: 12px;
|
|
956
|
-
border-radius:
|
|
962
|
+
border-radius: 8px;
|
|
957
963
|
}
|
|
958
964
|
|
|
959
965
|
/* ------------------------------------------------------------ forms */
|
|
@@ -974,6 +980,7 @@ body[data-ds-dark-theme] .panel[data-nf-theme='neumorph'] .buttonPrimary {
|
|
|
974
980
|
border: 1px solid var(--nf-border-strong);
|
|
975
981
|
background: var(--nf-bg-inset);
|
|
976
982
|
color: var(--nf-text);
|
|
983
|
+
color-scheme: light;
|
|
977
984
|
border-radius: 12px;
|
|
978
985
|
padding: 7px 11px;
|
|
979
986
|
font-size: 13px;
|
|
@@ -982,6 +989,28 @@ body[data-ds-dark-theme] .panel[data-nf-theme='neumorph'] .buttonPrimary {
|
|
|
982
989
|
transition: border-color 0.15s ease, box-shadow 0.15s ease;
|
|
983
990
|
}
|
|
984
991
|
|
|
992
|
+
/* 原生下拉浮层配色跟随主题(防白底白字) */
|
|
993
|
+
body[data-ds-dark-theme] .input {
|
|
994
|
+
color-scheme: dark;
|
|
995
|
+
}
|
|
996
|
+
.panel[data-nf-mode='dark'] .input {
|
|
997
|
+
color-scheme: dark;
|
|
998
|
+
}
|
|
999
|
+
.panel[data-nf-mode='light'] .input {
|
|
1000
|
+
color-scheme: light;
|
|
1001
|
+
}
|
|
1002
|
+
body:not([data-ds-dark-theme]) .panel[data-nf-theme='neumorph'] .input {
|
|
1003
|
+
color-scheme: light;
|
|
1004
|
+
}
|
|
1005
|
+
select.input {
|
|
1006
|
+
cursor: pointer;
|
|
1007
|
+
}
|
|
1008
|
+
.input option {
|
|
1009
|
+
color: var(--nf-text);
|
|
1010
|
+
background: var(--nf-bg-raise);
|
|
1011
|
+
font-size: 15px;
|
|
1012
|
+
}
|
|
1013
|
+
|
|
985
1014
|
.input:focus,
|
|
986
1015
|
.textarea:focus {
|
|
987
1016
|
outline: none;
|
|
@@ -2113,10 +2142,10 @@ body[data-ds-dark-theme] .panel[data-nf-theme='neumorph'] .buttonPrimary {
|
|
|
2113
2142
|
flex: 1;
|
|
2114
2143
|
min-height: 0;
|
|
2115
2144
|
overflow: auto;
|
|
2116
|
-
padding: 18px;
|
|
2145
|
+
padding: var(--nf-density-pad, 18px);
|
|
2117
2146
|
display: flex;
|
|
2118
2147
|
flex-direction: column;
|
|
2119
|
-
gap: 16px;
|
|
2148
|
+
gap: var(--nf-density-gap, 16px);
|
|
2120
2149
|
}
|
|
2121
2150
|
|
|
2122
2151
|
.shelfHeader {
|
|
@@ -2125,9 +2154,27 @@ body[data-ds-dark-theme] .panel[data-nf-theme='neumorph'] .buttonPrimary {
|
|
|
2125
2154
|
gap: 10px;
|
|
2126
2155
|
}
|
|
2127
2156
|
|
|
2157
|
+
/* 书架顶部主容器:加高玻璃卡 */
|
|
2158
|
+
.shelfHero {
|
|
2159
|
+
display: flex;
|
|
2160
|
+
flex-direction: column;
|
|
2161
|
+
gap: 14px;
|
|
2162
|
+
padding: var(--nf-density-card, 22px 24px);
|
|
2163
|
+
border: 1px solid var(--nf-glass-border);
|
|
2164
|
+
border-radius: 22px;
|
|
2165
|
+
background: var(--nf-glass-face);
|
|
2166
|
+
box-shadow: var(--nf-shadow), inset 0 1.5px 0 var(--nf-glass-sheen);
|
|
2167
|
+
}
|
|
2168
|
+
|
|
2169
|
+
.shelfHero .panelTitle {
|
|
2170
|
+
font-size: 22px;
|
|
2171
|
+
letter-spacing: 0.3px;
|
|
2172
|
+
}
|
|
2173
|
+
|
|
2128
2174
|
.shelfTitleRow {
|
|
2129
2175
|
display: flex;
|
|
2130
|
-
align-items:
|
|
2176
|
+
align-items: center;
|
|
2177
|
+
justify-content: space-between;
|
|
2131
2178
|
gap: 10px;
|
|
2132
2179
|
flex-wrap: wrap;
|
|
2133
2180
|
}
|
|
@@ -2145,10 +2192,91 @@ body[data-ds-dark-theme] .panel[data-nf-theme='neumorph'] .buttonPrimary {
|
|
|
2145
2192
|
max-width: 320px;
|
|
2146
2193
|
}
|
|
2147
2194
|
|
|
2148
|
-
.
|
|
2195
|
+
.shelfStats {
|
|
2196
|
+
display: grid;
|
|
2197
|
+
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
|
|
2198
|
+
gap: 10px;
|
|
2199
|
+
}
|
|
2200
|
+
|
|
2201
|
+
.shelfStat {
|
|
2149
2202
|
display: flex;
|
|
2150
|
-
|
|
2151
|
-
|
|
2203
|
+
align-items: baseline;
|
|
2204
|
+
justify-content: space-between;
|
|
2205
|
+
gap: 8px;
|
|
2206
|
+
padding: 10px 14px;
|
|
2207
|
+
border: 1px solid var(--nf-glass-border);
|
|
2208
|
+
border-radius: 14px;
|
|
2209
|
+
background: var(--nf-glass-face);
|
|
2210
|
+
box-shadow: var(--nf-shadow), inset 0 1px 0 var(--nf-glass-sheen);
|
|
2211
|
+
cursor: pointer;
|
|
2212
|
+
user-select: none;
|
|
2213
|
+
transition: border-color 0.15s ease, background 0.15s ease, box-shadow 0.15s ease, transform 0.1s ease;
|
|
2214
|
+
}
|
|
2215
|
+
|
|
2216
|
+
.shelfStat:hover {
|
|
2217
|
+
border-color: var(--nf-accent);
|
|
2218
|
+
transform: translateY(-1px);
|
|
2219
|
+
}
|
|
2220
|
+
|
|
2221
|
+
.shelfStatActive {
|
|
2222
|
+
border-color: var(--nf-accent);
|
|
2223
|
+
background: var(--nf-accent-soft);
|
|
2224
|
+
box-shadow: 0 0 0 2px var(--nf-accent-soft), var(--nf-shadow);
|
|
2225
|
+
}
|
|
2226
|
+
|
|
2227
|
+
.shelfStat b {
|
|
2228
|
+
font-size: 20px;
|
|
2229
|
+
font-weight: 800;
|
|
2230
|
+
color: var(--nf-accent);
|
|
2231
|
+
}
|
|
2232
|
+
|
|
2233
|
+
.shelfStat span {
|
|
2234
|
+
font-size: 12px;
|
|
2235
|
+
color: var(--nf-text-2);
|
|
2236
|
+
}
|
|
2237
|
+
|
|
2238
|
+
/* 筛选:胶囊分段控件 */
|
|
2239
|
+
.shelfFilters {
|
|
2240
|
+
display: inline-flex;
|
|
2241
|
+
gap: 2px;
|
|
2242
|
+
padding: 3px;
|
|
2243
|
+
border: 1px solid var(--nf-border);
|
|
2244
|
+
border-radius: 999px;
|
|
2245
|
+
background: var(--nf-bg-inset);
|
|
2246
|
+
}
|
|
2247
|
+
|
|
2248
|
+
.shelfFilter {
|
|
2249
|
+
border: none;
|
|
2250
|
+
background: transparent;
|
|
2251
|
+
color: var(--nf-text-2);
|
|
2252
|
+
font-size: 12.5px;
|
|
2253
|
+
font-weight: 600;
|
|
2254
|
+
padding: 5px 12px;
|
|
2255
|
+
border-radius: 999px;
|
|
2256
|
+
cursor: pointer;
|
|
2257
|
+
display: inline-flex;
|
|
2258
|
+
align-items: center;
|
|
2259
|
+
gap: 5px;
|
|
2260
|
+
white-space: nowrap;
|
|
2261
|
+
transition: background 0.15s ease, color 0.15s ease, box-shadow 0.15s ease;
|
|
2262
|
+
}
|
|
2263
|
+
|
|
2264
|
+
.shelfFilter:hover {
|
|
2265
|
+
color: var(--nf-text);
|
|
2266
|
+
}
|
|
2267
|
+
|
|
2268
|
+
.shelfFilterActive {
|
|
2269
|
+
background: linear-gradient(135deg, var(--nf-accent), var(--nf-accent-hover));
|
|
2270
|
+
color: var(--nf-accent-fg);
|
|
2271
|
+
box-shadow: 0 3px 12px color-mix(in srgb, var(--nf-accent) 40%, transparent);
|
|
2272
|
+
}
|
|
2273
|
+
|
|
2274
|
+
.shelfFilterCount {
|
|
2275
|
+
font-size: 10.5px;
|
|
2276
|
+
opacity: 0.8;
|
|
2277
|
+
background: color-mix(in srgb, currentColor 14%, transparent);
|
|
2278
|
+
border-radius: 999px;
|
|
2279
|
+
padding: 0 6px;
|
|
2152
2280
|
}
|
|
2153
2281
|
|
|
2154
2282
|
/* 书架空态 / 无结果引导卡 */
|
|
@@ -2180,10 +2308,171 @@ body[data-ds-dark-theme] .panel[data-nf-theme='neumorph'] .buttonPrimary {
|
|
|
2180
2308
|
.shelfGrid {
|
|
2181
2309
|
display: grid;
|
|
2182
2310
|
grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
|
|
2183
|
-
gap: 14px;
|
|
2311
|
+
gap: var(--nf-density-gap, 14px);
|
|
2184
2312
|
align-content: start;
|
|
2185
2313
|
}
|
|
2186
2314
|
|
|
2315
|
+
/* ------------------------------------------------------------
|
|
2316
|
+
* 外观设置扩展:强制显示模式 + 界面密度 + 主题暗色覆盖
|
|
2317
|
+
* ------------------------------------------------------------ */
|
|
2318
|
+
.panel {
|
|
2319
|
+
--nf-density-card: 16px 18px;
|
|
2320
|
+
--nf-density-gap: 14px;
|
|
2321
|
+
--nf-density-pad: 16px 18px 20px;
|
|
2322
|
+
--nf-density-nav: 16px 12px 14px;
|
|
2323
|
+
}
|
|
2324
|
+
|
|
2325
|
+
.panel[data-nf-density='compact'] {
|
|
2326
|
+
--nf-density-card: 12px 14px;
|
|
2327
|
+
--nf-density-gap: 8px;
|
|
2328
|
+
--nf-density-pad: 12px 14px;
|
|
2329
|
+
--nf-density-nav: 8px 8px;
|
|
2330
|
+
}
|
|
2331
|
+
|
|
2332
|
+
.panel[data-nf-density='spacious'] {
|
|
2333
|
+
--nf-density-card: 22px 26px;
|
|
2334
|
+
--nf-density-gap: 18px;
|
|
2335
|
+
--nf-density-pad: 22px 24px;
|
|
2336
|
+
--nf-density-nav: 18px 14px;
|
|
2337
|
+
}
|
|
2338
|
+
|
|
2339
|
+
/* 强制浅色(不跟随系统时覆盖 .view 的明暗变量) */
|
|
2340
|
+
.panel[data-nf-mode='light'] {
|
|
2341
|
+
color-scheme: light;
|
|
2342
|
+
--nf-bg: rgba(242, 242, 247, 0.86);
|
|
2343
|
+
--nf-bg-raise: rgba(255, 255, 255, 0.72);
|
|
2344
|
+
--nf-bg-inset: rgba(118, 118, 128, 0.12);
|
|
2345
|
+
--nf-border: rgba(60, 60, 67, 0.16);
|
|
2346
|
+
--nf-border-strong: rgba(60, 60, 67, 0.32);
|
|
2347
|
+
--nf-text: #1c1c1e;
|
|
2348
|
+
--nf-text-2: #3c3c43;
|
|
2349
|
+
--nf-text-2-alpha: rgba(60, 60, 67, 0.68);
|
|
2350
|
+
--nf-text-3: #8e8e93;
|
|
2351
|
+
--nf-accent: #00b85c;
|
|
2352
|
+
--nf-accent-hover: #00a04e;
|
|
2353
|
+
--nf-accent-soft: rgba(0, 184, 92, 0.12);
|
|
2354
|
+
--nf-accent-fg: #ffffff;
|
|
2355
|
+
--nf-hover: rgba(0, 0, 0, 0.05);
|
|
2356
|
+
--nf-success: #34c759;
|
|
2357
|
+
--nf-error: #ff3b30;
|
|
2358
|
+
--nf-warn: #ff9500;
|
|
2359
|
+
--nf-info: #00b85c;
|
|
2360
|
+
--nf-shadow: 0 1px 3px rgba(0, 0, 0, 0.06), 0 12px 32px rgba(0, 0, 0, 0.08);
|
|
2361
|
+
--nf-shadow-lg: 0 4px 12px rgba(0, 0, 0, 0.07), 0 20px 48px rgba(0, 0, 0, 0.12);
|
|
2362
|
+
--nf-card-shadow: 0 2px 6px rgba(0, 0, 0, 0.06), 0 14px 38px rgba(0, 0, 0, 0.14);
|
|
2363
|
+
--nf-card-shadow-hover: 0 4px 10px rgba(0, 0, 0, 0.08), 0 22px 52px rgba(0, 0, 0, 0.20);
|
|
2364
|
+
--nf-glass-face: linear-gradient(180deg, #f6f7f9 0%, #f0f2f5 26%, #e9ebef 52%, #e0e3e8 78%, #d6d9df 100%);
|
|
2365
|
+
--nf-glass-core: radial-gradient(30% 24% at 36% 28%, rgba(255, 255, 255, 0.5) 0%, rgba(255, 255, 255, 0.22) 45%, rgba(255, 255, 255, 0) 78%);
|
|
2366
|
+
--nf-glass-sheen: rgba(255, 255, 255, 0.55);
|
|
2367
|
+
--nf-glass-border: rgba(255, 255, 255, 0.65);
|
|
2368
|
+
--nf-glass-inset: rgba(255, 255, 255, 0.55);
|
|
2369
|
+
--nf-glass-orb-a: rgba(0, 184, 92, 0.18);
|
|
2370
|
+
--nf-glass-orb-b: rgba(120, 160, 255, 0.13);
|
|
2371
|
+
}
|
|
2372
|
+
|
|
2373
|
+
/* 强制深色 */
|
|
2374
|
+
.panel[data-nf-mode='dark'] {
|
|
2375
|
+
color-scheme: dark;
|
|
2376
|
+
--nf-bg: rgba(10, 11, 13, 0.86);
|
|
2377
|
+
--nf-bg-raise: rgba(28, 28, 30, 0.78);
|
|
2378
|
+
--nf-bg-inset: rgba(118, 118, 128, 0.18);
|
|
2379
|
+
--nf-border: rgba(255, 255, 255, 0.12);
|
|
2380
|
+
--nf-border-strong: rgba(255, 255, 255, 0.28);
|
|
2381
|
+
--nf-text: #f2f2f7;
|
|
2382
|
+
--nf-text-2: #d1d1d6;
|
|
2383
|
+
--nf-text-2-alpha: rgba(209, 209, 214, 0.72);
|
|
2384
|
+
--nf-text-3: #8e8e93;
|
|
2385
|
+
--nf-accent: #35d07a;
|
|
2386
|
+
--nf-accent-hover: #5ce695;
|
|
2387
|
+
--nf-accent-soft: rgba(53, 208, 122, 0.2);
|
|
2388
|
+
--nf-accent-fg: #062b18;
|
|
2389
|
+
--nf-hover: rgba(255, 255, 255, 0.09);
|
|
2390
|
+
--nf-success: #30d158;
|
|
2391
|
+
--nf-error: #ff453a;
|
|
2392
|
+
--nf-warn: #ff9f0a;
|
|
2393
|
+
--nf-info: #35d07a;
|
|
2394
|
+
--nf-shadow: 0 1px 2px rgba(0, 0, 0, 0.35), 0 10px 30px rgba(0, 0, 0, 0.4);
|
|
2395
|
+
--nf-shadow-lg: 0 4px 12px rgba(0, 0, 0, 0.4), 0 20px 48px rgba(0, 0, 0, 0.55);
|
|
2396
|
+
--nf-card-shadow: 0 2px 6px rgba(0, 0, 0, 0.35), 0 14px 38px rgba(0, 0, 0, 0.45);
|
|
2397
|
+
--nf-card-shadow-hover: 0 4px 10px rgba(0, 0, 0, 0.4), 0 22px 52px rgba(0, 0, 0, 0.55);
|
|
2398
|
+
--nf-glass-face: linear-gradient(180deg, rgba(112, 116, 122, 0.42) 0%, rgba(96, 100, 106, 0.42) 26%, rgba(82, 85, 90, 0.42) 52%, rgba(68, 71, 76, 0.42) 78%, rgba(56, 58, 63, 0.42) 100%);
|
|
2399
|
+
--nf-glass-core: radial-gradient(30% 24% at 36% 28%, rgba(255, 255, 255, 0.26) 0%, rgba(255, 255, 255, 0.10) 45%, rgba(255, 255, 255, 0) 78%);
|
|
2400
|
+
--nf-glass-sheen: rgba(255, 255, 255, 0.26);
|
|
2401
|
+
--nf-glass-border: rgba(255, 255, 255, 0.14);
|
|
2402
|
+
--nf-glass-inset: rgba(255, 255, 255, 0.07);
|
|
2403
|
+
--nf-glass-orb-a: rgba(0, 202, 82, 0.28);
|
|
2404
|
+
--nf-glass-orb-b: rgba(190, 200, 215, 0.10);
|
|
2405
|
+
}
|
|
2406
|
+
|
|
2407
|
+
/* 强制深色时:经典毛玻璃 / 新拟物 的暗色变体 */
|
|
2408
|
+
.panel[data-nf-mode='dark'][data-nf-theme='classic'] {
|
|
2409
|
+
--nf-accent: #0a84ff;
|
|
2410
|
+
--nf-accent-hover: #3a9bff;
|
|
2411
|
+
--nf-accent-soft: rgba(10, 132, 255, 0.2);
|
|
2412
|
+
--nf-accent-fg: #ffffff;
|
|
2413
|
+
--nf-info: #bf5af2;
|
|
2414
|
+
--nf-glass-face: var(--nf-bg-raise);
|
|
2415
|
+
--nf-glass-core: transparent;
|
|
2416
|
+
--nf-glass-sheen: rgba(255, 255, 255, 0);
|
|
2417
|
+
--nf-glass-border: var(--nf-border);
|
|
2418
|
+
--nf-glass-inset: var(--nf-bg-inset);
|
|
2419
|
+
--nf-glass-orb-a: transparent;
|
|
2420
|
+
--nf-glass-orb-b: transparent;
|
|
2421
|
+
--nf-glass-noise: none;
|
|
2422
|
+
}
|
|
2423
|
+
|
|
2424
|
+
.panel[data-nf-mode='dark'][data-nf-theme='neumorph'] {
|
|
2425
|
+
--nf-bg: #2b2f36;
|
|
2426
|
+
--nf-bg-raise: #2b2f36;
|
|
2427
|
+
--nf-bg-inset: #25292f;
|
|
2428
|
+
--nf-border: rgba(10, 12, 16, 0.5);
|
|
2429
|
+
--nf-border-strong: rgba(8, 10, 14, 0.6);
|
|
2430
|
+
--nf-text: #d6dae1;
|
|
2431
|
+
--nf-text-2: #a8aeb8;
|
|
2432
|
+
--nf-text-2-alpha: rgba(168, 174, 184, 0.7);
|
|
2433
|
+
--nf-text-3: #757c88;
|
|
2434
|
+
--nf-hover: rgba(255, 255, 255, 0.05);
|
|
2435
|
+
--nf-shadow: 4px 4px 10px rgba(0, 0, 0, 0.5), -4px -4px 10px rgba(96, 104, 118, 0.24);
|
|
2436
|
+
--nf-shadow-lg: 6px 6px 14px rgba(0, 0, 0, 0.55), -6px -6px 14px rgba(96, 104, 118, 0.26);
|
|
2437
|
+
--nf-card-shadow: 9px 9px 18px rgba(0, 0, 0, 0.5), -9px -9px 18px rgba(96, 104, 118, 0.24);
|
|
2438
|
+
--nf-card-shadow-hover: 12px 12px 24px rgba(0, 0, 0, 0.6), -12px -12px 24px rgba(96, 104, 118, 0.28);
|
|
2439
|
+
--nf-glass-face: #2b2f36;
|
|
2440
|
+
--nf-glass-core: transparent;
|
|
2441
|
+
--nf-glass-sheen: rgba(255, 255, 255, 0);
|
|
2442
|
+
--nf-glass-border: rgba(12, 14, 18, 0.45);
|
|
2443
|
+
--nf-glass-inset: #25292f;
|
|
2444
|
+
--nf-glass-orb-a: transparent;
|
|
2445
|
+
--nf-glass-orb-b: transparent;
|
|
2446
|
+
--nf-glass-noise: none;
|
|
2447
|
+
}
|
|
2448
|
+
|
|
2449
|
+
/* 强制浅色时:新拟物 的浅色变体(深色系统下也能用) */
|
|
2450
|
+
.panel[data-nf-mode='light'][data-nf-theme='neumorph'] {
|
|
2451
|
+
--nf-bg: #e4e9f2;
|
|
2452
|
+
--nf-bg-raise: #e4e9f2;
|
|
2453
|
+
--nf-bg-inset: #d9dfe8;
|
|
2454
|
+
--nf-border: rgba(140, 155, 175, 0.35);
|
|
2455
|
+
--nf-border-strong: rgba(120, 135, 158, 0.5);
|
|
2456
|
+
--nf-text: #3a4250;
|
|
2457
|
+
--nf-text-2: #5b6472;
|
|
2458
|
+
--nf-text-2-alpha: rgba(70, 80, 96, 0.7);
|
|
2459
|
+
--nf-text-3: #8b94a3;
|
|
2460
|
+
--nf-hover: rgba(90, 105, 125, 0.08);
|
|
2461
|
+
--nf-shadow: 4px 4px 10px rgba(163, 177, 198, 0.55), -4px -4px 10px rgba(255, 255, 255, 0.85);
|
|
2462
|
+
--nf-shadow-lg: 6px 6px 14px rgba(163, 177, 198, 0.6), -6px -6px 14px rgba(255, 255, 255, 0.9);
|
|
2463
|
+
--nf-card-shadow: 9px 9px 18px rgba(163, 177, 198, 0.55), -9px -9px 18px rgba(255, 255, 255, 0.85);
|
|
2464
|
+
--nf-card-shadow-hover: 12px 12px 24px rgba(163, 177, 198, 0.65), -12px -12px 24px rgba(255, 255, 255, 0.95);
|
|
2465
|
+
--nf-glass-face: #e4e9f2;
|
|
2466
|
+
--nf-glass-core: transparent;
|
|
2467
|
+
--nf-glass-sheen: rgba(255, 255, 255, 0);
|
|
2468
|
+
--nf-glass-border: rgba(163, 177, 198, 0.4);
|
|
2469
|
+
--nf-glass-inset: #d9dfe8;
|
|
2470
|
+
--nf-glass-orb-a: transparent;
|
|
2471
|
+
--nf-glass-orb-b: transparent;
|
|
2472
|
+
--nf-glass-noise: none;
|
|
2473
|
+
}
|
|
2474
|
+
|
|
2475
|
+
|
|
2187
2476
|
.bookCard {
|
|
2188
2477
|
display: flex;
|
|
2189
2478
|
flex-direction: column;
|
|
@@ -2220,13 +2509,35 @@ body[data-ds-dark-theme] .panel[data-nf-theme='neumorph'] .buttonPrimary {
|
|
|
2220
2509
|
display: flex;
|
|
2221
2510
|
align-items: center;
|
|
2222
2511
|
justify-content: center;
|
|
2512
|
+
position: relative;
|
|
2223
2513
|
}
|
|
2224
2514
|
|
|
2225
2515
|
.bookCardCover img {
|
|
2226
2516
|
width: 100%;
|
|
2227
2517
|
height: 100%;
|
|
2228
|
-
object-fit:
|
|
2518
|
+
object-fit: cover;
|
|
2229
2519
|
display: block;
|
|
2520
|
+
transition: transform 0.35s ease;
|
|
2521
|
+
}
|
|
2522
|
+
|
|
2523
|
+
.bookCard:hover .bookCardCover img {
|
|
2524
|
+
transform: scale(1.06);
|
|
2525
|
+
}
|
|
2526
|
+
|
|
2527
|
+
/* 封面底部渐暗(hover 出现,突出书名区) */
|
|
2528
|
+
.bookCardCover::after {
|
|
2529
|
+
content: '';
|
|
2530
|
+
position: absolute;
|
|
2531
|
+
inset: 0;
|
|
2532
|
+
border-radius: inherit;
|
|
2533
|
+
pointer-events: none;
|
|
2534
|
+
background: linear-gradient(180deg, transparent 55%, rgba(0, 0, 0, 0.28));
|
|
2535
|
+
opacity: 0;
|
|
2536
|
+
transition: opacity 0.25s ease;
|
|
2537
|
+
}
|
|
2538
|
+
|
|
2539
|
+
.bookCard:hover .bookCardCover::after {
|
|
2540
|
+
opacity: 1;
|
|
2230
2541
|
}
|
|
2231
2542
|
|
|
2232
2543
|
.bookCardCoverFallback {
|
|
@@ -2254,6 +2565,7 @@ body[data-ds-dark-theme] .panel[data-nf-theme='neumorph'] .buttonPrimary {
|
|
|
2254
2565
|
flex-direction: column;
|
|
2255
2566
|
gap: 5px;
|
|
2256
2567
|
min-width: 0;
|
|
2568
|
+
flex: 1;
|
|
2257
2569
|
}
|
|
2258
2570
|
|
|
2259
2571
|
.bookCardTitleRow {
|
|
@@ -2288,10 +2600,11 @@ body[data-ds-dark-theme] .panel[data-nf-theme='neumorph'] .buttonPrimary {
|
|
|
2288
2600
|
}
|
|
2289
2601
|
|
|
2290
2602
|
.bookCardProgressBar {
|
|
2291
|
-
height:
|
|
2603
|
+
height: 6px;
|
|
2292
2604
|
border-radius: 999px;
|
|
2293
2605
|
background: var(--nf-border);
|
|
2294
2606
|
overflow: hidden;
|
|
2607
|
+
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.12);
|
|
2295
2608
|
}
|
|
2296
2609
|
|
|
2297
2610
|
.bookCardProgressFill {
|
|
@@ -2310,16 +2623,25 @@ body[data-ds-dark-theme] .panel[data-nf-theme='neumorph'] .buttonPrimary {
|
|
|
2310
2623
|
border-style: dashed;
|
|
2311
2624
|
color: var(--nf-text-2);
|
|
2312
2625
|
min-height: 260px;
|
|
2626
|
+
transition: border-color 0.15s ease, color 0.15s ease, background 0.15s ease, transform 0.15s ease;
|
|
2313
2627
|
}
|
|
2314
2628
|
|
|
2315
2629
|
.bookAddCard:hover {
|
|
2630
|
+
border-color: var(--nf-accent);
|
|
2631
|
+
background: var(--nf-accent-soft);
|
|
2316
2632
|
color: var(--nf-accent);
|
|
2633
|
+
transform: translateY(-2px);
|
|
2317
2634
|
}
|
|
2318
2635
|
|
|
2319
2636
|
.bookAddIcon {
|
|
2320
2637
|
font-size: 34px;
|
|
2321
2638
|
line-height: 1;
|
|
2322
2639
|
color: var(--nf-accent);
|
|
2640
|
+
transition: transform 0.15s ease;
|
|
2641
|
+
}
|
|
2642
|
+
|
|
2643
|
+
.bookAddCard:hover .bookAddIcon {
|
|
2644
|
+
transform: scale(1.12);
|
|
2323
2645
|
}
|
|
2324
2646
|
|
|
2325
2647
|
.bookCreateCard {
|
|
@@ -2708,7 +3030,8 @@ body[data-ds-dark-theme] .panel[data-nf-theme='neumorph'] .buttonPrimary {
|
|
|
2708
3030
|
display: flex;
|
|
2709
3031
|
align-items: center;
|
|
2710
3032
|
gap: 6px;
|
|
2711
|
-
margin-top:
|
|
3033
|
+
margin-top: auto;
|
|
3034
|
+
padding-top: 8px;
|
|
2712
3035
|
}
|
|
2713
3036
|
|
|
2714
3037
|
.bookCardActions .button {
|
|
@@ -3112,3 +3435,64 @@ body[data-ds-dark-theme] .panel[data-nf-theme='neumorph'] .buttonPrimary {
|
|
|
3112
3435
|
.helpTip:focus-within .helpTipText {
|
|
3113
3436
|
display: block;
|
|
3114
3437
|
}
|
|
3438
|
+
|
|
3439
|
+
/* 设置页字号放大(标题明显大于正文) */
|
|
3440
|
+
.settingsCard {
|
|
3441
|
+
font-size: 15px;
|
|
3442
|
+
}
|
|
3443
|
+
.settingsCard .fieldLabel {
|
|
3444
|
+
font-size: 14px;
|
|
3445
|
+
}
|
|
3446
|
+
.settingsCard .input {
|
|
3447
|
+
font-size: 15.5px;
|
|
3448
|
+
}
|
|
3449
|
+
.settingsCard .meta {
|
|
3450
|
+
font-size: 13px;
|
|
3451
|
+
}
|
|
3452
|
+
.settingsCard .cardTitle {
|
|
3453
|
+
font-size: 20px;
|
|
3454
|
+
}
|
|
3455
|
+
.settingsCard .input {
|
|
3456
|
+
padding: 12px 16px;
|
|
3457
|
+
border-radius: 10px;
|
|
3458
|
+
}
|
|
3459
|
+
.settingsCard + .settingsCard {
|
|
3460
|
+
flex: 1;
|
|
3461
|
+
min-height: 0;
|
|
3462
|
+
|
|
3463
|
+
/* 设置页开关(滑块) */
|
|
3464
|
+
.switch {
|
|
3465
|
+
position: relative;
|
|
3466
|
+
width: 42px;
|
|
3467
|
+
height: 24px;
|
|
3468
|
+
border-radius: 999px;
|
|
3469
|
+
border: 1px solid var(--nf-border-strong);
|
|
3470
|
+
background: var(--nf-bg-inset);
|
|
3471
|
+
cursor: pointer;
|
|
3472
|
+
padding: 0;
|
|
3473
|
+
flex: none;
|
|
3474
|
+
transition: background 0.18s ease, border-color 0.18s ease;
|
|
3475
|
+
}
|
|
3476
|
+
|
|
3477
|
+
.switchKnob {
|
|
3478
|
+
position: absolute;
|
|
3479
|
+
top: 3px;
|
|
3480
|
+
left: 3px;
|
|
3481
|
+
width: 16px;
|
|
3482
|
+
height: 16px;
|
|
3483
|
+
border-radius: 50%;
|
|
3484
|
+
background: #fff;
|
|
3485
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
|
|
3486
|
+
transition: transform 0.18s ease;
|
|
3487
|
+
}
|
|
3488
|
+
|
|
3489
|
+
.switchOn {
|
|
3490
|
+
background: var(--nf-accent);
|
|
3491
|
+
border-color: var(--nf-accent);
|
|
3492
|
+
}
|
|
3493
|
+
|
|
3494
|
+
.switchOn .switchKnob {
|
|
3495
|
+
transform: translateX(18px);
|
|
3496
|
+
}
|
|
3497
|
+
|
|
3498
|
+
}
|
package/src/engine.ts
CHANGED
|
@@ -2001,6 +2001,40 @@ export async function breakdownBook(
|
|
|
2001
2001
|
}
|
|
2002
2002
|
}
|
|
2003
2003
|
|
|
2004
|
+
/** 生图接口连通性测试(设置页模型条目用):GET {baseURL}/models,计时返回延迟。 */
|
|
2005
|
+
export async function testImageEndpoint(baseURL: string, apiKey: string, model?: string): Promise<{ ok: boolean; ms: number; message?: string; modelFound?: boolean }> {
|
|
2006
|
+
const trimmed = baseURL.trim()
|
|
2007
|
+
if (trimmed === '') return { ok: false, ms: 0, message: '接口地址不能为空' }
|
|
2008
|
+
const url = trimmed.replace(/\/+$/, '') + '/models'
|
|
2009
|
+
const start = Date.now()
|
|
2010
|
+
try {
|
|
2011
|
+
const res = await fetch(url, {
|
|
2012
|
+
method: 'GET',
|
|
2013
|
+
headers: { Authorization: 'Bearer ' + apiKey, 'Content-Type': 'application/json' },
|
|
2014
|
+
})
|
|
2015
|
+
const ms = Date.now() - start
|
|
2016
|
+
if (!res.ok) {
|
|
2017
|
+
const text = (await res.text().catch(() => '')).slice(0, 200)
|
|
2018
|
+
return { ok: false, ms, message: 'HTTP ' + res.status + (text !== '' ? ':' + text : '') }
|
|
2019
|
+
}
|
|
2020
|
+
let modelFound: boolean | undefined
|
|
2021
|
+
if (model !== undefined && model !== '') {
|
|
2022
|
+
const json = await res.json().catch(() => null)
|
|
2023
|
+
const list = (json as { data?: unknown } | null)?.data
|
|
2024
|
+
if (Array.isArray(list)) {
|
|
2025
|
+
modelFound = list.some(m => {
|
|
2026
|
+
if (typeof m !== 'object' || m === null) return false
|
|
2027
|
+
const o = m as Record<string, unknown>
|
|
2028
|
+
return o.id === model || o.model === model
|
|
2029
|
+
})
|
|
2030
|
+
}
|
|
2031
|
+
}
|
|
2032
|
+
return { ok: true, ms, modelFound }
|
|
2033
|
+
} catch (err) {
|
|
2034
|
+
return { ok: false, ms: Date.now() - start, message: (err as Error).message }
|
|
2035
|
+
}
|
|
2036
|
+
}
|
|
2037
|
+
|
|
2004
2038
|
export async function generateRoleReferenceImage(
|
|
2005
2039
|
ctx: Context,
|
|
2006
2040
|
config: NovelConfig,
|
|
@@ -2008,15 +2042,21 @@ export async function generateRoleReferenceImage(
|
|
|
2008
2042
|
outputDir: string,
|
|
2009
2043
|
name: string,
|
|
2010
2044
|
style = '',
|
|
2045
|
+
modelId?: string,
|
|
2011
2046
|
): Promise<string> {
|
|
2012
2047
|
const role = project.roles?.find(r => r.name === name)
|
|
2013
2048
|
if (role === undefined) throw new Error(`角色 ${name} 不存在`)
|
|
2014
2049
|
if (role.imagePrompt === undefined) throw new Error(`角色 ${name} 还没有形象锚点,请先生成锚点`)
|
|
2015
|
-
if (config.imageApiEnabled !== true) throw new Error('
|
|
2016
|
-
const
|
|
2017
|
-
|
|
2050
|
+
if (config.imageApiEnabled !== true) throw new Error('生图未启用,请在设置中启用一个生图模型')
|
|
2051
|
+
const activeImage = (modelId !== undefined && modelId !== '' ? (config.imageModels ?? []).find(m => m.id === modelId) : undefined)
|
|
2052
|
+
?? (config.imageModels ?? []).find(m => m.enabled)
|
|
2053
|
+
?? (config.imageModels ?? [])[0]
|
|
2054
|
+
const apiKey = activeImage?.apiKey ?? config.imageApiKey
|
|
2055
|
+
const model = activeImage?.model ?? config.imageApiModel
|
|
2056
|
+
const baseURL = (activeImage?.baseURL ?? config.imageBaseUrl ?? '').replace(/\/+$/, '')
|
|
2057
|
+
if (baseURL === '') throw new Error('请先在设置中填写生图接口地址')
|
|
2018
2058
|
if (apiKey === undefined || apiKey === '' || model === undefined || model === '') {
|
|
2019
|
-
throw new Error('
|
|
2059
|
+
throw new Error('请先在设置中配置生图模型的 API Key 和模型 id')
|
|
2020
2060
|
}
|
|
2021
2061
|
const stylePrompt = getComicStylePrompt(style)
|
|
2022
2062
|
const prompt = [
|
|
@@ -2027,7 +2067,7 @@ export async function generateRoleReferenceImage(
|
|
|
2027
2067
|
'character reference sheet, front view, clean background, consistent design',
|
|
2028
2068
|
].filter(Boolean).join(', ')
|
|
2029
2069
|
|
|
2030
|
-
const res = await fetch('
|
|
2070
|
+
const res = await fetch(baseURL + '/images/generations', {
|
|
2031
2071
|
method: 'POST',
|
|
2032
2072
|
headers: {
|
|
2033
2073
|
'Content-Type': 'application/json',
|
|
@@ -2044,14 +2084,14 @@ export async function generateRoleReferenceImage(
|
|
|
2044
2084
|
})
|
|
2045
2085
|
if (!res.ok) {
|
|
2046
2086
|
const text = await res.text()
|
|
2047
|
-
throw new Error(
|
|
2087
|
+
throw new Error(`生图失败(${res.status}):${text}`)
|
|
2048
2088
|
}
|
|
2049
2089
|
const json = (await res.json()) as { data?: Array<{ url?: string }> }
|
|
2050
2090
|
const url = json.data?.[0]?.url
|
|
2051
|
-
if (url === undefined || url === '') throw new Error('
|
|
2091
|
+
if (url === undefined || url === '') throw new Error('生图接口未返回图片 URL')
|
|
2052
2092
|
|
|
2053
2093
|
const imgRes = await fetch(url)
|
|
2054
|
-
if (!imgRes.ok) throw new Error('
|
|
2094
|
+
if (!imgRes.ok) throw new Error('下载生图结果失败')
|
|
2055
2095
|
const buf = Buffer.from(await imgRes.arrayBuffer())
|
|
2056
2096
|
const contentType = imgRes.headers.get('content-type') || 'image/jpeg'
|
|
2057
2097
|
const dataUrl = `data:${contentType};base64,${buf.toString('base64')}`
|