@docmd/ui 0.5.0 → 0.5.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/README.md +2 -1
- package/assets/css/docmd-main.css +263 -17
- package/assets/js/docmd-main.js +114 -97
- package/package.json +2 -2
- package/templates/layout.ejs +209 -173
- package/templates/partials/menubar.ejs +129 -0
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@ Contains:
|
|
|
7
7
|
- **Assets:** Core CSS and JavaScript.
|
|
8
8
|
- **Icons:** SVG icon sets.
|
|
9
9
|
|
|
10
|
-
## The docmd Ecosystem
|
|
10
|
+
## The `docmd` Ecosystem
|
|
11
11
|
|
|
12
12
|
`docmd` is a modular system. Here are the official packages:
|
|
13
13
|
|
|
@@ -22,6 +22,7 @@ Contains:
|
|
|
22
22
|
|
|
23
23
|
**Plugins**
|
|
24
24
|
* [**@docmd/plugin-search**](https://www.npmjs.com/package/@docmd/plugin-search) - Offline full-text search.
|
|
25
|
+
* [**@docmd/plugin-pwa**](https://www.npmjs.com/package/@docmd/plugin-pwa) - Progressive Web App support.
|
|
25
26
|
* [**@docmd/plugin-mermaid**](https://www.npmjs.com/package/@docmd/plugin-mermaid) - Diagrams and flowcharts.
|
|
26
27
|
* [**@docmd/plugin-seo**](https://www.npmjs.com/package/@docmd/plugin-seo) - Meta tags and Open Graph data.
|
|
27
28
|
* [**@docmd/plugin-sitemap**](https://www.npmjs.com/package/@docmd/plugin-sitemap) - Automatic sitemap generation.
|
|
@@ -427,7 +427,7 @@ body.sidebar-collapsed .main-content-wrapper {
|
|
|
427
427
|
background-color: var(--header-bg);
|
|
428
428
|
border-bottom: 1px solid var(--header-border);
|
|
429
429
|
position: sticky;
|
|
430
|
-
top:
|
|
430
|
+
top: var(--header-top-offset);
|
|
431
431
|
z-index: 50;
|
|
432
432
|
backdrop-filter: blur(8px);
|
|
433
433
|
-webkit-backdrop-filter: blur(8px);
|
|
@@ -448,6 +448,265 @@ body.sidebar-collapsed .main-content-wrapper {
|
|
|
448
448
|
gap: 5px
|
|
449
449
|
}
|
|
450
450
|
|
|
451
|
+
:root {
|
|
452
|
+
--menubar-h: 52px;
|
|
453
|
+
--header-h: 54px;
|
|
454
|
+
|
|
455
|
+
--fixed-top-offset: 0px;
|
|
456
|
+
--header-top-offset: 0px;
|
|
457
|
+
--sticky-top-offset: 0px;
|
|
458
|
+
|
|
459
|
+
--menubar-bg: var(--bg-color);
|
|
460
|
+
--menubar-border: var(--border-color);
|
|
461
|
+
--menubar-text: var(--text-color);
|
|
462
|
+
--menubar-link-hover-bg: var(--sidebar-link-active-bg);
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
body.has-menubar-top {
|
|
466
|
+
--fixed-top-offset: var(--menubar-h);
|
|
467
|
+
--header-top-offset: var(--menubar-h);
|
|
468
|
+
--sticky-top-offset: var(--menubar-h);
|
|
469
|
+
padding-top: var(--menubar-h);
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
body:not(.no-header) {
|
|
473
|
+
--sticky-top-offset: var(--header-h);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
body.has-menubar-top:not(.no-header) {
|
|
477
|
+
--sticky-top-offset: calc(var(--menubar-h) + var(--header-h));
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
body.has-menubar-header {
|
|
481
|
+
--header-top-offset: var(--menubar-h);
|
|
482
|
+
--sticky-top-offset: var(--menubar-h);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
body.has-menubar-header:not(.no-header) {
|
|
486
|
+
--sticky-top-offset: calc(var(--menubar-h) + var(--header-h));
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
html {
|
|
490
|
+
scroll-padding-top: calc(var(--sticky-top-offset) + 1.5rem);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
.docmd-menubar {
|
|
494
|
+
z-index: 200;
|
|
495
|
+
height: var(--menubar-h);
|
|
496
|
+
background-color: var(--menubar-bg);
|
|
497
|
+
border-bottom: 1px solid var(--menubar-border);
|
|
498
|
+
backdrop-filter: blur(8px);
|
|
499
|
+
-webkit-backdrop-filter: blur(8px);
|
|
500
|
+
width: 100%;
|
|
501
|
+
box-sizing: border-box;
|
|
502
|
+
transition: background-color 0.3s;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
.menubar-options {
|
|
506
|
+
margin-left: 0.5rem;
|
|
507
|
+
padding-left: 0.5rem;
|
|
508
|
+
border-left: 1px solid var(--menubar-border);
|
|
509
|
+
display: flex;
|
|
510
|
+
align-items: center;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
body.has-menubar-top .docmd-menubar {
|
|
514
|
+
position: fixed;
|
|
515
|
+
top: 0;
|
|
516
|
+
left: 0;
|
|
517
|
+
right: 0;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
body.has-menubar-header .docmd-menubar {
|
|
521
|
+
position: sticky;
|
|
522
|
+
top: 0;
|
|
523
|
+
z-index: 150;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
.menubar-inner {
|
|
527
|
+
display: flex;
|
|
528
|
+
align-items: center;
|
|
529
|
+
justify-content: space-between;
|
|
530
|
+
height: 100%;
|
|
531
|
+
padding: 0 1.5rem;
|
|
532
|
+
gap: 1rem;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
.menubar-left,
|
|
536
|
+
.menubar-right {
|
|
537
|
+
display: flex;
|
|
538
|
+
align-items: center;
|
|
539
|
+
gap: 0.25rem;
|
|
540
|
+
flex-shrink: 0;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
.menubar-brand {
|
|
544
|
+
display: inline-flex;
|
|
545
|
+
align-items: center;
|
|
546
|
+
gap: 0.5rem;
|
|
547
|
+
text-decoration: none;
|
|
548
|
+
color: var(--text-heading);
|
|
549
|
+
font-weight: 700;
|
|
550
|
+
font-size: 1rem;
|
|
551
|
+
padding: 0.25rem 0.5rem;
|
|
552
|
+
border-radius: var(--ui-border-radius);
|
|
553
|
+
transition: opacity 0.2s;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
.menubar-brand:hover {
|
|
557
|
+
opacity: 0.8;
|
|
558
|
+
text-decoration: none;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
.menubar-brand-text {
|
|
562
|
+
white-space: nowrap;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
.menubar-link {
|
|
566
|
+
display: inline-flex;
|
|
567
|
+
align-items: center;
|
|
568
|
+
gap: 0.35rem;
|
|
569
|
+
padding: 0.35rem 0.65rem;
|
|
570
|
+
border-radius: var(--ui-border-radius);
|
|
571
|
+
font-size: 0.875rem;
|
|
572
|
+
color: var(--menubar-text);
|
|
573
|
+
text-decoration: none;
|
|
574
|
+
transition: background-color 0.15s, color 0.15s;
|
|
575
|
+
white-space: nowrap;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
.menubar-link:hover {
|
|
579
|
+
background-color: var(--menubar-link-hover-bg);
|
|
580
|
+
color: var(--text-heading);
|
|
581
|
+
text-decoration: none;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
.menubar-icon {
|
|
585
|
+
width: 1em;
|
|
586
|
+
height: 1em;
|
|
587
|
+
flex-shrink: 0;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
.menubar-ext-icon {
|
|
591
|
+
width: 0.75em;
|
|
592
|
+
height: 0.75em;
|
|
593
|
+
opacity: 0.6;
|
|
594
|
+
flex-shrink: 0;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
.menubar-dropdown {
|
|
598
|
+
position: relative;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
.menubar-dropdown-toggle {
|
|
602
|
+
display: inline-flex;
|
|
603
|
+
align-items: center;
|
|
604
|
+
gap: 0.35rem;
|
|
605
|
+
padding: 0.35rem 0.65rem;
|
|
606
|
+
border-radius: var(--ui-border-radius);
|
|
607
|
+
font-size: 0.875rem;
|
|
608
|
+
color: var(--menubar-text);
|
|
609
|
+
background: none;
|
|
610
|
+
border: none;
|
|
611
|
+
cursor: pointer;
|
|
612
|
+
font-family: inherit;
|
|
613
|
+
transition: background-color 0.15s, color 0.15s;
|
|
614
|
+
white-space: nowrap;
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
.menubar-dropdown-toggle:hover {
|
|
618
|
+
background-color: var(--menubar-link-hover-bg);
|
|
619
|
+
color: var(--text-heading);
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
.menubar-chevron {
|
|
623
|
+
width: 0.85em;
|
|
624
|
+
height: 0.85em;
|
|
625
|
+
opacity: 0.7;
|
|
626
|
+
transition: transform 0.2s ease;
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
.menubar-dropdown:hover .menubar-chevron,
|
|
630
|
+
.menubar-dropdown:focus-within .menubar-chevron {
|
|
631
|
+
transform: rotate(180deg);
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
.menubar-dropdown-menu {
|
|
635
|
+
position: absolute;
|
|
636
|
+
top: calc(100% + 6px);
|
|
637
|
+
left: 0;
|
|
638
|
+
min-width: 180px;
|
|
639
|
+
margin: 0;
|
|
640
|
+
padding: 0.25rem;
|
|
641
|
+
list-style: none;
|
|
642
|
+
background-color: var(--bg-color);
|
|
643
|
+
border: 1px solid var(--border-color);
|
|
644
|
+
border-radius: var(--ui-border-radius);
|
|
645
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08), 0 2px 4px rgba(0, 0, 0, 0.05);
|
|
646
|
+
z-index: 300;
|
|
647
|
+
opacity: 0;
|
|
648
|
+
visibility: hidden;
|
|
649
|
+
transform: translateY(-4px);
|
|
650
|
+
transition: opacity 0.15s, transform 0.15s, visibility 0.15s;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
.menubar-dropdown-menu.menubar-dropdown-right {
|
|
654
|
+
left: auto;
|
|
655
|
+
right: 0;
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
.menubar-dropdown:hover .menubar-dropdown-menu,
|
|
659
|
+
.menubar-dropdown:focus-within .menubar-dropdown-menu {
|
|
660
|
+
opacity: 1;
|
|
661
|
+
visibility: visible;
|
|
662
|
+
transform: translateY(0);
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
.menubar-dropdown-menu li a {
|
|
666
|
+
display: flex;
|
|
667
|
+
align-items: center;
|
|
668
|
+
gap: 0.5rem;
|
|
669
|
+
padding: 0.4rem 0.6rem;
|
|
670
|
+
font-size: 0.875rem;
|
|
671
|
+
color: var(--text-color);
|
|
672
|
+
text-decoration: none;
|
|
673
|
+
border-radius: 4px;
|
|
674
|
+
transition: background-color 0.15s, color 0.15s;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
.menubar-dropdown-menu li a:hover {
|
|
678
|
+
background-color: var(--sidebar-link-active-bg);
|
|
679
|
+
color: var(--text-heading);
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
.sidebar {
|
|
683
|
+
top: var(--fixed-top-offset);
|
|
684
|
+
height: calc(100vh - var(--fixed-top-offset));
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
.toc-sidebar {
|
|
688
|
+
position: sticky;
|
|
689
|
+
top: calc(var(--sticky-top-offset) + 2rem);
|
|
690
|
+
width: 240px;
|
|
691
|
+
flex-shrink: 0;
|
|
692
|
+
margin: 1rem 0;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
@media (max-width: 768px) {
|
|
696
|
+
.docmd-menubar {
|
|
697
|
+
padding: 0;
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
.menubar-brand-text {
|
|
701
|
+
display: none;
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
.menubar-link span,
|
|
705
|
+
.menubar-dropdown-toggle span:not(.menubar-chevron) {
|
|
706
|
+
display: none;
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
|
|
451
710
|
.docmd-options-menu {
|
|
452
711
|
display: flex;
|
|
453
712
|
align-items: center;
|
|
@@ -540,17 +799,12 @@ body.sidebar-collapsed .main-content-wrapper {
|
|
|
540
799
|
/* --- Version Dropdown (Flat UI) --- */
|
|
541
800
|
.sidebar-version-wrapper {
|
|
542
801
|
padding: 0.25rem .5em;
|
|
543
|
-
border-bottom: 1px solid var(--border-color);
|
|
544
802
|
}
|
|
545
803
|
|
|
546
804
|
.sidebar-bottom-group.mt-auto {
|
|
547
805
|
margin-top: auto;
|
|
548
806
|
}
|
|
549
807
|
|
|
550
|
-
.sidebar-bottom-group .sidebar-version-wrapper {
|
|
551
|
-
border-bottom: none;
|
|
552
|
-
}
|
|
553
|
-
|
|
554
808
|
.docmd-version-dropdown {
|
|
555
809
|
position: relative;
|
|
556
810
|
width: 100%;
|
|
@@ -659,7 +913,7 @@ body.sidebar-collapsed .main-content-wrapper {
|
|
|
659
913
|
}
|
|
660
914
|
|
|
661
915
|
.content-area {
|
|
662
|
-
padding:
|
|
916
|
+
padding: 1rem 5%;
|
|
663
917
|
max-width: 1200px;
|
|
664
918
|
margin: 0 auto;
|
|
665
919
|
width: 100%;
|
|
@@ -1251,15 +1505,6 @@ details[open]>.collapsible-summary .collapsible-arrow svg {
|
|
|
1251
1505
|
background-color: rgba(59, 130, 246, 0.1)
|
|
1252
1506
|
}
|
|
1253
1507
|
|
|
1254
|
-
.toc-sidebar {
|
|
1255
|
-
position: -webkit-sticky;
|
|
1256
|
-
position: sticky;
|
|
1257
|
-
top: 2rem;
|
|
1258
|
-
width: 240px;
|
|
1259
|
-
flex-shrink: 0;
|
|
1260
|
-
margin: 1rem 0
|
|
1261
|
-
}
|
|
1262
|
-
|
|
1263
1508
|
.toc-title {
|
|
1264
1509
|
font-size: .85em;
|
|
1265
1510
|
display: contents;
|
|
@@ -1984,6 +2229,7 @@ hr {
|
|
|
1984
2229
|
width: 100%;
|
|
1985
2230
|
height: auto;
|
|
1986
2231
|
position: relative;
|
|
2232
|
+
top: 0;
|
|
1987
2233
|
border-right-width: medium;
|
|
1988
2234
|
border-right-style: none;
|
|
1989
2235
|
border-right-color: currentcolor;
|
|
@@ -2041,7 +2287,7 @@ hr {
|
|
|
2041
2287
|
}
|
|
2042
2288
|
|
|
2043
2289
|
.content-area {
|
|
2044
|
-
padding: 15px
|
|
2290
|
+
padding: 1.5rem 15px 15px
|
|
2045
2291
|
}
|
|
2046
2292
|
|
|
2047
2293
|
.page-navigation {
|
package/assets/js/docmd-main.js
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
* --------------------------------------------------------------------
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
|
-
(function() {
|
|
21
|
+
(function () {
|
|
22
22
|
|
|
23
23
|
// 1. EVENT DELEGATION
|
|
24
24
|
document.addEventListener('click', (e) => {
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
item.classList.toggle('expanded', !isExpanded);
|
|
33
33
|
item.setAttribute('aria-expanded', !isExpanded);
|
|
34
34
|
}
|
|
35
|
-
if (navLabel.classList.contains('collapse-icon-wrapper')) return;
|
|
35
|
+
if (navLabel.classList.contains('collapse-icon-wrapper')) return;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
// Toggles
|
|
@@ -54,14 +54,14 @@
|
|
|
54
54
|
const navItems = Array.from(tabsContainer.querySelectorAll('.docmd-tabs-nav-item'));
|
|
55
55
|
const tabPanes = Array.from(tabsContainer.querySelectorAll('.docmd-tab-pane'));
|
|
56
56
|
const index = navItems.indexOf(tabItem);
|
|
57
|
-
|
|
57
|
+
|
|
58
58
|
navItems.forEach(item => item.classList.remove('active'));
|
|
59
59
|
tabPanes.forEach(pane => pane.classList.remove('active'));
|
|
60
|
-
|
|
60
|
+
|
|
61
61
|
tabItem.classList.add('active');
|
|
62
62
|
if (tabPanes[index]) tabPanes[index].classList.add('active');
|
|
63
63
|
}
|
|
64
|
-
|
|
64
|
+
|
|
65
65
|
// Version Dropdown Toggle
|
|
66
66
|
const versionToggle = e.target.closest('.version-dropdown-toggle');
|
|
67
67
|
if (versionToggle) {
|
|
@@ -75,28 +75,28 @@
|
|
|
75
75
|
// Sticky Version Switching (Path Preservation)
|
|
76
76
|
const versionLink = e.target.closest('.version-dropdown-item');
|
|
77
77
|
if (versionLink) {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
}
|
|
78
|
+
const targetRoot = versionLink.dataset.versionRoot;
|
|
79
|
+
// Use global fallback if undefined (e.g. on 404 pages)
|
|
80
|
+
const currentRoot = window.DOCMD_VERSION_ROOT || '/';
|
|
81
|
+
|
|
82
|
+
if (targetRoot && window.location.pathname) {
|
|
83
|
+
try {
|
|
84
|
+
let currentPath = window.location.pathname;
|
|
85
|
+
const normCurrentRoot = currentRoot.endsWith('/') ? currentRoot : currentRoot + '/';
|
|
86
|
+
|
|
87
|
+
// Only try sticky if we are actually INSIDE the known version path
|
|
88
|
+
if (currentPath.startsWith(normCurrentRoot)) {
|
|
89
|
+
e.preventDefault();
|
|
90
|
+
const suffix = currentPath.substring(normCurrentRoot.length);
|
|
91
|
+
const normTargetRoot = targetRoot.endsWith('/') ? targetRoot : targetRoot + '/';
|
|
92
|
+
window.location.href = normTargetRoot + suffix + window.location.hash;
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
} catch (e) {
|
|
96
|
+
// Ignore errors, let default click happen
|
|
98
97
|
}
|
|
99
|
-
|
|
98
|
+
}
|
|
99
|
+
// If sticky logic skipped (e.g. on 404 page or outside root), default <a> click handles it
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
// Close Dropdown if clicked outside
|
|
@@ -128,15 +128,15 @@
|
|
|
128
128
|
function injectCopyButtons() {
|
|
129
129
|
if (document.body.dataset.copyCodeEnabled !== 'true') return;
|
|
130
130
|
const svg = `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-copy"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"></rect><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"></path></svg>`;
|
|
131
|
-
|
|
131
|
+
|
|
132
132
|
document.querySelectorAll('pre').forEach(preElement => {
|
|
133
|
-
if (preElement.closest('.code-wrapper')) return;
|
|
133
|
+
if (preElement.closest('.code-wrapper')) return;
|
|
134
134
|
const wrapper = document.createElement('div');
|
|
135
135
|
wrapper.className = 'code-wrapper';
|
|
136
136
|
wrapper.style.position = 'relative';
|
|
137
137
|
preElement.parentNode.insertBefore(wrapper, preElement);
|
|
138
138
|
wrapper.appendChild(preElement);
|
|
139
|
-
|
|
139
|
+
|
|
140
140
|
const copyButton = document.createElement('button');
|
|
141
141
|
copyButton.className = 'copy-code-button';
|
|
142
142
|
copyButton.innerHTML = svg;
|
|
@@ -150,7 +150,7 @@
|
|
|
150
150
|
const tocLinks = document.querySelectorAll('.toc-link');
|
|
151
151
|
const headings = document.querySelectorAll('.main-content h2, .main-content h3, .main-content h4');
|
|
152
152
|
const tocContainer = document.querySelector('.toc-list');
|
|
153
|
-
|
|
153
|
+
|
|
154
154
|
if (tocLinks.length === 0 || headings.length === 0) return;
|
|
155
155
|
|
|
156
156
|
scrollObserver = new IntersectionObserver((entries) => {
|
|
@@ -159,7 +159,7 @@
|
|
|
159
159
|
tocLinks.forEach(link => link.classList.remove('active'));
|
|
160
160
|
const id = entry.target.getAttribute('id');
|
|
161
161
|
const activeLink = document.querySelector(`.toc-link[href="#${id}"]`);
|
|
162
|
-
|
|
162
|
+
|
|
163
163
|
if (activeLink) {
|
|
164
164
|
activeLink.classList.add('active');
|
|
165
165
|
if (tocContainer) {
|
|
@@ -197,9 +197,9 @@
|
|
|
197
197
|
|
|
198
198
|
// Intent-based Hover Prefetching
|
|
199
199
|
document.addEventListener('mouseover', (e) => {
|
|
200
|
-
const link = e.target.closest('.sidebar-nav a, .page-navigation a');
|
|
200
|
+
const link = e.target.closest('.sidebar-nav a, .page-navigation a, .page-footer a, .main-content a');
|
|
201
201
|
if (!link || link.target === '_blank' || link.hasAttribute('download')) return;
|
|
202
|
-
|
|
202
|
+
|
|
203
203
|
const url = new URL(link.href).href;
|
|
204
204
|
if (new URL(url).origin !== location.origin) return;
|
|
205
205
|
if (pageCache.has(url)) return;
|
|
@@ -207,10 +207,10 @@
|
|
|
207
207
|
// Wait 65ms to ensure the user actually intends to click
|
|
208
208
|
clearTimeout(prefetchTimer);
|
|
209
209
|
prefetchTimer = setTimeout(() => {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
210
|
+
pageCache.set(url, fetch(url).then(res => {
|
|
211
|
+
if (!res.ok) throw new Error('Prefetch failed');
|
|
212
|
+
return { html: res.text(), finalUrl: res.url };
|
|
213
|
+
}).catch(() => pageCache.delete(url)));
|
|
214
214
|
}, 65);
|
|
215
215
|
});
|
|
216
216
|
|
|
@@ -222,42 +222,42 @@
|
|
|
222
222
|
|
|
223
223
|
if (e.target.closest('[data-spa-ignore]')) return;
|
|
224
224
|
|
|
225
|
-
const link = e.target.closest('.sidebar-nav a, .page-navigation a');
|
|
225
|
+
const link = e.target.closest('.sidebar-nav a, .page-navigation a, .page-footer a, .main-content a');
|
|
226
226
|
if (!link || link.target === '_blank' || link.hasAttribute('download')) return;
|
|
227
|
-
|
|
227
|
+
|
|
228
228
|
const url = new URL(link.href);
|
|
229
229
|
if (url.origin !== location.origin) return;
|
|
230
230
|
if (url.pathname === window.location.pathname && url.hash) return;
|
|
231
|
-
|
|
231
|
+
|
|
232
232
|
e.preventDefault();
|
|
233
233
|
await navigateTo(url.href);
|
|
234
234
|
});
|
|
235
235
|
|
|
236
236
|
window.addEventListener('popstate', () => {
|
|
237
|
-
if (window.location.pathname === currentPath) return;
|
|
237
|
+
if (window.location.pathname === currentPath) return;
|
|
238
238
|
navigateTo(window.location.href, false);
|
|
239
239
|
});
|
|
240
240
|
|
|
241
241
|
async function navigateTo(url, pushHistory = true) {
|
|
242
242
|
const layout = document.querySelector('.content-layout');
|
|
243
|
-
|
|
243
|
+
|
|
244
244
|
try {
|
|
245
245
|
if (layout) layout.style.minHeight = layout.getBoundingClientRect().height + 'px';
|
|
246
|
-
|
|
246
|
+
|
|
247
247
|
let data;
|
|
248
248
|
if (pageCache.has(url)) {
|
|
249
|
-
|
|
250
|
-
|
|
249
|
+
data = await pageCache.get(url);
|
|
250
|
+
data.html = await data.html;
|
|
251
251
|
} else {
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
252
|
+
const res = await fetch(url);
|
|
253
|
+
if (!res.ok) throw new Error('Fetch failed');
|
|
254
|
+
data = { html: await res.text(), finalUrl: res.url };
|
|
255
|
+
pageCache.set(url, Promise.resolve(data));
|
|
256
256
|
}
|
|
257
257
|
|
|
258
258
|
const finalUrl = data.finalUrl;
|
|
259
259
|
const html = data.html;
|
|
260
|
-
|
|
260
|
+
|
|
261
261
|
const parser = new DOMParser();
|
|
262
262
|
const doc = parser.parseFromString(html, 'text/html');
|
|
263
263
|
|
|
@@ -271,58 +271,62 @@
|
|
|
271
271
|
const newAssets = Array.from(doc.head.querySelectorAll(assetSelectors));
|
|
272
272
|
|
|
273
273
|
newAssets.forEach((newAsset, index) => {
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
}
|
|
278
|
-
} else {
|
|
279
|
-
document.head.appendChild(newAsset.cloneNode(true));
|
|
274
|
+
if (oldAssets[index]) {
|
|
275
|
+
if (oldAssets[index].getAttribute('href') !== newAsset.getAttribute('href')) {
|
|
276
|
+
oldAssets[index].setAttribute('href', newAsset.getAttribute('href'));
|
|
280
277
|
}
|
|
278
|
+
} else {
|
|
279
|
+
document.head.appendChild(newAsset.cloneNode(true));
|
|
280
|
+
}
|
|
281
281
|
});
|
|
282
282
|
|
|
283
283
|
// Sync Sidebar State
|
|
284
284
|
const oldLis = Array.from(document.querySelectorAll('.sidebar-nav li'));
|
|
285
285
|
const newLis = Array.from(doc.querySelectorAll('.sidebar-nav li'));
|
|
286
|
-
|
|
286
|
+
|
|
287
287
|
oldLis.forEach((oldLi, i) => {
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
}
|
|
288
|
+
const newLi = newLis[i];
|
|
289
|
+
if (newLi) {
|
|
290
|
+
oldLi.classList.toggle('active', newLi.classList.contains('active'));
|
|
291
|
+
oldLi.classList.toggle('active-parent', newLi.classList.contains('active-parent'));
|
|
292
|
+
|
|
293
|
+
if (newLi.classList.contains('expanded')) {
|
|
294
|
+
oldLi.classList.add('expanded');
|
|
295
|
+
oldLi.setAttribute('aria-expanded', 'true');
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
const oldA = oldLi.querySelector('a');
|
|
299
|
+
const newA = newLi.querySelector('a');
|
|
300
|
+
if (oldA && newA) {
|
|
301
|
+
oldA.setAttribute('href', newA.getAttribute('href'));
|
|
302
|
+
oldA.classList.toggle('active', newA.classList.contains('active'));
|
|
304
303
|
}
|
|
304
|
+
}
|
|
305
305
|
});
|
|
306
306
|
|
|
307
|
-
const selectorsToSwap =[
|
|
308
|
-
'.content-layout',
|
|
309
|
-
'.page-header .header-title',
|
|
310
|
-
'.page-footer',
|
|
307
|
+
const selectorsToSwap = [
|
|
308
|
+
'.content-layout',
|
|
309
|
+
'.page-header .header-title',
|
|
310
|
+
'.page-footer',
|
|
311
311
|
'.footer-complete',
|
|
312
312
|
'.page-footer-actions'
|
|
313
313
|
];
|
|
314
314
|
|
|
315
315
|
selectorsToSwap.forEach(selector => {
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
316
|
+
const oldEl = document.querySelector(selector);
|
|
317
|
+
const newEl = doc.querySelector(selector);
|
|
318
|
+
if (oldEl && newEl) oldEl.innerHTML = newEl.innerHTML;
|
|
319
319
|
});
|
|
320
320
|
|
|
321
321
|
const hash = new URL(finalUrl).hash;
|
|
322
322
|
if (hash) {
|
|
323
|
+
try {
|
|
323
324
|
document.querySelector(hash)?.scrollIntoView();
|
|
325
|
+
} catch (e) {
|
|
326
|
+
document.getElementById(hash.substring(1))?.scrollIntoView();
|
|
327
|
+
}
|
|
324
328
|
} else {
|
|
325
|
-
|
|
329
|
+
window.scrollTo(0, 0);
|
|
326
330
|
}
|
|
327
331
|
|
|
328
332
|
injectCopyButtons();
|
|
@@ -333,11 +337,11 @@
|
|
|
333
337
|
document.dispatchEvent(new CustomEvent('docmd:page-mounted', { detail: { url: finalUrl } }));
|
|
334
338
|
|
|
335
339
|
setTimeout(() => {
|
|
336
|
-
|
|
337
|
-
|
|
340
|
+
const newLayout = document.querySelector('.content-layout');
|
|
341
|
+
if (newLayout) newLayout.style.minHeight = '';
|
|
338
342
|
}, 100);
|
|
339
343
|
|
|
340
|
-
} catch(e) {
|
|
344
|
+
} catch (e) {
|
|
341
345
|
window.location.assign(url);
|
|
342
346
|
}
|
|
343
347
|
}
|
|
@@ -346,21 +350,21 @@
|
|
|
346
350
|
// 4. BOOTSTRAP
|
|
347
351
|
document.addEventListener('DOMContentLoaded', () => {
|
|
348
352
|
if (localStorage.getItem('docmd-sidebar-collapsed') === 'true') {
|
|
349
|
-
|
|
353
|
+
document.body.classList.add('sidebar-collapsed');
|
|
350
354
|
}
|
|
351
|
-
|
|
355
|
+
|
|
352
356
|
document.querySelectorAll('.theme-toggle-button').forEach(btn => {
|
|
353
357
|
btn.addEventListener('click', () => {
|
|
354
358
|
const t = document.documentElement.getAttribute('data-theme') === 'light' ? 'dark' : 'light';
|
|
355
359
|
document.documentElement.setAttribute('data-theme', t);
|
|
356
360
|
document.body.setAttribute('data-theme', t);
|
|
357
361
|
localStorage.setItem('docmd-theme', t);
|
|
358
|
-
|
|
362
|
+
|
|
359
363
|
const lightLink = document.getElementById('hljs-light');
|
|
360
364
|
const darkLink = document.getElementById('hljs-dark');
|
|
361
365
|
if (lightLink && darkLink) {
|
|
362
|
-
|
|
363
|
-
|
|
366
|
+
lightLink.disabled = t === 'dark';
|
|
367
|
+
darkLink.disabled = t === 'light';
|
|
364
368
|
}
|
|
365
369
|
});
|
|
366
370
|
});
|
|
@@ -368,16 +372,29 @@
|
|
|
368
372
|
injectCopyButtons();
|
|
369
373
|
initializeScrollSpy();
|
|
370
374
|
initializeSPA();
|
|
371
|
-
|
|
375
|
+
|
|
372
376
|
setTimeout(() => {
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
377
|
+
// PWA Unregistration Safety Net:
|
|
378
|
+
// If the PWA plugin is removed from docmd.config.js, the <link rel="manifest"> disappears.
|
|
379
|
+
// We explicitly unregister all ghost service workers to safely kill the offline cache.
|
|
380
|
+
if ('serviceWorker' in navigator && !document.querySelector('link[rel="manifest"]')) {
|
|
381
|
+
navigator.serviceWorker.getRegistrations().then(registrations => {
|
|
382
|
+
registrations.forEach(reg => reg.unregister().catch(() => { }));
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
const activeNav = document.querySelector('.sidebar-nav a.active');
|
|
387
|
+
const sidebarNav = document.querySelector('.sidebar-nav');
|
|
388
|
+
if (activeNav && sidebarNav) {
|
|
389
|
+
sidebarNav.scrollTo({ top: activeNav.offsetTop - (sidebarNav.clientHeight / 2), behavior: 'instant' });
|
|
390
|
+
}
|
|
391
|
+
if (window.location.hash) {
|
|
392
|
+
try {
|
|
393
|
+
document.querySelector(window.location.hash)?.scrollIntoView();
|
|
394
|
+
} catch (e) {
|
|
395
|
+
document.getElementById(window.location.hash.substring(1))?.scrollIntoView();
|
|
380
396
|
}
|
|
397
|
+
}
|
|
381
398
|
}, 100);
|
|
382
399
|
});
|
|
383
400
|
|
package/package.json
CHANGED
package/templates/layout.ejs
CHANGED
|
@@ -8,189 +8,225 @@
|
|
|
8
8
|
|
|
9
9
|
<!DOCTYPE html>
|
|
10
10
|
<html lang="en">
|
|
11
|
+
|
|
11
12
|
<head>
|
|
12
13
|
<meta charset="UTF-8">
|
|
13
14
|
<meta name="generator" content="docmd v0.5.x">
|
|
14
15
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
15
|
-
<%
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
%>
|
|
54
|
-
<link rel="stylesheet"
|
|
55
|
-
href="<%= relativePathToRoot %>assets/css/docmd-highlight-light.css?v=<%= buildHash %>"
|
|
56
|
-
id="hljs-light"
|
|
57
|
-
<%= isDarkDefault ? 'disabled' : '' %>>
|
|
58
|
-
|
|
59
|
-
<link rel="stylesheet"
|
|
60
|
-
href="<%= relativePathToRoot %>assets/css/docmd-highlight-dark.css?v=<%= buildHash %>"
|
|
61
|
-
id="hljs-dark"
|
|
62
|
-
<%= isDarkDefault ? '' : 'disabled' %>>
|
|
63
|
-
<% } %>
|
|
64
|
-
<%- pluginHeadScriptsHtml || '' %>
|
|
65
|
-
<% (customCssFiles || []).forEach(cssFile => { %>
|
|
66
|
-
<link rel="stylesheet" href="<%= relativePathToRoot %><%- cssFile.startsWith('/') ? cssFile.substring(1) : cssFile %>?v=<%= buildHash %>">
|
|
67
|
-
<% }); %>
|
|
68
|
-
<%- themeInitScript %>
|
|
16
|
+
<% let versionRoot='/' ; let siteRoot=relativePathToRoot; if (config.versions?.current && config._activeVersion?.id)
|
|
17
|
+
{ const isSubVersion=config.versions.current !==config._activeVersion.id; versionRoot=isSubVersion ? '/' +
|
|
18
|
+
config._activeVersion.id + '/' : '/' ; if (isSubVersion) { siteRoot=(relativePathToRoot==='./' ? '' :
|
|
19
|
+
relativePathToRoot) + '../' ; } } if (locals.isOfflineMode) { versionRoot='' ; } %>
|
|
20
|
+
<script>
|
|
21
|
+
var root = "<%= relativePathToRoot %>";
|
|
22
|
+
if (root && !root.endsWith('/')) root += '/';
|
|
23
|
+
if (root === '') root = './';
|
|
24
|
+
window.DOCMD_ROOT = root;
|
|
25
|
+
|
|
26
|
+
var siteRoot = "<%= siteRoot %>";
|
|
27
|
+
if (siteRoot && !siteRoot.endsWith('/')) siteRoot += '/';
|
|
28
|
+
if (siteRoot === '') siteRoot = './';
|
|
29
|
+
window.DOCMD_SITE_ROOT = siteRoot;
|
|
30
|
+
|
|
31
|
+
window.DOCMD_DEFAULT_MODE = "<%= defaultMode %>";
|
|
32
|
+
window.DOCMD_VERSION_ROOT = "<%- versionRoot %>";
|
|
33
|
+
</script>
|
|
34
|
+
<title>
|
|
35
|
+
<%= pageTitle %>
|
|
36
|
+
</title>
|
|
37
|
+
<%- faviconLinkHtml || '' %>
|
|
38
|
+
<link rel="stylesheet" href="<%= relativePathToRoot %>assets/css/docmd-main.css?v=<%= buildHash %>">
|
|
39
|
+
<% if (config.theme?.codeHighlight !==false) { const isDarkDefault=defaultMode==='dark' ; %>
|
|
40
|
+
<link rel="stylesheet"
|
|
41
|
+
href="<%= relativePathToRoot %>assets/css/docmd-highlight-light.css?v=<%= buildHash %>"
|
|
42
|
+
id="hljs-light" <%=isDarkDefault ? 'disabled' : '' %>>
|
|
43
|
+
|
|
44
|
+
<link rel="stylesheet"
|
|
45
|
+
href="<%= relativePathToRoot %>assets/css/docmd-highlight-dark.css?v=<%= buildHash %>"
|
|
46
|
+
id="hljs-dark" <%=isDarkDefault ? '' : 'disabled' %>>
|
|
47
|
+
<% } %>
|
|
48
|
+
<%- pluginHeadScriptsHtml || '' %>
|
|
49
|
+
<% (customCssFiles || []).forEach(cssFile=> { %>
|
|
50
|
+
<link rel="stylesheet"
|
|
51
|
+
href="<%= relativePathToRoot %><%- cssFile.startsWith('/') ? cssFile.substring(1) : cssFile %>?v=<%= buildHash %>">
|
|
52
|
+
<% }); %>
|
|
53
|
+
<%- themeInitScript %>
|
|
69
54
|
</head>
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
data-
|
|
74
|
-
|
|
55
|
+
|
|
56
|
+
<body
|
|
57
|
+
class="<%= sidebarConfig?.enabled === false ? 'no-sidebar' : (sidebarConfig?.collapsible ? 'sidebar-collapsible' : 'sidebar-not-collapsible') %><%= (locals.menubarConfig && menubarConfig?.enabled !== false) ? ' has-menubar has-menubar-' + (menubarConfig.position || 'top') : '' %><%= headerConfig?.enabled === false ? ' no-header' : '' %>"
|
|
58
|
+
data-default-collapsed="<%= sidebarConfig?.defaultCollapsed %>"
|
|
59
|
+
data-copy-code-enabled="<%= config.copyCode === true %>" data-spa-enabled="<%= config.layout?.spa !== false %>">
|
|
60
|
+
|
|
75
61
|
<a href="#main-content" class="skip-link">Skip to main content</a>
|
|
76
62
|
|
|
77
|
-
<% if (
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
<a href="<%= logo.href || relativePathToRoot %>" class="logo-link">
|
|
82
|
-
<img src="<%= relativePathToRoot %><%- logo.light.startsWith('/') ? logo.light.substring(1) : logo.light %>" alt="<%= logo.alt || siteTitle %>" class="logo-light" <% if (logo.height) { %>style="height: <%= logo.height %>;"<% } %>>
|
|
83
|
-
<img src="<%= relativePathToRoot %><%- logo.dark.startsWith('/') ? logo.dark.substring(1) : logo.dark %>" alt="<%= logo.alt || siteTitle %>" class="logo-dark" <% if (logo.height) { %>style="height: <%= logo.height %>;"<% } %>>
|
|
84
|
-
</a>
|
|
85
|
-
<% } else { %>
|
|
86
|
-
<h1><a href="<%= relativePathToRoot %>index.html"><%= siteTitle %></a></h1>
|
|
87
|
-
<% } %>
|
|
88
|
-
<span class="mobile-view sidebar-menu-button float-right">
|
|
89
|
-
<%- renderIcon("menu") %>
|
|
90
|
-
</span>
|
|
91
|
-
</div>
|
|
92
|
-
|
|
93
|
-
<div class="sidebar-top-group">
|
|
94
|
-
<% if (locals.optionsMenu && optionsMenu.position === 'sidebar-top') { %>
|
|
95
|
-
<div class="sidebar-options-wrapper">
|
|
96
|
-
<%- include('partials/options-menu', { optionsMenu }) %>
|
|
97
|
-
</div>
|
|
98
|
-
<% } %>
|
|
99
|
-
|
|
100
|
-
<% if (config.versions && config.versions.position === 'sidebar-top') { %>
|
|
101
|
-
<div class="sidebar-version-wrapper">
|
|
102
|
-
<%- include('partials/version-dropdown', { versions: config.versions, activeVersion: config._activeVersion, relativePathToRoot }) %>
|
|
103
|
-
</div>
|
|
104
|
-
<% } %>
|
|
105
|
-
</div>
|
|
63
|
+
<% if (locals.menubarConfig && menubarConfig?.enabled !==false && menubarConfig.position !=='header' ) { %>
|
|
64
|
+
<%- include('partials/menubar', { menubarConfig, relativePathToRoot, renderIcon, optionsMenu: locals.optionsMenu
|
|
65
|
+
}) %>
|
|
66
|
+
<% } %>
|
|
106
67
|
|
|
107
|
-
|
|
68
|
+
<% if (sidebarConfig?.enabled !==false) { %>
|
|
69
|
+
<aside class="sidebar">
|
|
70
|
+
<div class="sidebar-header">
|
|
71
|
+
<% if (logo && logo.light && logo.dark) { %>
|
|
72
|
+
<a href="<%= logo.href || relativePathToRoot %>" class="logo-link">
|
|
73
|
+
<img src="<%= relativePathToRoot %><%- logo.light.startsWith('/') ? logo.light.substring(1) : logo.light %>"
|
|
74
|
+
alt="<%= logo.alt || siteTitle %>" class="logo-light" <% if (logo.height) {
|
|
75
|
+
%>style="height: <%= logo.height %>;"<% } %>>
|
|
76
|
+
<img src="<%= relativePathToRoot %><%- logo.dark.startsWith('/') ? logo.dark.substring(1) : logo.dark %>"
|
|
77
|
+
alt="<%= logo.alt || siteTitle %>" class="logo-dark" <% if (logo.height)
|
|
78
|
+
{ %>style="height: <%= logo.height %>;"<% } %>>
|
|
79
|
+
</a>
|
|
80
|
+
<% } else { %>
|
|
81
|
+
<h1><a href="<%= relativePathToRoot %>index.html">
|
|
82
|
+
<%= siteTitle %>
|
|
83
|
+
</a></h1>
|
|
84
|
+
<% } %>
|
|
85
|
+
<span class="mobile-view sidebar-menu-button float-right">
|
|
86
|
+
<%- renderIcon("menu") %>
|
|
87
|
+
</span>
|
|
88
|
+
</div>
|
|
108
89
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
90
|
+
<div class="sidebar-top-group">
|
|
91
|
+
<% if (locals.optionsMenu && optionsMenu.position==='sidebar-top' ) { %>
|
|
92
|
+
<div class="sidebar-options-wrapper">
|
|
93
|
+
<%- include('partials/options-menu', { optionsMenu }) %>
|
|
94
|
+
</div>
|
|
95
|
+
<% } %>
|
|
115
96
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
</div>
|
|
142
|
-
</header>
|
|
143
|
-
<% } %>
|
|
144
|
-
|
|
145
|
-
<main class="content-area" id="main-content">
|
|
146
|
-
<div class="content-layout">
|
|
147
|
-
<div class="main-content">
|
|
148
|
-
<% if (headerConfig?.enabled === false) { %>
|
|
149
|
-
<h1><%= pageTitle %></h1>
|
|
150
|
-
<% } %>
|
|
151
|
-
|
|
152
|
-
<%- content %>
|
|
153
|
-
|
|
154
|
-
<% if (config.pageNavigation && (prevPage || nextPage)) { %>
|
|
155
|
-
<div class="page-navigation">
|
|
156
|
-
<% if (prevPage) { %>
|
|
157
|
-
<a href="<%= prevPage.url %>" class="prev-page">
|
|
158
|
-
<%- renderIcon('arrow-left', { class: 'page-nav-icon' }) %>
|
|
159
|
-
<span><small>Previous</small><strong><%= prevPage.title %></strong></span>
|
|
160
|
-
</a>
|
|
161
|
-
<% } else { %><div class="prev-page-placeholder"></div><% } %>
|
|
162
|
-
<% if (nextPage) { %>
|
|
163
|
-
<a href="<%= nextPage.url %>" class="next-page">
|
|
164
|
-
<span><small>Next</small><strong><%= nextPage.title %></strong></span>
|
|
165
|
-
<%- renderIcon('arrow-right', { class: 'page-nav-icon' }) %>
|
|
166
|
-
</a>
|
|
167
|
-
<% } else { %><div class="next-page-placeholder"></div><% } %>
|
|
168
|
-
</div>
|
|
97
|
+
<% if (config.versions && config.versions.position==='sidebar-top' ) { %>
|
|
98
|
+
<div class="sidebar-version-wrapper">
|
|
99
|
+
<%- include('partials/version-dropdown', { versions: config.versions,
|
|
100
|
+
activeVersion: config._activeVersion, relativePathToRoot }) %>
|
|
101
|
+
</div>
|
|
102
|
+
<% } %>
|
|
103
|
+
</div>
|
|
104
|
+
|
|
105
|
+
<%- navigationHtml %>
|
|
106
|
+
|
|
107
|
+
<div class="sidebar-bottom-group mt-auto">
|
|
108
|
+
<% if (config.versions && config.versions.position==='sidebar-bottom' ) { %>
|
|
109
|
+
<div class="sidebar-version-wrapper">
|
|
110
|
+
<%- include('partials/version-dropdown', { versions: config.versions,
|
|
111
|
+
activeVersion: config._activeVersion, relativePathToRoot }) %>
|
|
112
|
+
</div>
|
|
113
|
+
<% } %>
|
|
114
|
+
|
|
115
|
+
<% if (locals.optionsMenu && optionsMenu.position==='sidebar-bottom' ) { %>
|
|
116
|
+
<div class="sidebar-options-wrapper">
|
|
117
|
+
<%- include('partials/options-menu', { optionsMenu }) %>
|
|
118
|
+
</div>
|
|
119
|
+
<% } %>
|
|
120
|
+
</div>
|
|
121
|
+
</aside>
|
|
169
122
|
<% } %>
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
123
|
+
|
|
124
|
+
<div class="main-content-wrapper">
|
|
125
|
+
<% if (locals.menubarConfig && menubarConfig?.enabled !==false &&
|
|
126
|
+
menubarConfig.position==='header' ) { %>
|
|
127
|
+
<%- include('partials/menubar', { menubarConfig, relativePathToRoot, renderIcon,
|
|
128
|
+
optionsMenu: locals.optionsMenu }) %>
|
|
129
|
+
<% } %>
|
|
130
|
+
<% if (headerConfig?.enabled !==false) { %>
|
|
131
|
+
<header class="page-header">
|
|
132
|
+
<div class="header-left">
|
|
133
|
+
<% if (sidebarConfig?.collapsible) { %>
|
|
134
|
+
<button id="sidebar-toggle-button" class="sidebar-toggle-button"
|
|
135
|
+
aria-label="Toggle Sidebar">
|
|
136
|
+
<%- renderIcon('panel-left-close') %>
|
|
137
|
+
</button>
|
|
138
|
+
<% } %>
|
|
139
|
+
<span class="header-title">
|
|
140
|
+
<%= pageTitle %>
|
|
141
|
+
</span>
|
|
142
|
+
</div>
|
|
143
|
+
|
|
144
|
+
<div class="header-right">
|
|
145
|
+
<% if (optionsMenu?.position==='header' ) { %>
|
|
146
|
+
<%- include('partials/options-menu', { optionsMenu }) %>
|
|
147
|
+
<% } %>
|
|
148
|
+
</div>
|
|
149
|
+
</header>
|
|
150
|
+
<% } %>
|
|
151
|
+
|
|
152
|
+
<main class="content-area" id="main-content">
|
|
153
|
+
<div class="content-layout">
|
|
154
|
+
<div class="main-content">
|
|
155
|
+
<% if (headerConfig?.enabled===false) { %>
|
|
156
|
+
<h1>
|
|
157
|
+
<%= pageTitle %>
|
|
158
|
+
</h1>
|
|
159
|
+
<% } %>
|
|
160
|
+
|
|
161
|
+
<%- content %>
|
|
162
|
+
|
|
163
|
+
<% if (config.pageNavigation && (prevPage ||
|
|
164
|
+
nextPage)) { %>
|
|
165
|
+
<div class="page-navigation">
|
|
166
|
+
<% if (prevPage) { %>
|
|
167
|
+
<a href="<%= prevPage.url %>"
|
|
168
|
+
class="prev-page">
|
|
169
|
+
<%- renderIcon('arrow-left', {
|
|
170
|
+
class: 'page-nav-icon' }) %>
|
|
171
|
+
<span><small>Previous</small><strong>
|
|
172
|
+
<%= prevPage.title
|
|
173
|
+
%>
|
|
174
|
+
</strong></span>
|
|
175
|
+
</a>
|
|
176
|
+
<% } else { %>
|
|
177
|
+
<div
|
|
178
|
+
class="prev-page-placeholder">
|
|
179
|
+
</div>
|
|
180
|
+
<% } %>
|
|
181
|
+
<% if (nextPage) { %>
|
|
182
|
+
<a href="<%= nextPage.url %>"
|
|
183
|
+
class="next-page">
|
|
184
|
+
<span><small>Next</small><strong>
|
|
185
|
+
<%= nextPage.title
|
|
186
|
+
%>
|
|
187
|
+
</strong></span>
|
|
188
|
+
<%- renderIcon('arrow-right',
|
|
189
|
+
{
|
|
190
|
+
class: 'page-nav-icon'
|
|
191
|
+
}) %>
|
|
192
|
+
</a>
|
|
193
|
+
<% } else { %>
|
|
194
|
+
<div
|
|
195
|
+
class="next-page-placeholder">
|
|
196
|
+
</div>
|
|
197
|
+
<% } %>
|
|
198
|
+
</div>
|
|
199
|
+
<% } %>
|
|
200
|
+
</div>
|
|
201
|
+
|
|
202
|
+
<div class="toc-sidebar">
|
|
203
|
+
<%- include('toc', { content, headings, navigationHtml,
|
|
204
|
+
isActivePage }) %>
|
|
205
|
+
</div>
|
|
206
|
+
</div>
|
|
207
|
+
|
|
208
|
+
<div class="page-footer-actions">
|
|
209
|
+
<% if (locals.editUrl) { %>
|
|
210
|
+
<a href="<%= editUrl %>" target="_blank"
|
|
211
|
+
rel="noopener noreferrer" class="edit-link">
|
|
212
|
+
<%- renderIcon('pencil') %>
|
|
213
|
+
<%= editLinkText %>
|
|
214
|
+
</a>
|
|
215
|
+
<% } %>
|
|
216
|
+
</div>
|
|
217
|
+
</main>
|
|
218
|
+
|
|
219
|
+
<%- include('partials/footer', { footerConfig, config,
|
|
220
|
+
relativePathToRoot, logo, siteTitle, footerHtml }) %>
|
|
221
|
+
</div>
|
|
222
|
+
|
|
223
|
+
<script src="<%= relativePathToRoot %>assets/js/docmd-main.js?v=<%= buildHash %>"></script>
|
|
224
|
+
<%- pluginBodyScriptsHtml || '' %>
|
|
225
|
+
<% (customJsFiles || []).forEach(jsFile=> {
|
|
226
|
+
if (jsFile && jsFile.trim() !== '') { %>
|
|
227
|
+
<script
|
|
228
|
+
src="<%= relativePathToRoot %><%- jsFile.startsWith('/') ? jsFile.substring(1) : jsFile %>?v=<%= buildHash %>"></script>
|
|
229
|
+
<% } }); %>
|
|
195
230
|
</body>
|
|
231
|
+
|
|
196
232
|
</html>
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
<%# ---------------------------------------------------------------
|
|
2
|
+
# docmd : the minimalist, zero-config documentation generator.
|
|
3
|
+
# @website https://docmd.io
|
|
4
|
+
# [docmd-source] - Please do not remove this header.
|
|
5
|
+
# ---------------------------------------------------------------
|
|
6
|
+
%>
|
|
7
|
+
|
|
8
|
+
<% function menubarHref(item) { if (!item.url) return '#' ; if (item.external || item.url.startsWith('http')) return
|
|
9
|
+
item.url; let clean=item.url.replace(/^\//, '' ); return relativePathToRoot + clean; } function menubarTarget(item)
|
|
10
|
+
{ return (item.external || (item.url && item.url.startsWith('http'))) ? ' target="_blank" rel="noopener noreferrer"'
|
|
11
|
+
: '' ; } %>
|
|
12
|
+
|
|
13
|
+
<div class="docmd-menubar">
|
|
14
|
+
<div class="menubar-inner">
|
|
15
|
+
<div class="menubar-left">
|
|
16
|
+
<% if (menubarConfig.left && menubarConfig.left.length> 0) { %>
|
|
17
|
+
<% menubarConfig.left.forEach(item=> { %>
|
|
18
|
+
<% if (item.type==='title' ) { %>
|
|
19
|
+
<a href="<%= menubarHref(item) %>" class="menubar-brand" <%- menubarTarget(item) %>>
|
|
20
|
+
<% if (item.icon) { %>
|
|
21
|
+
<%- renderIcon(item.icon, { class: 'menubar-icon' }) %>
|
|
22
|
+
<% } %>
|
|
23
|
+
<% if (item.text) { %>
|
|
24
|
+
<span class="menubar-brand-text">
|
|
25
|
+
<%= item.text %>
|
|
26
|
+
</span>
|
|
27
|
+
<% } %>
|
|
28
|
+
</a>
|
|
29
|
+
<% } else if (item.type==='dropdown' ) { %>
|
|
30
|
+
<div class="menubar-dropdown">
|
|
31
|
+
<button class="menubar-dropdown-toggle" type="button" aria-expanded="false">
|
|
32
|
+
<% if (item.icon) { %>
|
|
33
|
+
<%- renderIcon(item.icon, { class: 'menubar-icon' }) %>
|
|
34
|
+
<% } %>
|
|
35
|
+
<span>
|
|
36
|
+
<%= item.text %>
|
|
37
|
+
</span>
|
|
38
|
+
<%- renderIcon('chevron-down', { class: 'menubar-chevron' }) %>
|
|
39
|
+
</button>
|
|
40
|
+
<ul class="menubar-dropdown-menu">
|
|
41
|
+
<% if (item.items && item.items.length> 0) { %>
|
|
42
|
+
<% item.items.forEach(sub=> { %>
|
|
43
|
+
<li>
|
|
44
|
+
<a href="<%= menubarHref(sub) %>" <%- menubarTarget(sub) %>>
|
|
45
|
+
<% if (sub.icon) { %>
|
|
46
|
+
<%- renderIcon(sub.icon, { class: 'menubar-icon' }) %>
|
|
47
|
+
<% } %>
|
|
48
|
+
<%= sub.text %>
|
|
49
|
+
<% if (sub.external || (sub.url && sub.url.startsWith('http'))) { %>
|
|
50
|
+
<%- renderIcon('external-link', { class: 'menubar-ext-icon' }) %>
|
|
51
|
+
<% } %>
|
|
52
|
+
</a>
|
|
53
|
+
</li>
|
|
54
|
+
<% }) %>
|
|
55
|
+
<% } %>
|
|
56
|
+
</ul>
|
|
57
|
+
</div>
|
|
58
|
+
<% } else { %>
|
|
59
|
+
<a href="<%= menubarHref(item) %>" class="menubar-link" <%- menubarTarget(item) %>>
|
|
60
|
+
<% if (item.icon) { %>
|
|
61
|
+
<%- renderIcon(item.icon, { class: 'menubar-icon' }) %>
|
|
62
|
+
<% } %>
|
|
63
|
+
<span>
|
|
64
|
+
<%= item.text %>
|
|
65
|
+
</span>
|
|
66
|
+
<% if (item.external || (item.url && item.url.startsWith('http'))) { %>
|
|
67
|
+
<%- renderIcon('external-link', { class: 'menubar-ext-icon' }) %>
|
|
68
|
+
<% } %>
|
|
69
|
+
</a>
|
|
70
|
+
<% } %>
|
|
71
|
+
<% }) %>
|
|
72
|
+
</div>
|
|
73
|
+
<% } %>
|
|
74
|
+
</div>
|
|
75
|
+
<div class="menubar-right">
|
|
76
|
+
<% if (menubarConfig.right && menubarConfig.right.length> 0) { %>
|
|
77
|
+
<% menubarConfig.right.forEach(item=> { %>
|
|
78
|
+
<% if (item.type==='dropdown' ) { %>
|
|
79
|
+
<div class="menubar-dropdown">
|
|
80
|
+
<button class="menubar-dropdown-toggle" type="button" aria-expanded="false">
|
|
81
|
+
<% if (item.icon) { %>
|
|
82
|
+
<%- renderIcon(item.icon, { class: 'menubar-icon' }) %>
|
|
83
|
+
<% } %>
|
|
84
|
+
<span>
|
|
85
|
+
<%= item.text %>
|
|
86
|
+
</span>
|
|
87
|
+
<%- renderIcon('chevron-down', { class: 'menubar-chevron' }) %>
|
|
88
|
+
</button>
|
|
89
|
+
<ul class="menubar-dropdown-menu menubar-dropdown-right">
|
|
90
|
+
<% if (item.items && item.items.length> 0) { %>
|
|
91
|
+
<% item.items.forEach(sub=> { %>
|
|
92
|
+
<li>
|
|
93
|
+
<a href="<%= menubarHref(sub) %>" <%- menubarTarget(sub) %>>
|
|
94
|
+
<% if (sub.icon) { %>
|
|
95
|
+
<%- renderIcon(sub.icon, { class: 'menubar-icon' }) %>
|
|
96
|
+
<% } %>
|
|
97
|
+
<%= sub.text %>
|
|
98
|
+
<% if (sub.external || (sub.url && sub.url.startsWith('http'))) { %>
|
|
99
|
+
<%- renderIcon('external-link', { class: 'menubar-ext-icon' }) %>
|
|
100
|
+
<% } %>
|
|
101
|
+
</a>
|
|
102
|
+
</li>
|
|
103
|
+
<% }) %>
|
|
104
|
+
<% } %>
|
|
105
|
+
</ul>
|
|
106
|
+
</div>
|
|
107
|
+
<% } else { %>
|
|
108
|
+
<a href="<%= menubarHref(item) %>" class="menubar-link" <%- menubarTarget(item) %>>
|
|
109
|
+
<% if (item.icon) { %>
|
|
110
|
+
<%- renderIcon(item.icon, { class: 'menubar-icon' }) %>
|
|
111
|
+
<% } %>
|
|
112
|
+
<span>
|
|
113
|
+
<%= item.text %>
|
|
114
|
+
</span>
|
|
115
|
+
<% if (item.external || (item.url && item.url.startsWith('http'))) { %>
|
|
116
|
+
<%- renderIcon('external-link', { class: 'menubar-ext-icon' }) %>
|
|
117
|
+
<% } %>
|
|
118
|
+
</a>
|
|
119
|
+
<% } %>
|
|
120
|
+
<% }) %>
|
|
121
|
+
<% } %>
|
|
122
|
+
<% if (optionsMenu && optionsMenu.position==='menubar' ) { %>
|
|
123
|
+
<div class="menubar-options">
|
|
124
|
+
<%- include('options-menu', { optionsMenu }) %>
|
|
125
|
+
</div>
|
|
126
|
+
<% } %>
|
|
127
|
+
</div>
|
|
128
|
+
</div>
|
|
129
|
+
</div>
|