@waterwx/dsh-novel-forge 1.1.9 → 1.3.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.
@@ -178,18 +178,19 @@ export function ShelfView({
178
178
  value={query}
179
179
  onChange={e => { setQuery(e.target.value) }}
180
180
  />
181
- <div className={css.shelfFilters}>
182
- {filters.map(f => (
183
- <button
184
- key={f.id}
185
- type="button"
186
- className={`${css.button} ${css.buttonSmall} ${filter === f.id ? css.buttonPrimary : ''}`}
187
- onClick={() => { setFilter(f.id) }}
188
- >
189
- {f.label}{f.count > 0 ? `(${f.count})` : ''}
190
- </button>
191
- ))}
192
- </div>
181
+ </div>
182
+ <div className={css.shelfFilters} style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
183
+ {filters.map(f => (
184
+ <button
185
+ key={f.id}
186
+ type="button"
187
+ className={`${css.button} ${filter === f.id ? css.buttonPrimary : ''}`}
188
+ style={{ fontSize: 14, flex: 1 }}
189
+ onClick={() => { setFilter(f.id) }}
190
+ >
191
+ {f.label}{f.count > 0 ? `(${f.count})` : ''}
192
+ </button>
193
+ ))}
193
194
  </div>
194
195
  </div>
195
196
 
@@ -96,8 +96,8 @@ body[data-ds-dark-theme] .entry {
96
96
  --nf-glass-sheen: rgba(255, 255, 255, 0.55);
97
97
  --nf-glass-border: rgba(255, 255, 255, 0.65);
98
98
  --nf-glass-inset: rgba(255, 255, 255, 0.55);
99
- --nf-glass-orb-a: rgba(0, 184, 92, 0.14);
100
- --nf-glass-orb-b: rgba(120, 160, 255, 0.10);
99
+ --nf-glass-orb-a: rgba(0, 184, 92, 0.18);
100
+ --nf-glass-orb-b: rgba(120, 160, 255, 0.13);
101
101
  --nf-glass-noise: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)'/%3E%3C/svg%3E");
102
102
  background: var(--nf-bg);
103
103
  /* Frosted glass: blur whatever is behind the panel (the chat dialog),
@@ -138,8 +138,8 @@ body[data-ds-dark-theme] .view {
138
138
  --nf-glass-sheen: rgba(255, 255, 255, 0.26);
139
139
  --nf-glass-border: rgba(255, 255, 255, 0.14);
140
140
  --nf-glass-inset: rgba(255, 255, 255, 0.07);
141
- --nf-glass-orb-a: rgba(0, 202, 82, 0.20);
142
- --nf-glass-orb-b: rgba(190, 200, 215, 0.07);
141
+ --nf-glass-orb-a: rgba(0, 202, 82, 0.28);
142
+ --nf-glass-orb-b: rgba(190, 200, 215, 0.10);
143
143
  --nf-glass-noise: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)'/%3E%3C/svg%3E");
144
144
  }
145
145
 
@@ -334,23 +334,6 @@ body[data-ds-dark-theme] .panel[data-nf-theme='neumorph'] .buttonPrimary {
334
334
  radial-gradient(120% 95% at 50% 42%, transparent 55%, rgba(2, 2, 3, 0.10) 100%);
335
335
  }
336
336
 
337
- .panelHeader {
338
- display: flex;
339
- align-items: center;
340
- justify-content: space-between;
341
- margin: 10px 12px 0;
342
- padding: 10px 16px;
343
- border: 1px solid var(--nf-glass-border);
344
- border-radius: 18px;
345
- flex-shrink: 0;
346
- background: var(--nf-glass-face);
347
- box-shadow: var(--nf-shadow), inset 0 1px 0 var(--nf-glass-sheen);
348
- -webkit-backdrop-filter: blur(28px) saturate(175%);
349
- backdrop-filter: blur(28px) saturate(175%);
350
- /* 固定在面板顶部(panel 为 flex 列布局,header 正常占位),
351
- 下方内容在 panelBody 内独立滚动,header 永不遮挡内容。 */
352
- }
353
-
354
337
  .panelTitle {
355
338
  margin: 0;
356
339
  font-size: 16px;
@@ -456,15 +439,15 @@ body[data-ds-dark-theme] .panel[data-nf-theme='neumorph'] .buttonPrimary {
456
439
 
457
440
  .panelNav {
458
441
  flex: none;
459
- align-self: flex-start;
460
- width: 142px;
442
+ align-self: stretch;
443
+ width: 200px;
461
444
  display: flex;
462
445
  flex-direction: column;
463
446
  gap: 4px;
464
447
  margin: 10px 0 10px 12px;
465
- padding: 10px 8px;
448
+ padding: 14px 10px 12px;
466
449
  border: 1px solid var(--nf-glass-border);
467
- border-radius: 16px;
450
+ border-radius: 18px;
468
451
  background: var(--nf-glass-face);
469
452
  box-shadow: var(--nf-shadow), inset 0 1px 0 var(--nf-glass-sheen);
470
453
  -webkit-backdrop-filter: blur(28px) saturate(175%);
@@ -490,7 +473,7 @@ body[data-ds-dark-theme] .panel[data-nf-theme='neumorph'] .buttonPrimary {
490
473
  letter-spacing: 0.6px;
491
474
  text-transform: uppercase;
492
475
  color: var(--nf-text-3);
493
- padding: 8px 10px 3px;
476
+ padding: 10px 10px 4px;
494
477
  user-select: none;
495
478
  }
496
479
 
@@ -622,15 +605,15 @@ body[data-ds-dark-theme] .panel[data-nf-theme='neumorph'] .buttonPrimary {
622
605
  align-items: center;
623
606
  gap: 8px;
624
607
  width: 100%;
625
- border: none;
608
+ border: 1px solid transparent;
626
609
  background: transparent;
627
610
  cursor: pointer;
628
- border-radius: 12px;
629
- padding: 8px 10px;
611
+ border-radius: 10px;
612
+ padding: 9px 10px;
630
613
  font-size: 13px;
631
614
  color: var(--nf-text-2-alpha, var(--nf-text-2));
632
615
  font-weight: 500;
633
- transition: color 0.15s ease, background 0.15s ease;
616
+ transition: color 0.15s ease, background 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
634
617
  position: relative;
635
618
  text-align: left;
636
619
  white-space: nowrap;
@@ -649,27 +632,20 @@ body[data-ds-dark-theme] .panel[data-nf-theme='neumorph'] .buttonPrimary {
649
632
  .navTab[data-active] {
650
633
  color: var(--nf-accent);
651
634
  font-weight: 600;
652
- background: var(--nf-accent-soft);
653
- }
654
-
655
- .navTab[data-active]::before {
656
- content: '';
657
- position: absolute;
658
- left: -8px;
659
- top: 20%;
660
- bottom: 20%;
661
- width: 3px;
662
- border-radius: 999px;
663
- background: var(--nf-accent);
635
+ background: color-mix(in srgb, var(--nf-text) 8%, transparent);
636
+ border-color: color-mix(in srgb, var(--nf-text) 16%, transparent);
637
+ box-shadow: inset 0 1px 0 color-mix(in srgb, var(--nf-text) 6%, transparent);
664
638
  }
665
639
 
666
- .panelNavCollapsed .navTab[data-active]::before {
667
- left: -6px;
640
+ .navTab[data-active] .navTabIcon {
641
+ color: var(--nf-accent);
668
642
  }
669
643
 
670
644
  .navTabIcon {
671
645
  flex: none;
672
- font-size: 15px;
646
+ width: 20px;
647
+ text-align: center;
648
+ font-size: 16px;
673
649
  line-height: 1;
674
650
  }
675
651
 
@@ -678,43 +654,183 @@ body[data-ds-dark-theme] .panel[data-nf-theme='neumorph'] .buttonPrimary {
678
654
  text-overflow: ellipsis;
679
655
  }
680
656
 
681
- /* 顶栏副标题行:书名 + 进度摘要(iOS 大标题下方副标题) */
682
- .panelSubtitle {
657
+ /* demo 风格:侧栏标题区(Logo + 小说工坊 + 当前书名) */
658
+ .navTitle {
683
659
  display: flex;
684
660
  align-items: center;
685
- gap: 8px;
686
- font-size: 12px;
687
- color: var(--nf-text-2);
688
- padding: 0 4px 2px;
661
+ gap: 10px;
662
+ padding: 2px 6px 12px;
663
+ border-bottom: 1px solid var(--nf-border);
664
+ margin-bottom: 6px;
665
+ flex: none;
689
666
  min-width: 0;
690
- flex-wrap: wrap;
667
+ }
668
+
669
+ .navTitleLogo {
670
+ width: 34px;
671
+ height: 34px;
672
+ border-radius: 10px;
673
+ background: linear-gradient(145deg, var(--nf-accent), var(--nf-accent-hover));
674
+ color: var(--nf-accent-fg);
675
+ font-weight: 800;
676
+ font-size: 15px;
677
+ display: flex;
678
+ align-items: center;
679
+ justify-content: center;
680
+ flex: none;
681
+ box-shadow: 0 6px 16px var(--nf-accent-soft);
682
+ }
683
+
684
+ .navTitleName {
685
+ font-weight: 700;
686
+ font-size: 15px;
687
+ letter-spacing: 0.2px;
688
+ white-space: nowrap;
689
+ overflow: hidden;
690
+ text-overflow: ellipsis;
691
+ }
692
+
693
+ .navTitleBook {
694
+ font-size: 11px;
695
+ color: var(--nf-text-3);
691
696
  white-space: nowrap;
697
+ overflow: hidden;
698
+ text-overflow: ellipsis;
692
699
  }
693
700
 
694
- .headerProgress {
695
- font-size: 12px;
696
- font-weight: 400;
701
+ .panelNavCollapsed .navTitle {
702
+ justify-content: center;
703
+ padding: 2px 0 10px;
704
+ }
705
+
706
+ .panelNavCollapsed .navTitleLogo {
707
+ width: 32px;
708
+ height: 32px;
709
+ }
710
+
711
+ /* 操作行:收起导航 / 关闭面板 */
712
+ .navActions {
713
+ flex: none;
714
+ display: flex;
715
+ gap: 6px;
716
+ margin-top: 8px;
717
+ padding-top: 8px;
718
+ border-top: 1px solid var(--nf-border);
719
+ }
720
+
721
+ .navActionBtn {
722
+ flex: 1;
723
+ border: 1px solid var(--nf-border);
724
+ background: rgba(0, 0, 0, 0);
697
725
  color: var(--nf-text-2);
726
+ cursor: pointer;
727
+ border-radius: 10px;
728
+ height: 32px;
729
+ font-size: 14px;
730
+ line-height: 1;
698
731
  display: inline-flex;
699
732
  align-items: center;
700
- gap: 6px;
701
- margin-left: 0;
702
- white-space: nowrap;
733
+ justify-content: center;
734
+ transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
703
735
  }
704
736
 
705
- .headerProgress b {
706
- color: var(--nf-accent);
737
+ .navActionBtn:hover {
738
+ background: var(--nf-hover);
739
+ color: var(--nf-text);
740
+ border-color: var(--nf-border-strong);
741
+ }
742
+
743
+ .panelNavCollapsed .navActions {
744
+ flex-direction: column;
745
+ align-items: stretch;
746
+ }
747
+
748
+ /* demo 风格:底部当前书切换卡(封面首字 + 书名/进度 + 箭头) */
749
+ .bookSwitch {
750
+ flex: none;
751
+ display: flex;
752
+ align-items: center;
753
+ gap: 8px;
754
+ margin-top: 4px;
755
+ padding: 9px;
756
+ border-radius: 12px;
757
+ background: var(--nf-bg-inset);
758
+ border: 1px solid var(--nf-border);
759
+ cursor: pointer;
760
+ text-align: left;
761
+ font: inherit;
762
+ color: var(--nf-text);
763
+ min-width: 0;
764
+ transition: background 0.15s ease, border-color 0.15s ease;
765
+ }
766
+
767
+ .bookSwitch:hover {
768
+ background: var(--nf-hover);
769
+ border-color: var(--nf-border-strong);
770
+ }
771
+
772
+ .bookSwitchCover {
773
+ width: 26px;
774
+ height: 34px;
775
+ border-radius: 5px;
776
+ background: linear-gradient(160deg, var(--nf-accent), color-mix(in srgb, var(--nf-accent) 45%, #000));
777
+ color: var(--nf-accent-fg);
778
+ display: flex;
779
+ align-items: center;
780
+ justify-content: center;
781
+ font-size: 11px;
707
782
  font-weight: 700;
783
+ flex: none;
708
784
  }
709
785
 
710
- .headerProgressDot {
711
- width: 3px;
712
- height: 3px;
713
- border-radius: 50%;
714
- background: var(--nf-border-strong, var(--nf-text-3));
715
- display: inline-block;
786
+ .bookSwitchName {
787
+ font-size: 12.5px;
788
+ font-weight: 600;
789
+ overflow: hidden;
790
+ text-overflow: ellipsis;
791
+ white-space: nowrap;
716
792
  }
717
793
 
794
+ .bookSwitchMeta {
795
+ font-size: 11px;
796
+ color: var(--nf-text-3);
797
+ overflow: hidden;
798
+ text-overflow: ellipsis;
799
+ white-space: nowrap;
800
+ }
801
+
802
+ .bookSwitchArrow {
803
+ margin-left: auto;
804
+ color: var(--nf-text-3);
805
+ font-size: 12px;
806
+ flex: none;
807
+ }
808
+
809
+ /* demo 风格统计卡(今日待写 / 写作中 / 已通过 / 待审稿) */
810
+ .statRowD { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px; }
811
+ .statCardD { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; padding: 14px 16px; border-radius: 16px; background: var(--nf-bg-inset); border: 1px solid var(--nf-border); min-width: 0; }
812
+ .statCardDLabel { font-size: 12px; color: var(--nf-text-3); }
813
+ .statCardDValue { font-size: 22px; font-weight: 700; margin-top: 2px; color: var(--nf-text); }
814
+ .statCardDUnit { font-size: 12px; color: var(--nf-text-3); font-weight: 400; }
815
+ .statCardDDetail { font-size: 11.5px; color: var(--nf-text-3); margin-top: 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
816
+ .statCardDDown { color: var(--nf-error); }
817
+ .statCardDIcon { width: 38px; height: 38px; border-radius: 12px; display: flex; align-items: center; justify-content: center; font-size: 18px; flex: none; background: var(--nf-accent-soft); }
818
+ .statCardDIconRed { background: color-mix(in srgb, var(--nf-error) 13%, transparent); }
819
+
820
+ /* demo 风格创作时间线(6 阶段分段条,点击跳转对应 tab) */
821
+ .tlBar { display: flex; gap: 6px; margin-top: 8px; }
822
+ .tlSeg { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 4px; border: none; background: transparent; padding: 0; cursor: pointer; font: inherit; }
823
+ .tlSegTrack { height: 8px; border-radius: 999px; background: var(--nf-hover); border: 1px solid var(--nf-border); overflow: hidden; }
824
+ .tlSegFill { display: block; height: 100%; width: 100%; border-radius: 999px; background: var(--nf-accent); }
825
+ .tlSegTodo .tlSegFill { opacity: 0; }
826
+ .tlSegTodo .tlSegTrack { background: transparent; }
827
+ .tlSegCurrent .tlSegTrack { border-color: var(--nf-accent); box-shadow: 0 0 0 2px var(--nf-accent-soft); }
828
+ .tlSegCurrent .tlSegFill { opacity: 0.45; }
829
+ .tlSegLabel { font-size: 10.5px; color: var(--nf-text-3); text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
830
+ .tlSegDone .tlSegLabel { color: var(--nf-accent); font-weight: 600; }
831
+ .tlSeg:hover .tlSegTrack { border-color: var(--nf-border-strong); }
832
+
833
+
718
834
  /* ------------------------------------------------------------ cards */
719
835
 
720
836
  .card {
@@ -1592,8 +1708,16 @@ body[data-ds-dark-theme] .panel[data-nf-theme='neumorph'] .buttonPrimary {
1592
1708
  display: flex;
1593
1709
  flex-direction: column;
1594
1710
  gap: 4px;
1595
- background: var(--nf-glass-inset);
1596
- box-shadow: inset 0 1px 0 var(--nf-glass-sheen);
1711
+ background: var(--nf-glass-face);
1712
+ box-shadow: var(--nf-card-shadow), inset 0 1px 0 var(--nf-glass-sheen);
1713
+ -webkit-backdrop-filter: blur(30px) saturate(180%);
1714
+ backdrop-filter: blur(30px) saturate(180%);
1715
+ transition: transform 0.22s ease, box-shadow 0.22s ease;
1716
+ }
1717
+
1718
+ .assetStat:hover {
1719
+ transform: translateY(-3px);
1720
+ box-shadow: var(--nf-card-shadow-hover), inset 0 1px 0 var(--nf-glass-sheen);
1597
1721
  }
1598
1722
 
1599
1723
  .assetStatLabel {
@@ -0,0 +1,67 @@
1
+ /** 漫画风格预设:每个预设对应一组出图提示词与排版偏好。 */
2
+
3
+ export interface ComicStylePreset {
4
+ id: string
5
+ label: string
6
+ /** 注入 imagePrompt 的风格描述词。 */
7
+ prompt: string
8
+ /** 可选:排版偏好说明。 */
9
+ layoutHint?: string
10
+ }
11
+
12
+ export const COMIC_STYLE_PRESETS: ComicStylePreset[] = [
13
+ {
14
+ id: 'japan',
15
+ label: '日漫 / 黑白',
16
+ prompt: 'manga style, screentone, bold ink lines, high contrast, black and white, cel shading',
17
+ layoutHint: '页漫优先',
18
+ },
19
+ {
20
+ id: 'korea',
21
+ label: '韩漫 / 条漫',
22
+ prompt: 'manhwa style, soft cel shading, vibrant colors, clean lineart, webtoon vertical composition, glossy highlights',
23
+ layoutHint: '条漫优先',
24
+ },
25
+ {
26
+ id: 'china',
27
+ label: '国漫 / 古风',
28
+ prompt: 'chinese ink painting style, flowing brush strokes, traditional palette, ethereal atmosphere, xianxia aesthetic',
29
+ layoutHint: '页漫/条漫均可',
30
+ },
31
+ {
32
+ id: 'america',
33
+ label: '美漫 / 超级英雄',
34
+ prompt: 'american comic style, bold outlines, dramatic lighting, dynamic poses, vibrant colors, halftone shading',
35
+ layoutHint: '页漫优先',
36
+ },
37
+ {
38
+ id: 'chibi',
39
+ label: 'Q版 / 搞笑',
40
+ prompt: 'chibi style, cute proportions, big head, exaggerated expressions, simple background, bright colors',
41
+ layoutHint: '条漫/四格优先',
42
+ },
43
+ {
44
+ id: 'realistic',
45
+ label: '写实 / 电影感',
46
+ prompt: 'realistic cinematic style, detailed textures, natural lighting, film grain, high detail',
47
+ layoutHint: '页漫/全彩',
48
+ },
49
+ {
50
+ id: 'cyber',
51
+ label: '赛博 / 暗黑',
52
+ prompt: 'cyberpunk style, neon lights, dark atmosphere, high contrast, futuristic city, cool tones',
53
+ layoutHint: '页漫/全彩',
54
+ },
55
+ ]
56
+
57
+ export function getComicStylePrompt(styleId?: string): string {
58
+ if (!styleId) return ''
59
+ const preset = COMIC_STYLE_PRESETS.find(s => s.id === styleId)
60
+ return preset?.prompt ?? ''
61
+ }
62
+
63
+ export function getComicStyleLabel(styleId?: string): string {
64
+ if (!styleId) return ''
65
+ const preset = COMIC_STYLE_PRESETS.find(s => s.id === styleId)
66
+ return preset?.label ?? styleId
67
+ }