tangled
alpha
login
or
join now
tokono.ma
/
diffuse
5
fork
atom
A music player that connects to your cloud/distributed storage.
5
fork
atom
overview
issues
4
pulls
pipelines
chore: dashboard nav loading anim
Steven Vandevelde
2 weeks ago
4e3ab7df
3a559e4a
+42
-9
2 changed files
expand all
collapse all
unified
split
src
_components
nav.vto
common
pages
ppr.js
+9
-9
src/_components/nav.vto
reviewed
···
4
4
<div class="nav-container">
5
5
<nav id="diffuse-nav">
6
6
<a href="dashboard/" class="button {{ colorClass("dashboard/") }} button--border">
7
7
-
<span class="with-icon">
7
7
+
<span>
8
8
<i class="ph-fill ph-person"></i>
9
9
Your Diffuse
10
10
</span>
11
11
</a>
12
12
13
13
<a href="guide/" class="button {{ colorClass("guide/") }} button--border">
14
14
-
<span class="with-icon">
14
14
+
<span>
15
15
<i class="ph-fill ph-book-open-text"></i>
16
16
Guide
17
17
</span>
18
18
</a>
19
19
20
20
<a href="featured/" class="button {{ colorClass("featured/") }} button--border">
21
21
-
<span class="with-icon">
21
21
+
<span>
22
22
<i class="ph-fill ph-sparkle"></i>
23
23
Featured
24
24
</span>
25
25
</a>
26
26
27
27
<a href="build/" class="button {{ colorClass("build/") }} button--border">
28
28
-
<span class="with-icon">
28
28
+
<span>
29
29
<i class="ph-fill ph-hammer"></i>
30
30
Build
31
31
</span>
···
34
34
<div class="divider"></div>
35
35
36
36
<a href="data/" class="button {{ colorClass("data/") }} button--border">
37
37
-
Input & Output
37
37
+
<span>Input & Output</span>
38
38
</a>
39
39
40
40
<a href="playback/" class="button {{ colorClass("playback/") }} button--border">
41
41
-
Playback
41
41
+
<span>Playback</span>
42
42
</a>
43
43
44
44
<a href="browsing/" class="button {{ colorClass("browsing/") }} button--border">
45
45
-
Browsing
45
45
+
<span>Browsing</span>
46
46
</a>
47
47
48
48
<a href="themes/" class="button {{ colorClass("themes/") }} button--border">
49
49
-
Themes
49
49
+
<span>Themes</span>
50
50
</a>
51
51
52
52
<a href="misc/" class="button {{ colorClass("misc/") }} button--border">
53
53
-
<span class="with-icon">
53
53
+
<span>
54
54
<i class="ph-fill ph-treasure-chest"></i>
55
55
</span>
56
56
</a>
+33
src/common/pages/ppr.js
reviewed
···
86
86
event.intercept({
87
87
scroll: "manual",
88
88
async handler() {
89
89
+
const navLinks = /** @type {HTMLAnchorElement[]} */ ([
90
90
+
...document.querySelectorAll("#diffuse-nav a, #nav-overflow-menu a"),
91
91
+
]);
92
92
+
const stripSlash = (/** @type {string} */ p) => p.replace(/^\//, "");
93
93
+
const navLink = navLinks.find(
94
94
+
(a) =>
95
95
+
stripSlash(new URL(a.href).pathname) === stripSlash(url.pathname),
96
96
+
);
97
97
+
98
98
+
const icon = navLink?.querySelector("i");
99
99
+
const originalIconClass = icon?.className;
100
100
+
let addedSpinner = /** @type {HTMLElement | undefined} */ (undefined);
101
101
+
102
102
+
const loadingTimer = navLink
103
103
+
? setTimeout(() => {
104
104
+
if (icon) {
105
105
+
icon.className = "ph-bold ph-spinner animate-spin";
106
106
+
} else {
107
107
+
addedSpinner = document.createElement("i");
108
108
+
addedSpinner.className = "ph-bold ph-spinner animate-spin";
109
109
+
const span = navLink.querySelector("span");
110
110
+
(span ?? navLink).prepend(addedSpinner);
111
111
+
}
112
112
+
}, 250)
113
113
+
: undefined;
114
114
+
89
115
let html;
90
116
91
117
try {
···
93
119
if (!response.ok) throw new Error(`${response.status}`);
94
120
html = await response.text();
95
121
} catch {
122
122
+
clearTimeout(loadingTimer);
123
123
+
if (icon && originalIconClass !== undefined) icon.className = originalIconClass;
124
124
+
addedSpinner?.remove();
96
125
location.href = url.href;
97
126
return;
127
127
+
} finally {
128
128
+
clearTimeout(loadingTimer);
129
129
+
if (icon && originalIconClass !== undefined) icon.className = originalIconClass;
130
130
+
addedSpinner?.remove();
98
131
}
99
132
100
133
const parser = new DOMParser();