@docmd/ui 0.5.1 → 0.5.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.
@@ -355,16 +355,18 @@
355
355
 
356
356
  document.querySelectorAll('.theme-toggle-button').forEach(btn => {
357
357
  btn.addEventListener('click', () => {
358
- const t = document.documentElement.getAttribute('data-theme') === 'light' ? 'dark' : 'light';
359
- document.documentElement.setAttribute('data-theme', t);
360
- document.body.setAttribute('data-theme', t);
361
- localStorage.setItem('docmd-theme', t);
358
+ const currentTheme = document.documentElement.getAttribute('data-theme');
359
+ const nextTheme = currentTheme === 'light' ? 'dark' : 'light';
360
+
361
+ document.documentElement.setAttribute('data-theme', nextTheme);
362
+ document.body.setAttribute('data-theme', nextTheme);
363
+ localStorage.setItem('docmd-theme', nextTheme);
362
364
 
363
365
  const lightLink = document.getElementById('hljs-light');
364
366
  const darkLink = document.getElementById('hljs-dark');
365
367
  if (lightLink && darkLink) {
366
- lightLink.disabled = t === 'dark';
367
- darkLink.disabled = t === 'light';
368
+ lightLink.disabled = nextTheme === 'dark';
369
+ darkLink.disabled = nextTheme === 'light';
368
370
  }
369
371
  });
370
372
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@docmd/ui",
3
- "version": "0.5.1",
3
+ "version": "0.5.3",
4
4
  "description": "Base UI templates and assets for docmd.",
5
5
  "main": "index.js",
6
6
  "files": [
@@ -8,189 +8,210 @@
8
8
 
9
9
  <!DOCTYPE html>
10
10
  <html lang="en">
11
+
11
12
  <head>
12
- <meta charset="UTF-8">
13
- <meta name="generator" content="docmd v0.5.x">
14
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
15
- <%
16
- let versionRoot = '/';
17
- let siteRoot = relativePathToRoot;
18
-
19
- if (config.versions?.current && config._activeVersion?.id) {
20
- const isSubVersion = config.versions.current !== config._activeVersion.id;
21
- versionRoot = isSubVersion ? '/' + config._activeVersion.id + '/' : '/';
22
-
23
- // If we are in a sub-version (v04/), the relativePathToRoot takes us to /v04/.
24
- // We need to go up one more level to reach the true site root.
25
- if (isSubVersion) {
26
- siteRoot = (relativePathToRoot === './' ? '' : relativePathToRoot) + '../';
27
- }
28
- }
29
-
30
- if (locals.isOfflineMode) {
31
- versionRoot = '';
32
- }
33
- %>
34
- <script>
13
+ <meta charset="UTF-8">
14
+ <meta name="generator" content="docmd v0.5.x">
15
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
16
+ <%- themeInitScript %>
17
+ <style>
18
+ html {
19
+ visibility: hidden;
20
+ }
21
+ </style>
22
+ <% let versionRoot='/' ; let siteRoot=relativePathToRoot; if (config.versions?.current && config._activeVersion?.id)
23
+ { const isSubVersion=config.versions.current !==config._activeVersion.id; versionRoot=isSubVersion ? '/' +
24
+ config._activeVersion.id + '/' : '/' ; if (isSubVersion) { siteRoot=(relativePathToRoot==='./' ? '' :
25
+ relativePathToRoot) + '../' ; } } if (locals.isOfflineMode) { versionRoot='' ; } %>
26
+ <script>
35
27
  var root = "<%= relativePathToRoot %>";
36
28
  if (root && !root.endsWith('/')) root += '/';
37
29
  if (root === '') root = './';
38
- window.DOCMD_ROOT = root; // Context Root (Assets)
39
-
30
+ window.DOCMD_ROOT = root;
31
+
40
32
  var siteRoot = "<%= siteRoot %>";
41
33
  if (siteRoot && !siteRoot.endsWith('/')) siteRoot += '/';
42
34
  if (siteRoot === '') siteRoot = './';
43
- window.DOCMD_SITE_ROOT = siteRoot; // True Site Root (Search Index)
44
-
45
- window.DOCMD_DEFAULT_MODE = "<%= defaultMode %>";
35
+ window.DOCMD_SITE_ROOT = siteRoot;
36
+
37
+ window.DOCMD_APPEARANCE = "<%= appearance %>";
46
38
  window.DOCMD_VERSION_ROOT = "<%- versionRoot %>";
47
- </script>
48
- <title><%= pageTitle %></title>
49
- <%- faviconLinkHtml || '' %>
50
- <link rel="stylesheet" href="<%= relativePathToRoot %>assets/css/docmd-main.css?v=<%= buildHash %>">
51
- <% if (config.theme?.codeHighlight !== false) {
52
- const isDarkDefault = defaultMode === 'dark';
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 %>
39
+ </script>
40
+ <title>
41
+ <%= pageTitle %>
42
+ </title>
43
+ <%- faviconLinkHtml || '' %>
44
+ <link rel="stylesheet" href="<%= relativePathToRoot %>assets/css/docmd-main.css?v=<%= buildHash %>">
45
+ <% if (config.theme?.codeHighlight !==false) { const isDarkDefault=appearance==='dark' ; %>
46
+ <link rel="stylesheet" href="<%= relativePathToRoot %>assets/css/docmd-highlight-light.css?v=<%= buildHash %>"
47
+ id="hljs-light" <%=isDarkDefault ? 'disabled' : '' %>>
48
+
49
+ <link rel="stylesheet" href="<%= relativePathToRoot %>assets/css/docmd-highlight-dark.css?v=<%= buildHash %>"
50
+ id="hljs-dark" <%=isDarkDefault ? '' : 'disabled' %>>
51
+ <% } %>
52
+ <%- pluginHeadScriptsHtml || '' %>
53
+ <% (customCssFiles || []).forEach(cssFile=> { %>
54
+ <link rel="stylesheet"
55
+ href="<%= relativePathToRoot %><%- cssFile.startsWith('/') ? cssFile.substring(1) : cssFile %>?v=<%= buildHash %>">
56
+ <% }); %>
57
+ <%- themeInitScript %>
69
58
  </head>
70
- <body class="<%= sidebarConfig?.enabled === false ? 'no-sidebar' : (sidebarConfig?.collapsible ? 'sidebar-collapsible' : 'sidebar-not-collapsible') %>"
71
- data-default-collapsed="<%= sidebarConfig?.defaultCollapsed %>"
72
- data-copy-code-enabled="<%= config.copyCode === true %>"
73
- data-spa-enabled="<%= config.layout?.spa !== false %>">
74
-
75
- <a href="#main-content" class="skip-link">Skip to main content</a>
76
59
 
77
- <% if (sidebarConfig?.enabled !== false) { %>
78
- <aside class="sidebar">
60
+ <body
61
+ 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' : '' %>"
62
+ data-default-collapsed="<%= sidebarConfig?.defaultCollapsed %>"
63
+ data-copy-code-enabled="<%= config.copyCode === true %>" data-spa-enabled="<%= config.layout?.spa !== false %>">
64
+
65
+ <a href="#main-content" class="skip-link">Skip to main content</a>
66
+
67
+ <% if (locals.menubarConfig && menubarConfig?.enabled !==false && menubarConfig.position !=='header' ) { %>
68
+ <%- include('partials/menubar', { menubarConfig, relativePathToRoot, renderIcon, optionsMenu: locals.optionsMenu })
69
+ %>
70
+ <% } %>
71
+
72
+ <% if (sidebarConfig?.enabled !==false) { %>
73
+ <aside class="sidebar">
79
74
  <div class="sidebar-header">
80
- <% if (logo && logo.light && logo.dark) { %>
75
+ <% if (logo && logo.light && logo.dark) { %>
81
76
  <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 %>;"<% } %>>
77
+ <img
78
+ src="<%= relativePathToRoot %><%- logo.light.startsWith('/') ? logo.light.substring(1) : logo.light %>"
79
+ alt="<%= logo.alt || siteTitle %>" class="logo-light" <% if (logo.height) { %>style="height: <%=
80
+ logo.height %>;"<% } %>>
81
+ <img
82
+ src="<%= relativePathToRoot %><%- logo.dark.startsWith('/') ? logo.dark.substring(1) : logo.dark %>"
83
+ alt="<%= logo.alt || siteTitle %>" class="logo-dark" <% if (logo.height) { %>style="height: <%=
84
+ logo.height %>;"<% } %>>
84
85
  </a>
85
86
  <% } 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>
87
+ <h1><a href="<%= relativePathToRoot %>index.html">
88
+ <%= siteTitle %>
89
+ </a></h1>
90
+ <% } %>
91
+ <span class="mobile-view sidebar-menu-button float-right">
92
+ <%- renderIcon("menu") %>
93
+ </span>
91
94
  </div>
92
95
 
93
96
  <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>
97
+ <% if (locals.optionsMenu && optionsMenu.position==='sidebar-top' ) { %>
98
+ <div class="sidebar-options-wrapper">
99
+ <%- include('partials/options-menu', { optionsMenu }) %>
100
+ </div>
98
101
  <% } %>
99
-
100
- <% if (config.versions && config.versions.position === 'sidebar-top') { %>
102
+ <% if (config.versions && config.versions.position==='sidebar-top' ) { %>
101
103
  <div class="sidebar-version-wrapper">
102
- <%- include('partials/version-dropdown', { versions: config.versions, activeVersion: config._activeVersion, relativePathToRoot }) %>
104
+ <%- include('partials/version-dropdown', { versions: config.versions, activeVersion:
105
+ config._activeVersion, relativePathToRoot }) %>
103
106
  </div>
104
- <% } %>
107
+ <% } %>
105
108
  </div>
106
109
 
107
110
  <%- navigationHtml %>
108
111
 
109
- <div class="sidebar-bottom-group mt-auto">
110
- <% if (config.versions && config.versions.position === 'sidebar-bottom') { %>
111
- <div class="sidebar-version-wrapper">
112
- <%- include('partials/version-dropdown', { versions: config.versions, activeVersion: config._activeVersion, relativePathToRoot }) %>
113
- </div>
114
- <% } %>
115
-
116
- <% if (locals.optionsMenu && optionsMenu.position === 'sidebar-bottom') { %>
117
- <div class="sidebar-options-wrapper">
112
+ <div class="sidebar-bottom-group mt-auto">
113
+ <% if (config.versions && config.versions.position==='sidebar-bottom' ) { %>
114
+ <div class="sidebar-version-wrapper">
115
+ <%- include('partials/version-dropdown', { versions: config.versions, activeVersion:
116
+ config._activeVersion, relativePathToRoot }) %>
117
+ </div>
118
+ <% } %>
119
+ <% if (locals.optionsMenu && optionsMenu.position==='sidebar-bottom' ) { %>
120
+ <div class="sidebar-options-wrapper">
118
121
  <%- include('partials/options-menu', { optionsMenu }) %>
119
- </div>
120
- <% } %>
121
- </div>
122
- </aside>
123
- <% } %>
122
+ </div>
123
+ <% } %>
124
+ </div>
125
+ </aside>
126
+ <% } %>
127
+ <div class="main-content-wrapper">
128
+ <% if (locals.menubarConfig && menubarConfig?.enabled !==false && menubarConfig.position==='header' ) { %>
129
+ <%- include('partials/menubar', { menubarConfig, relativePathToRoot, renderIcon, optionsMenu:
130
+ locals.optionsMenu }) %>
131
+ <% } %>
132
+ <% if (headerConfig?.enabled !==false) { %>
133
+ <header class="page-header">
134
+ <div class="header-left">
135
+ <% if (sidebarConfig?.collapsible) { %>
136
+ <button id="sidebar-toggle-button" class="sidebar-toggle-button"
137
+ aria-label="Toggle Sidebar">
138
+ <%- renderIcon('panel-left-close') %>
139
+ </button>
140
+ <% } %>
141
+ <span class="header-title">
142
+ <%= pageTitle %>
143
+ </span>
144
+ </div>
124
145
 
125
- <div class="main-content-wrapper">
126
- <% if (headerConfig?.enabled !== false) { %>
127
- <header class="page-header">
128
- <div class="header-left">
129
- <% if (sidebarConfig?.collapsible) { %>
130
- <button id="sidebar-toggle-button" class="sidebar-toggle-button" aria-label="Toggle Sidebar">
131
- <%- renderIcon('panel-left-close') %>
132
- </button>
133
- <% } %>
134
- <span class="header-title"><%= pageTitle %></span>
135
- </div>
136
-
137
- <div class="header-right">
138
- <% if (optionsMenu?.position === 'header') { %>
139
- <%- include('partials/options-menu', { optionsMenu }) %>
140
- <% } %>
146
+ <div class="header-right">
147
+ <% if (optionsMenu?.position==='header' ) { %>
148
+ <%- include('partials/options-menu', { optionsMenu }) %>
149
+ <% } %>
150
+ </div>
151
+ </header>
152
+ <% } %>
153
+ <div class="content-theme-cover">
154
+ <main class="content-area" id="main-content">
155
+ <div class="content-layout">
156
+ <div class="main-content">
157
+ <% if (headerConfig?.enabled===false) { %>
158
+ <h1>
159
+ <%= pageTitle %>
160
+ </h1>
161
+ <% } %>
162
+ <%- content %>
163
+ <% if (config.pageNavigation && (prevPage || nextPage)) { %>
164
+ <div class="page-navigation">
165
+ <% if (prevPage) { %>
166
+ <a href="<%= prevPage.url %>" class="prev-page">
167
+ <%- renderIcon('arrow-left', { class: 'page-nav-icon' }) %>
168
+ <span><small>Previous</small><strong>
169
+ <%= prevPage.title %>
170
+ </strong></span>
171
+ </a>
172
+ <% } else { %>
173
+ <div class="prev-page-placeholder">
174
+ </div>
175
+ <% } %>
176
+ <% if (nextPage) { %>
177
+ <a href="<%= nextPage.url %>" class="next-page">
178
+ <span><small>Next</small>
179
+ <strong>
180
+ <%= nextPage.title %>
181
+ </strong></span>
182
+ <%- renderIcon('arrow-right', { class: 'page-nav-icon' }) %>
183
+ </a>
184
+ <% } else { %>
185
+ <div class="next-page-placeholder">
186
+ </div>
187
+ <% } %>
188
+ </div>
189
+ <% } %>
190
+ </div>
191
+ <div class="toc-sidebar">
192
+ <%- include('toc', { content, headings, navigationHtml, isActivePage }) %>
193
+ </div>
194
+ </div>
195
+ <div class="page-footer-actions">
196
+ <% if (locals.editUrl) { %>
197
+ <a href="<%= editUrl %>" target="_blank" rel="noopener noreferrer" class="edit-link">
198
+ <%- renderIcon('pencil') %>
199
+ <%= editLinkText %>
200
+ </a>
201
+ <% } %>
202
+ </div>
203
+ </main>
204
+ <%- include('partials/footer', { footerConfig, config, relativePathToRoot, logo, siteTitle,
205
+ footerHtml }) %>
206
+ </div>
141
207
  </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>
169
- <% } %>
170
- </div>
171
-
172
- <div class="toc-sidebar">
173
- <%- include('toc', { content, headings, navigationHtml, isActivePage }) %>
174
- </div>
175
- </div>
176
-
177
- <div class="page-footer-actions">
178
- <% if (locals.editUrl) { %>
179
- <a href="<%= editUrl %>" target="_blank" rel="noopener noreferrer" class="edit-link">
180
- <%- renderIcon('pencil') %> <%= editLinkText %>
181
- </a>
182
- <% } %>
183
- </div>
184
- </main>
185
-
186
- <%- include('partials/footer', { footerConfig, config, relativePathToRoot, logo, siteTitle, footerHtml }) %>
187
- </div>
188
-
189
- <script src="<%= relativePathToRoot %>assets/js/docmd-main.js?v=<%= buildHash %>"></script>
190
- <%- pluginBodyScriptsHtml || '' %>
191
- <% (customJsFiles || []).forEach(jsFile => {
192
- if (jsFile && jsFile.trim() !== '') { %>
193
- <script src="<%= relativePathToRoot %><%- jsFile.startsWith('/') ? jsFile.substring(1) : jsFile %>?v=<%= buildHash %>"></script>
194
- <% } }); %>
208
+ <script src="<%= relativePathToRoot %>assets/js/docmd-main.js?v=<%= buildHash %>"></script>
209
+ <%- pluginBodyScriptsHtml || '' %>
210
+ <% (customJsFiles || []).forEach(jsFile=> {
211
+ if (jsFile && jsFile.trim() !== '') { %>
212
+ <script
213
+ src="<%= relativePathToRoot %><%- jsFile.startsWith('/') ? jsFile.substring(1) : jsFile %>?v=<%= buildHash %>"></script>
214
+ <% } }); %>
195
215
  </body>
216
+
196
217
  </html>
@@ -7,107 +7,90 @@
7
7
 
8
8
  <nav class="sidebar-nav" aria-label="Main Navigation">
9
9
  <ul>
10
- <%
11
- function normalizePath(p) {
12
- if (!p || p === '#') return '#';
13
- if (p.startsWith('http')) return p;
14
-
15
- // 1. Strip dot-slash and leading slash
16
- let path = p.replace(/^(\.\/|\/)+/, '');
17
-
18
- // 2. Remove extensions and index
19
- path = path.replace(/(\/index\.html|index\.html|\.html|\.md)$/, '');
20
-
21
- // 3. Remove trailing slash
22
- path = path.replace(/\/$/, '');
23
-
24
- // 4. Return with leading slash for comparison
25
- return '/' + path;
26
- }
27
-
28
- function isChildActive(item, currentPath) {
29
- if (!item.children) return false;
30
- const currentNorm = normalizePath(currentPath);
31
- return item.children.some(child => {
32
- const childNorm = normalizePath(child.path);
33
- if (childNorm === currentNorm) return true;
34
- return isChildActive(child, currentPath);
35
- });
10
+ <% function normalizePath(p) { if (!p || p==='#' ) return '#' ; if (p.startsWith('http')) return p; let
11
+ path=p.replace(/^(\.\/|\/)+/, '' ); path=path.replace(/(\/index\.html|index\.html|\.html|\.md)$/, '' );
12
+ path=path.replace(/\/$/, '' ); return '/' + path; } function isChildActive(item, currentPath) { if
13
+ (!item.children) return false; const currentNorm=normalizePath(currentPath); return item.children.some(child=> {
14
+ const childNorm = normalizePath(child.path);
15
+ if (childNorm === currentNorm) return true;
16
+ return isChildActive(child, currentPath);
17
+ });
36
18
  }
37
19
 
38
20
  function renderNav(items) {
39
21
  if (!items || !Array.isArray(items)) return;
40
-
22
+
41
23
  items.forEach(item => {
42
- const isExternal = item.external || false;
43
- const hasChildren = item.children && item.children.length > 0;
44
-
45
- // Determine interactions
46
- // It is collapsible ONLY if it has children AND config doesn't say 'false'
47
- const isInteractive = hasChildren && item.collapsible !== false;
48
-
49
- const itemNorm = normalizePath(item.path);
50
- const currentNorm = normalizePath(currentPagePath);
51
-
52
- const isDummyLink = !item.path || item.path === '#' || item.path === 'javascript:;';
53
- const isActive = itemNorm === currentNorm;
54
- const isParentOfActive = !isActive && isChildActive(item, currentPagePath);
55
-
56
- // Expand Logic:
57
- // 1. If Interactive: Expand if parent of active, or if it was previously toggled open.
58
- // 2. If NOT Interactive (collapsible: false): ALWAYS expand.
59
- const isOpen = isInteractive
60
- ? (isParentOfActive || (isActive && isInteractive))
61
- : true;
24
+ const isExternal = item.external || false;
25
+ const hasChildren = item.children && item.children.length > 0;
26
+ const isInteractive = hasChildren && item.collapsible !== false;
27
+
28
+ const itemNorm = normalizePath(item.path);
29
+ const currentNorm = normalizePath(currentPagePath);
30
+
31
+ const isDummyLink = !item.path || item.path === '#' || item.path === 'javascript:;';
32
+ const isActive = itemNorm === currentNorm;
33
+ const isParentOfActive = !isActive && isChildActive(item, currentPagePath);
34
+
35
+ const isOpen = isInteractive
36
+ ? (isParentOfActive || (isActive && isInteractive))
37
+ : true;
62
38
 
63
- const liClasses = [];
64
- if (isActive) liClasses.push('active');
65
- if (isParentOfActive) liClasses.push('active-parent');
66
-
67
- // Only add 'collapsible' class if we want the arrow and click behavior
68
- if (isInteractive) liClasses.push('collapsible');
69
-
70
- // Add 'expanded' to show children (via CSS)
71
- if (hasChildren && isOpen) liClasses.push('expanded');
72
-
73
- let href = item.path || '#';
74
- if (!isExternal && !isDummyLink && !href.startsWith('http')) {
75
- let cleanPath = href.replace(/^(\.\/|\/)+/, '');
76
- href = relativePathToRoot + cleanPath;
77
- if (isOfflineMode) {
78
- if (href.endsWith('/')) href += 'index.html';
79
- else if (!href.endsWith('.html')) href += '/index.html';
80
- } else {
81
- if (href.endsWith('/index.html')) href = href.slice(0, -10);
82
- }
83
- }
84
- %>
85
- <li class="<%= liClasses.join(' ') %>" <% if(isInteractive) { %> aria-expanded="<%= isOpen %>" <% } %>>
39
+ const liClasses = [];
40
+ if (isActive) liClasses.push('active');
41
+ if (isParentOfActive) liClasses.push('active-parent');
42
+ if (isInteractive) liClasses.push('collapsible');
43
+ if (hasChildren && isOpen) liClasses.push('expanded');
44
+ if (hasChildren) liClasses.push('nav-group');
45
+
46
+ let href = item.path || '#';
47
+ if (!isExternal && !isDummyLink && !href.startsWith('http')) {
48
+ let cleanPath = href.replace(/^(\.\/|\/)+/, '');
49
+ href = relativePathToRoot + cleanPath;
50
+ if (isOfflineMode) {
51
+ if (href.endsWith('/')) href += 'index.html';
52
+ else if (!href.endsWith('.html')) href += '/index.html';
53
+ } else {
54
+ if (href.endsWith('/index.html')) href = href.slice(0, -10);
55
+ }
56
+ }
57
+ %>
58
+ <li class="<%= liClasses.join(' ') %>" <% if(isInteractive) { %> aria-expanded="<%= isOpen %>" <% } %>>
86
59
  <% if (isDummyLink) { %>
87
- <span class="nav-label">
88
- <% if (item.icon) { %> <%- renderIcon(item.icon) %> <% } %>
89
- <span class="nav-item-title"><%= item.title %></span>
90
- <% if (isInteractive) { %>
91
- <span class="collapse-icon-wrapper"><%- renderIcon('chevron-right', { class: 'collapse-icon' }) %></span>
60
+ <span class="nav-label <%= hasChildren ? 'nav-group' : '' %>">
61
+ <% if (item.icon) { %> <%- renderIcon(item.icon) %>
62
+ <% } %>
63
+ <span class="nav-item-title">
64
+ <%= item.title %>
65
+ </span>
66
+ <% if (isInteractive) { %>
67
+ <span class="collapse-icon-wrapper"><%- renderIcon('chevron-right', { class: 'collapse-icon'
68
+ }) %></span>
92
69
  <% } %>
93
70
  </span>
94
- <% } else { %>
95
- <a href="<%= href %>" class="<%= isActive ? 'active' : '' %>" <%= isExternal ? 'target="_blank" rel="noopener"' : '' %>>
96
- <% if (item.icon) { %> <%- renderIcon(item.icon) %> <% } %>
97
- <span class="nav-item-title"><%= item.title %></span>
98
- <% if (isInteractive) { %>
99
- <span class="collapse-icon-wrapper"><%- renderIcon('chevron-right', { class: 'collapse-icon' }) %></span>
71
+ <% } else { %>
72
+ <a href="<%= href %>" class="<%= isActive ? 'active' : '' %> <%= hasChildren ? 'nav-group' : '' %>"
73
+ <%=isExternal ? 'target="_blank" rel="noopener"' : '' %>>
74
+ <% if (item.icon) { %> <%- renderIcon(item.icon) %>
75
+ <% } %>
76
+ <span class="nav-item-title">
77
+ <%= item.title %>
78
+ </span>
79
+ <% if (isInteractive) { %>
80
+ <span class="collapse-icon-wrapper"><%- renderIcon('chevron-right', { class: 'collapse-icon'
81
+ }) %></span>
82
+ <% } %>
83
+ <% if (isExternal) { %> <%- renderIcon('external-link', { class: 'nav-external-icon' }) %>
100
84
  <% } %>
101
- <% if (isExternal) { %> <%- renderIcon('external-link', { class: 'nav-external-icon' }) %> <% } %>
102
85
  </a>
103
- <% } %>
104
-
105
- <% if (hasChildren) { %>
106
- <ul class="submenu">
107
- <% renderNav(item.children); %>
108
- </ul>
109
- <% } %>
110
- </li>
86
+ <% } %>
87
+
88
+ <% if (hasChildren) { %>
89
+ <ul class="submenu">
90
+ <% renderNav(item.children); %>
91
+ </ul>
92
+ <% } %>
93
+ </li>
111
94
  <% }); } renderNav(navItems); %>
112
95
  </ul>
113
96
  </nav>