docnest 0.1.13 → 0.1.15
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/package.json
CHANGED
|
@@ -179,13 +179,26 @@ body {
|
|
|
179
179
|
}
|
|
180
180
|
|
|
181
181
|
.doc-pdf-export-root {
|
|
182
|
+
/* PDF pages use a light paper palette, independently of the live reading mode. */
|
|
183
|
+
--linear-bg: #ffffff;
|
|
184
|
+
--linear-bg-subtle: #fafafa;
|
|
185
|
+
--linear-border: #e5e5e5;
|
|
186
|
+
--linear-text: #111111;
|
|
187
|
+
--linear-text-muted: #6b6b6b;
|
|
188
|
+
--linear-accent: #5e6ad2;
|
|
189
|
+
--linear-accent-hover: #4c57b8;
|
|
190
|
+
--doc-surface-raised: #ffffff;
|
|
191
|
+
--doc-rule-strong: #bfc0c5;
|
|
192
|
+
--doc-accent-soft: rgba(94, 106, 210, 0.12);
|
|
193
|
+
--doc-code-bg: #f6f7f8;
|
|
194
|
+
--doc-code-text: #24262b;
|
|
182
195
|
position: absolute;
|
|
183
196
|
left: 0;
|
|
184
197
|
top: 0;
|
|
185
198
|
width: 960px;
|
|
186
199
|
padding: 24px 32px;
|
|
187
|
-
background:
|
|
188
|
-
color:
|
|
200
|
+
background: var(--doc-surface-raised);
|
|
201
|
+
color: var(--linear-text);
|
|
189
202
|
z-index: -1;
|
|
190
203
|
pointer-events: none;
|
|
191
204
|
overflow: visible;
|
|
@@ -522,6 +535,7 @@ body[data-theme="dark"] .dir-toggle.active {
|
|
|
522
535
|
/* 主内容区 - 白底、留白 */
|
|
523
536
|
.main-content {
|
|
524
537
|
flex: 1;
|
|
538
|
+
min-width: 0;
|
|
525
539
|
overflow-y: auto;
|
|
526
540
|
overflow-x: hidden;
|
|
527
541
|
padding: 2rem 2.5rem;
|
|
@@ -535,6 +549,7 @@ body[data-theme="dark"] .dir-toggle.active {
|
|
|
535
549
|
align-items: flex-start;
|
|
536
550
|
gap: 24px;
|
|
537
551
|
width: min(1400px, 100%);
|
|
552
|
+
min-width: 0;
|
|
538
553
|
margin: 0 auto;
|
|
539
554
|
}
|
|
540
555
|
|
|
@@ -1032,7 +1047,8 @@ body[data-theme="dark"] .dir-toggle.active {
|
|
|
1032
1047
|
/* Markdown 内容 - 限宽、舒适行距;普通显示器上更宽,超宽屏用 92% 避免单行过长 */
|
|
1033
1048
|
.markdown-body {
|
|
1034
1049
|
flex: 1;
|
|
1035
|
-
width:
|
|
1050
|
+
min-width: 0;
|
|
1051
|
+
width: min(var(--doc-reading-width, 1024px), 100%);
|
|
1036
1052
|
max-width: 100%;
|
|
1037
1053
|
margin: 0;
|
|
1038
1054
|
box-sizing: border-box;
|
|
@@ -1050,7 +1066,7 @@ body[data-theme="dark"] .dir-toggle.active {
|
|
|
1050
1066
|
}
|
|
1051
1067
|
|
|
1052
1068
|
.doc-layout {
|
|
1053
|
-
width: min(1024px, 100%);
|
|
1069
|
+
width: min(var(--doc-reading-width, 1024px), 100%);
|
|
1054
1070
|
}
|
|
1055
1071
|
}
|
|
1056
1072
|
|
|
@@ -1254,6 +1270,9 @@ body[data-theme="dark"] .not-found-path {
|
|
|
1254
1270
|
text-align: center;
|
|
1255
1271
|
background: var(--linear-bg-subtle);
|
|
1256
1272
|
padding: 16px;
|
|
1273
|
+
min-width: 0;
|
|
1274
|
+
max-width: 100%;
|
|
1275
|
+
box-sizing: border-box;
|
|
1257
1276
|
border-radius: var(--linear-radius);
|
|
1258
1277
|
border: 1px solid var(--linear-border);
|
|
1259
1278
|
overflow-x: auto;
|
|
@@ -1301,9 +1320,12 @@ body[data-theme="dark"] .markdown-body .mermaid::after {
|
|
|
1301
1320
|
|
|
1302
1321
|
/* 确保 Mermaid SVG 正确显示 */
|
|
1303
1322
|
.markdown-body .mermaid svg {
|
|
1304
|
-
|
|
1305
|
-
|
|
1323
|
+
width: 100% !important;
|
|
1324
|
+
max-width: 100% !important;
|
|
1325
|
+
min-width: 0 !important;
|
|
1326
|
+
height: auto !important;
|
|
1306
1327
|
display: block;
|
|
1328
|
+
margin: 0 auto;
|
|
1307
1329
|
}
|
|
1308
1330
|
|
|
1309
1331
|
/* Mermaid 下载按钮 */
|
|
@@ -2079,7 +2101,7 @@ body[data-theme="dark"] .tree-nav::-webkit-scrollbar-thumb:hover {
|
|
|
2079
2101
|
.markdown-body .mermaid svg {
|
|
2080
2102
|
max-width: 100% !important;
|
|
2081
2103
|
max-height: 75vh !important; /* 高流程图缩放到单页内 */
|
|
2082
|
-
width:
|
|
2104
|
+
width: 100% !important;
|
|
2083
2105
|
height: auto !important;
|
|
2084
2106
|
display: block !important;
|
|
2085
2107
|
margin: 0 auto !important;
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
* DocNest theme profiles
|
|
3
3
|
*
|
|
4
4
|
* One semantic DOM, five visual systems. The original DocNest rules remain
|
|
5
|
-
* the Slate Modern baseline
|
|
6
|
-
*
|
|
5
|
+
* the Slate Modern baseline for page geometry (main-content padding,
|
|
6
|
+
* doc-layout max-width/gap, markdown reading width). This file owns theme
|
|
7
|
+
* tokens and visual character without forking templates or client behavior.
|
|
7
8
|
*/
|
|
8
9
|
|
|
9
10
|
:root {
|
|
@@ -19,6 +20,7 @@
|
|
|
19
20
|
--doc-code-bg: #f6f7f8;
|
|
20
21
|
--doc-code-text: #24262b;
|
|
21
22
|
--doc-header-height: auto;
|
|
23
|
+
/* Shared with Slate Modern; theme profiles must not override page geometry. */
|
|
22
24
|
--doc-reading-width: 1024px;
|
|
23
25
|
}
|
|
24
26
|
|
|
@@ -377,7 +379,8 @@ body[data-doc-theme][data-theme="dark"] .pdf-export-modal__btn {
|
|
|
377
379
|
}
|
|
378
380
|
|
|
379
381
|
/* Theme 01: Slate Modern — the package's original visual language. */
|
|
380
|
-
body[data-doc-theme="slate-modern"]
|
|
382
|
+
body[data-doc-theme="slate-modern"],
|
|
383
|
+
.doc-pdf-export-root[data-doc-theme="slate-modern"] {
|
|
381
384
|
--doc-font-ui: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC",
|
|
382
385
|
"Hiragino Sans GB", "Microsoft YaHei", sans-serif;
|
|
383
386
|
--doc-font-reading: var(--doc-font-ui);
|
|
@@ -385,7 +388,8 @@ body[data-doc-theme="slate-modern"] {
|
|
|
385
388
|
}
|
|
386
389
|
|
|
387
390
|
/* Theme 02: Editorial Atlas */
|
|
388
|
-
body[data-doc-theme="editorial-atlas"]
|
|
391
|
+
body[data-doc-theme="editorial-atlas"],
|
|
392
|
+
.doc-pdf-export-root[data-doc-theme="editorial-atlas"] {
|
|
389
393
|
--linear-bg: #f3f0e7;
|
|
390
394
|
--linear-bg-subtle: #ebe6da;
|
|
391
395
|
--linear-sidebar: #eee9dd;
|
|
@@ -405,7 +409,6 @@ body[data-doc-theme="editorial-atlas"] {
|
|
|
405
409
|
"Microsoft YaHei", sans-serif;
|
|
406
410
|
--doc-font-reading: "Songti SC", SimSun, "Noto Serif CJK SC", serif;
|
|
407
411
|
--doc-font-display: "Songti SC", SimSun, "Noto Serif CJK SC", serif;
|
|
408
|
-
--doc-reading-width: 860px;
|
|
409
412
|
}
|
|
410
413
|
|
|
411
414
|
body[data-doc-theme="editorial-atlas"][data-theme="dark"] {
|
|
@@ -452,18 +455,7 @@ body[data-doc-theme="editorial-atlas"] .sidebar {
|
|
|
452
455
|
border-right-color: var(--doc-rule-strong);
|
|
453
456
|
}
|
|
454
457
|
|
|
455
|
-
body[data-doc-theme="editorial-atlas"] .main-content {
|
|
456
|
-
padding: clamp(2rem, 4vw, 4.75rem) clamp(1.5rem, 5vw, 5.5rem);
|
|
457
|
-
background: var(--linear-bg);
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
body[data-doc-theme="editorial-atlas"] .doc-layout {
|
|
461
|
-
width: min(1240px, 100%);
|
|
462
|
-
gap: 42px;
|
|
463
|
-
}
|
|
464
|
-
|
|
465
458
|
body[data-doc-theme="editorial-atlas"] .markdown-body {
|
|
466
|
-
width: min(var(--doc-reading-width), 100%);
|
|
467
459
|
background: transparent;
|
|
468
460
|
font-size: 1rem;
|
|
469
461
|
line-height: 1.9;
|
|
@@ -500,7 +492,8 @@ body[data-doc-theme="editorial-atlas"] .doc-toc {
|
|
|
500
492
|
}
|
|
501
493
|
|
|
502
494
|
/* Theme 03: Precision Index */
|
|
503
|
-
body[data-doc-theme="precision-index"]
|
|
495
|
+
body[data-doc-theme="precision-index"],
|
|
496
|
+
.doc-pdf-export-root[data-doc-theme="precision-index"] {
|
|
504
497
|
--linear-bg: #eef2f3;
|
|
505
498
|
--linear-bg-subtle: #e4eaec;
|
|
506
499
|
--linear-sidebar: #e9eef0;
|
|
@@ -520,7 +513,6 @@ body[data-doc-theme="precision-index"] {
|
|
|
520
513
|
"Microsoft YaHei", sans-serif;
|
|
521
514
|
--doc-font-reading: var(--doc-font-ui);
|
|
522
515
|
--doc-font-display: var(--doc-font-ui);
|
|
523
|
-
--doc-reading-width: 980px;
|
|
524
516
|
}
|
|
525
517
|
|
|
526
518
|
body[data-doc-theme="precision-index"][data-theme="dark"] {
|
|
@@ -597,28 +589,17 @@ body[data-doc-theme="precision-index"] .file-link.active {
|
|
|
597
589
|
background: var(--doc-surface-raised);
|
|
598
590
|
}
|
|
599
591
|
|
|
600
|
-
body[data-doc-theme="precision-index"] .main-content {
|
|
601
|
-
padding: 0;
|
|
602
|
-
background: var(--linear-bg);
|
|
603
|
-
}
|
|
604
|
-
|
|
605
592
|
body[data-doc-theme="precision-index"] .breadcrumbs {
|
|
606
|
-
margin: 0;
|
|
607
|
-
padding: 0.75rem 1.5rem;
|
|
608
593
|
border-bottom: 1px solid var(--doc-rule-strong);
|
|
609
594
|
background: var(--linear-bg-subtle);
|
|
610
595
|
font-size: 0.6875rem;
|
|
611
596
|
}
|
|
612
597
|
|
|
613
598
|
body[data-doc-theme="precision-index"] .doc-layout {
|
|
614
|
-
width: 100%;
|
|
615
|
-
gap: 0;
|
|
616
599
|
background: var(--doc-surface-raised);
|
|
617
600
|
}
|
|
618
601
|
|
|
619
602
|
body[data-doc-theme="precision-index"] .markdown-body {
|
|
620
|
-
width: min(var(--doc-reading-width), 100%);
|
|
621
|
-
padding: clamp(2.5rem, 5vw, 5rem);
|
|
622
603
|
border-right: 1px solid var(--doc-rule-strong);
|
|
623
604
|
font-size: 0.9rem;
|
|
624
605
|
line-height: 1.75;
|
|
@@ -651,11 +632,6 @@ body[data-doc-theme="precision-index"] .markdown-body h2 {
|
|
|
651
632
|
}
|
|
652
633
|
|
|
653
634
|
body[data-doc-theme="precision-index"] .doc-toc {
|
|
654
|
-
top: 0;
|
|
655
|
-
width: 216px;
|
|
656
|
-
flex-basis: 216px;
|
|
657
|
-
max-height: calc(100vh - 54px);
|
|
658
|
-
padding: 1.25rem;
|
|
659
635
|
border: 0;
|
|
660
636
|
border-radius: 0;
|
|
661
637
|
background: var(--linear-bg-subtle);
|
|
@@ -666,14 +642,9 @@ body[data-doc-theme="precision-index"] .doc-toc-title {
|
|
|
666
642
|
text-transform: uppercase;
|
|
667
643
|
}
|
|
668
644
|
|
|
669
|
-
body[data-doc-theme="precision-index"] .dir-listing-page,
|
|
670
|
-
body[data-doc-theme="precision-index"] .welcome {
|
|
671
|
-
margin: 0;
|
|
672
|
-
padding: clamp(2rem, 5vw, 5rem);
|
|
673
|
-
}
|
|
674
|
-
|
|
675
645
|
/* Theme 04: Archive Room */
|
|
676
|
-
body[data-doc-theme="archive-room"]
|
|
646
|
+
body[data-doc-theme="archive-room"],
|
|
647
|
+
.doc-pdf-export-root[data-doc-theme="archive-room"] {
|
|
677
648
|
--linear-bg: #f3efe4;
|
|
678
649
|
--linear-bg-subtle: #e9e2d3;
|
|
679
650
|
--linear-sidebar: #ebe5d8;
|
|
@@ -693,7 +664,6 @@ body[data-doc-theme="archive-room"] {
|
|
|
693
664
|
"Microsoft YaHei", sans-serif;
|
|
694
665
|
--doc-font-reading: "Songti SC", SimSun, "Noto Serif CJK SC", serif;
|
|
695
666
|
--doc-font-display: "Songti SC", SimSun, "Noto Serif CJK SC", serif;
|
|
696
|
-
--doc-reading-width: 900px;
|
|
697
667
|
}
|
|
698
668
|
|
|
699
669
|
body[data-doc-theme="archive-room"][data-theme="dark"] {
|
|
@@ -761,7 +731,6 @@ body[data-doc-theme="archive-room"][data-theme="dark"] .file-link.active {
|
|
|
761
731
|
}
|
|
762
732
|
|
|
763
733
|
body[data-doc-theme="archive-room"] .main-content {
|
|
764
|
-
padding: clamp(2rem, 4vw, 4.5rem);
|
|
765
734
|
background-color: var(--linear-bg);
|
|
766
735
|
background-image:
|
|
767
736
|
linear-gradient(rgba(93, 96, 85, 0.045) 1px, transparent 1px),
|
|
@@ -769,14 +738,8 @@ body[data-doc-theme="archive-room"] .main-content {
|
|
|
769
738
|
background-size: 24px 24px;
|
|
770
739
|
}
|
|
771
740
|
|
|
772
|
-
body[data-doc-theme="archive-room"] .doc-layout {
|
|
773
|
-
width: min(1280px, 100%);
|
|
774
|
-
gap: 34px;
|
|
775
|
-
}
|
|
776
|
-
|
|
777
741
|
body[data-doc-theme="archive-room"] .markdown-body {
|
|
778
|
-
|
|
779
|
-
padding: clamp(1.5rem, 3vw, 3rem);
|
|
742
|
+
padding: 1.5rem 1.5rem 3rem;
|
|
780
743
|
border: 1px solid var(--doc-rule-strong);
|
|
781
744
|
background: var(--doc-surface-raised);
|
|
782
745
|
box-shadow: 7px 7px 0 var(--linear-border);
|
|
@@ -816,7 +779,8 @@ body[data-doc-theme="archive-room"] .doc-toc {
|
|
|
816
779
|
}
|
|
817
780
|
|
|
818
781
|
/* Theme 05: Swiss Manual */
|
|
819
|
-
body[data-doc-theme="swiss-manual"]
|
|
782
|
+
body[data-doc-theme="swiss-manual"],
|
|
783
|
+
.doc-pdf-export-root[data-doc-theme="swiss-manual"] {
|
|
820
784
|
--linear-bg: #f4f3ef;
|
|
821
785
|
--linear-bg-subtle: #e9e7e0;
|
|
822
786
|
--linear-sidebar: #eeece6;
|
|
@@ -836,7 +800,6 @@ body[data-doc-theme="swiss-manual"] {
|
|
|
836
800
|
"Microsoft YaHei", sans-serif;
|
|
837
801
|
--doc-font-reading: var(--doc-font-ui);
|
|
838
802
|
--doc-font-display: var(--doc-font-ui);
|
|
839
|
-
--doc-reading-width: 960px;
|
|
840
803
|
}
|
|
841
804
|
|
|
842
805
|
body[data-doc-theme="swiss-manual"][data-theme="dark"] {
|
|
@@ -939,27 +902,13 @@ body[data-doc-theme="swiss-manual"] .file-link.active {
|
|
|
939
902
|
font-weight: 800;
|
|
940
903
|
}
|
|
941
904
|
|
|
942
|
-
body[data-doc-theme="swiss-manual"] .main-content {
|
|
943
|
-
padding: 0;
|
|
944
|
-
background: var(--doc-surface-raised);
|
|
945
|
-
}
|
|
946
|
-
|
|
947
905
|
body[data-doc-theme="swiss-manual"] .breadcrumbs {
|
|
948
|
-
margin: 0;
|
|
949
|
-
padding: 0.85rem 1.5rem;
|
|
950
906
|
border-bottom: 1px solid var(--doc-rule-strong);
|
|
951
907
|
background: var(--linear-bg-subtle);
|
|
952
908
|
font-size: 0.65rem;
|
|
953
909
|
}
|
|
954
910
|
|
|
955
|
-
body[data-doc-theme="swiss-manual"] .doc-layout {
|
|
956
|
-
width: 100%;
|
|
957
|
-
gap: 0;
|
|
958
|
-
}
|
|
959
|
-
|
|
960
911
|
body[data-doc-theme="swiss-manual"] .markdown-body {
|
|
961
|
-
width: min(var(--doc-reading-width), 100%);
|
|
962
|
-
padding: clamp(2.5rem, 6vw, 6rem);
|
|
963
912
|
border-right: 1px solid var(--doc-rule-strong);
|
|
964
913
|
font-size: 0.95rem;
|
|
965
914
|
line-height: 1.72;
|
|
@@ -1000,22 +949,11 @@ body[data-doc-theme="swiss-manual"] .markdown-body blockquote {
|
|
|
1000
949
|
}
|
|
1001
950
|
|
|
1002
951
|
body[data-doc-theme="swiss-manual"] .doc-toc {
|
|
1003
|
-
top: 0;
|
|
1004
|
-
width: 220px;
|
|
1005
|
-
flex-basis: 220px;
|
|
1006
|
-
max-height: calc(100vh - 72px);
|
|
1007
|
-
padding: 1.25rem;
|
|
1008
952
|
border: 0;
|
|
1009
953
|
border-radius: 0;
|
|
1010
954
|
background: var(--linear-bg-subtle);
|
|
1011
955
|
}
|
|
1012
956
|
|
|
1013
|
-
body[data-doc-theme="swiss-manual"] .dir-listing-page,
|
|
1014
|
-
body[data-doc-theme="swiss-manual"] .welcome {
|
|
1015
|
-
margin: 0;
|
|
1016
|
-
padding: clamp(2rem, 6vw, 6rem);
|
|
1017
|
-
}
|
|
1018
|
-
|
|
1019
957
|
/* Shared component refinements for the four independent profiles. */
|
|
1020
958
|
body:not([data-doc-theme="slate-modern"]) .markdown-body code:not(pre code) {
|
|
1021
959
|
border: 1px solid var(--linear-border);
|
|
@@ -1206,26 +1144,11 @@ body[data-doc-theme="swiss-manual"].not-found-page .deep-space-404__code {
|
|
|
1206
1144
|
overflow-y: auto;
|
|
1207
1145
|
}
|
|
1208
1146
|
|
|
1209
|
-
body[data-doc-theme="editorial-atlas"] .main-content,
|
|
1210
|
-
body[data-doc-theme="archive-room"] .main-content {
|
|
1211
|
-
padding: 1.25rem;
|
|
1212
|
-
}
|
|
1213
|
-
|
|
1214
1147
|
body[data-doc-theme="archive-room"] .markdown-body {
|
|
1215
1148
|
padding: 1.25rem;
|
|
1216
1149
|
box-shadow: 4px 4px 0 var(--linear-border);
|
|
1217
1150
|
}
|
|
1218
1151
|
|
|
1219
|
-
body[data-doc-theme="precision-index"] .main-content,
|
|
1220
|
-
body[data-doc-theme="swiss-manual"] .main-content {
|
|
1221
|
-
padding: 0;
|
|
1222
|
-
}
|
|
1223
|
-
|
|
1224
|
-
body[data-doc-theme="precision-index"] .markdown-body,
|
|
1225
|
-
body[data-doc-theme="swiss-manual"] .markdown-body {
|
|
1226
|
-
padding: 1.25rem;
|
|
1227
|
-
}
|
|
1228
|
-
|
|
1229
1152
|
body[data-doc-theme="precision-index"] .markdown-body h1,
|
|
1230
1153
|
body[data-doc-theme="swiss-manual"] .markdown-body h1 {
|
|
1231
1154
|
font-size: clamp(2rem, 12vw, 3.25rem);
|
|
@@ -93,9 +93,40 @@
|
|
|
93
93
|
function createExportRoot(article) {
|
|
94
94
|
var root = document.createElement('div');
|
|
95
95
|
root.className = EXPORT_CLASS;
|
|
96
|
+
root.setAttribute('data-doc-theme', document.body.getAttribute('data-doc-theme') || 'slate-modern');
|
|
97
|
+
root.setAttribute('data-theme', 'light');
|
|
96
98
|
|
|
97
99
|
var clone = article.cloneNode(true);
|
|
98
100
|
removeTransientNodes(clone);
|
|
101
|
+
// html2canvas may paint closed <details> descendants without reserving their
|
|
102
|
+
// height. Export static, expanded sections while leaving the live page alone.
|
|
103
|
+
Array.prototype.slice.call(clone.querySelectorAll('details')).reverse().forEach(function(details) {
|
|
104
|
+
var section = document.createElement('section');
|
|
105
|
+
Array.prototype.slice.call(details.attributes).forEach(function(attribute) {
|
|
106
|
+
if (attribute.name !== 'open') section.setAttribute(attribute.name, attribute.value);
|
|
107
|
+
});
|
|
108
|
+
section.style.display = 'block';
|
|
109
|
+
section.style.height = 'auto';
|
|
110
|
+
section.style.maxHeight = 'none';
|
|
111
|
+
section.style.overflow = 'visible';
|
|
112
|
+
section.style.margin = '1em 0';
|
|
113
|
+
while (details.firstChild) {
|
|
114
|
+
var child = details.firstChild;
|
|
115
|
+
if (child.tagName === 'SUMMARY') {
|
|
116
|
+
var heading = document.createElement('div');
|
|
117
|
+
heading.className = 'doc-pdf-section-title';
|
|
118
|
+
heading.style.fontWeight = '700';
|
|
119
|
+
heading.style.marginBottom = '12px';
|
|
120
|
+
while (child.firstChild) heading.appendChild(child.firstChild);
|
|
121
|
+
section.appendChild(heading);
|
|
122
|
+
details.removeChild(child);
|
|
123
|
+
} else {
|
|
124
|
+
section.appendChild(child);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
details.parentNode.replaceChild(section, details);
|
|
128
|
+
});
|
|
129
|
+
clone.querySelectorAll('img').forEach(function(img) { img.loading = 'eager'; });
|
|
99
130
|
root.appendChild(clone);
|
|
100
131
|
document.body.appendChild(root);
|
|
101
132
|
|
|
@@ -137,18 +168,60 @@
|
|
|
137
168
|
return breakpoints;
|
|
138
169
|
}
|
|
139
170
|
|
|
171
|
+
function collectProtectedRegions(root, canvasScale) {
|
|
172
|
+
var rootRect = root.getBoundingClientRect();
|
|
173
|
+
var regions = [];
|
|
174
|
+
root.querySelectorAll('img, svg, canvas, figure, .mermaid').forEach(function(node) {
|
|
175
|
+
var rect = node.getBoundingClientRect();
|
|
176
|
+
if (rect.width <= 0 || rect.height <= 0) return;
|
|
177
|
+
regions.push({
|
|
178
|
+
top: Math.max(0, Math.floor((rect.top - rootRect.top) * canvasScale)),
|
|
179
|
+
bottom: Math.max(0, Math.ceil((rect.bottom - rootRect.top) * canvasScale)),
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
regions.sort(function(a, b) { return a.top - b.top || b.bottom - a.bottom; });
|
|
183
|
+
var merged = [];
|
|
184
|
+
regions.forEach(function(region) {
|
|
185
|
+
var last = merged[merged.length - 1];
|
|
186
|
+
if (last && region.top < last.bottom) {
|
|
187
|
+
last.bottom = Math.max(last.bottom, region.bottom);
|
|
188
|
+
} else {
|
|
189
|
+
merged.push(region);
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
return merged;
|
|
193
|
+
}
|
|
194
|
+
|
|
140
195
|
function cleanupExportRoot(root) {
|
|
141
196
|
if (root && root.parentNode) {
|
|
142
197
|
root.parentNode.removeChild(root);
|
|
143
198
|
}
|
|
144
199
|
}
|
|
145
200
|
|
|
146
|
-
function waitForExportReady() {
|
|
201
|
+
function waitForExportReady(root) {
|
|
147
202
|
var fontReady = document.fonts && document.fonts.ready
|
|
148
203
|
? document.fonts.ready.catch(function() {})
|
|
149
204
|
: Promise.resolve();
|
|
150
205
|
|
|
151
|
-
|
|
206
|
+
var imagesReady = Promise.all(Array.prototype.map.call(root.querySelectorAll('img'), function(img) {
|
|
207
|
+
if (img.complete) {
|
|
208
|
+
return img.naturalWidth > 0 ? Promise.resolve() : Promise.reject(new Error('文档图片加载失败'));
|
|
209
|
+
}
|
|
210
|
+
return new Promise(function(resolve, reject) {
|
|
211
|
+
var timer = setTimeout(function() { finish(new Error('等待文档图片超时')); }, 15000);
|
|
212
|
+
function finish(error) {
|
|
213
|
+
clearTimeout(timer);
|
|
214
|
+
img.removeEventListener('load', loaded);
|
|
215
|
+
img.removeEventListener('error', failed);
|
|
216
|
+
if (error) reject(error); else resolve();
|
|
217
|
+
}
|
|
218
|
+
function loaded() { finish(); }
|
|
219
|
+
function failed() { finish(new Error('文档图片加载失败')); }
|
|
220
|
+
img.addEventListener('load', loaded, { once: true });
|
|
221
|
+
img.addEventListener('error', failed, { once: true });
|
|
222
|
+
});
|
|
223
|
+
}));
|
|
224
|
+
return Promise.all([fontReady, imagesReady]).then(function() {
|
|
152
225
|
return new Promise(function(resolve) {
|
|
153
226
|
requestAnimationFrame(function() {
|
|
154
227
|
requestAnimationFrame(resolve);
|
|
@@ -169,8 +242,9 @@
|
|
|
169
242
|
logging: false,
|
|
170
243
|
width: width,
|
|
171
244
|
height: height,
|
|
172
|
-
|
|
173
|
-
|
|
245
|
+
// Keep vw/vh styles and media queries identical to the measured DOM.
|
|
246
|
+
windowWidth: window.innerWidth,
|
|
247
|
+
windowHeight: window.innerHeight,
|
|
174
248
|
scrollX: 0,
|
|
175
249
|
scrollY: 0,
|
|
176
250
|
});
|
|
@@ -313,7 +387,7 @@
|
|
|
313
387
|
return Math.max(minBreakY - startY, searchStartY + bestRow - startY);
|
|
314
388
|
}
|
|
315
389
|
|
|
316
|
-
function addCanvasToPdf(pdf, canvas, margin, blockBreakpoints, watermark) {
|
|
390
|
+
function addCanvasToPdf(pdf, canvas, margin, blockBreakpoints, watermark, protectedRegions) {
|
|
317
391
|
var pageWidth = pdf.internal.pageSize.getWidth();
|
|
318
392
|
var pageHeight = pdf.internal.pageSize.getHeight();
|
|
319
393
|
var usableWidth = pageWidth - margin * 2;
|
|
@@ -338,6 +412,16 @@
|
|
|
338
412
|
sliceHeight = findBestPageBreak(canvas, sourceCtx, offsetY, pageCanvasHeight);
|
|
339
413
|
}
|
|
340
414
|
}
|
|
415
|
+
sliceHeight = Math.min(sliceHeight, remainingHeight, pageCanvasHeight);
|
|
416
|
+
var sliceEnd = offsetY + sliceHeight;
|
|
417
|
+
(protectedRegions || []).forEach(function(region) {
|
|
418
|
+
if (region.top < sliceEnd && region.bottom > sliceEnd) {
|
|
419
|
+
// Move a fitting image to the next page even if this leaves whitespace.
|
|
420
|
+
// A taller-than-page image receives one whole, scaled PDF page.
|
|
421
|
+
sliceEnd = region.top > offsetY ? region.top : Math.min(region.bottom, canvas.height);
|
|
422
|
+
}
|
|
423
|
+
});
|
|
424
|
+
sliceHeight = Math.max(1, sliceEnd - offsetY);
|
|
341
425
|
var pageCanvas = document.createElement('canvas');
|
|
342
426
|
pageCanvas.width = canvas.width;
|
|
343
427
|
pageCanvas.height = sliceHeight;
|
|
@@ -362,7 +446,7 @@
|
|
|
362
446
|
context,
|
|
363
447
|
pageCanvas.width,
|
|
364
448
|
pageCanvas.height,
|
|
365
|
-
pageCanvasHeight,
|
|
449
|
+
Math.max(pageCanvasHeight, sliceHeight),
|
|
366
450
|
watermark.text,
|
|
367
451
|
);
|
|
368
452
|
}
|
|
@@ -371,13 +455,14 @@
|
|
|
371
455
|
pdf.addPage();
|
|
372
456
|
}
|
|
373
457
|
|
|
374
|
-
var
|
|
458
|
+
var imageWidth = Math.min(usableWidth, (usableHeight * canvas.width) / sliceHeight);
|
|
459
|
+
var imageHeight = (sliceHeight * imageWidth) / canvas.width;
|
|
375
460
|
pdf.addImage(
|
|
376
461
|
pageCanvas.toDataURL('image/png'),
|
|
377
462
|
'PNG',
|
|
463
|
+
margin + (usableWidth - imageWidth) / 2,
|
|
378
464
|
margin,
|
|
379
|
-
|
|
380
|
-
usableWidth,
|
|
465
|
+
imageWidth,
|
|
381
466
|
imageHeight,
|
|
382
467
|
undefined,
|
|
383
468
|
'FAST'
|
|
@@ -586,13 +671,15 @@
|
|
|
586
671
|
format: 'a4',
|
|
587
672
|
compress: true,
|
|
588
673
|
});
|
|
589
|
-
return waitForExportReady()
|
|
674
|
+
return waitForExportReady(exportRoot)
|
|
590
675
|
.then(function() {
|
|
591
676
|
return renderCanvas(exportRoot);
|
|
592
677
|
})
|
|
593
678
|
.then(function(canvas) {
|
|
594
|
-
var
|
|
595
|
-
|
|
679
|
+
var canvasScale = canvas.height / Math.max(exportRoot.scrollHeight, 1);
|
|
680
|
+
var blockBreakpoints = collectBlockBreakpoints(exportRoot, canvasScale);
|
|
681
|
+
var protectedRegions = collectProtectedRegions(exportRoot, canvasScale);
|
|
682
|
+
addCanvasToPdf(pdf, canvas, margin, blockBreakpoints, watermark, protectedRegions);
|
|
596
683
|
pdf.save(getExportFileName() + '.pdf');
|
|
597
684
|
})
|
|
598
685
|
.finally(function() {
|
|
@@ -8,6 +8,41 @@ function isDocNestRestrictedMode() {
|
|
|
8
8
|
return !!(window.DOCNEST_CONFIG && window.DOCNEST_CONFIG.restrictedMode === true);
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
+
function parseSvgAbsoluteDimension(value) {
|
|
12
|
+
if (typeof value !== 'string' || !/^\s*\d*\.?\d+(?:e[+-]?\d+)?(?:px)?\s*$/i.test(value)) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const dimension = Number.parseFloat(value);
|
|
17
|
+
return Number.isFinite(dimension) && dimension > 0 ? dimension : null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function getDiagramIntrinsicDimensions(svgElement) {
|
|
21
|
+
const viewBox = svgElement.getAttribute('viewBox');
|
|
22
|
+
if (viewBox) {
|
|
23
|
+
const parts = viewBox.trim().split(/[\s,]+/).map(Number);
|
|
24
|
+
const viewBoxWidth = parts[2];
|
|
25
|
+
const viewBoxHeight = parts[3];
|
|
26
|
+
if (
|
|
27
|
+
parts.length === 4 &&
|
|
28
|
+
parts.every(Number.isFinite) &&
|
|
29
|
+
viewBoxWidth > 0 &&
|
|
30
|
+
viewBoxHeight > 0
|
|
31
|
+
) {
|
|
32
|
+
// viewBox 是图表的实际坐标范围,优先于 Mermaid 的 width="100%"。
|
|
33
|
+
return { width: viewBoxWidth, height: viewBoxHeight };
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const width = parseSvgAbsoluteDimension(svgElement.getAttribute('width'));
|
|
38
|
+
const height = parseSvgAbsoluteDimension(svgElement.getAttribute('height'));
|
|
39
|
+
if (width && height) return { width, height };
|
|
40
|
+
if (width) return { width, height: width * 0.75 };
|
|
41
|
+
if (height) return { width: height * (4 / 3), height };
|
|
42
|
+
|
|
43
|
+
return { width: 800, height: 600 };
|
|
44
|
+
}
|
|
45
|
+
|
|
11
46
|
function setupDiagramViewer() {
|
|
12
47
|
if (isDocNestRestrictedMode()) return;
|
|
13
48
|
const diagrams = document.querySelectorAll('.markdown-body .mermaid');
|
|
@@ -49,39 +84,16 @@ function openDiagramViewer(svgElement) {
|
|
|
49
84
|
|
|
50
85
|
if (!viewer || !container) return;
|
|
51
86
|
|
|
52
|
-
//
|
|
53
|
-
|
|
54
|
-
let originalHeight = parseFloat(svgElement.getAttribute('height'));
|
|
55
|
-
|
|
56
|
-
// 如果没有 width/height,尝试从 viewBox 获取
|
|
57
|
-
if (!originalWidth || !originalHeight || isNaN(originalWidth) || isNaN(originalHeight)) {
|
|
58
|
-
const viewBox = svgElement.getAttribute('viewBox');
|
|
59
|
-
if (viewBox) {
|
|
60
|
-
const parts = viewBox.split(/\s+/);
|
|
61
|
-
if (parts.length >= 4) {
|
|
62
|
-
originalWidth = parseFloat(parts[2]) || 800;
|
|
63
|
-
originalHeight = parseFloat(parts[3]) || 600;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// 如果还是没有,使用默认值
|
|
69
|
-
if (!originalWidth || !originalHeight || isNaN(originalWidth) || isNaN(originalHeight)) {
|
|
70
|
-
originalWidth = 800;
|
|
71
|
-
originalHeight = 600;
|
|
72
|
-
}
|
|
87
|
+
// viewBox 才是图表的实际尺寸;不能把 Mermaid 的 width="100%" 解析成 100。
|
|
88
|
+
const { width: originalWidth, height: originalHeight } = getDiagramIntrinsicDimensions(svgElement);
|
|
73
89
|
|
|
74
90
|
// 设置 SVG 样式,确保充分利用空间
|
|
75
91
|
svgElement.setAttribute('class', 'diagram-viewer-svg');
|
|
76
92
|
// 清除之前的样式,但保留必要的属性
|
|
77
93
|
svgElement.removeAttribute('style');
|
|
78
|
-
//
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
}
|
|
82
|
-
if (!svgElement.getAttribute('height')) {
|
|
83
|
-
svgElement.setAttribute('height', originalHeight);
|
|
84
|
-
}
|
|
94
|
+
// 查看器需要固定的像素基准;内嵌图仍然保持响应式,不会被这个克隆影响。
|
|
95
|
+
svgElement.setAttribute('width', originalWidth);
|
|
96
|
+
svgElement.setAttribute('height', originalHeight);
|
|
85
97
|
|
|
86
98
|
// 包装元素本身还包含边界 padding,因此适配比例必须把容器 padding 和图表边界一并算入。
|
|
87
99
|
const padding = 40;
|
|
@@ -205,9 +217,8 @@ function resetDiagramZoom() {
|
|
|
205
217
|
const wrapper = container.querySelector('.diagram-viewer-svg-wrapper');
|
|
206
218
|
if (!wrapper) return;
|
|
207
219
|
|
|
208
|
-
//
|
|
209
|
-
const originalWidth
|
|
210
|
-
const originalHeight = parseFloat(currentSvg.style.height) || parseFloat(currentSvg.getAttribute('height')) || 600;
|
|
220
|
+
// 始终从统一的尺寸解析逻辑获取原始尺寸,避免缩放/重置再次误读百分比宽度。
|
|
221
|
+
const { width: originalWidth, height: originalHeight } = getDiagramIntrinsicDimensions(currentSvg);
|
|
211
222
|
|
|
212
223
|
const padding = 40; // 边界 padding 大小(像素)
|
|
213
224
|
currentZoom = defaultZoom;
|
|
@@ -8,9 +8,8 @@ function zoomDiagram(direction) {
|
|
|
8
8
|
const wrapper = container.querySelector('.diagram-viewer-svg-wrapper');
|
|
9
9
|
if (!wrapper) return;
|
|
10
10
|
|
|
11
|
-
//
|
|
12
|
-
const originalWidth
|
|
13
|
-
const originalHeight = parseFloat(currentSvg.style.height) || parseFloat(currentSvg.getAttribute('height')) || 600;
|
|
11
|
+
// 与查看器使用同一套尺寸解析逻辑,不能把 width="100%" 解析成 100。
|
|
12
|
+
const { width: originalWidth, height: originalHeight } = getDiagramIntrinsicDimensions(currentSvg);
|
|
14
13
|
|
|
15
14
|
// 边界 padding 大小(与 diagram-viewer.js 中保持一致)
|
|
16
15
|
const padding = 40;
|