utopia-project 0.38.0 → 0.40.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/lib/utopia/project/base.rb +4 -14
- data/lib/utopia/project/guides.rb +66 -0
- data/lib/utopia/project/import_map.rb +2 -0
- data/lib/utopia/project/sidebar.rb +6 -16
- data/lib/utopia/project/version.rb +1 -1
- data/pages/_page.xnode +1 -18
- data/pages/_usage.xnode +2 -2
- data/pages/guides/index.xnode +17 -8
- data/pages/guides/show.xnode +34 -1
- data/pages/releases/index.xnode +0 -1
- data/public/_static/application.js +24 -0
- data/public/_static/links.js +18 -16
- data/public/_static/sidebar.js +205 -133
- data/public/_static/site.css +34 -0
- data/readme.md +6 -4
- data/releases.md +6 -0
- data.tar.gz.sig +0 -0
- metadata +6 -77
- metadata.gz.sig +3 -1
- data/public/_components/jquery/jquery.js +0 -10716
- data/public/_components/jquery/jquery.min.js +0 -2
- data/public/_components/jquery/jquery.min.map +0 -1
- data/public/_components/jquery/jquery.slim.js +0 -8617
- data/public/_components/jquery/jquery.slim.min.js +0 -2
- data/public/_components/jquery/jquery.slim.min.map +0 -1
- data/public/_components/jquery-litebox/jquery.litebox.css +0 -23
- data/public/_components/jquery-litebox/jquery.litebox.gallery.css +0 -48
- data/public/_components/jquery-litebox/jquery.litebox.js +0 -30
- data/public/_components/jquery-syntax/base/jquery.syntax.brush.apache.css +0 -12
- data/public/_components/jquery-syntax/base/jquery.syntax.brush.applescript.css +0 -5
- data/public/_components/jquery-syntax/base/jquery.syntax.brush.assembly.css +0 -8
- data/public/_components/jquery-syntax/base/jquery.syntax.brush.bash-script.css +0 -4
- data/public/_components/jquery-syntax/base/jquery.syntax.brush.bash.css +0 -2
- data/public/_components/jquery-syntax/base/jquery.syntax.brush.clang.css +0 -6
- data/public/_components/jquery-syntax/base/jquery.syntax.brush.css.css +0 -14
- data/public/_components/jquery-syntax/base/jquery.syntax.brush.diff.css +0 -16
- data/public/_components/jquery-syntax/base/jquery.syntax.brush.html.css +0 -3
- data/public/_components/jquery-syntax/base/jquery.syntax.brush.ocaml.css +0 -3
- data/public/_components/jquery-syntax/base/jquery.syntax.brush.protobuf.css +0 -2
- data/public/_components/jquery-syntax/base/jquery.syntax.brush.python.css +0 -6
- data/public/_components/jquery-syntax/base/jquery.syntax.brush.ruby.css +0 -2
- data/public/_components/jquery-syntax/base/jquery.syntax.brush.xml.css +0 -35
- data/public/_components/jquery-syntax/base/jquery.syntax.core.css +0 -58
- data/public/_components/jquery-syntax/base/jquery.syntax.editor.css +0 -6
- data/public/_components/jquery-syntax/base/theme.js +0 -1
- data/public/_components/jquery-syntax/bright/jquery.syntax.core.css +0 -27
- data/public/_components/jquery-syntax/bright/theme.js +0 -1
- data/public/_components/jquery-syntax/jquery.syntax.brush.apache.js +0 -3
- data/public/_components/jquery-syntax/jquery.syntax.brush.applescript.js +0 -5
- data/public/_components/jquery-syntax/jquery.syntax.brush.assembly.js +0 -3
- data/public/_components/jquery-syntax/jquery.syntax.brush.bash-script.js +0 -4
- data/public/_components/jquery-syntax/jquery.syntax.brush.bash.js +0 -2
- data/public/_components/jquery-syntax/jquery.syntax.brush.basic.js +0 -5
- data/public/_components/jquery-syntax/jquery.syntax.brush.clang.js +0 -5
- data/public/_components/jquery-syntax/jquery.syntax.brush.csharp.js +0 -4
- data/public/_components/jquery-syntax/jquery.syntax.brush.css.js +0 -5
- data/public/_components/jquery-syntax/jquery.syntax.brush.diff.js +0 -2
- data/public/_components/jquery-syntax/jquery.syntax.brush.go.js +0 -3
- data/public/_components/jquery-syntax/jquery.syntax.brush.haskell.js +0 -3
- data/public/_components/jquery-syntax/jquery.syntax.brush.html.js +0 -4
- data/public/_components/jquery-syntax/jquery.syntax.brush.io.js +0 -3
- data/public/_components/jquery-syntax/jquery.syntax.brush.java.js +0 -4
- data/public/_components/jquery-syntax/jquery.syntax.brush.javascript.js +0 -3
- data/public/_components/jquery-syntax/jquery.syntax.brush.kai.js +0 -2
- data/public/_components/jquery-syntax/jquery.syntax.brush.lisp.js +0 -2
- data/public/_components/jquery-syntax/jquery.syntax.brush.lua.js +0 -3
- data/public/_components/jquery-syntax/jquery.syntax.brush.nginx.js +0 -2
- data/public/_components/jquery-syntax/jquery.syntax.brush.ocaml.js +0 -4
- data/public/_components/jquery-syntax/jquery.syntax.brush.ooc.js +0 -4
- data/public/_components/jquery-syntax/jquery.syntax.brush.pascal.js +0 -4
- data/public/_components/jquery-syntax/jquery.syntax.brush.perl5.js +0 -3
- data/public/_components/jquery-syntax/jquery.syntax.brush.php-script.js +0 -4
- data/public/_components/jquery-syntax/jquery.syntax.brush.php.js +0 -2
- data/public/_components/jquery-syntax/jquery.syntax.brush.plain.js +0 -2
- data/public/_components/jquery-syntax/jquery.syntax.brush.protobuf.js +0 -3
- data/public/_components/jquery-syntax/jquery.syntax.brush.python.js +0 -5
- data/public/_components/jquery-syntax/jquery.syntax.brush.ruby.js +0 -5
- data/public/_components/jquery-syntax/jquery.syntax.brush.scala.js +0 -4
- data/public/_components/jquery-syntax/jquery.syntax.brush.smalltalk.js +0 -2
- data/public/_components/jquery-syntax/jquery.syntax.brush.sql.js +0 -4
- data/public/_components/jquery-syntax/jquery.syntax.brush.super-collider.js +0 -3
- data/public/_components/jquery-syntax/jquery.syntax.brush.swift.js +0 -3
- data/public/_components/jquery-syntax/jquery.syntax.brush.xml.js +0 -4
- data/public/_components/jquery-syntax/jquery.syntax.brush.xrb.js +0 -2
- data/public/_components/jquery-syntax/jquery.syntax.brush.yaml.js +0 -2
- data/public/_components/jquery-syntax/jquery.syntax.cache.js +0 -7
- data/public/_components/jquery-syntax/jquery.syntax.core.js +0 -34
- data/public/_components/jquery-syntax/jquery.syntax.editor.js +0 -11
- data/public/_components/jquery-syntax/jquery.syntax.js +0 -8
- data/public/_components/jquery-syntax/jquery.syntax.min.js +0 -13
- data/public/_components/jquery-syntax/paper/jquery.syntax.core.css +0 -31
- data/public/_components/jquery-syntax/paper/theme.js +0 -1
data/public/_static/sidebar.js
CHANGED
|
@@ -3,77 +3,116 @@
|
|
|
3
3
|
* Progressive enhancement for sidebar navigation with scroll tracking
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
if (!sidebarNav) return;
|
|
12
|
-
|
|
13
|
-
const navLinks = sidebarNav.querySelectorAll('a[href*="#"]');
|
|
14
|
-
|
|
15
|
-
// Build a map of sidebar links by their fragment IDs
|
|
16
|
-
const sidebarLinksByFragment = new Map();
|
|
17
|
-
navLinks.forEach(link => {
|
|
18
|
-
const href = link.getAttribute('href');
|
|
19
|
-
const fragmentIndex = href.indexOf('#');
|
|
20
|
-
if (fragmentIndex !== -1) {
|
|
21
|
-
const fragment = href.substring(fragmentIndex + 1);
|
|
22
|
-
sidebarLinksByFragment.set(fragment, link);
|
|
23
|
-
}
|
|
24
|
-
});
|
|
6
|
+
class SidebarNavigation {
|
|
7
|
+
static extractFragment(href) {
|
|
8
|
+
const index = href.indexOf('#');
|
|
9
|
+
return index !== -1 ? href.substring(index + 1) : null;
|
|
10
|
+
}
|
|
25
11
|
|
|
26
|
-
|
|
12
|
+
constructor(sidebarNav, sidebarLinksByFragment, allSections, sections, navLinks, sectionToSidebarLinkMap) {
|
|
13
|
+
this.sidebarNav = sidebarNav;
|
|
14
|
+
this.navLinks = navLinks;
|
|
15
|
+
this.currentActive = null;
|
|
16
|
+
this.sidebarLinksByFragment = sidebarLinksByFragment;
|
|
17
|
+
this.allSections = allSections;
|
|
18
|
+
this.sections = sections;
|
|
19
|
+
this.sectionToSidebarLinkMap = sectionToSidebarLinkMap;
|
|
20
|
+
|
|
21
|
+
// Store references for cleanup
|
|
22
|
+
this.scrollTimer = null;
|
|
23
|
+
this.scrollHandler = null;
|
|
24
|
+
this.resizeHandler = null;
|
|
25
|
+
this.clickHandlers = new Map();
|
|
26
|
+
|
|
27
|
+
// Initialize
|
|
28
|
+
this.setupEventListeners();
|
|
29
|
+
|
|
30
|
+
// Initial update without changing page state (preserves URL fragments)
|
|
31
|
+
this.updateActiveLink(false);
|
|
32
|
+
}
|
|
27
33
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
.
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
setupEventListeners() {
|
|
35
|
+
// Throttled scroll handler
|
|
36
|
+
this.scrollHandler = () => {
|
|
37
|
+
if (this.scrollTimer) return;
|
|
38
|
+
|
|
39
|
+
this.scrollTimer = setTimeout(() => {
|
|
40
|
+
this.updateActiveLink();
|
|
41
|
+
this.scrollTimer = null;
|
|
42
|
+
}, 100);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
this.resizeHandler = () => this.updateActiveLink();
|
|
46
|
+
|
|
47
|
+
// Set up event listeners
|
|
48
|
+
window.addEventListener('scroll', this.scrollHandler, { passive: true });
|
|
49
|
+
window.addEventListener('resize', this.resizeHandler, { passive: true });
|
|
50
|
+
|
|
51
|
+
// Smooth scroll enhancement for sidebar navigation links
|
|
52
|
+
this.navLinks.forEach(link => {
|
|
53
|
+
const clickHandler = (event) => {
|
|
54
|
+
const href = link.getAttribute('href');
|
|
55
|
+
const fragment = SidebarNavigation.extractFragment(href);
|
|
56
|
+
|
|
57
|
+
if (!fragment) return;
|
|
58
|
+
|
|
59
|
+
const target = document.getElementById(fragment);
|
|
60
|
+
|
|
61
|
+
if (target) {
|
|
62
|
+
event.preventDefault();
|
|
63
|
+
|
|
64
|
+
// Update URL to trigger :target and let browser handle scrolling
|
|
65
|
+
window.location.hash = fragment;
|
|
66
|
+
|
|
67
|
+
link.focus();
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
this.clickHandlers.set(link, clickHandler);
|
|
72
|
+
link.addEventListener('click', clickHandler);
|
|
35
73
|
});
|
|
74
|
+
}
|
|
36
75
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
// This section has a sidebar link - use it
|
|
43
|
-
lastSeenSidebarId = id;
|
|
44
|
-
}
|
|
45
|
-
// Annotate the section element with the sidebar link to activate
|
|
46
|
-
if (lastSeenSidebarId) {
|
|
47
|
-
element.dataset.sidebarLink = lastSeenSidebarId;
|
|
76
|
+
destroy() {
|
|
77
|
+
// Clear any pending timer
|
|
78
|
+
if (this.scrollTimer) {
|
|
79
|
+
clearTimeout(this.scrollTimer);
|
|
80
|
+
this.scrollTimer = null;
|
|
48
81
|
}
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
// Build sections array with link references for active state tracking
|
|
52
|
-
const sections = Array.from(sidebarLinksByFragment.entries()).map(([id, link]) => {
|
|
53
|
-
let sectionElement = document.getElementById(id);
|
|
54
82
|
|
|
55
|
-
|
|
56
|
-
|
|
83
|
+
// Remove window event listeners
|
|
84
|
+
if (this.scrollHandler) {
|
|
85
|
+
window.removeEventListener('scroll', this.scrollHandler);
|
|
86
|
+
this.scrollHandler = null;
|
|
57
87
|
}
|
|
58
88
|
|
|
59
|
-
if (
|
|
60
|
-
|
|
89
|
+
if (this.resizeHandler) {
|
|
90
|
+
window.removeEventListener('resize', this.resizeHandler);
|
|
91
|
+
this.resizeHandler = null;
|
|
61
92
|
}
|
|
62
93
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
94
|
+
// Remove click handlers from all links
|
|
95
|
+
this.clickHandlers.forEach((handler, link) => {
|
|
96
|
+
link.removeEventListener('click', handler);
|
|
97
|
+
});
|
|
98
|
+
this.clickHandlers.clear();
|
|
99
|
+
|
|
100
|
+
// Clear the section-to-sidebar-link mapping
|
|
101
|
+
this.sectionToSidebarLinkMap.clear();
|
|
102
|
+
|
|
103
|
+
// Remove active class from current link
|
|
104
|
+
if (this.currentActive) {
|
|
105
|
+
this.currentActive.link.classList.remove('active');
|
|
106
|
+
this.currentActive = null;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
69
109
|
|
|
70
|
-
|
|
71
|
-
let activeSectionData = null;
|
|
110
|
+
findCurrentSection() {
|
|
72
111
|
let smallestValidBottom = Infinity;
|
|
73
112
|
let currentSectionElement = null;
|
|
74
113
|
|
|
75
114
|
// Find which section the user is currently viewing
|
|
76
|
-
allSections.forEach(({element}) => {
|
|
115
|
+
this.allSections.forEach(({element}) => {
|
|
77
116
|
const rect = element.getBoundingClientRect();
|
|
78
117
|
const sectionBottom = rect.bottom;
|
|
79
118
|
|
|
@@ -87,54 +126,68 @@
|
|
|
87
126
|
}
|
|
88
127
|
});
|
|
89
128
|
|
|
90
|
-
// Look up which sidebar link should be active using the
|
|
91
|
-
if (currentSectionElement
|
|
92
|
-
const sidebarLinkId =
|
|
93
|
-
|
|
129
|
+
// Look up which sidebar link should be active using the map
|
|
130
|
+
if (currentSectionElement) {
|
|
131
|
+
const sidebarLinkId = this.sectionToSidebarLinkMap.get(currentSectionElement);
|
|
132
|
+
if (sidebarLinkId) {
|
|
133
|
+
return this.sections.find(s => s.id === sidebarLinkId);
|
|
134
|
+
}
|
|
94
135
|
}
|
|
95
136
|
|
|
96
|
-
// If
|
|
97
|
-
|
|
98
|
-
|
|
137
|
+
// If no section found, fall back to the last section
|
|
138
|
+
return this.sections.length > 0 ? this.sections[this.sections.length - 1] : null;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
setActiveSection(activeSectionData) {
|
|
142
|
+
// Remove previous active
|
|
143
|
+
if (this.currentActive) {
|
|
144
|
+
this.currentActive.link.classList.remove('active');
|
|
99
145
|
}
|
|
100
146
|
|
|
101
|
-
//
|
|
102
|
-
if (activeSectionData
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
147
|
+
// Set new active
|
|
148
|
+
if (activeSectionData) {
|
|
149
|
+
activeSectionData.link.classList.add('active');
|
|
150
|
+
this.currentActive = activeSectionData;
|
|
151
|
+
} else {
|
|
152
|
+
this.currentActive = null;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
updateUrlFragment(sectionId) {
|
|
157
|
+
if (sectionId) {
|
|
158
|
+
const newFragment = '#' + sectionId;
|
|
159
|
+
if (window.location.hash !== newFragment) {
|
|
160
|
+
history.replaceState(null, null, newFragment);
|
|
161
|
+
}
|
|
162
|
+
} else {
|
|
163
|
+
// Clear fragment if no active section
|
|
164
|
+
if (window.location.hash) {
|
|
165
|
+
history.replaceState(null, null, window.location.pathname);
|
|
106
166
|
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
updateActiveLink(updatePageState = true) {
|
|
171
|
+
const activeSectionData = this.findCurrentSection();
|
|
172
|
+
|
|
173
|
+
// Only update if section changed
|
|
174
|
+
if (activeSectionData !== this.currentActive) {
|
|
175
|
+
this.setActiveSection(activeSectionData);
|
|
107
176
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
// Update URL fragment to reflect current section
|
|
115
|
-
const newFragment = '#' + activeSectionData.id;
|
|
116
|
-
if (window.location.hash !== newFragment) {
|
|
117
|
-
history.replaceState(null, null, newFragment);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// Auto-scroll sidebar to keep active item visible
|
|
121
|
-
scrollToActiveItem(activeSectionData.link);
|
|
122
|
-
}
|
|
123
|
-
} else {
|
|
124
|
-
currentActive = null;
|
|
125
|
-
|
|
126
|
-
if (updatePageState) {
|
|
127
|
-
// Clear fragment if no active section
|
|
128
|
-
if (window.location.hash) {
|
|
129
|
-
history.replaceState(null, null, window.location.pathname);
|
|
130
|
-
}
|
|
177
|
+
if (updatePageState) {
|
|
178
|
+
if (activeSectionData) {
|
|
179
|
+
this.updateUrlFragment(activeSectionData.id);
|
|
180
|
+
this.scrollToActiveItem(activeSectionData.link);
|
|
181
|
+
} else {
|
|
182
|
+
this.updateUrlFragment(null);
|
|
131
183
|
}
|
|
132
184
|
}
|
|
133
185
|
}
|
|
134
186
|
}
|
|
135
187
|
|
|
136
|
-
|
|
137
|
-
|
|
188
|
+
scrollToActiveItem(activeLink) {
|
|
189
|
+
// Use the sidebar nav container we already have
|
|
190
|
+
const sidebar = this.sidebarNav.closest('.sidebar');
|
|
138
191
|
if (!sidebar) return;
|
|
139
192
|
|
|
140
193
|
const sidebarRect = sidebar.getBoundingClientRect();
|
|
@@ -159,50 +212,69 @@
|
|
|
159
212
|
}
|
|
160
213
|
}
|
|
161
214
|
|
|
162
|
-
//
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
if (scrollTimer) return;
|
|
215
|
+
// Static method to initialize with default selector
|
|
216
|
+
static initialize(selector = '.sidebar nav') {
|
|
217
|
+
const sidebarNav = document.querySelector(selector);
|
|
218
|
+
if (!sidebarNav) return null;
|
|
167
219
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
// Initialize and set up event listeners
|
|
175
|
-
window.addEventListener('scroll', onScroll, { passive: true });
|
|
176
|
-
window.addEventListener('resize', updateActiveLink, { passive: true });
|
|
177
|
-
|
|
178
|
-
// Initial update without changing page state (preserves URL fragments):
|
|
179
|
-
updateActiveLink(false);
|
|
180
|
-
|
|
181
|
-
// Smooth scroll enhancement for sidebar navigation links
|
|
182
|
-
navLinks.forEach(link => {
|
|
183
|
-
link.addEventListener('click', (event) => {
|
|
220
|
+
const navLinks = sidebarNav.querySelectorAll('a[href*="#"]');
|
|
221
|
+
|
|
222
|
+
// Build a map of sidebar links by their fragment IDs
|
|
223
|
+
const sidebarLinksByFragment = new Map();
|
|
224
|
+
navLinks.forEach(link => {
|
|
184
225
|
const href = link.getAttribute('href');
|
|
185
|
-
|
|
186
|
-
const fragmentIndex = href.indexOf('#');
|
|
187
|
-
if (fragmentIndex === -1) return;
|
|
188
|
-
const fragment = href.substring(fragmentIndex + 1);
|
|
226
|
+
const fragment = SidebarNavigation.extractFragment(href);
|
|
189
227
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
228
|
+
if (fragment) {
|
|
229
|
+
sidebarLinksByFragment.set(fragment, link);
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
// Early exit if no sidebar links with fragments
|
|
234
|
+
if (sidebarLinksByFragment.size === 0) return null;
|
|
235
|
+
|
|
236
|
+
// Get all sections/headings on the page and annotate them with their sidebar link
|
|
237
|
+
const allSections = Array.from(document.querySelectorAll('section, h1, h2, h3, h4, h5, h6'))
|
|
238
|
+
.filter(el => el.id) // Only keep elements with IDs
|
|
239
|
+
.map(el => {
|
|
240
|
+
// Get the section element (section or heading's parent)
|
|
241
|
+
const sectionElement = el.tagName === 'SECTION' ? el : (el.closest('section') || el.parentElement);
|
|
242
|
+
return { element: sectionElement, id: el.id };
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
// Annotate each section with which sidebar link should be active
|
|
246
|
+
// Walk through in DOM order and track the "last seen" sidebar link
|
|
247
|
+
// Store mapping in a Map instead of mutating DOM with data attributes
|
|
248
|
+
const sectionToSidebarLinkMap = new Map();
|
|
249
|
+
let lastSeenSidebarId = null;
|
|
250
|
+
allSections.forEach(({element, id}) => {
|
|
251
|
+
if (sidebarLinksByFragment.has(id)) {
|
|
252
|
+
// This section has a sidebar link - use it
|
|
253
|
+
lastSeenSidebarId = id;
|
|
254
|
+
}
|
|
255
|
+
// Map the section element to the sidebar link to activate
|
|
256
|
+
if (lastSeenSidebarId) {
|
|
257
|
+
sectionToSidebarLinkMap.set(element, lastSeenSidebarId);
|
|
196
258
|
}
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
// Build sections array with link references for active state tracking
|
|
262
|
+
const sections = Array.from(sidebarLinksByFragment.entries()).map(([id, link]) => {
|
|
263
|
+
let sectionElement = document.getElementById(id);
|
|
197
264
|
|
|
198
|
-
if (
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
// Update URL to trigger :target and let browser handle scrolling
|
|
202
|
-
window.location.hash = fragment;
|
|
265
|
+
if (sectionElement && sectionElement.tagName.match(/^H[1-6]$/)) {
|
|
266
|
+
sectionElement = sectionElement.closest('section') || sectionElement.parentElement;
|
|
203
267
|
}
|
|
268
|
+
|
|
269
|
+
return sectionElement ? { link, sectionElement, id } : null;
|
|
270
|
+
}).filter(Boolean);
|
|
271
|
+
|
|
272
|
+
// Early exit if no valid sections found
|
|
273
|
+
if (sections.length === 0) return null;
|
|
274
|
+
|
|
275
|
+
// All checks passed - create the instance
|
|
276
|
+
return new SidebarNavigation(sidebarNav, sidebarLinksByFragment, allSections, sections, navLinks, sectionToSidebarLinkMap);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
204
279
|
|
|
205
|
-
|
|
206
|
-
});
|
|
207
|
-
});
|
|
208
|
-
})();
|
|
280
|
+
export { SidebarNavigation };
|
data/public/_static/site.css
CHANGED
|
@@ -594,3 +594,37 @@ ul.pragmas li.asynchronous {
|
|
|
594
594
|
border-left-color: var(--accent-color);
|
|
595
595
|
font-weight: 500;
|
|
596
596
|
}
|
|
597
|
+
|
|
598
|
+
/* Guide navigation (previous/next) */
|
|
599
|
+
.content nav {
|
|
600
|
+
display: flex;
|
|
601
|
+
justify-content: space-between;
|
|
602
|
+
gap: 1rem;
|
|
603
|
+
margin: 1rem;
|
|
604
|
+
font-size: 0.9rem;
|
|
605
|
+
font-weight: 500;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
.content nav.top {
|
|
609
|
+
border-bottom: 1px solid var(--underlay-color);
|
|
610
|
+
padding-bottom: 0.5rem;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
.content nav.bottom {
|
|
614
|
+
border-top: 1px solid var(--underlay-color);
|
|
615
|
+
padding-top: 0.5rem;
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
.content nav .next {
|
|
619
|
+
margin-left: auto;
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
@media (max-width: 768px) {
|
|
623
|
+
.content nav {
|
|
624
|
+
flex-direction: column;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
.content nav .next {
|
|
628
|
+
margin-left: 0;
|
|
629
|
+
}
|
|
630
|
+
}
|
data/readme.md
CHANGED
|
@@ -33,6 +33,12 @@ Please see the [project documentation](https://socketry.github.io/utopia-project
|
|
|
33
33
|
|
|
34
34
|
Please see the [project releases](https://socketry.github.io/utopia-project/releases/index) for all releases.
|
|
35
35
|
|
|
36
|
+
### v0.40.0
|
|
37
|
+
|
|
38
|
+
- Fixed duplicate heading IDs when multiple sections have the same title. Permalinks and sidebar scroll tracking now work correctly when you have headings with identical text in different sections (e.g., multiple "Deployment" subsections under "Kubernetes" and "Systemd").
|
|
39
|
+
- Improved guides index page to show guide summaries (first paragraph) instead of just listing titles.
|
|
40
|
+
- Added previous/next navigation at the top and bottom of guide pages for easier sequential reading.
|
|
41
|
+
|
|
36
42
|
### v0.37.3
|
|
37
43
|
|
|
38
44
|
- Support for `@example` pragmas from the `decode` gem, allowing inline code examples to be rendered in API documentation.
|
|
@@ -69,10 +75,6 @@ Please see the [project releases](https://socketry.github.io/utopia-project/rele
|
|
|
69
75
|
|
|
70
76
|
- [Rename `changes.md` to `releases.md`](https://socketry.github.io/utopia-project/releases/index#rename-changes.md-to-releases.md)
|
|
71
77
|
|
|
72
|
-
### v0.29.0
|
|
73
|
-
|
|
74
|
-
- [Improve `changes.md` document organization](https://socketry.github.io/utopia-project/releases/index#improve-changes.md-document-organization)
|
|
75
|
-
|
|
76
78
|
## See Also
|
|
77
79
|
|
|
78
80
|
- [Utopia](https://github.com/socketry/utopia) — The website framework which powers this web application.
|
data/releases.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changes
|
|
2
2
|
|
|
3
|
+
## v0.40.0
|
|
4
|
+
|
|
5
|
+
- Fixed duplicate heading IDs when multiple sections have the same title. Permalinks and sidebar scroll tracking now work correctly when you have headings with identical text in different sections (e.g., multiple "Deployment" subsections under "Kubernetes" and "Systemd").
|
|
6
|
+
- Improved guides index page to show guide summaries (first paragraph) instead of just listing titles.
|
|
7
|
+
- Added previous/next navigation at the top and bottom of guide pages for easier sequential reading.
|
|
8
|
+
|
|
3
9
|
## v0.37.3
|
|
4
10
|
|
|
5
11
|
- Support for `@example` pragmas from the `decode` gem, allowing inline code examples to be rendered in API documentation.
|
data.tar.gz.sig
CHANGED
|
Binary file
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: utopia-project
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.40.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Samuel Williams
|
|
@@ -75,14 +75,14 @@ dependencies:
|
|
|
75
75
|
requirements:
|
|
76
76
|
- - "~>"
|
|
77
77
|
- !ruby/object:Gem::Version
|
|
78
|
-
version: '0.
|
|
78
|
+
version: '0.15'
|
|
79
79
|
type: :runtime
|
|
80
80
|
prerelease: false
|
|
81
81
|
version_requirements: !ruby/object:Gem::Requirement
|
|
82
82
|
requirements:
|
|
83
83
|
- - "~>"
|
|
84
84
|
- !ruby/object:Gem::Version
|
|
85
|
-
version: '0.
|
|
85
|
+
version: '0.15'
|
|
86
86
|
- !ruby/object:Gem::Dependency
|
|
87
87
|
name: rackula
|
|
88
88
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -142,6 +142,7 @@ files:
|
|
|
142
142
|
- lib/utopia/project/base.rb
|
|
143
143
|
- lib/utopia/project/document.rb
|
|
144
144
|
- lib/utopia/project/guide.rb
|
|
145
|
+
- lib/utopia/project/guides.rb
|
|
145
146
|
- lib/utopia/project/import_map.rb
|
|
146
147
|
- lib/utopia/project/linkify.rb
|
|
147
148
|
- lib/utopia/project/releases_document.rb
|
|
@@ -267,79 +268,6 @@ files:
|
|
|
267
268
|
- public/_components/@socketry/syntax/themes/base/xrb.css
|
|
268
269
|
- public/_components/@socketry/syntax/themes/base/yaml.css
|
|
269
270
|
- public/_components/@socketry/syntax/themes/theming.md
|
|
270
|
-
- public/_components/jquery-litebox/jquery.litebox.css
|
|
271
|
-
- public/_components/jquery-litebox/jquery.litebox.gallery.css
|
|
272
|
-
- public/_components/jquery-litebox/jquery.litebox.js
|
|
273
|
-
- public/_components/jquery-syntax/base/jquery.syntax.brush.apache.css
|
|
274
|
-
- public/_components/jquery-syntax/base/jquery.syntax.brush.applescript.css
|
|
275
|
-
- public/_components/jquery-syntax/base/jquery.syntax.brush.assembly.css
|
|
276
|
-
- public/_components/jquery-syntax/base/jquery.syntax.brush.bash-script.css
|
|
277
|
-
- public/_components/jquery-syntax/base/jquery.syntax.brush.bash.css
|
|
278
|
-
- public/_components/jquery-syntax/base/jquery.syntax.brush.clang.css
|
|
279
|
-
- public/_components/jquery-syntax/base/jquery.syntax.brush.css.css
|
|
280
|
-
- public/_components/jquery-syntax/base/jquery.syntax.brush.diff.css
|
|
281
|
-
- public/_components/jquery-syntax/base/jquery.syntax.brush.html.css
|
|
282
|
-
- public/_components/jquery-syntax/base/jquery.syntax.brush.ocaml.css
|
|
283
|
-
- public/_components/jquery-syntax/base/jquery.syntax.brush.protobuf.css
|
|
284
|
-
- public/_components/jquery-syntax/base/jquery.syntax.brush.python.css
|
|
285
|
-
- public/_components/jquery-syntax/base/jquery.syntax.brush.ruby.css
|
|
286
|
-
- public/_components/jquery-syntax/base/jquery.syntax.brush.xml.css
|
|
287
|
-
- public/_components/jquery-syntax/base/jquery.syntax.core.css
|
|
288
|
-
- public/_components/jquery-syntax/base/jquery.syntax.editor.css
|
|
289
|
-
- public/_components/jquery-syntax/base/theme.js
|
|
290
|
-
- public/_components/jquery-syntax/bright/jquery.syntax.core.css
|
|
291
|
-
- public/_components/jquery-syntax/bright/theme.js
|
|
292
|
-
- public/_components/jquery-syntax/jquery.syntax.brush.apache.js
|
|
293
|
-
- public/_components/jquery-syntax/jquery.syntax.brush.applescript.js
|
|
294
|
-
- public/_components/jquery-syntax/jquery.syntax.brush.assembly.js
|
|
295
|
-
- public/_components/jquery-syntax/jquery.syntax.brush.bash-script.js
|
|
296
|
-
- public/_components/jquery-syntax/jquery.syntax.brush.bash.js
|
|
297
|
-
- public/_components/jquery-syntax/jquery.syntax.brush.basic.js
|
|
298
|
-
- public/_components/jquery-syntax/jquery.syntax.brush.clang.js
|
|
299
|
-
- public/_components/jquery-syntax/jquery.syntax.brush.csharp.js
|
|
300
|
-
- public/_components/jquery-syntax/jquery.syntax.brush.css.js
|
|
301
|
-
- public/_components/jquery-syntax/jquery.syntax.brush.diff.js
|
|
302
|
-
- public/_components/jquery-syntax/jquery.syntax.brush.go.js
|
|
303
|
-
- public/_components/jquery-syntax/jquery.syntax.brush.haskell.js
|
|
304
|
-
- public/_components/jquery-syntax/jquery.syntax.brush.html.js
|
|
305
|
-
- public/_components/jquery-syntax/jquery.syntax.brush.io.js
|
|
306
|
-
- public/_components/jquery-syntax/jquery.syntax.brush.java.js
|
|
307
|
-
- public/_components/jquery-syntax/jquery.syntax.brush.javascript.js
|
|
308
|
-
- public/_components/jquery-syntax/jquery.syntax.brush.kai.js
|
|
309
|
-
- public/_components/jquery-syntax/jquery.syntax.brush.lisp.js
|
|
310
|
-
- public/_components/jquery-syntax/jquery.syntax.brush.lua.js
|
|
311
|
-
- public/_components/jquery-syntax/jquery.syntax.brush.nginx.js
|
|
312
|
-
- public/_components/jquery-syntax/jquery.syntax.brush.ocaml.js
|
|
313
|
-
- public/_components/jquery-syntax/jquery.syntax.brush.ooc.js
|
|
314
|
-
- public/_components/jquery-syntax/jquery.syntax.brush.pascal.js
|
|
315
|
-
- public/_components/jquery-syntax/jquery.syntax.brush.perl5.js
|
|
316
|
-
- public/_components/jquery-syntax/jquery.syntax.brush.php-script.js
|
|
317
|
-
- public/_components/jquery-syntax/jquery.syntax.brush.php.js
|
|
318
|
-
- public/_components/jquery-syntax/jquery.syntax.brush.plain.js
|
|
319
|
-
- public/_components/jquery-syntax/jquery.syntax.brush.protobuf.js
|
|
320
|
-
- public/_components/jquery-syntax/jquery.syntax.brush.python.js
|
|
321
|
-
- public/_components/jquery-syntax/jquery.syntax.brush.ruby.js
|
|
322
|
-
- public/_components/jquery-syntax/jquery.syntax.brush.scala.js
|
|
323
|
-
- public/_components/jquery-syntax/jquery.syntax.brush.smalltalk.js
|
|
324
|
-
- public/_components/jquery-syntax/jquery.syntax.brush.sql.js
|
|
325
|
-
- public/_components/jquery-syntax/jquery.syntax.brush.super-collider.js
|
|
326
|
-
- public/_components/jquery-syntax/jquery.syntax.brush.swift.js
|
|
327
|
-
- public/_components/jquery-syntax/jquery.syntax.brush.xml.js
|
|
328
|
-
- public/_components/jquery-syntax/jquery.syntax.brush.xrb.js
|
|
329
|
-
- public/_components/jquery-syntax/jquery.syntax.brush.yaml.js
|
|
330
|
-
- public/_components/jquery-syntax/jquery.syntax.cache.js
|
|
331
|
-
- public/_components/jquery-syntax/jquery.syntax.core.js
|
|
332
|
-
- public/_components/jquery-syntax/jquery.syntax.editor.js
|
|
333
|
-
- public/_components/jquery-syntax/jquery.syntax.js
|
|
334
|
-
- public/_components/jquery-syntax/jquery.syntax.min.js
|
|
335
|
-
- public/_components/jquery-syntax/paper/jquery.syntax.core.css
|
|
336
|
-
- public/_components/jquery-syntax/paper/theme.js
|
|
337
|
-
- public/_components/jquery/jquery.js
|
|
338
|
-
- public/_components/jquery/jquery.min.js
|
|
339
|
-
- public/_components/jquery/jquery.min.map
|
|
340
|
-
- public/_components/jquery/jquery.slim.js
|
|
341
|
-
- public/_components/jquery/jquery.slim.min.js
|
|
342
|
-
- public/_components/jquery/jquery.slim.min.map
|
|
343
271
|
- public/_components/mermaid/chunks/mermaid.core/architectureDiagram-VXUJARFQ.mjs
|
|
344
272
|
- public/_components/mermaid/chunks/mermaid.core/architectureDiagram-VXUJARFQ.mjs.map
|
|
345
273
|
- public/_components/mermaid/chunks/mermaid.core/blockDiagram-VD42YOAC.mjs
|
|
@@ -738,6 +666,7 @@ files:
|
|
|
738
666
|
- public/_components/mermaid/mermaid.js.map
|
|
739
667
|
- public/_components/mermaid/mermaid.min.js
|
|
740
668
|
- public/_components/mermaid/mermaid.min.js.map
|
|
669
|
+
- public/_static/application.js
|
|
741
670
|
- public/_static/icon.png
|
|
742
671
|
- public/_static/links.js
|
|
743
672
|
- public/_static/sidebar.js
|
|
@@ -769,7 +698,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
769
698
|
- !ruby/object:Gem::Version
|
|
770
699
|
version: '0'
|
|
771
700
|
requirements: []
|
|
772
|
-
rubygems_version: 3.
|
|
701
|
+
rubygems_version: 3.6.9
|
|
773
702
|
specification_version: 4
|
|
774
703
|
summary: A project documentation tool based on Utopia.
|
|
775
704
|
test_files: []
|
metadata.gz.sig
CHANGED
|
@@ -1 +1,3 @@
|
|
|
1
|
-
|
|
1
|
+
h��j���d�D1}i����HB�*���%4�V��7^��Eki>�#n&����æ�I^�
|
|
2
|
+
��i��t����g�&1�����7�o�~��^jLԪ�r^=s~������Q����s�_���4��
|
|
3
|
+
@;(>H\��n��Bc��&;\pȝ��w�1�9��Lq��x!���kMJ�s�RМ*d
|