jekyll-obsidian 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,403 @@
1
+ <body>
2
+ <div id="canvas-content"></div>
3
+ </body>
4
+
5
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/two.js/0.8.14/two.min.js"></script>
6
+
7
+ <script>
8
+ let _scrollLeft = 0; let _scrollTop = 0;
9
+ var EDGES = null;
10
+ function loadCanvas(canvasPath) {
11
+ const fullFilePath = getFullFilePath(canvasPath);
12
+ generateBreadcrumbs(canvasPath);
13
+ console.log("fullFilePath Canvas: " + fullFilePath)
14
+
15
+ fetch(fullFilePath).then(response => {
16
+ if (!response.ok)
17
+ throw new Error('Network response: ' + response.statusText);
18
+ return response.text();
19
+ }).then(content => {
20
+ try {
21
+ FILEREAD.scrollTop = 0;
22
+ FILEREAD.scrollLeft = 0;
23
+ const canvasParsed = JSON.parse(content);
24
+ if (!canvasParsed.nodes || !Array.isArray(canvasParsed.nodes)) {
25
+ console.error('Invalid or missing nodes array');
26
+ return;
27
+ }
28
+
29
+ const canvasContent = CANVAS.querySelector('#canvas-content');
30
+ while (canvasContent.firstChild)
31
+ canvasContent.removeChild(canvasContent.firstChild);
32
+ canvasContent.style.transform = `scale(1)`;
33
+
34
+ const nodesKeysList = canvasParsed.nodes.map(node => Object.keys(node));
35
+
36
+ const canvasWidth = parseInt(window.getComputedStyle(CANVAS).width);
37
+
38
+ const minX = canvasParsed.nodes.reduce((min, node) => Math.min(min, node.x), Infinity);
39
+ const maxX = canvasParsed.nodes.reduce((max, node) => Math.max(max, node.x), -Infinity);
40
+ const minY = canvasParsed.nodes.reduce((min, node) => Math.min(min, node.y), Infinity);
41
+ const maxY = canvasParsed.nodes.reduce((max, node) => Math.max(max, node.y), -Infinity);
42
+
43
+ const centerX = (minX + maxX) / 2;
44
+ const centerY = (minY + maxY) / 2;
45
+ console.warn(`Center point: (${centerX}, ${centerY})`);
46
+
47
+ // <!-- ----------------------------- Draw Edges ------------------------------ -->
48
+ const svgElement = CANVAS.querySelector('svg');
49
+ if (svgElement) svgElement.remove();
50
+ const edgesKeysList = canvasParsed.edges.map(edge => Object.keys(edge))
51
+ const params = { width: canvasWidth, height: canvasWidth };
52
+ const two = new Two(params).appendTo(CANVAS);
53
+ canvasParsed.edges.forEach(edge => {
54
+ const fromNode = canvasParsed.nodes.find(node => node.id === edge.fromNode);
55
+ const toNode = canvasParsed.nodes.find(node => node.id === edge.toNode);
56
+
57
+ if (fromNode && toNode) {
58
+ function getSideOffset(node, offsetX, offsetY, side) {
59
+ let sideOffsetX = offsetX;
60
+ let sideOffsetY = offsetY;
61
+ switch (side) {
62
+ case "top":
63
+ sideOffsetY = (offsetY - node.height / 2) + 5; break;
64
+ case "bottom":
65
+ sideOffsetY = (offsetY + node.height / 2) - 5; break;
66
+ case "right":
67
+ sideOffsetX = (offsetX + node.width / 2) - 5; break;
68
+ case "left":
69
+ sideOffsetX = (offsetX - node.width / 2) + 5; break;
70
+ }
71
+ return { sideOffsetX, sideOffsetY };
72
+ }
73
+
74
+ // Calculate common offset values
75
+ const offsetXFrom = (-minX) + (canvasWidth / 2) + fromNode.width / 2;
76
+ const offsetYFrom = (-minY) + (canvasWidth / 2) + fromNode.height / 2;
77
+
78
+ const offsetXTo = (-minX) + (canvasWidth / 2) + toNode.width / 2;
79
+ const offsetYTo = (-minY) + (canvasWidth / 2) + toNode.height / 2;
80
+
81
+ const fromOffsets = getSideOffset(fromNode, offsetXFrom, offsetYFrom, edge.fromSide);
82
+ const from_SideOffsetX = fromOffsets.sideOffsetX;
83
+ const from_SideOffsetY = fromOffsets.sideOffsetY;
84
+
85
+ const toOffsets = getSideOffset(toNode, offsetXTo, offsetYTo, edge.toSide);
86
+ const to_SideOffsetX = toOffsets.sideOffsetX;
87
+ const to_SideOffsetY = toOffsets.sideOffsetY;
88
+
89
+ function getControlPointOffset(node, side) {
90
+ const controlOffset = 5;
91
+ let controlOffsetX = 0;
92
+ let controlOffsetY = 0;
93
+
94
+ switch (side) {
95
+ case "top":
96
+ controlOffsetY = -controlOffset; break;
97
+ case "bottom":
98
+ controlOffsetY = controlOffset; break;
99
+ case "right":
100
+ controlOffsetX = controlOffset;
101
+ controlOffsetY = 0; break;
102
+ case "left":
103
+ controlOffsetX = -controlOffset;
104
+ controlOffsetY = 0; break;
105
+ }
106
+ return { controlOffsetX, controlOffsetY };
107
+ }
108
+
109
+ // Calculate the start and end offsets based on node side
110
+ const fromCurveOffset = getControlPointOffset(fromNode, edge.fromSide);
111
+ const toCurveOffset = getControlPointOffset(toNode, edge.toSide);
112
+
113
+ const curve = two.makeCurve(
114
+ fromNode.x + from_SideOffsetX,
115
+ fromNode.y + from_SideOffsetY,
116
+
117
+ fromNode.x + from_SideOffsetX + fromCurveOffset.controlOffsetX,
118
+ fromNode.y + from_SideOffsetY + fromCurveOffset.controlOffsetY,
119
+
120
+ toNode.x + to_SideOffsetX + toCurveOffset.controlOffsetX,
121
+ toNode.y + to_SideOffsetY + toCurveOffset.controlOffsetY,
122
+
123
+ // End point at toNode
124
+ toNode.x + to_SideOffsetX,
125
+ toNode.y + to_SideOffsetY,
126
+
127
+ false // Not a closed path
128
+ );
129
+
130
+ if ('color' in edge) {
131
+ curve.stroke = getColorByIndex(edge.color);
132
+ } else curve.stroke = '#c0c0c0';
133
+ curve.linewidth = 4;
134
+ curve.fill = 'transparent';
135
+ curve.fillOpacity = 0;
136
+ curve.closed = false;
137
+ }
138
+ });
139
+ two.update()
140
+ EDGES = CANVAS.querySelector('svg');
141
+ // <!-- --------------------------- Draw Edges END ---------------------------- -->
142
+
143
+ canvasParsed.nodes.forEach(node => {
144
+ const card = document.createElement('div');
145
+ if ('color' in node) card.style.borderColor = getColorByIndex(node.color);
146
+ switch (node.type) {
147
+ case "text":
148
+ default:
149
+ card.classList.add('card', 'text');
150
+ if (node.text) {
151
+ const cardDiv = parseStringToMarkdown(node.text);
152
+ card.innerHTML = DOMPurify.sanitize(cardDiv.innerHTML);
153
+ cardDiv.remove();
154
+ if (BACKLINKS) mapBacklinksToJson(BACKLINKS);
155
+ }
156
+ break;
157
+ case "file":
158
+ card.classList.add('card', 'file');
159
+ card.textContent = node.file;
160
+ break;
161
+ case "link":
162
+ card.classList.add('card', 'link');
163
+ card.textContent = node.link;
164
+ break;
165
+ case "group":
166
+ card.classList.add('card', 'group');
167
+ if (node.label !== "") {
168
+ const groupLabel = document.createElement('p')
169
+ groupLabel.textContent = node.label;
170
+ card.appendChild(groupLabel);
171
+ }
172
+ break;
173
+ }
174
+ card.style.position = 'absolute';
175
+ card.style.top = `${node.y + (-minY) + (canvasWidth / 2)}px`;
176
+ card.style.left = `${node.x + (-minX) + (canvasWidth / 2)}px`;
177
+
178
+ card.style.width = `${node.width}px`;
179
+ card.style.height = `${node.height}px`;
180
+
181
+ canvasContent.appendChild(card);
182
+ });
183
+
184
+ const boundingBox = getBoundingBoxOfChildren(canvasContent);
185
+ if (boundingBox) {
186
+ const center = getCenterOfBoundingBox(boundingBox);
187
+ console.info(`Canvas center: x=${center.x}, y=${center.y}`);
188
+ const FILEREADWidth = FILEREAD.offsetWidth;
189
+ const FILEREADHeight = FILEREAD.offsetHeight;
190
+
191
+ const boundingBoxVolume = boundingBox.height * boundingBox.width;
192
+ const canvasVolume = canvasWidth ** 2;
193
+
194
+ const scale = (boundingBoxVolume / canvasVolume);
195
+
196
+ canvasContent.style.transform = `scale(${(1 - scale) / 2})`;
197
+ EDGES.style.transform = `scale(${(1 - scale) / 2})`;
198
+
199
+ _scrollLeft = center.x - boundingBox.width / 2;
200
+ _scrollTop = center.y - boundingBox.height / 2;
201
+
202
+ if (window.innerWidth < 481) {
203
+ _scrollLeft += window.innerWidth;
204
+ _scrollTop += window.innerHeight / 2;
205
+ }
206
+ FILEREAD.scrollLeft = _scrollLeft; FILEREAD.scrollTop = _scrollTop;
207
+ } else console.warn('The canvas has no children.');
208
+
209
+ FILEREAD.addEventListener('wheel', adjustCanvasScaleOnScroll);
210
+ } catch (e) {
211
+ console.error("Error parsing canvas:", e);
212
+ }
213
+ });
214
+ }
215
+ </script>
216
+
217
+ <!-- --------------------- Canvas movement and zooming --------------------- -->
218
+ <script>
219
+ function resetCanvasPosition() {
220
+ if (_scrollLeft) FILEREAD.scrollLeft = _scrollLeft;
221
+ if (_scrollTop) FILEREAD.scrollTop = _scrollTop;
222
+ }
223
+
224
+ function getBoundingBoxOfChildren(parentElement) {
225
+ const children = parentElement.children;
226
+ if (children.length === 0) {
227
+ return null;
228
+ }
229
+ // Initialize the bounding box with the first child's bounding rectangle
230
+ const firstChildRect = children[0].getBoundingClientRect();
231
+ let minX = firstChildRect.left;
232
+ let minY = firstChildRect.top;
233
+ let maxX = firstChildRect.right;
234
+ let maxY = firstChildRect.bottom;
235
+
236
+ // Iterate over all children to find the bounding box
237
+ for (let i = 1; i < children.length; i++) {
238
+ const rect = children[i].getBoundingClientRect();
239
+ if (rect.left < minX) minX = rect.left;
240
+ if (rect.top < minY) minY = rect.top;
241
+ if (rect.right > maxX) maxX = rect.right;
242
+ if (rect.bottom > maxY) maxY = rect.bottom;
243
+ }
244
+
245
+ const boundingBox = {
246
+ left: minX,
247
+ top: minY,
248
+ right: maxX,
249
+ bottom: maxY,
250
+ width: maxX - minX,
251
+ height: maxY - minY,
252
+ };
253
+ return boundingBox;
254
+ }
255
+
256
+ function getColorByIndex(colorInt) {
257
+ switch (parseInt(colorInt)) {
258
+ case 1: return '#ea3b50';
259
+ case 2: return '#ee7e0f';
260
+ case 3: return '#e0ac00';
261
+ case 4: return '#09b94f';
262
+ case 5: return '#18c5c2';
263
+ default: return '#c0c0c0';
264
+ }
265
+ }
266
+
267
+ // Function to calculate the center of the bounding box
268
+ function getCenterOfBoundingBox(boundingBox) {
269
+ const centerX = boundingBox.left + (boundingBox.width / 2);
270
+ const centerY = boundingBox.top + (boundingBox.height / 2);
271
+ return { x: centerX, y: centerY };
272
+ }
273
+
274
+ function adjustCanvasScaleOnScroll(e) {
275
+ if (e.ctrlKey) {
276
+ e.preventDefault();
277
+
278
+ const canvasContent = CANVAS.querySelector('#canvas-content');
279
+ let scale = parseFloat(canvasContent.style.transform.replace(/[^0-9.-]/g, ''));
280
+ if (isNaN(scale)) scale = 1; // Default scale
281
+
282
+ // Get cursor position relative to the canvas
283
+ const rect = CANVAS.getBoundingClientRect();
284
+ const x = e.clientX - rect.left;
285
+ const y = e.clientY - rect.top;
286
+
287
+ // Calculate the point on the canvas before scaling
288
+ const pointBeforeScale = {
289
+ x: (FILEREAD.scrollLeft + x) / scale,
290
+ y: (FILEREAD.scrollTop + y) / scale
291
+ };
292
+
293
+ console.info("Scroll direction: " + (e.deltaY > 0 ? "down" : "up"));
294
+ if (e.deltaY > 0) {
295
+ scale = Math.max(0.1, scale - 0.01);
296
+ } else {
297
+ scale = Math.min(1, scale + 0.01);
298
+ }
299
+
300
+ canvasContent.style.transform = `scale(${scale})`;
301
+ EDGES.style.transform = `scale(${scale})`;
302
+ EDGES.style.transformOrigin = 'center center';
303
+
304
+ const scrollMultiplier = 0.02;
305
+ const deltaX = (pointBeforeScale.x * scale - (FILEREAD.scrollLeft + x)) * scrollMultiplier;
306
+ const deltaY = (pointBeforeScale.y * scale - (FILEREAD.scrollTop + y)) * scrollMultiplier;
307
+ FILEREAD.scrollLeft += deltaX;
308
+ FILEREAD.scrollTop += deltaY;
309
+ }
310
+ }
311
+ </script>
312
+
313
+ <script>
314
+ document.addEventListener('DOMContentLoaded', () => {
315
+ const homepage = '{{ site.obsidian_homepage | escape }}';
316
+ if (homepage && homepage.endsWith('.canvas')) {
317
+ loadCanvas(homepage);
318
+ console.log("canvas read loaded: " + homepage);
319
+ }
320
+
321
+ CANVAS.addEventListener('mousemove', function (e) {
322
+ const rect = CANVAS.getBoundingClientRect();
323
+ const mouseX = e.clientX - rect.left;
324
+ const mouseY = e.clientY - rect.top;
325
+ // console.log(`Mouse X: ${mouseX}, Mouse Y: ${mouseY}`);
326
+ });
327
+ });
328
+
329
+ document.addEventListener('obsidian_canvasSelect', function (event) {
330
+ switchPage(event.detail.filePath);
331
+ loadCanvas(event.detail.filePath);
332
+ });
333
+ </script>
334
+
335
+ <!-- --------------------------- Drag Listeners ---------------------------- -->
336
+ <!-- <script>
337
+ const fileRead = document.querySelector('#fileread');
338
+ let isMouseDown = false;
339
+ let lastMouseX = 0;
340
+ let lastMouseY = 0;
341
+ let lastTime = 0;
342
+
343
+ fileRead.addEventListener('mousedown', (event) => {
344
+ isMouseDown = true;
345
+ const canvasContent = CANVAS.querySelector('#canvas-content');
346
+ canvasContent.style.pointerEvents = 'none';
347
+ canvasContent.style.userSelect = 'none';
348
+
349
+ lastMouseX = event.offsetX;
350
+ lastMouseY = event.offsetY;
351
+ lastTime = performance.now(); // Record the time when mouse is pressed
352
+
353
+ console.log(`Mouse pressed at: ${lastMouseX}, ${lastMouseY}`);
354
+ });
355
+
356
+ // Mouse move event to track the mouse movement
357
+ fileRead.addEventListener('mousemove', (event) => {
358
+ if (isMouseDown) {
359
+ const currentMouseX = event.offsetX;
360
+ const currentMouseY = event.offsetY;
361
+ const currentTime = performance.now();
362
+
363
+ let deltaX = currentMouseX - lastMouseX;
364
+ let deltaY = currentMouseY - lastMouseY;
365
+ const deltaTime = currentTime - lastTime;
366
+
367
+ let velocityX = deltaX / deltaTime;
368
+ velocityX = velocityX.toFixed(1)
369
+ let velocityY = deltaY / deltaTime;
370
+ velocityY = velocityY.toFixed(1)
371
+
372
+ // if (Math.abs(deltaX) > 1) deltaX = Math.sign(deltaX) * 1;
373
+ // if (Math.abs(deltaY) > 1) deltaY = Math.sign(deltaY) * 1;
374
+
375
+ // if (Math.abs(velocityX) > 1) velocityX = Math.sign(velocityX) * 1;
376
+ // if (Math.abs(velocityY) > 1) velocityY = Math.sign(velocityY) * 1;
377
+
378
+ console.log(`Velocity X: ${velocityX} px/ms, Velocity Y: ${velocityY} px/ms`);
379
+ FILEREAD.scrollLeft -= velocityX * 20; FILEREAD.scrollTop -= velocityY * 20;
380
+
381
+ lastMouseX = currentMouseX;
382
+ lastMouseY = currentMouseY;
383
+ lastTime = currentTime;
384
+ }
385
+ });
386
+
387
+ // Mouse up event to stop tracking
388
+ fileRead.addEventListener('mouseup', () => {
389
+ isMouseDown = false;
390
+ const canvasContent = CANVAS.querySelector('#canvas-content');
391
+ canvasContent.style.pointerEvents = 'auto';
392
+ canvasContent.style.userSelect = 'auto';
393
+ console.log('Mouse released');
394
+ });
395
+
396
+ fileRead.addEventListener('mouseleave', () => {
397
+ console.log('Mouse left the element!');
398
+ isMouseDown = false;
399
+ const canvasContent = CANVAS.querySelector('#canvas-content');
400
+ canvasContent.style.pointerEvents = 'auto';
401
+ canvasContent.style.userSelect = 'auto';
402
+ });
403
+ </script> -->
@@ -0,0 +1,202 @@
1
+ <body>
2
+ <div id="vault-name">
3
+ <div id="text">
4
+ {{ site.obsidian_vault | split: "/" | last }}</div>
5
+ <button id="collapseExpand"></button>
6
+ </div>
7
+ <div id="file-tree"></div>
8
+ </body>
9
+
10
+ <!-- ------------------------- Touch screen docker ------------------------- -->
11
+ <script>
12
+
13
+ let touchStartX = 0;
14
+ let touchCurrentX = 0;
15
+ let isDraggingTouch = false;
16
+ let explorerDisplayed = false;
17
+ let activationDistance = 0;
18
+
19
+ document.addEventListener('touchstart', handleTouchStart, false);
20
+ document.addEventListener('touchmove', handleTouchMove, false);
21
+ document.addEventListener('touchend', handleTouchEnd, false);
22
+
23
+ function handleTouchStart(evt) {
24
+ const firstTouch = evt.touches[0];
25
+ touchStartX = firstTouch.clientX;
26
+ let touchStartY = firstTouch.clientY;
27
+
28
+ explorerDisplayed = isDisplayNone(EXPLORER);
29
+ activationDistance = window.innerWidth - 120;
30
+
31
+ if (!explorerDisplayed) {
32
+ if (touchStartX < 40 && touchStartY > 150
33
+ && touchStartY < window.innerHeight - 45) {
34
+ isDraggingTouch = true;
35
+ EXPLORER.style.display = '';
36
+ }
37
+ }
38
+ else {
39
+ if (touchStartX > window.innerWidth - 40
40
+ && touchStartY > 100) {
41
+ isDraggingTouch = true;
42
+ FILEREAD.style.display = '';
43
+ }
44
+ }
45
+
46
+ }
47
+
48
+ function handleTouchMove(evt) {
49
+ if (!isDraggingTouch) return;
50
+ touchCurrentX = evt.touches[0].clientX;
51
+
52
+ if (!explorerDisplayed) {
53
+ // Dragging to adjust the explorer width from left to right
54
+ let diffX = touchCurrentX - touchStartX;
55
+ let padding = linearMapInRange(diffX, 0, activationDistance, 1, 100);
56
+ EXPLORER.style.width = `calc(${padding}% - 2rem)`;
57
+ } else {
58
+ // Dragging to reveal the explorer from right to left
59
+ let diffX = window.innerWidth - touchCurrentX;
60
+ let padding = linearMapInRange(diffX, 0, activationDistance, 100, 1);
61
+ EXPLORER.style.width = `calc(${padding}% - 2rem)`;
62
+ }
63
+ }
64
+
65
+ function handleTouchEnd(evt) {
66
+ if (!isDraggingTouch) return;
67
+
68
+ if (!explorerDisplayed) {
69
+ let diffX = touchCurrentX - touchStartX;
70
+ if (diffX > activationDistance) {
71
+ EXPLORER.style.width = 'calc(100% - 2rem)';
72
+ FILEREAD.style.display = 'none';
73
+ } else {
74
+ EXPLORER.style.display = 'none';
75
+ EXPLORER.style.width = '1%';
76
+ }
77
+ } else {
78
+ let diffX = window.innerWidth - touchCurrentX;
79
+ if (diffX > activationDistance) {
80
+ EXPLORER.style.display = 'none';
81
+ EXPLORER.style.width = '1%';
82
+ } else {
83
+ FILEREAD.style.display = '';
84
+ EXPLORER.style.width = 'calc(100% - 2rem)';
85
+ }
86
+ }
87
+ isDraggingTouch = false;
88
+ touchStartX = 0; touchCurrentX = 0;
89
+ }
90
+
91
+ function isDisplayNone(element) {
92
+ const style = getComputedStyle(element);
93
+ return style.display !== 'none';
94
+ }
95
+
96
+ </script>
97
+ <!-- ------------------------- File tree generator ------------------------- -->
98
+ <script lang="text/javascript">
99
+
100
+ function buildFileTree(rootElement, tree, expandRoot = false) {
101
+ const EXPLORER = OBSIDIAN.querySelector('#explorer');
102
+ const FILE_TREE = EXPLORER.querySelector(' #file-tree');
103
+ const old_ul = rootElement.querySelector('ul');
104
+ if (old_ul) rootElement.removeChild(old_ul);
105
+ const ul = document.createElement('ul');
106
+ rootElement.appendChild(ul);
107
+
108
+ tree.forEach(child => {
109
+ const li = document.createElement('li');
110
+ ul.appendChild(li);
111
+
112
+ const button = document.createElement('button');
113
+ const decodedString = he.decode(child.name);
114
+ button.textContent = decodedString;
115
+ li.appendChild(button);
116
+
117
+ if (child.type === 'dir') {
118
+ li.classList.add('dir');
119
+
120
+ button.innerHTML =
121
+ DOMPurify.sanitize(getSVGIcon(Icon.RightArrow) + button.textContent);
122
+ var expanded = false;
123
+ button.addEventListener('click', () => {
124
+ expanded = !expanded;
125
+ button.innerHTML =
126
+ DOMPurify.sanitize((expanded ? getSVGIcon(Icon.DownArrow)
127
+ : getSVGIcon(Icon.RightArrow)) + button.textContent);
128
+
129
+ if (expanded) {
130
+ if (!li.querySelector('ul'))
131
+ buildFileTree(li, child.children);
132
+ } else {
133
+ const nestedUl = li.querySelector('ul');
134
+ if (nestedUl) li.removeChild(nestedUl);
135
+ }
136
+ });
137
+ if (expandRoot === true) {
138
+ expanded = true;
139
+ button.innerHTML =
140
+ DOMPurify.sanitize(getSVGIcon(Icon.DownArrow) + button.textContent);
141
+ if (!li.querySelector('ul'))
142
+ buildFileTree(li, child.children, true);
143
+ }
144
+
145
+ } else if (child.type === 'file') {
146
+ li.classList.add('file');
147
+ button.addEventListener('click', () => {
148
+ dispatchFileSelectEvt(he.decode(child.path));
149
+ });
150
+ const fileName = child.name.replace(/\.[^/.]+$/, "")
151
+ button.textContent = he.decode(fileName);
152
+ }
153
+ });
154
+ }
155
+
156
+ function sortObsidianVaultFiles(tree) {
157
+ const EXPLORER = OBSIDIAN.querySelector('#explorer');
158
+ const FILE_TREE = EXPLORER.querySelector(' #file-tree');
159
+ tree.sort((a, b) => {
160
+ if (a.type === 'dir' && b.type === 'file') {
161
+ return -1;
162
+ } else if (a.type === 'file' && b.type === 'dir') {
163
+ return 1;
164
+ } else return a.name.localeCompare(b.name);
165
+ });
166
+ tree.forEach(child => {
167
+ if (child.type === 'dir') {
168
+ sortObsidianVaultFiles(child.children);
169
+ }
170
+ });
171
+ return tree;
172
+ }
173
+
174
+ let expandOrCollapseFileTree = false;
175
+ document.addEventListener('DOMContentLoaded', () => {
176
+ const VAULT_FILES =
177
+ JSON.parse('{{ site.data.obsidian.vault_files | escape }}'.replace(/&quot;/g, '"'));
178
+ const EXPLORER = OBSIDIAN.querySelector('#explorer');
179
+ const FILE_TREE = EXPLORER.querySelector(' #file-tree');
180
+ const sortedVaultFiles = sortObsidianVaultFiles(VAULT_FILES);
181
+ buildFileTree(FILE_TREE, sortedVaultFiles);
182
+
183
+ const collapseExpand = EXPLORER.querySelector('#vault-name #collapseExpand');
184
+ collapseExpand.innerHTML = DOMPurify.sanitize(getSVGIcon(Icon.ChevronExpand));
185
+ collapseExpand.addEventListener('click', () => {
186
+ expandOrCollapseFileTree = !expandOrCollapseFileTree;
187
+ if (expandOrCollapseFileTree)
188
+ EXPLORER.classList.add('hide-scrollbar');
189
+ buildFileTree(FILE_TREE, sortedVaultFiles, expandOrCollapseFileTree);
190
+ collapseExpand.innerHTML = DOMPurify.sanitize((expandOrCollapseFileTree ?
191
+ getSVGIcon(Icon.ChevronCollapse)
192
+ : getSVGIcon(Icon.ChevronExpand)));
193
+ });
194
+
195
+ EXPLORER.addEventListener('scroll', () => {
196
+ if (EXPLORER.scrollTop < 250) {
197
+ EXPLORER.classList.add('hide-scrollbar');
198
+ } else
199
+ EXPLORER.classList.remove('hide-scrollbar');
200
+ });
201
+ });
202
+ </script>