@mgks/docmd 0.2.1 → 0.2.3

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/config.js CHANGED
@@ -28,7 +28,7 @@ module.exports = {
28
28
 
29
29
  // Theme Configuration
30
30
  theme: {
31
- name: 'sky', // Themes: 'default', 'sky', 'retro', 'ruby'
31
+ name: 'sky', // Themes: 'default', 'sky', 'retro', 'ruby'
32
32
  defaultMode: 'light', // Initial color mode: 'light' or 'dark'
33
33
  enableModeToggle: true, // Show UI button to toggle light/dark modes
34
34
  positionMode: 'top', // 'top' or 'bottom' for the theme toggle
@@ -107,6 +107,7 @@ module.exports = {
107
107
  title: 'Content',
108
108
  icon: 'layout-template',
109
109
  path: '/content/',
110
+ collapsible: true,
110
111
  children: [
111
112
  { title: 'Frontmatter', path: '/content/frontmatter', icon: 'file-text' },
112
113
  { title: 'Markdown Syntax', path: '/content/markdown-syntax', icon: 'code-2' },
@@ -115,6 +116,7 @@ module.exports = {
115
116
  title: 'Custom Containers',
116
117
  path: '/content/containers/',
117
118
  icon: 'box',
119
+ collapsible: true,
118
120
  children: [
119
121
  { title: 'Callouts', path: '/content/containers/callouts', icon: 'megaphone' },
120
122
  { title: 'Cards', path: '/content/containers/cards', icon: 'panel-top' },
@@ -133,6 +135,7 @@ module.exports = {
133
135
  title: 'Theming',
134
136
  icon: 'palette',
135
137
  path: '/theming/',
138
+ collapsible: true,
136
139
  children: [
137
140
  { title: 'Available Themes', path: '/theming/available-themes', icon: 'layout-grid' },
138
141
  { title: 'Light & Dark Mode', path: '/theming/light-dark-mode', icon: 'sun-moon' },
@@ -144,6 +147,7 @@ module.exports = {
144
147
  title: 'Plugins',
145
148
  icon: 'puzzle',
146
149
  path: '/plugins/',
150
+ collapsible: true,
147
151
  children: [
148
152
  { title: 'SEO & Meta Tags', path: '/plugins/seo', icon: 'search' },
149
153
  { title: 'Analytics', path: '/plugins/analytics', icon: 'bar-chart' },
@@ -32,7 +32,7 @@ module.exports = {
32
32
  name: 'sky',
33
33
  defaultMode: 'light',
34
34
  enableModeToggle: true,
35
- positionMode: 'bottom', // 'top' or 'bottom'
35
+ positionMode: 'top', // 'top' or 'bottom'
36
36
  customCss: [ // Array of paths to your custom CSS files
37
37
  // '/css/override-styles.css', // Paths are relative to the outputDir root
38
38
  ],
@@ -84,6 +84,7 @@ module.exports = {
84
84
  {
85
85
  title: 'Guides',
86
86
  icon: 'book-open',
87
+ collapsible: true, // This makes the 'Guides' section collapsible
87
88
  children: [
88
89
  { title: 'Installation', path: '/guides/installation', icon: 'download' },
89
90
  { title: 'Project GitHub', path: 'https://github.com/mgks/docmd', icon: 'github', external: true }
@@ -225,7 +226,9 @@ Configures the visual theme of your site.
225
226
  * `path` (String, Required for direct links)
226
227
  * `children` (Array, Optional)
227
228
  * `icon` (String, Optional): The name of an SVG icon to display next to the navigation item. `docmd` will look for an SVG file named `icon-name.svg` in its bundled assets (e.g., `home` for `home.svg`). Ensure the chosen icon name corresponds to an available SVG. See [Theming > Icons](/theming/icons/) for more details.
229
+ * `collapsible` (Boolean, Optional): If set to `true` on a parent item (an item with `children`), the item will become a collapsible accordion. It will be collapsed by default unless one of its children is the currently active page. User interactions (opening/closing) are saved in `sessionStorage`. Defaults to `false`.
228
230
  * `external` (Boolean, Optional): If set to `true`, the `path` is treated as an absolute external URL and the link will open in a new tab (`target="_blank"`). Defaults to `false`.
231
+ * `collapsible` (Boolean, Optional): If set to `true` on a parent item (an item with `children`), the item will become a collapsible accordion. It will be collapsed by default unless one of its children is the currently active page. User interactions (opening/closing) are saved in `sessionStorage`. Defaults to `false`.
229
232
 
230
233
  ## `footer` (String, Optional)
231
234
  * **Description:** Custom footer text (Markdown supported). **Note:** For noStyle pages, the footer must be explicitly enabled via `components.footer: true`.
@@ -74,7 +74,7 @@ You can include cards, callouts, and buttons inside steps for richer content:
74
74
  3. **Initialize Project**
75
75
  Create the project structure and configuration files.
76
76
 
77
- ::: button Create_Project external:https://github.com/new color:blue
77
+ ::: button Create_Project external:https://github.com/new color:#2564e4
78
78
 
79
79
  4. **Start Coding**
80
80
  Begin implementing your application features.
@@ -110,7 +110,7 @@ You can include cards, callouts, and buttons inside steps for richer content:
110
110
  3. **Initialize Project**
111
111
  Create the project structure and configuration files.
112
112
 
113
- ::: button Create_Project external:https://github.com/new color:blue
113
+ ::: button Create_Project external:https://github.com/new color:#2564e4
114
114
 
115
115
  4. **Start Coding**
116
116
  Begin implementing your application features.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mgks/docmd",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "Generate beautiful, lightweight static documentation sites directly from your Markdown files. Zero clutter, just content.",
5
5
  "main": "src/index.js",
6
6
  "exports": {
@@ -3,5 +3,5 @@
3
3
  /*
4
4
  * Main CSS file for docmd
5
5
  */
6
-
7
- .docmd-container.steps-reset .docmd-container.steps-reset ol.steps-list>li.step-item::before,.docmd-container.steps-reset ol.steps-list>li.step-item::before,.docmd-container.steps-reset ol.steps-list[start]>li.step-item::before{content:counter(list-counter) ".";font-weight:700;margin-right:.5em;color:var(--accent-color,#007acc)}.docmd-tab-pane.active,.logo-link img,.logo-link img.logo-light,.tab-panel.active,.theme-toggle-button .icon-sun,body.sidebar-collapsible .sidebar-toggle-button,html[data-theme=dark] .logo-link img.logo-dark,html[data-theme=dark] .theme-toggle-button .icon-moon,img{display:block}:root{--font-family-sans:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;--font-family-mono:"SFMono-Regular",Consolas,"Liberation Mono",Menlo,Courier,monospace;--bg-color:#ffffff;--text-color:#333333;--sidebar-bg:#f4f7f9;--sidebar-text:#2c3e50;--sidebar-link-active-bg:#e0e7ec;--sidebar-link-active-parent-bg:#e9eff3;--link-color:#007bff;--border-color:#e0e0e0;--code-bg:#f8f8f8;--code-text:#333;--header-bg:#ffffff;--header-border:#e0e0e0;--image-border-color:#e0e0e0;--image-shadow:0 2px 8px rgba(0, 0, 0, 0.1);--image-caption-bg:#f8f8f8;--image-caption-text:#666;--lightbox-bg:rgba(0, 0, 0, 0.9);--lightbox-text:#fff}[data-theme=dark]{--bg-color:#1a1a1a;--text-color:#e0e0e0;--sidebar-bg:#2c2c2c;--sidebar-text:#bdc3c7;--sidebar-link-active-bg:#3a3a3a;--sidebar-link-active-parent-bg:#343434;--link-color:#58a6ff;--border-color:#444444;--code-bg:#282c34;--code-text:#abb2bf;--header-bg:#1a1a1a;--header-border:#444444;--image-border-color:#444444;--image-shadow:0 2px 8px rgba(0, 0, 0, 0.3);--image-caption-bg:#2c2c2c;--image-caption-text:#bdc3c7;--lightbox-bg:rgba(0, 0, 0, 0.95);--lightbox-text:#fff}body{font-family:var(--font-family-sans);background-color:var(--bg-color);color:var(--text-color);margin:0;display:flex;min-height:100vh;line-height:1.6}code,pre{font-family:var(--font-family-mono);background-color:var(--code-bg)}.sidebar{width:260px;background-color:var(--sidebar-bg);color:var(--sidebar-text);padding:20px;border-right:1px solid var(--border-color);height:100vh;position:fixed;top:0;left:0;overflow-y:auto;box-sizing:border-box;flex-shrink:0}.sidebar h1{font-size:1.5em;margin-top:0;margin-bottom:20px;padding-bottom:10px;border-bottom:1px solid var(--border-color)}.sidebar nav ul{list-style:none;padding:0;margin:0}.sidebar nav li a{display:block;padding:8px 10px;text-decoration:none;color:var(--sidebar-text);border-radius:4px;transition:background-color .2s}.copy-code-button:hover,.docmd-tabs-nav-item:hover,.sidebar nav li a.active,.sidebar nav li a:hover,.theme-toggle-button:hover{background-color:var(--sidebar-link-active-bg)}.sidebar nav li a.active{font-weight:600;color:var(--link-color)}.sidebar nav li.active-parent>a{background-color:var(--sidebar-link-active-parent-bg);font-weight:500;position:relative}.sidebar nav li.active-parent>a::before{content:"";position:absolute;left:0;top:0;bottom:0;width:3px;background-color:var(--link-color);opacity:.5}.sidebar nav li.active-parent>a.active::before,div:hover>.copy-code-button,.copy-code-button:hover{opacity:1}.sidebar nav ul ul{padding-left:20px;margin-top:5px}.sidebar-toggle-button{background:0 0;border:1px solid transparent;color:var(--text-color);cursor:pointer;padding:0;margin:.5em 0 0;display:none;border-radius:4px}.sidebar-toggle-button:hover{background-color:var(--sidebar-bg);border-color:var(--border-color)}.sidebar-toggle-button .lucide-icon{width:2em;height:2em}body.sidebar-collapsed .sidebar{transform:translateX(-100%);visibility:hidden}.toc-level-2,body.sidebar-collapsed .main-content-wrapper{margin-left:0}.main-content-wrapper,.sidebar{transition:transform .3s,margin-left .3s,visibility .3s}.main-content-wrapper{margin-left:260px;flex-grow:1;display:flex;flex-direction:column;overflow:hidden}.header-left,.page-header{align-items:center;display:flex}.page-header{padding:15px 30px;border-bottom:1px solid var(--header-border);background-color:var(--header-bg);justify-content:space-between;min-height:2.5em}.header-left{gap:15px}.header-right{display:flex;align-items:center}.page-header h1{margin:0;font-size:1.8em}.theme-toggle-header{padding:8px;background:var(--content-bg);border:1px solid var(--border-color);border-radius:6px;cursor:pointer;transition:.2s}.theme-toggle-header:hover{background:var(--sidebar-bg);border-color:var(--accent-color)}.card .card-title,.sidebar-header{border-bottom:1px solid var(--border-color)}.content-area{padding:2.5rem 2rem;max-width:1200px;margin:0 auto;width:100%;box-sizing:border-box}pre{color:var(--code-text);padding:1em;border-radius:4px;overflow-x:auto;position:relative}code{padding:.2em .4em;border-radius:3px;font-size:.9em}pre code{background-color:transparent;padding:0;font-size:inherit}.sidebar-header{padding-bottom:10px;margin-bottom:10px;text-align:center;height:2.5em}.sidebar-header h1{font-size:1.5em;margin-top:0;margin-bottom:0}.logo-link img{max-height:40px;width:auto;margin:0 auto}.docmd-tab-pane,.logo-link img.logo-dark,.tab-panel,.theme-toggle-button .icon-moon,html[data-theme=dark] .logo-link img.logo-light,html[data-theme=dark] .theme-toggle-button .icon-sun{display:none}.sidebar-nav .lucide-icon{width:1em;height:1em;margin-right:.5em;vertical-align:-.15em;stroke-width:2}.sidebar-nav .nav-external-icon{width:1em;height:1.5em;float:right;margin-left:.3em;opacity:.7}.theme-toggle-button{background:0 0;border:1px solid var(--border-color);color:var(--sidebar-text);padding:8px;border-radius:4px;cursor:pointer;margin-top:.5em;display:flex;align-items:center;justify-content:center;width:100%}.next-page,.prev-page,.step::before{color:var(--link-color);display:flex}.callout .callout-content>:first-child,.card .card-content>:first-child,.docmd-container>:first-child,.step-content>:first-child,.step-title{margin-top:0}.theme-toggle-button .lucide-icon{width:1.2em;height:1.2em}.docmd-container{padding:1rem 1.5rem;margin-bottom:1.5rem;border-radius:6px;border:1px solid var(--border-color);background-color:var(--code-bg)}.callout .callout-content>:last-child,.card .card-content>:last-child,.docmd-container>:last-child,.step-content>:last-child{margin-bottom:0}.callout{border-left-width:5px;background-color:transparent}.callout-title{font-weight:700;margin-bottom:.5em}.callout-info{border-left-color:#3498db;background-color:rgba(52,152,219,.07)}.callout-warning{border-left-color:#f39c12;background-color:rgba(243,156,18,.07)}.callout-success,.callout-tip{border-left-color:#2ecc71;background-color:rgba(46,204,113,.07)}.callout-danger{border-left-color:#e74c3c;background-color:rgba(231,76,60,.07)}.card .card-title{font-weight:700;font-size:1.1em;margin:-1rem -1.5rem 1rem;padding:.75rem 1.5rem}.docmd-container.steps{position:relative;padding-left:3rem;border:none;background:0 0;box-shadow:none}.docmd-container.steps::before{content:"";position:absolute;top:1rem;bottom:1rem;left:2.5rem;width:2px;background-color:var(--border-color)}.step{position:relative;padding-bottom:1.5rem}.step:last-child{padding-bottom:0}.step::before{content:attr(data-step);position:absolute;left:-3rem;top:.1rem;width:2.5rem;height:2.5rem;background-color:var(--bg-color);border:2px solid var(--border-color);border-radius:50%;align-items:center;justify-content:center;font-size:1rem;font-weight:600;z-index:1}.step-title{font-size:1.25rem;font-weight:600;margin-bottom:.5rem}.docmd-container.steps-reset{counter-reset:step-counter 0}.docmd-container.steps-reset ol.steps-list{counter-reset:list-counter 0;list-style:none}.docmd-container.steps-reset ol.steps-list>li.step-item{counter-increment:list-counter 1;position:relative;padding-left:0;margin-bottom:2.5rem}.docmd-container.steps-reset ol.steps-list>li.step-item::before{font-size:2rem}.docmd-container.steps-reset .docmd-container.steps-reset ol.steps-list,.docmd-container.steps-reset ol.steps-list[start]{counter-reset:list-counter 0}.docmd-container.steps-reset .docmd-container.steps-reset ol.steps-list>li.step-item,.docmd-container.steps-reset ol.steps-list[start]>li.step-item{counter-increment:list-counter 1}.docmd-container.steps-reset ol:not(.steps-list)::before,.docmd-container.steps-reset ol:not(.steps-list)>li::before,.docmd-container.steps-reset ul::before,.docmd-container.steps-reset ul>li::before{width:.75rem;height:.75rem;left:-1.5rem;top:.5rem;content:""!important}:focus-visible{outline:2px solid var(--link-color);outline-offset:2px}:focus:not(:focus-visible){outline:currentcolor}.sidebar nav li a:focus-visible{background-color:var(--sidebar-link-active-bg);outline:2px solid var(--link-color);outline-offset:-2px}.theme-toggle-button:focus-visible{border-color:var(--link-color);box-shadow:0 0 0 2px var(--link-color)}.page-footer,.page-navigation{border-top:1px solid var(--border-color)}.page-navigation{display:flex;justify-content:space-between;margin-top:3rem;padding-top:1.5rem}.next-page,.prev-page{align-items:center;text-decoration:none;padding:.75rem;border-radius:6px;transition:background-color .2s;width:48%;max-width:48%}.next-page:hover,.prev-page:hover{background-color:rgba(0,0,0,.05);text-decoration:none}[data-theme=dark] .next-page:hover,[data-theme=dark] .prev-page:hover{background-color:rgba(255,255,255,.05)}.prev-page{justify-content:flex-start}.next-page{justify-content:flex-end;text-align:right}.next-page-placeholder,.prev-page-placeholder{width:48%}.next-page span,.prev-page span{display:flex;flex-direction:column}.next-page small,.prev-page small{font-size:.8rem;opacity:.8;margin-bottom:.25rem}.next-page strong,.prev-page strong{font-weight:500}.page-nav-icon{width:1.2rem;height:1.2rem}.prev-page .page-nav-icon{margin-right:.75rem}.next-page .page-nav-icon{margin-left:.75rem}.page-footer{text-align:center;padding:20px 30px;margin-top:auto;font-size:.9em;color:var(--text-color);background-color:var(--sidebar-bg)}.footer-content{display:flex;justify-content:space-between;align-items:center;margin:0 auto;width:100%}.user-footer{text-align:left}.branding-footer{text-align:right;opacity:.9;font-weight:500}.branding-footer svg{color:#fb3a3a}.page-footer a{color:var(--link-color);text-decoration:none}.page-footer a:hover,.toc-link:hover{text-decoration:underline}.content-layout{display:flex;gap:2rem;width:100%}.main-content{flex:1 1 0%;min-inline-size:0px}.toc-container{margin:0;padding:0;border:none;background-color:transparent}.docmd-container figure img,.toc-title{margin-bottom:.5rem}.toc-title{margin-top:0;font-size:1rem;font-weight:700;color:var(--text-muted)}.toc-list{list-style:none;padding-left:0;margin:0}.toc-item{margin-bottom:.25rem;line-height:1.4}.toc-link{text-decoration:none;color:var(--link-color);display:inline-block;padding:.1rem 0;font-size:.9rem;font-weight:500}.toc-level-3{margin-left:.75rem;font-size:.85rem}.toc-level-4{margin-left:1.5rem;font-size:.8rem}.toc-sidebar{width:180px;position:sticky;top:2rem;max-height:calc(-4rem + 100vh);overflow-y:auto;align-self:flex-start}@media (max-width:1024px){.content-layout{flex-direction:column;display:flex;flex-direction:column-reverse}.toc-sidebar{width:100%;position:static;margin-bottom:1rem}}.docmd-tabs,img{margin:1.5rem 0}img{max-width:100%;height:auto}img.align-left{float:left;margin-right:1.5rem;margin-bottom:1rem}img.align-center{margin-left:auto;margin-right:auto}img.align-right{float:right;margin-left:1.5rem;margin-bottom:1rem}img.size-small{max-width:300px}img.size-medium{max-width:500px}img.size-large{max-width:800px}img.with-border{border:1px solid var(--image-border-color);padding:4px}img.with-shadow{box-shadow:var(--image-shadow)}.docmd-container figure{margin:2rem 0}.docmd-container figcaption{font-size:.9rem;color:var(--image-caption-text);text-align:center;padding:.5rem;background-color:var(--image-caption-bg);border-radius:0 0 4px 4px}.docmd-container .image-gallery{display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:1rem;margin:2rem 0}.docmd-container .image-gallery figure{margin:0}.docmd-container .clear-float::after{content:"";display:table;clear:both}.docmd-tabs{border:1px solid var(--border-color);border-radius:6px;overflow:hidden;box-shadow:rgba(0,0,0,.05) 0 1px 3px}.docmd-tabs-nav{display:flex;background-color:var(--sidebar-bg);border-bottom:1px solid var(--border-color);overflow:auto hidden}.docmd-tabs-nav-item{padding:.75rem 1.25rem;cursor:pointer;border-bottom:3px solid transparent;margin-bottom:-1px;font-weight:500;color:var(--sidebar-text);white-space:nowrap}.docmd-tabs-nav-item.active{color:var(--link-color);border-bottom-color:var(--link-color);background-color:var(--bg-color)}.docmd-tabs-content{padding:1.5rem}.tabs-container{margin:1rem 0;border:1px solid #e1e5e9;border-radius:.375rem}.tab-navigation{display:flex;background-color:#f8f9fa;border-bottom:1px solid #e1e5e9;border-radius:.375rem .375rem 0 0}.tab-button{padding:.75rem 1rem;border-width:medium medium 2px;border-style:none none solid;border-color:currentcolor currentcolor transparent;border-image:none;background:0 0;cursor:pointer;transition:.2s}.tab-button:hover{background-color:#e9ecef}.tab-button.active{border-bottom-color:#007bff;background-color:#fff}.tab-content{padding:1rem}.docmd-lightbox{display:none;position:fixed;top:0;left:0;width:100%;height:100%;background-color:var(--lightbox-bg);z-index:9999;justify-content:center;align-items:center;flex-direction:column}.copy-code-button svg,.sponsor-icon{width:1rem;height:1rem}.docmd-lightbox-content{position:relative;max-width:90%;max-height:90%;text-align:center}.docmd-lightbox-content img{max-width:100%;max-height:80vh;object-fit:contain;margin:0 auto;box-shadow:rgba(0,0,0,.3) 0 0 20px}.docmd-lightbox-caption{color:var(--lightbox-text);padding:1rem;font-size:1rem;max-width:100%}.docmd-lightbox-close{position:absolute;top:20px;right:30px;color:var(--lightbox-text);font-size:2.5rem;cursor:pointer;z-index:10000}.docmd-lightbox-close:hover{color:#ddd}.docmd-button,.sponsor-link,.sponsor-link:hover{color:#fff;text-decoration:none}.docmd-container .image-gallery img,img.lightbox{cursor:zoom-in}.docmd-button{display:inline-block;padding:.6rem 1.2rem;margin:.5rem;border-radius:6px;background-color:var(--link-color);font-weight:500;transition:background-color .2s,transform .2s;border:none;cursor:pointer}.docmd-button:hover{text-decoration:none;filter:brightness(90%);transform:translateY(-1px)}.sponsor-ribbon{position:fixed;bottom:60px;right:10px;z-index:1000;transform:rotate(0);transform-origin:center}.sponsor-link{display:flex;align-items:center;gap:.5rem;background:linear-gradient(135deg,#ff6b6b,#ee5a24);padding:.75rem 1.5rem;border-radius:5px;box-shadow:0 4px 12px rgba(255,107,107,.3);font-weight:600;font-size:.875rem;transition:.3s;white-space:nowrap}.sponsor-link:hover{transform:scale(1.02);box-shadow:0 6px 20px rgba(255,107,107,.4)}.sponsor-icon{animation:2s ease-in-out infinite heartbeat}.sponsor-text{font-family:inherit}@keyframes heartbeat{0%,100%{transform:scale(1)}50%{transform:scale(1.1)}}@media (max-width:768px){body{flex-direction:column}.sidebar{width:100%;height:auto;position:static;border-right:currentcolor;border-bottom:1px solid var(--border-color)}.sidebar-toggle-button{display:block}.main-content-wrapper{margin-left:0}.content-area{padding:15px}.footer-content,.page-navigation{flex-direction:column;gap:1rem}.branding-footer,.user-footer{text-align:center}.next-page,.next-page-placeholder,.prev-page,.prev-page-placeholder{width:100%;max-width:100%}img.align-left,img.align-right{float:none;margin-left:auto;margin-right:auto}.docmd-container .image-gallery{grid-template-columns:1fr}.sponsor-ribbon{bottom:10px;right:10px}.sponsor-link{padding:.5rem 1rem;font-size:.75rem}.sponsor-icon{width:.875rem;height:.875rem}}html[data-theme=dark] .sponsor-link{background:linear-gradient(135deg,#ff6b6b,#c44569);box-shadow:0 4px 12px rgba(255,107,107,.2)}html[data-theme=dark] .sponsor-link:hover{box-shadow:0 6px 20px rgba(255,107,107,.3)}.copy-code-button{position:absolute;top:.75rem;right:.75rem;padding:.5rem;background-color:var(--code-bg);border:1px solid var(--border-color);border-radius:6px;cursor:pointer;opacity:0;transition:opacity .2s ease-in-out,background-color .2s;color:var(--sidebar-text);display:flex;align-items:center;justify-content:center;z-index:10;pointer-events:auto}.copy-code-button.copied{color:#10b981;opacity:1}
6
+
7
+ .docmd-container.steps-reset .docmd-container.steps-reset ol.steps-list>li.step-item::before,.docmd-container.steps-reset ol.steps-list>li.step-item::before,.docmd-container.steps-reset ol.steps-list[start]>li.step-item::before{content:counter(list-counter) ".";font-weight:700;margin-right:.5em;color:var(--accent-color,#007acc)}.docmd-tab-pane.active,.logo-link img,.logo-link img.logo-light,.tab-panel.active,.theme-toggle-button .icon-sun,body.sidebar-collapsible .sidebar-toggle-button,html[data-theme=dark] .logo-link img.logo-dark,html[data-theme=dark] .theme-toggle-button .icon-moon,img{display:block}:root{--font-family-sans:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;--font-family-mono:"SFMono-Regular",Consolas,"Liberation Mono",Menlo,Courier,monospace;--bg-color:#ffffff;--text-color:#333333;--sidebar-bg:#f4f7f9;--sidebar-text:#2c3e50;--sidebar-link-active-bg:#e0e7ec;--sidebar-link-active-parent-bg:#e9eff3;--link-color:#007bff;--border-color:#e0e0e0;--code-bg:#f8f8f8;--code-text:#333;--header-bg:#ffffff;--header-border:#e0e0e0;--image-border-color:#e0e0e0;--image-shadow:0 2px 8px rgba(0, 0, 0, 0.1);--image-caption-bg:#f8f8f8;--image-caption-text:#666;--lightbox-bg:rgba(0, 0, 0, 0.9);--lightbox-text:#fff}[data-theme=dark]{--bg-color:#1a1a1a;--text-color:#e0e0e0;--sidebar-bg:#2c2c2c;--sidebar-text:#bdc3c7;--sidebar-link-active-bg:#3a3a3a;--sidebar-link-active-parent-bg:#343434;--link-color:#58a6ff;--border-color:#444444;--code-bg:#282c34;--code-text:#abb2bf;--header-bg:#1a1a1a;--header-border:#444444;--image-border-color:#444444;--image-shadow:0 2px 8px rgba(0, 0, 0, 0.3);--image-caption-bg:#2c2c2c;--image-caption-text:#bdc3c7;--lightbox-bg:rgba(0, 0, 0, 0.95);--lightbox-text:#fff}body{font-family:var(--font-family-sans);background-color:var(--bg-color);color:var(--text-color);margin:0;display:flex;min-height:100vh;line-height:1.6}code,pre{font-family:var(--font-family-mono);background-color:var(--code-bg)}.sidebar{width:260px;background-color:var(--sidebar-bg);color:var(--sidebar-text);padding:20px;border-right:1px solid var(--border-color);height:100vh;position:fixed;top:0;left:0;overflow-y:auto;box-sizing:border-box;flex-shrink:0}.sidebar h1{font-size:1.5em;margin-top:0;margin-bottom:20px;padding-bottom:10px;border-bottom:1px solid var(--border-color)}.sidebar nav ul{list-style:none;padding:0;margin:0}.sidebar nav li a{display:block;padding:8px 10px;text-decoration:none;color:var(--sidebar-text);border-radius:4px;transition:background-color .2s}.copy-code-button:hover,.docmd-tabs-nav-item:hover,.sidebar nav li a.active,.sidebar nav li a:hover,.theme-toggle-button:hover{background-color:var(--sidebar-link-active-bg)}.sidebar nav li a.active{font-weight:600;color:var(--link-color)}.sidebar nav li.active-parent>a{background-color:var(--sidebar-link-active-parent-bg);font-weight:500;position:relative}.sidebar nav li.active-parent>a::before{content:"";position:absolute;left:0;top:0;bottom:0;width:3px;background-color:var(--link-color);opacity:.5}.copy-code-button:hover,.sidebar nav li.active-parent>a.active::before,div:hover>.copy-code-button{opacity:1}.sidebar nav ul ul{padding-left:20px;margin-top:5px}.sidebar-toggle-button{background:0 0;border:1px solid transparent;color:var(--text-color);cursor:pointer;padding:0;margin:.5em 0 0;display:none;border-radius:4px}.sidebar-toggle-button:hover{background-color:var(--sidebar-bg);border-color:var(--border-color)}.sidebar-toggle-button .lucide-icon{width:2em;height:2em}body.sidebar-collapsed .sidebar{transform:translateX(-100%);visibility:hidden}.toc-level-2,body.sidebar-collapsed .main-content-wrapper{margin-left:0}.main-content-wrapper,.sidebar{transition:transform .3s,margin-left .3s,visibility .3s}.main-content-wrapper{margin-left:260px;flex-grow:1;display:flex;flex-direction:column;overflow:hidden}.header-left,.page-header{align-items:center;display:flex}.page-header{padding:15px 30px;border-bottom:1px solid var(--header-border);background-color:var(--header-bg);justify-content:space-between;min-height:2.5em}.header-left{gap:15px}.header-right{display:flex;align-items:center}.page-header h1{margin:0;font-size:1.8em}.theme-toggle-header{padding:8px;background:var(--content-bg);border:1px solid var(--border-color);border-radius:6px;cursor:pointer;transition:.2s}.theme-toggle-header:hover{background:var(--sidebar-bg);border-color:var(--accent-color)}.card .card-title,.sidebar-header{border-bottom:1px solid var(--border-color)}.content-area{padding:2.5rem 2rem;max-width:1200px;margin:0 auto;width:100%;box-sizing:border-box}pre{color:var(--code-text);padding:1em;border-radius:4px;overflow-x:auto;position:relative}code{padding:.2em .4em;border-radius:3px;font-size:.9em}pre code{background-color:transparent;padding:0;font-size:inherit}.sidebar-header{padding-bottom:10px;margin-bottom:10px;text-align:center;height:2.5em}.sidebar-header h1{font-size:1.5em;margin-top:0;margin-bottom:0}.logo-link img{max-height:40px;width:auto;margin:0 auto}.docmd-tab-pane,.logo-link img.logo-dark,.tab-panel,.theme-toggle-button .icon-moon,html[data-theme=dark] .logo-link img.logo-light,html[data-theme=dark] .theme-toggle-button .icon-sun,.sidebar nav li.collapsible:not([aria-expanded=true])>.submenu{display:none}.sidebar-nav .lucide-icon{width:1em;height:1em;margin-right:.5em;vertical-align:-.15em;stroke-width:2}.sidebar-nav .nav-external-icon{width:1em;height:1.5em;float:right;margin-left:.3em;opacity:.7}.theme-toggle-button{background:0 0;border:1px solid var(--border-color);color:var(--sidebar-text);padding:8px;border-radius:4px;cursor:pointer;margin-top:.5em;display:flex;align-items:center;justify-content:center;width:100%}.next-page,.prev-page,.step::before{color:var(--link-color);display:flex}.callout .callout-content>:first-child,.card .card-content>:first-child,.docmd-container>:first-child,.step-content>:first-child,.step-title{margin-top:0}.theme-toggle-button .lucide-icon{width:1.2em;height:1.2em}.docmd-container{padding:1rem 1.5rem;margin-bottom:1.5rem;border-radius:6px;border:1px solid var(--border-color);background-color:var(--code-bg)}.callout .callout-content>:last-child,.card .card-content>:last-child,.docmd-container>:last-child,.step-content>:last-child{margin-bottom:0}.callout{border-left-width:5px;background-color:transparent}.callout-title{font-weight:700;margin-bottom:.5em}.callout-info{border-left-color:#3498db;background-color:rgba(52,152,219,.07)}.callout-warning{border-left-color:#f39c12;background-color:rgba(243,156,18,.07)}.callout-success,.callout-tip{border-left-color:#2ecc71;background-color:rgba(46,204,113,.07)}.callout-danger{border-left-color:#e74c3c;background-color:rgba(231,76,60,.07)}.card .card-title{font-weight:700;font-size:1.1em;margin:-1rem -1.5rem 1rem;padding:.75rem 1.5rem}.docmd-container.steps{position:relative;padding-left:3rem;border:none;background:0 0;box-shadow:none}.docmd-container.steps::before{content:"";position:absolute;top:1rem;bottom:1rem;left:2.5rem;width:2px;background-color:var(--border-color)}.step{position:relative;padding-bottom:1.5rem}.step:last-child{padding-bottom:0}.step::before{content:attr(data-step);position:absolute;left:-3rem;top:.1rem;width:2.5rem;height:2.5rem;background-color:var(--bg-color);border:2px solid var(--border-color);border-radius:50%;align-items:center;justify-content:center;font-size:1rem;font-weight:600;z-index:1}.step-title{font-size:1.25rem;font-weight:600;margin-bottom:.5rem}.docmd-container.steps-reset{counter-reset:step-counter 0}.docmd-container.steps-reset ol.steps-list{counter-reset:list-counter 0;list-style:none}.docmd-container.steps-reset ol.steps-list>li.step-item{counter-increment:list-counter 1;position:relative;padding-left:0;margin-bottom:2.5rem}.docmd-container.steps-reset ol.steps-list>li.step-item::before{font-size:2rem}.docmd-container.steps-reset .docmd-container.steps-reset ol.steps-list,.docmd-container.steps-reset ol.steps-list[start]{counter-reset:list-counter 0}.docmd-container.steps-reset .docmd-container.steps-reset ol.steps-list>li.step-item,.docmd-container.steps-reset ol.steps-list[start]>li.step-item{counter-increment:list-counter 1}.docmd-container.steps-reset ol:not(.steps-list)::before,.docmd-container.steps-reset ol:not(.steps-list)>li::before,.docmd-container.steps-reset ul::before,.docmd-container.steps-reset ul>li::before{width:.75rem;height:.75rem;left:-1.5rem;top:.5rem;content:""!important}:focus-visible{outline:2px solid var(--link-color);outline-offset:2px}:focus:not(:focus-visible){outline:currentcolor}.sidebar nav li a:focus-visible{background-color:var(--sidebar-link-active-bg);outline:2px solid var(--link-color);outline-offset:-2px}.theme-toggle-button:focus-visible{border-color:var(--link-color);box-shadow:0 0 0 2px var(--link-color)}.page-footer,.page-navigation{border-top:1px solid var(--border-color)}.page-navigation{display:flex;justify-content:space-between;margin-top:3rem;padding-top:1.5rem}.next-page,.prev-page{align-items:center;text-decoration:none;padding:.75rem;border-radius:6px;transition:background-color .2s;width:48%;max-width:48%}.next-page:hover,.prev-page:hover{background-color:rgba(0,0,0,.05);text-decoration:none}[data-theme=dark] .next-page:hover,[data-theme=dark] .prev-page:hover{background-color:rgba(255,255,255,.05)}.prev-page{justify-content:flex-start}.next-page{justify-content:flex-end;text-align:right}.next-page-placeholder,.prev-page-placeholder{width:48%}.next-page span,.prev-page span{display:flex;flex-direction:column}.next-page small,.prev-page small{font-size:.8rem;opacity:.8;margin-bottom:.25rem}.next-page strong,.prev-page strong{font-weight:500}.page-nav-icon{width:1.2rem;height:1.2rem}.prev-page .page-nav-icon{margin-right:.75rem}.next-page .page-nav-icon{margin-left:.75rem}.page-footer{text-align:center;padding:20px 30px;margin-top:auto;font-size:.9em;color:var(--text-color);background-color:var(--sidebar-bg)}.footer-content{display:flex;justify-content:space-between;align-items:center;margin:0 auto;width:100%}.user-footer{text-align:left}.branding-footer{text-align:right;opacity:.9;font-weight:500}.branding-footer svg{color:#fb3a3a}.page-footer a{color:var(--link-color);text-decoration:none}.page-footer a:hover,.toc-link:hover{text-decoration:underline}.content-layout{display:flex;gap:2rem;width:100%}.main-content{flex:1 1 0%;min-inline-size:0px}.toc-container{margin:0;padding:0;border:none;background-color:transparent}.docmd-container figure img,.toc-title{margin-bottom:.5rem}.toc-title{margin-top:0;font-size:1rem;font-weight:700;color:var(--text-muted)}.toc-list{list-style:none;padding-left:0;margin:0}.toc-item{margin-bottom:.25rem;line-height:1.4}.toc-link{text-decoration:none;color:var(--link-color);display:inline-block;padding:.1rem 0;font-size:.9rem;font-weight:500}.toc-level-3{margin-left:.75rem;font-size:.85rem}.toc-level-4{margin-left:1.5rem;font-size:.8rem}.toc-sidebar{width:180px;position:sticky;top:2rem;max-height:calc(-4rem + 100vh);overflow-y:auto;align-self:flex-start}@media (max-width:1024px){.content-layout{display:flex;flex-direction:column-reverse}.toc-sidebar{width:100%;position:static;margin-bottom:1rem}}.docmd-tabs,img{margin:1.5rem 0}img{max-width:100%;height:auto}img.align-left{float:left;margin-right:1.5rem;margin-bottom:1rem}img.align-center{margin-left:auto;margin-right:auto}img.align-right{float:right;margin-left:1.5rem;margin-bottom:1rem}img.size-small{max-width:300px}img.size-medium{max-width:500px}img.size-large{max-width:800px}img.with-border{border:1px solid var(--image-border-color);padding:4px}img.with-shadow{box-shadow:var(--image-shadow)}.docmd-container figure{margin:2rem 0}.docmd-container figcaption{font-size:.9rem;color:var(--image-caption-text);text-align:center;padding:.5rem;background-color:var(--image-caption-bg);border-radius:0 0 4px 4px}.docmd-container .image-gallery{display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:1rem;margin:2rem 0}.docmd-container .image-gallery figure{margin:0}.docmd-container .clear-float::after{content:"";display:table;clear:both}.docmd-tabs{border:1px solid var(--border-color);border-radius:6px;overflow:hidden;box-shadow:rgba(0,0,0,.05) 0 1px 3px}.docmd-tabs-nav{display:flex;background-color:var(--sidebar-bg);border-bottom:1px solid var(--border-color);overflow:auto hidden}.docmd-tabs-nav-item{padding:.75rem 1.25rem;cursor:pointer;border-bottom:3px solid transparent;margin-bottom:-1px;font-weight:500;color:var(--sidebar-text);white-space:nowrap}.docmd-tabs-nav-item.active{color:var(--link-color);border-bottom-color:var(--link-color);background-color:var(--bg-color)}.docmd-tabs-content{padding:1.5rem}.tabs-container{margin:1rem 0;border:1px solid #e1e5e9;border-radius:.375rem}.tab-navigation{display:flex;background-color:#f8f9fa;border-bottom:1px solid #e1e5e9;border-radius:.375rem .375rem 0 0}.tab-button{padding:.75rem 1rem;border-width:medium medium 2px;border-style:none none solid;border-color:currentcolor currentcolor transparent;border-image:none;background:0 0;cursor:pointer;transition:.2s}.tab-button:hover{background-color:#e9ecef}.tab-button.active{border-bottom-color:#007bff;background-color:#fff}.tab-content{padding:1rem}.docmd-lightbox{display:none;position:fixed;top:0;left:0;width:100%;height:100%;background-color:var(--lightbox-bg);z-index:9999;justify-content:center;align-items:center;flex-direction:column}.copy-code-button svg,.sponsor-icon{width:1rem;height:1rem}.docmd-lightbox-content{position:relative;max-width:90%;max-height:90%;text-align:center}.docmd-lightbox-content img{max-width:100%;max-height:80vh;object-fit:contain;margin:0 auto;box-shadow:rgba(0,0,0,.3) 0 0 20px}.docmd-lightbox-caption{color:var(--lightbox-text);padding:1rem;font-size:1rem;max-width:100%}.docmd-lightbox-close{position:absolute;top:20px;right:30px;color:var(--lightbox-text);font-size:2.5rem;cursor:pointer;z-index:10000}.docmd-lightbox-close:hover{color:#ddd}.docmd-button,.sponsor-link,.sponsor-link:hover{color:#fff;text-decoration:none}.docmd-container .image-gallery img,img.lightbox{cursor:zoom-in}.docmd-button{display:inline-block;padding:.6rem 1.2rem;margin:.5rem;border-radius:6px;background-color:var(--link-color);font-weight:500;transition:background-color .2s,transform .2s;border:none;cursor:pointer}.docmd-button:hover{text-decoration:none;filter:brightness(90%);transform:translateY(-1px)}.sponsor-ribbon{position:fixed;bottom:75px;right:10px;z-index:1000;transform:rotate(0);transform-origin:center center;opacity:.75}.sponsor-link{display:flex;align-items:center;gap:.5rem;background:linear-gradient(135deg,#ff6b6b,#ee5a24);padding:.75rem 1.5rem;border-radius:5px;box-shadow:rgba(255,107,107,.3) 0 4px 12px;font-weight:600;font-size:.875rem;transition:.3s;white-space:nowrap}.sponsor-link:hover{transform:scale(1.02);box-shadow:rgba(255,107,107,.4) 0 6px 20px}.sponsor-icon{animation:2s ease-in-out infinite heartbeat}.sponsor-text{font-family:inherit}@keyframes heartbeat{0%,100%{transform:scale(1)}50%{transform:scale(1.1)}}@media (max-width:768px){body{flex-direction:column}.sidebar{width:100%;height:auto;position:static;border-right:currentcolor;border-bottom:1px solid var(--border-color)}.sidebar-toggle-button{display:block}.main-content-wrapper{margin-left:0}.content-area{padding:15px}.footer-content,.page-navigation{flex-direction:column;gap:1rem}.branding-footer,.user-footer{text-align:center}.next-page,.next-page-placeholder,.prev-page,.prev-page-placeholder{width:100%;max-width:100%}img.align-left,img.align-right{float:none;margin-left:auto;margin-right:auto}.docmd-container .image-gallery{grid-template-columns:1fr}.sponsor-ribbon{bottom:10px;right:10px}.sponsor-link{padding:.5rem 1rem;font-size:.75rem}.sponsor-icon{width:.875rem;height:.875rem}}html[data-theme=dark] .sponsor-link{background:linear-gradient(135deg,#ff6b6b,#c44569);box-shadow:rgba(255,107,107,.2) 0 4px 12px}html[data-theme=dark] .sponsor-link:hover{box-shadow:rgba(255,107,107,.3) 0 6px 20px}.copy-code-button{position:absolute;top:.75rem;right:.75rem;padding:.5rem;background-color:var(--code-bg);border:1px solid var(--border-color);border-radius:6px;cursor:pointer;opacity:0;transition:opacity .2s ease-in-out,background-color .2s;color:var(--sidebar-text);display:flex;align-items:center;justify-content:center;z-index:10;pointer-events:auto}.copy-code-button.copied{color:#10b981;opacity:1}.sidebar nav li.collapsible>a{display:flex;justify-content:space-between;align-items:center}.sidebar nav li.collapsible>a .nav-item-title{flex-grow:1}.sidebar nav .collapse-icon{transition:transform .2s ease-in-out;flex-shrink:0;margin-left:.5em}.sidebar nav li.collapsible[aria-expanded=true]>a>.collapse-icon{transform:rotate(90deg)}hr{color:rgba(245,245,245,.27);border-top-width:1px}
@@ -6,4 +6,4 @@
6
6
  * Features: Deep ruby red, elegant serif fonts, subtle gem-like effects
7
7
  */
8
8
 
9
- @import url(https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;500;600;700&family=Source+Sans+Pro:wght@300;400;600;700&display=swap);h1,h2{padding-bottom:.5rem}.sidebar,pre{box-shadow:var(--shadow-sm)}.sidebar nav li a.active,pre{border-left:3px solid var(--ruby-primary)}pre,table{margin:1.5em 0}a:hover,th{color:var(--ruby-primary-dark)}.sidebar-header,th{border-bottom:2px solid var(--ruby-border)}td,th{padding:.75rem 1rem}.content-area a:not(.button):not(.no-underline)::after,.docmd-container::before,h1::after{background:linear-gradient(90deg,var(--ruby-primary),var(--ruby-accent));position:absolute;left:0}.callout-info .callout-title,.docmd-container.steps-reset ol.steps-list>li.step-item::before,.sidebar nav li a:hover{color:var(--ruby-primary)}.card .card-content,.card .card-title{padding:1rem 1.5rem}figure img,img{max-width:100%}.image-gallery img,.image-gallery.zoom img{transition:transform .3s}:root[data-theme=light]{--ruby-font-family-sans:'Source Sans Pro',system-ui,-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Arial,sans-serif;--ruby-font-family-serif:'Playfair Display',Georgia,'Times New Roman',serif;--ruby-font-family-mono:'JetBrains Mono','SFMono-Regular',Consolas,'Liberation Mono',Menlo,monospace;--ruby-primary:#b30000;--ruby-primary-light:#ffebee;--ruby-primary-dark:#8e0000;--ruby-accent:#7b1fa2;--ruby-accent-light:#f3e5f5;--ruby-text:#2d2d2d;--ruby-text-light:#5a5a5a;--ruby-text-lightest:#757575;--ruby-background:#ffffff;--ruby-background-alt:#fafafa;--ruby-border:#e0e0e0;--ruby-border-light:#f0f0f0;--bg-color:var(--ruby-background);--text-color:var(--ruby-text);--sidebar-bg:#f8f5f5;--sidebar-text:var(--ruby-text-light);--sidebar-link-active-bg:#f8e7e7;--sidebar-link-active-text:var(--ruby-primary);--link-color:var(--ruby-primary);--border-color:var(--ruby-border);--code-bg:var(--ruby-primary-light);--code-text:var(--ruby-primary-dark);--header-bg:var(--ruby-background);--header-border:var(--ruby-border);--shadow-sm:0 2px 4px rgba(179, 0, 0, 0.05);--shadow-md:0 4px 8px rgba(179, 0, 0, 0.1);--shadow-lg:0 8px 16px rgba(179, 0, 0, 0.15);--image-border-color:var(--ruby-border);--image-shadow:var(--shadow-md);--image-caption-bg:var(--ruby-background-alt);--image-caption-text:var(--ruby-text-light);--image-hover-transform:translateY(-3px);--image-hover-shadow:var(--shadow-lg);--image-border-radius:6px;--image-transition:all 0.3s ease}:root[data-theme=dark]{--ruby-primary:#ff5252;--ruby-primary-light:#3c1a1a;--ruby-primary-dark:#ff7b7b;--ruby-accent:#ce93d8;--ruby-accent-light:#2a1a2a;--ruby-text:#f0f0f0;--ruby-text-light:#c0c0c0;--ruby-text-lightest:#a0a0a0;--ruby-background:#1a0a0a;--ruby-background-alt:#2a1515;--ruby-border:#3a2020;--ruby-border-light:#2a1818;--bg-color:var(--ruby-background);--text-color:var(--ruby-text);--sidebar-bg:#1a0a0a;--sidebar-text:var(--ruby-text-light);--sidebar-link-active-bg:#2a1515;--sidebar-link-active-text:var(--ruby-primary);--link-color:var(--ruby-primary);--border-color:var(--ruby-border);--code-bg:var(--ruby-primary-light);--code-text:var(--ruby-text);--header-bg:var(--ruby-background);--header-border:var(--ruby-border);--shadow-sm:0 2px 4px rgba(0, 0, 0, 0.3);--shadow-md:0 4px 8px rgba(0, 0, 0, 0.4);--shadow-lg:0 8px 16px rgba(0, 0, 0, 0.5);--image-border-color:var(--ruby-border);--image-shadow:0 4px 8px rgba(0, 0, 0, 0.5);--image-caption-bg:var(--ruby-background-alt);--image-caption-text:var(--ruby-text-light);--image-hover-transform:translateY(-3px);--image-hover-shadow:0 6px 12px rgba(0, 0, 0, 0.7);--image-border-radius:6px;--image-transition:all 0.3s ease}body{font-family:var(--ruby-font-family-sans);line-height:1.7;letter-spacing:.01em}.callout-title,.card .card-title,.steps h4,figure.polaroid figcaption,h1,h2,h3,h4,h5,h6{font-family:var(--ruby-font-family-serif)}h1,h2,h3,h4,h5,h6{font-weight:600;line-height:1.3;margin-top:2em;margin-bottom:.7em;color:var(--ruby-text);letter-spacing:-.01em}h1{font-size:2.5rem;font-weight:700;margin-top:0;position:relative}h1::after{content:"";bottom:0;width:60px;height:3px;border-radius:3px}.callout,.docmd-container,.steps,.steps h4,a{position:relative}h2{font-size:1.9rem;border-bottom:1px solid var(--ruby-border-light)}h3{font-size:1.6rem}h4{font-size:1.3rem}a{color:var(--link-color);text-decoration:none;transition:color .2s}.content-area a:not(.button):not(.no-underline)::after{content:'';width:100%;height:1px;bottom:0;transform:scaleX(0);transform-origin:bottom right;transition:transform .3s}.content-area a:not(.button):not(.no-underline):hover::after{transform:scaleX(1);transform-origin:bottom left}p{margin:.7em 0;padding:.3em 0;line-height:1.8}.sidebar{border-right:1px solid var(--ruby-border)}.sidebar-header{margin-bottom:1.5rem;padding-bottom:1rem}.sidebar nav li a{border-radius:4px;margin-bottom:3px;transition:.3s;padding:.6rem .8rem;font-weight:400}.sidebar nav li a:hover{background-color:var(--sidebar-link-active-bg);transform:translateX(3px)}.sidebar nav li a.active{background-color:var(--sidebar-link-active-bg);color:var(--sidebar-link-active-text);font-weight:600}.content-area{padding:2.5rem 5%}pre{background-color:var(--code-bg);border-radius:6px;padding:1.25em}code{font-family:var(--ruby-font-family-mono);font-size:.9em;border-radius:4px;padding:.2em .4em}.docmd-container,table{border-radius:6px;box-shadow:var(--shadow-sm);overflow:hidden}table{width:100%;border-collapse:separate;border-spacing:0}th{background-color:var(--ruby-primary-light);text-align:left;font-weight:600}td{border-top:1px solid var(--ruby-border-light)}tr:hover{background-color:var(--ruby-background-alt)}.docmd-container{padding:1.2rem 1.5rem;margin:1.75rem 0;border:1px solid var(--ruby-border-light);background-color:var(--ruby-background)}.docmd-container::before{content:'';top:0;width:100%;height:3px}.docmd-container.steps::before{height:initial!important}.callout{border:none;border-left:4px solid;background-color:var(--ruby-background-alt)}.callout-title{font-weight:600;margin-bottom:.75em;display:flex;align-items:center;font-size:1.1em}.callout-title::before{margin-right:.5rem;font-size:1.1em}.callout-info{border-left-color:var(--ruby-primary)}.callout-warning{border-left-color:#f39c12}.callout-warning .callout-title{color:#f39c12}.callout-success,.callout-tip{border-left-color:#2ecc71}.callout-success .callout-title,.callout-tip .callout-title{color:#2ecc71}.callout-danger{border-left-color:#e74c3c}.callout-danger .callout-title{color:#e74c3c}.card{border:none;border-radius:6px;background:linear-gradient(135deg,var(--ruby-background) 0,var(--ruby-background-alt) 100%);box-shadow:var(--shadow-md);transition:.3s;overflow:hidden}.button,.steps h4::before,button{background:linear-gradient(135deg,var(--ruby-primary) 0,var(--ruby-accent) 100%);font-weight:600;box-shadow:var(--shadow-sm)}.card:hover{transform:translateY(-5px);box-shadow:var(--shadow-lg)}.card .card-title{font-weight:600;margin:0;background:linear-gradient(90deg,var(--ruby-primary-light),var(--ruby-accent-light));color:var(--ruby-primary-dark);border-bottom:1px solid var(--ruby-border)}.steps{counter-reset:step-counter;padding-left:1rem}.steps h4{padding-left:2.5rem;margin-top:2rem;margin-bottom:1rem}.steps h4::before{content:counter(step-counter);counter-increment:step-counter;position:absolute;left:0;top:50%;transform:translateY(-50%);width:1.8rem;height:1.8rem;color:#fff;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:.9rem}.button,button{color:#fff;border:none;padding:.6rem 1.2rem;border-radius:4px;cursor:pointer;transition:.3s}.image-gallery figcaption,figcaption{background-color:var(--image-caption-bg);color:var(--image-caption-text)}figure,img{transition:var(--image-transition)}.docmd-button:hover{color:#fff}.button:hover,button:hover{box-shadow:var(--shadow-md);transform:translateY(-2px)}figure:hover,img.with-shadow:hover{transform:var(--image-hover-transform)}.theme-toggle-button{background:0 0;color:var(--ruby-text-light);box-shadow:none}.theme-toggle-button:hover{background:var(--ruby-background-alt);color:var(--ruby-primary);box-shadow:var(--shadow-sm);transform:translateY(0)}img{height:auto;border-radius:var(--image-border-radius)}img.with-border{border:1px solid var(--image-border-color);padding:4px}.image-gallery figure,figure img{border-radius:var(--image-border-radius)}img.with-shadow{box-shadow:var(--image-shadow)}img.with-shadow:hover{box-shadow:var(--image-hover-shadow)}figure{margin:1.5em 0;text-align:center}figcaption{padding:.5em;font-size:.9em;border-radius:0 0 var(--image-border-radius) var(--image-border-radius);font-style:italic}.image-gallery{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:1rem;margin:1.5em 0}.image-gallery figure{margin:0;height:100%;display:flex;flex-direction:column;overflow:hidden;box-shadow:var(--shadow-sm)}.image-gallery figure:hover{box-shadow:var(--shadow-md)}.image-gallery img{width:100%;height:100%;object-fit:cover;border-radius:var(--image-border-radius) var(--image-border-radius) 0 0}.image-gallery figcaption{padding:.5rem;font-size:.85rem;border-radius:0}.image-gallery.zoom figure:hover img{transform:scale(1.05)}img.lightbox{cursor:zoom-in}img.framed{border:8px solid #fff;box-shadow:0 0 0 1px var(--ruby-border),var(--shadow-md);border-radius:3px}figure.polaroid{background:#fff;padding:10px 10px 20px;box-shadow:var(--shadow-md);border-radius:3px}figure.polaroid img{border-radius:2px}figure.polaroid figcaption{background:#fff;color:var(--ruby-text);font-style:italic}@media (max-width:768px){.content-area{padding:1.5rem 1rem}h1{font-size:2rem}h2{font-size:1.6rem}h3{font-size:1.3rem}.image-gallery{grid-template-columns:repeat(auto-fill,minmax(150px,1fr))}.image-gallery img{height:120px}}
9
+ @import url(https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;500;600;700&family=Source+Sans+Pro:wght@300;400;600;700&display=swap);.docmd-container,.sidebar,pre,table{box-shadow:var(--shadow-sm)}h1,h2{padding-bottom:.5rem}.sidebar nav li a.active,pre{border-left:3px solid var(--ruby-primary)}pre,table{margin:1.5em 0}a:hover,th{color:var(--ruby-primary-dark)}.sidebar-header,th{border-bottom:2px solid var(--ruby-border)}td,th{padding:.75rem 1rem}.content-area a:not(.button):not(.no-underline)::after,.docmd-container::before,h1::after{background:linear-gradient(90deg,var(--ruby-primary),var(--ruby-accent));position:absolute;left:0}.callout,.docmd-container,.steps,.steps h4,a,h1{position:relative}.callout-info .callout-title,.docmd-container.steps-reset ol.steps-list>li.step-item::before,.sidebar nav li a:hover{color:var(--ruby-primary)}.card .card-content,.card .card-title{padding:1rem 1.5rem}figure img,img{max-width:100%}.image-gallery img,.image-gallery.zoom img{transition:transform .3s}:root{--ruby-font-family-sans:"Source Sans Pro",system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;--ruby-font-family-serif:"Playfair Display",Georgia,"Times New Roman",serif;--ruby-font-family-mono:"JetBrains Mono","SFMono-Regular",Consolas,"Liberation Mono",Menlo,monospace}:root[data-theme=light]{--ruby-primary:#b30000;--ruby-primary-light:#ffebee;--ruby-primary-dark:#8e0000;--ruby-accent:#7b1fa2;--ruby-accent-light:#f3e5f5;--ruby-text:#2d2d2d;--ruby-text-light:#5a5a5a;--ruby-text-lightest:#757575;--ruby-background:#ffffff;--ruby-background-alt:#fafafa;--ruby-border:#e0e0e0;--ruby-border-light:#f0f0f0;--bg-color:var(--ruby-background);--text-color:var(--ruby-text);--sidebar-bg:#f8f5f5;--sidebar-text:var(--ruby-text-light);--sidebar-link-active-bg:#f8e7e7;--sidebar-link-active-text:var(--ruby-primary);--link-color:var(--ruby-primary);--border-color:var(--ruby-border);--code-bg:var(--ruby-primary-light);--code-text:var(--ruby-primary-dark);--header-bg:var(--ruby-background);--header-border:var(--ruby-border);--shadow-sm:0 2px 4px rgba(179, 0, 0, 0.05);--shadow-md:0 4px 8px rgba(179, 0, 0, 0.1);--shadow-lg:0 8px 16px rgba(179, 0, 0, 0.15);--image-border-color:var(--ruby-border);--image-shadow:var(--shadow-md);--image-caption-bg:var(--ruby-background-alt);--image-caption-text:var(--ruby-text-light);--image-hover-transform:translateY(-3px);--image-hover-shadow:var(--shadow-lg);--image-border-radius:6px;--image-transition:all 0.3s ease}:root[data-theme=dark]{--ruby-primary:#ff5252;--ruby-primary-light:#3c1a1a;--ruby-primary-dark:#ff7b7b;--ruby-accent:#ce93d8;--ruby-accent-light:#2a1a2a;--ruby-text:#f0f0f0;--ruby-text-light:#c0c0c0;--ruby-text-lightest:#a0a0a0;--ruby-background:#1a0a0a;--ruby-background-alt:#2a1515;--ruby-border:#3a2020;--ruby-border-light:#2a1818;--bg-color:var(--ruby-background);--text-color:var(--ruby-text);--sidebar-bg:#1a0a0a;--sidebar-text:var(--ruby-text-light);--sidebar-link-active-bg:#2a1515;--sidebar-link-active-text:var(--ruby-primary);--link-color:var(--ruby-primary);--border-color:var(--ruby-border);--code-bg:var(--ruby-primary-light);--code-text:var(--ruby-text);--header-bg:var(--ruby-background);--header-border:var(--ruby-border);--shadow-sm:0 2px 4px rgba(0, 0, 0, 0.3);--shadow-md:0 4px 8px rgba(0, 0, 0, 0.4);--shadow-lg:0 8px 16px rgba(0, 0, 0, 0.5);--image-border-color:var(--ruby-border);--image-shadow:0 4px 8px rgba(0, 0, 0, 0.5);--image-caption-bg:var(--ruby-background-alt);--image-caption-text:var(--ruby-text-light);--image-hover-transform:translateY(-3px);--image-hover-shadow:0 6px 12px rgba(0, 0, 0, 0.7);--image-border-radius:6px;--image-transition:all 0.3s ease}body{font-family:var(--ruby-font-family-sans);line-height:1.7;letter-spacing:.01em}.callout-title,.card .card-title,.steps h4,figure.polaroid figcaption,h1,h2,h3,h4,h5,h6{font-family:var(--ruby-font-family-serif)}h1,h2,h3,h4,h5,h6{font-weight:600;line-height:1.3;margin-top:2em;margin-bottom:.7em;color:var(--ruby-text);letter-spacing:-.01em}h1{font-size:2.5rem;font-weight:700;margin-top:0}h1::after{content:"";bottom:0;width:60px;height:3px;border-radius:3px}h2{font-size:1.9rem;border-bottom:1px solid var(--ruby-border-light)}h3{font-size:1.6rem}h4{font-size:1.3rem}a{color:var(--link-color);text-decoration:none;transition:color .2s}.content-area a:not(.button):not(.no-underline)::after{content:"";width:100%;height:1px;bottom:0;transform:scaleX(0);transform-origin:right bottom;transition:transform .3s}.content-area a:not(.button):not(.no-underline):hover::after{transform:scaleX(1);transform-origin:left bottom}p{margin:.7em 0;padding:.3em 0;line-height:1.8}.sidebar{border-right:1px solid var(--ruby-border)}.sidebar-header{margin-bottom:1.5rem;padding-bottom:1rem}.sidebar nav li a{border-radius:4px;margin-bottom:3px;transition:.3s;padding:.6rem .8rem;font-weight:400}.sidebar nav li a:hover{background-color:var(--sidebar-link-active-bg);transform:translateX(3px)}.sidebar nav li a.active{background-color:var(--sidebar-link-active-bg);color:var(--sidebar-link-active-text);font-weight:600}.content-area{padding:2.5rem 5%}pre{background-color:var(--code-bg);border-radius:6px;padding:1.25em}code{font-family:var(--ruby-font-family-mono);font-size:.9em;border-radius:4px;padding:.2em .4em}.docmd-container,table{border-radius:6px;overflow:hidden}table{width:100%;border-collapse:separate;border-spacing:0px}th{background-color:var(--ruby-primary-light);text-align:left;font-weight:600}td{border-top:1px solid var(--ruby-border-light)}tr:hover{background-color:var(--ruby-background-alt)}.docmd-container{padding:1.2rem 1.5rem;margin:1.75rem 0;border:1px solid var(--ruby-border-light);background-color:var(--ruby-background)}.docmd-container::before{content:"";top:0;width:100%;height:3px}.docmd-container.steps::before{height:initial!important}.callout{border-width:medium medium medium 4px;border-style:none none none solid;border-color:currentcolor;border-image:none;background-color:var(--ruby-background-alt)}.callout-title{font-weight:600;margin-bottom:.75em;display:flex;align-items:center;font-size:1.1em}.callout-title::before{margin-right:.5rem;font-size:1.1em}.callout-info{border-left-color:var(--ruby-primary)}.callout-warning{border-left-color:#f39c12}.callout-warning .callout-title{color:#f39c12}.callout-success,.callout-tip{border-left-color:#2ecc71}.callout-success .callout-title,.callout-tip .callout-title{color:#2ecc71}.callout-danger{border-left-color:#e74c3c}.callout-danger .callout-title{color:#e74c3c}.card{border:none;border-radius:6px;background:linear-gradient(135deg,var(--ruby-background) 0,var(--ruby-background-alt) 100%);box-shadow:var(--shadow-md);transition:.3s;overflow:hidden}.button,.steps h4::before,button{background:linear-gradient(135deg,var(--ruby-primary) 0,var(--ruby-accent) 100%);font-weight:600;box-shadow:var(--shadow-sm)}.card:hover{transform:translateY(-5px);box-shadow:var(--shadow-lg)}.card .card-title{font-weight:600;margin:0;background:linear-gradient(90deg,var(--ruby-primary-light),var(--ruby-accent-light));color:var(--ruby-primary-dark);border-bottom:1px solid var(--ruby-border)}.steps{counter-reset:step-counter 0;padding-left:1rem}.steps h4{padding-left:2.5rem;margin-top:2rem;margin-bottom:1rem}.steps h4::before{content:counter(step-counter);counter-increment:step-counter 1;position:absolute;left:0;top:50%;transform:translateY(-50%);width:1.8rem;height:1.8rem;color:#fff;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:.9rem}.button,button{color:#fff;border:none;padding:.6rem 1.2rem;border-radius:4px;cursor:pointer;transition:.3s}.image-gallery figcaption,figcaption{background-color:var(--image-caption-bg);color:var(--image-caption-text)}figure,img{transition:var(--image-transition)}.docmd-button:hover{color:#fff}.button:hover,button:hover{box-shadow:var(--shadow-md);transform:translateY(-2px)}figure:hover,img.with-shadow:hover{transform:var(--image-hover-transform)}.theme-toggle-button{background:0 0;color:var(--ruby-text-light);box-shadow:none}.theme-toggle-button:hover{background:var(--ruby-background-alt);color:var(--ruby-primary);box-shadow:var(--shadow-sm);transform:translateY(0)}img{height:auto;border-radius:var(--image-border-radius)}img.with-border{border:1px solid var(--image-border-color);padding:4px}.image-gallery figure,figure img{border-radius:var(--image-border-radius)}img.with-shadow{box-shadow:var(--image-shadow)}img.with-shadow:hover{box-shadow:var(--image-hover-shadow)}figure{margin:1.5em 0;text-align:center}figcaption{padding:.5em;font-size:.9em;border-radius:0 0 var(--image-border-radius) var(--image-border-radius);font-style:italic}.image-gallery{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:1rem;margin:1.5em 0}.image-gallery figure{margin:0;height:100%;display:flex;flex-direction:column;overflow:hidden;box-shadow:var(--shadow-sm)}.image-gallery figure:hover{box-shadow:var(--shadow-md)}.image-gallery img{width:100%;height:100%;object-fit:cover;border-radius:var(--image-border-radius) var(--image-border-radius) 0 0}.image-gallery figcaption{padding:.5rem;font-size:.85rem;border-radius:0}.image-gallery.zoom figure:hover img{transform:scale(1.05)}img.lightbox{cursor:zoom-in}img.framed{border:8px solid #fff;box-shadow:0 0 0 1px var(--ruby-border),var(--shadow-md);border-radius:3px}figure.polaroid{background:#fff;padding:10px 10px 20px;box-shadow:var(--shadow-md);border-radius:3px}figure.polaroid img{border-radius:2px}figure.polaroid figcaption{background:#fff;color:var(--ruby-text);font-style:italic}@media (max-width:768px){.content-area{padding:1.5rem 1rem}h1{font-size:2rem}h2{font-size:1.6rem}h3{font-size:1.3rem}.image-gallery{grid-template-columns:repeat(auto-fill,minmax(150px,1fr))}.image-gallery img{height:120px}}.page-header{border-bottom:1px solid var(--ruby-border)}
@@ -3,6 +3,79 @@
3
3
  /*
4
4
  * Main client-side script for docmd UI interactions
5
5
  */
6
+ // --- Collapsible Navigation Logic ---
7
+ function initializeCollapsibleNav() {
8
+ const nav = document.querySelector('.sidebar-nav');
9
+ if (!nav) return;
10
+
11
+ let navStates = {};
12
+ try {
13
+ // Use sessionStorage to remember state only for the current session
14
+ navStates = JSON.parse(sessionStorage.getItem('docmd-nav-states')) || {};
15
+ } catch (e) { /* silent fail */ }
16
+
17
+ nav.querySelectorAll('li.collapsible').forEach(item => {
18
+ const navId = item.dataset.navId;
19
+ const anchor = item.querySelector('a');
20
+ const submenu = item.querySelector('.submenu');
21
+
22
+ if (!navId || !anchor || !submenu) return;
23
+
24
+ const isParentActive = item.classList.contains('active-parent');
25
+ // Default to expanded if it's a parent of the active page, otherwise check stored state.
26
+ let isExpanded = isParentActive || (navStates[navId] === true);
27
+
28
+ const toggleSubmenu = (expand) => {
29
+ item.setAttribute('aria-expanded', expand);
30
+ submenu.style.display = expand ? 'block' : 'none';
31
+ navStates[navId] = expand;
32
+ sessionStorage.setItem('docmd-nav-states', JSON.stringify(navStates));
33
+ };
34
+
35
+ // Set initial state on page load
36
+ toggleSubmenu(isExpanded);
37
+
38
+ anchor.addEventListener('click', (e) => {
39
+ // If the click target is the icon, ALWAYS prevent navigation and toggle.
40
+ if (e.target.closest('.collapse-icon')) {
41
+ e.preventDefault();
42
+ toggleSubmenu(item.getAttribute('aria-expanded') !== 'true');
43
+ }
44
+ // If the link is just a placeholder, also prevent navigation and toggle.
45
+ else if (anchor.getAttribute('href') === '#') {
46
+ e.preventDefault();
47
+ toggleSubmenu(item.getAttribute('aria-expanded') !== 'true');
48
+ }
49
+ // Otherwise, let the click proceed to navigate to the link.
50
+ });
51
+ });
52
+ }
53
+
54
+ // --- Sidebar Scroll Preservation ---
55
+ function initializeSidebarScroll() {
56
+ const sidebar = document.querySelector('.sidebar');
57
+ if (!sidebar) return;
58
+
59
+ setTimeout(() => {
60
+ const activeElement = sidebar.querySelector('a.active') || sidebar.querySelector('.active-parent > a');
61
+
62
+ if (activeElement) {
63
+ const sidebarRect = sidebar.getBoundingClientRect();
64
+ const elementRect = activeElement.getBoundingClientRect();
65
+
66
+ // Check if the element's top or bottom is outside the sidebar's visible area
67
+ const isNotInView = elementRect.top < sidebarRect.top || elementRect.bottom > sidebarRect.bottom;
68
+
69
+ if (isNotInView) {
70
+ activeElement.scrollIntoView({
71
+ behavior: 'auto',
72
+ block: 'center',
73
+ inline: 'nearest'
74
+ });
75
+ }
76
+ }
77
+ }, 10);
78
+ }
6
79
 
7
80
  // --- Theme Toggle Logic ---
8
81
  function setupThemeToggleListener() {
@@ -154,4 +227,6 @@ document.addEventListener('DOMContentLoaded', () => {
154
227
  initializeSidebarToggle();
155
228
  initializeTabs();
156
229
  initializeCopyCodeButtons();
230
+ initializeCollapsibleNav();
231
+ initializeSidebarScroll();
157
232
  });
@@ -221,25 +221,24 @@ async function buildSite(configPath, options = { isDev: false, preserve: false,
221
221
  const depth = outputHtmlPath.split(path.sep).length - 1;
222
222
  const relativePathToRoot = depth > 0 ? '../'.repeat(depth) : './';
223
223
 
224
- let currentPagePathForNav;
225
- let normalizedPath;
226
-
227
- if (isIndexFile) {
228
- const dirPath = path.dirname(relativePath);
229
- if (dirPath === '.') {
230
- currentPagePathForNav = 'index.html';
231
- normalizedPath = '/';
232
- } else {
233
- currentPagePathForNav = dirPath + '/';
234
- normalizedPath = '/' + dirPath;
224
+ let normalizedPath = path.relative(SRC_DIR, filePath).replace(/\\/g, '/');
225
+ if (path.basename(normalizedPath) === 'index.md') {
226
+ normalizedPath = path.dirname(normalizedPath);
227
+ if (normalizedPath === '.') {
228
+ normalizedPath = '';
235
229
  }
236
230
  } else {
237
- const pathWithoutExt = relativePath.replace(/\.md$/, '');
238
- currentPagePathForNav = pathWithoutExt + '/';
239
- normalizedPath = '/' + pathWithoutExt;
231
+ normalizedPath = normalizedPath.replace(/\.md$/, '');
240
232
  }
241
-
242
- currentPagePathForNav = currentPagePathForNav.replace(/\\/g, '/');
233
+
234
+ if (!normalizedPath.startsWith('/')) {
235
+ normalizedPath = '/' + normalizedPath;
236
+ }
237
+ if (normalizedPath.length > 1 && !normalizedPath.endsWith('/')) {
238
+ normalizedPath += '/';
239
+ }
240
+
241
+ const currentPagePathForNav = normalizedPath;
243
242
 
244
243
  const navigationHtml = await generateNavigationHtml(
245
244
  config.navigation,
@@ -35,7 +35,7 @@ module.exports = {
35
35
  name: 'sky', // Themes: 'default', 'sky'
36
36
  defaultMode: 'light', // Initial color mode: 'light' or 'dark'
37
37
  enableModeToggle: true, // Show UI button to toggle light/dark modes
38
- positionMode: 'bottom', // 'top' or 'bottom' for the theme toggle
38
+ positionMode: 'top', // 'top' or 'bottom' for the theme toggle
39
39
  codeHighlight: true, // Enable/disable codeblock highlighting and import of highlight.js
40
40
  customCss: [ // Array of paths to custom CSS files
41
41
  // '/assets/css/custom.css', // Custom TOC styles
@@ -96,6 +96,7 @@ module.exports = {
96
96
  title: 'Getting Started',
97
97
  icon: 'rocket',
98
98
  path: '#',
99
+ collapsible: true, // This makes the menu section collapsible
99
100
  children: [
100
101
  { title: 'Documentation', path: 'https://docmd.mgks.dev', icon: 'scroll', external: true },
101
102
  { title: 'Installation', path: 'https://docmd.mgks.dev/getting-started/installation', icon: 'download', external: true },
@@ -51,6 +51,7 @@ function createMarkdownItInstance(config) {
51
51
  md.use(markdown_it_task_lists);
52
52
  md.use(markdown_it_abbr);
53
53
  md.use(markdown_it_deflist);
54
+ md.use(headingIdPlugin);
54
55
 
55
56
  // Register renderers for all containers
56
57
  Object.keys(containers).forEach(containerName => {
@@ -184,8 +185,6 @@ const containers = {
184
185
  // }
185
186
  };
186
187
 
187
-
188
-
189
188
  // Advanced container rule with proper nesting support
190
189
  function advancedContainerRule(state, startLine, endLine, silent) {
191
190
  const start = state.bMarks[startLine] + state.tShift[startLine];
@@ -660,21 +659,32 @@ const customImageRenderer = function(tokens, idx, options, env, self) {
660
659
 
661
660
  // Add IDs to headings for anchor links, used by the Table of Contents.
662
661
  const headingIdPlugin = (md) => {
663
- const defaultRender = function(tokens, idx, options, env, self) {
662
+ const originalHeadingOpen = md.renderer.rules.heading_open || function(tokens, idx, options, env, self) {
664
663
  return self.renderToken(tokens, idx, options);
665
664
  };
666
- const headingOpenRenderer = function(tokens, idx, options, env, self) {
665
+
666
+ md.renderer.rules.heading_open = function(tokens, idx, options, env, self) {
667
667
  const token = tokens[idx];
668
668
  const contentToken = tokens[idx + 1];
669
- if (contentToken && contentToken.type === 'inline') {
669
+
670
+ if (contentToken && contentToken.type === 'inline' && contentToken.content) {
670
671
  const headingText = contentToken.content;
671
- const id = headingText.toLowerCase().replace(/\s+/g, '-').replace(/[^\w-]/g, '').replace(/--+/g, '-').replace(/^-+|-+$/g, '');
672
- if (id) { token.attrSet('id', id); }
672
+ const id = headingText
673
+ .toLowerCase()
674
+ .replace(/\s+/g, '-') // Replace spaces with -
675
+ .replace(/[^\w-]+/g, '') // Remove all non-word chars
676
+ .replace(/--+/g, '-') // Replace multiple - with single -
677
+ .replace(/^-+/, '') // Trim - from start of text
678
+ .replace(/-+$/, ''); // Trim - from end of text
679
+
680
+ if (id) {
681
+ token.attrSet('id', id);
682
+ }
673
683
  }
674
- return defaultRender(tokens, idx, options, env, self);
675
- }
676
- }
677
-
684
+
685
+ return originalHeadingOpen(tokens, idx, options, env, self);
686
+ };
687
+ };
678
688
 
679
689
  // ===================================================================
680
690
  // --- SAFE CONTAINER WRAPPER (FOR SIMPLE CONTAINERS) ---
@@ -1,107 +1,78 @@
1
- <%# src/templates/navigation.ejs %>
2
-
3
- <%# renderIcon is passed from html-generator.js %>
4
-
5
- <%
6
- // Debug function - uncomment to troubleshoot paths
7
- function debugNavPaths(item, itemPath, currentPath, isActive, isParentActive) {
8
- console.log('\nDEBUG NAV ITEM:');
9
- console.log(`Title: ${item.title}`);
10
- console.log(`Path: ${item.path}`);
11
- console.log(`Computed item path: ${itemPath}`);
12
- console.log(`Current page path: ${currentPath}`);
13
- console.log(`Is directly active: ${isActive}`);
14
- console.log(`Is parent active: ${isParentActive}`);
15
- }
16
-
17
- function renderNavItems(items, currentLevelPagePath, rootPath) { %>
1
+ <%# navigation.ejs - Renders the sidebar navigation %>
2
+ <nav class="sidebar-nav" aria-label="Main navigation">
18
3
  <ul>
19
- <% items.forEach(item => { %>
20
- <%
21
- let itemHref = '#'; // Default for non-linking parents or error
22
- let isCurrentPageActive = false;
23
- let isActivePage = false; // For the direct page itself
24
- const isExternal = item.external === true;
25
- const targetBlank = isExternal ? 'target="_blank" rel="noopener noreferrer"' : '';
26
- let iconHtml = '';
27
- let externalLinkIconHtml = '';
28
-
29
- if (item.icon) {
30
- // Use custom class for nav icons for specific styling
31
- iconHtml = renderIcon(item.icon, { class: 'nav-item-icon' });
4
+ <%
5
+ // A robust, centralized function to normalize navigation paths
6
+ function normalizePath(p) {
7
+ if (!p) return '#';
8
+ let path = p.replace(/\\/g, '/');
9
+
10
+ if (path.endsWith('index.md')) {
11
+ path = path.slice(0, -'index.md'.length);
12
+ } else {
13
+ path = path.replace(/\.md$/, '');
32
14
  }
33
15
 
34
- if (isExternal) {
35
- itemHref = item.path; // Full URL for external links
36
- // Use a Lucide icon like 'arrow-up-right' or 'external-link'
37
- externalLinkIconHtml = renderIcon('arrow-up-right', { class: 'nav-external-icon', width: '0.8em', height: '0.8em' });
38
- } else {
39
- // Path normalization for internal links
40
- let cleanPath = item.path.startsWith('/') ? item.path : '/' + item.path; // Ensure leading slash
16
+ if (!path.startsWith('/')) path = '/' + path;
41
17
 
42
- // Handle paths with pretty URLs
43
- if (cleanPath === '/') {
44
- // Root path goes to index.html
45
- itemHref = rootPath + 'index.html';
46
- } else {
47
- // Remove any trailing slash for consistency
48
- const pathWithoutTrailingSlash = cleanPath.endsWith('/') ? cleanPath.slice(0, -1) : cleanPath;
49
-
50
- // For all other paths, link to the directory (pretty URL)
51
- // Remove leading slash and ensure clean path
52
- const cleanedPath = pathWithoutTrailingSlash.substring(1);
53
- itemHref = rootPath + cleanedPath + '/';
54
- }
18
+ if (path.length > 1 && !path.endsWith('/')) {
19
+ path += '/';
20
+ }
21
+
22
+ // Handle root case where path might be "" after stripping index.md
23
+ if (path === '') path = '/';
24
+
25
+ return path;
26
+ }
27
+
28
+ // Helper to check for active children recursively
29
+ function hasActiveChild(item, currentPagePath) {
30
+ if (!item.children || !Array.isArray(item.children)) return false;
31
+ return item.children.some(child => {
32
+ if (!child.path || child.external) return false;
33
+ const childPath = normalizePath(child.path);
34
+ if (currentPagePath === childPath) return true;
35
+ return hasActiveChild(child, currentPagePath);
36
+ });
37
+ }
55
38
 
56
- // SIMPLIFIED ACTIVE STATE LOGIC - START
57
- // 1. Prepare the paths for comparison
58
- // The item path in the format used in the navigation config
59
- const normalizedItemPath = cleanPath.substring(1) || '';
39
+ // Recursive function to render navigation items
40
+ function renderNav(items) {
41
+ if (!items || !Array.isArray(items)) return;
42
+ items.forEach(item => {
43
+ const isExternal = item.external || false;
44
+ let itemPath = item.path || '#';
60
45
 
61
- // Special handling for root path
62
- if (cleanPath === '/') {
63
- isActivePage = currentLevelPagePath === 'index.html';
64
- isCurrentPageActive = isActivePage;
65
- }
66
- // Parent folder with index.md
67
- else if (cleanPath.endsWith('/')) {
68
- // Direct match for folder/index.html pages
69
- const folderPath = cleanPath.substring(1, cleanPath.length - 1); // Remove leading / and trailing /
70
- isActivePage = currentLevelPagePath === folderPath + '/';
71
- isCurrentPageActive = isActivePage;
72
-
73
- // Check if any children are active
74
- // If current path starts with this item's path, it's a parent of the active page
75
- if (!isActivePage && currentLevelPagePath.startsWith(normalizedItemPath)) {
76
- isCurrentPageActive = true;
77
- }
78
- }
79
- // Regular page
80
- else {
81
- const pagePath = cleanPath.substring(1) + '/';
82
- isActivePage = currentLevelPagePath === pagePath;
83
- isCurrentPageActive = isActivePage;
84
- }
85
- // SIMPLIFIED ACTIVE STATE LOGIC - END
86
- }
87
- %>
88
- <li class="<%= isCurrentPageActive ? 'active-parent' : '' %>">
89
- <a href="<%= itemHref %>"
90
- class="<%= isActivePage ? 'active' : '' %>"
91
- <%- targetBlank %>>
92
- <% if (iconHtml) { %><%- iconHtml %><% } %>
93
- <span><%- item.title %></span> <%# Wrap title in span for styling if needed %>
94
- <% if (externalLinkIconHtml) { %><%- externalLinkIconHtml %><% } %>
95
- </a>
46
+ const normalizedItemPath = isExternal ? itemPath : normalizePath(itemPath);
96
47
 
97
- <% if (item.children && item.children.length > 0) { %>
98
- <%- renderNavItems(item.children, currentLevelPagePath, rootPath) %>
99
- <% } %>
100
- </li>
101
- <% }); %>
102
- </ul>
103
- <% } %>
48
+ const isActive = !isExternal && currentPagePath === normalizedItemPath;
49
+ const isParentOfActive = !isActive && hasActiveChild(item, currentPagePath);
50
+ const isCollapsible = item.children && item.collapsible;
104
51
 
105
- <nav class="sidebar-nav">
106
- <%- renderNavItems(navItems, currentPagePath, relativePathToRoot) %>
52
+ const liClasses = [];
53
+ if (isActive) liClasses.push('active');
54
+ if (isParentOfActive) liClasses.push('active-parent');
55
+ if (isCollapsible) liClasses.push('collapsible');
56
+
57
+ const finalHref = isExternal ? item.path : (itemPath === '#' ? '#' : (relativePathToRoot + (item.path.startsWith('/') ? item.path.substring(1) : item.path)));
58
+ %>
59
+ <li class="<%= liClasses.join(' ') %>" <%- isCollapsible ? `data-nav-id="${item.path}"` : '' %>>
60
+ <a href="<%- finalHref %>" class="<%- isActive ? 'active' : '' %>" <%- isExternal ? 'target="_blank" rel="noopener"' : '' %>>
61
+ <% if (item.icon) { %> <%- renderIcon(item.icon) %> <% } %>
62
+ <span class="nav-item-title"><%= item.title %></span>
63
+ <% if (isCollapsible) { %> <%- renderIcon('chevron-right', { class: 'collapse-icon' }) %> <% } %>
64
+ <% if (isExternal) { %> <%- renderIcon('external-link', { class: 'nav-external-icon' }) %> <% } %>
65
+ </a>
66
+ <% if (item.children) { %>
67
+ <ul class="submenu">
68
+ <% renderNav(item.children); %>
69
+ </ul>
70
+ <% } %>
71
+ </li>
72
+ <%
73
+ });
74
+ }
75
+ renderNav(navItems);
76
+ %>
77
+ </ul>
107
78
  </nav>