@rmdes/indiekit-frontend 1.0.0-beta.39 → 1.0.0-beta.41

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.
@@ -1,6 +1,51 @@
1
1
  {% from "../logo/macro.njk" import logo with context %}
2
2
  {% set items = opts.navigation.items %}
3
3
  {% set renames = { "Reader": "Microsub" } %}
4
+
5
+ {#
6
+ Section categorization for multi-site plugin loadouts.
7
+ Each section defines URL patterns; items whose href contains ANY pattern
8
+ in a section's list bucket into that section. Sections with zero items
9
+ collapse (no empty header). Items not matching any known pattern fall
10
+ into "Other".
11
+
12
+ Keep `knownPaths` in sync with the union of all section patterns —
13
+ it's used by the "Other" catch-all to identify unmatched items.
14
+ #}
15
+ {% set knownPaths = [
16
+ "/posts", "/files",
17
+ "/microsub", "/webmention", "/webmention-sender", "/comments",
18
+ "/blogroll", "/podroll", "/rss",
19
+ "/homepage", "/cv", "/site-config",
20
+ "/github", "/lastfm", "/funkwhale", "/youtube",
21
+ "/activitypub",
22
+ "/linkedin"
23
+ ] %}
24
+
25
+ {# Reusable section macro: only renders when matched items exist (no empty headers). #}
26
+ {% macro sidebarSection(label, items, patterns, renames) %}
27
+ {% set sectionItems = [] %}
28
+ {% for item in items %}{% if item.href and item.text %}
29
+ {% set isMatch = false %}
30
+ {% for pattern in patterns %}{% if pattern in item.href %}{% set isMatch = true %}{% endif %}{% endfor %}
31
+ {% if isMatch %}{% set sectionItems = sectionItems.concat([item]) %}{% endif %}
32
+ {% endif %}{% endfor %}
33
+ {% if sectionItems | length > 0 %}
34
+ <div class="sidebar__group">
35
+ <span class="sidebar__group-label">{{ label }}</span>
36
+ <ul class="sidebar__list" role="list">
37
+ {% for item in sectionItems %}
38
+ <li class="sidebar__list-item">
39
+ <a href="{{ item.href }}"{{- attributes(item.attributes) }}>
40
+ {%- if renames and renames[item.text] %}{{ renames[item.text] }}{% else %}{{ item.text | safe }}{% endif -%}
41
+ </a>
42
+ </li>
43
+ {% endfor %}
44
+ </ul>
45
+ </div>
46
+ {% endif %}
47
+ {% endmacro %}
48
+
4
49
  <sidebar-nav class="{{ classes("sidebar", opts) }}" aria-label="Main">
5
50
  <div class="sidebar__header">
6
51
  <a class="sidebar__title u-url" href="{{ opts.url or "/" }}">
@@ -13,110 +58,19 @@
13
58
  </button>
14
59
  </div>
15
60
  <nav class="sidebar__nav">
16
- {# --- PUBLISH --- #}
17
- <div class="sidebar__group">
18
- <span class="sidebar__group-label">Publish</span>
19
- <ul class="sidebar__list" role="list">
20
- {% for item in items %}{% if item.href and item.text %}
21
- {% if "/posts" in item.href or "/files" in item.href %}
22
- <li class="sidebar__list-item">
23
- <a href="{{ item.href }}"{{- attributes(item.attributes) }}>
24
- {{- item.text | safe -}}
25
- </a>
26
- </li>
27
- {% endif %}
28
- {% endif %}{% endfor %}
29
- </ul>
30
- </div>
31
-
32
- {# --- READ & ENGAGE --- #}
33
- <div class="sidebar__group">
34
- <span class="sidebar__group-label">Read & Engage</span>
35
- <ul class="sidebar__list" role="list">
36
- {% for item in items %}{% if item.href and item.text %}
37
- {% if "/microsub" in item.href or "/webmention" in item.href %}
38
- <li class="sidebar__list-item">
39
- <a href="{{ item.href }}"{{- attributes(item.attributes) }}>
40
- {%- if renames[item.text] %}{{ renames[item.text] }}{% else %}{{ item.text | safe }}{% endif -%}
41
- </a>
42
- </li>
43
- {% endif %}
44
- {% endif %}{% endfor %}
45
- </ul>
46
- </div>
47
-
48
- {# --- CURATE --- #}
49
- <div class="sidebar__group">
50
- <span class="sidebar__group-label">Curate</span>
51
- <ul class="sidebar__list" role="list">
52
- {% for item in items %}{% if item.href and item.text %}
53
- {% if "/blogroll" in item.href or "/podroll" in item.href %}
54
- <li class="sidebar__list-item">
55
- <a href="{{ item.href }}"{{- attributes(item.attributes) }}>
56
- {{- item.text | safe -}}
57
- </a>
58
- </li>
59
- {% endif %}
60
- {% endif %}{% endfor %}
61
- </ul>
62
- </div>
63
-
64
- {# --- BUILD --- #}
65
- <div class="sidebar__group">
66
- <span class="sidebar__group-label">Build</span>
67
- <ul class="sidebar__list" role="list">
68
- {% for item in items %}{% if item.href and item.text %}
69
- {% if "/homepage" in item.href or "/cv" in item.href %}
70
- <li class="sidebar__list-item">
71
- <a href="{{ item.href }}"{{- attributes(item.attributes) }}>
72
- {{- item.text | safe -}}
73
- </a>
74
- </li>
75
- {% endif %}
76
- {% endif %}{% endfor %}
77
- </ul>
78
- </div>
79
-
80
- {# --- ACTIVITY --- #}
81
- <div class="sidebar__group">
82
- <span class="sidebar__group-label">Activity</span>
83
- <ul class="sidebar__list" role="list">
84
- {% for item in items %}{% if item.href and item.text %}
85
- {% if "/github" in item.href or "/lastfm" in item.href or "/funkwhale" in item.href or "/youtube" in item.href or "/rss" in item.href %}
86
- <li class="sidebar__list-item">
87
- <a href="{{ item.href }}"{{- attributes(item.attributes) }}>
88
- {{- item.text | safe -}}
89
- </a>
90
- </li>
91
- {% endif %}
92
- {% endif %}{% endfor %}
93
- </ul>
94
- </div>
95
-
96
- {# --- FEDIVERSE --- #}
97
- <div class="sidebar__group">
98
- <span class="sidebar__group-label">Fediverse</span>
99
- <ul class="sidebar__list" role="list">
100
- {% for item in items %}{% if item.href and item.text %}
101
- {% if "/activitypub" in item.href %}
102
- <li class="sidebar__list-item">
103
- <a href="{{ item.href }}"{{- attributes(item.attributes) }}>
104
- {{- item.text | safe -}}
105
- </a>
106
- </li>
107
- {% endif %}
108
- {% endif %}{% endfor %}
109
- </ul>
110
- </div>
61
+ {{ sidebarSection("Publish", items, ["/posts", "/files"]) }}
62
+ {{ sidebarSection("Read & Engage", items, ["/microsub", "/webmention", "/webmention-sender", "/comments"], renames) }}
63
+ {{ sidebarSection("Curate", items, ["/blogroll", "/podroll", "/rss"]) }}
64
+ {{ sidebarSection("Build", items, ["/homepage", "/cv", "/site-config"]) }}
65
+ {{ sidebarSection("Activity", items, ["/github", "/lastfm", "/funkwhale", "/youtube"]) }}
66
+ {{ sidebarSection("Fediverse", items, ["/activitypub"]) }}
67
+ {{ sidebarSection("Syndication", items, ["/linkedin"]) }}
111
68
 
112
- {# --- UNCATEGORIZED (catch-all for future plugins) --- #}
113
- {% set knownPaths = ["/posts", "/files", "/microsub", "/webmention", "/blogroll", "/podroll", "/homepage", "/cv", "/github", "/lastfm", "/funkwhale", "/youtube", "/rss", "/activitypub"] %}
69
+ {# OTHER: catch-all for items not matching any known pattern (future plugins). #}
114
70
  {% set hasOther = [] %}
115
71
  {% for item in items %}{% if item.href and item.text %}
116
72
  {% set matched = false %}
117
- {% for kp in knownPaths %}
118
- {% if kp in item.href %}{% set matched = true %}{% endif %}
119
- {% endfor %}
73
+ {% for kp in knownPaths %}{% if kp in item.href %}{% set matched = true %}{% endif %}{% endfor %}
120
74
  {% if not matched %}{% set hasOther = hasOther.concat([item]) %}{% endif %}
121
75
  {% endif %}{% endfor %}
122
76
  {% if hasOther | length > 0 %}
@@ -134,7 +88,7 @@
134
88
  </div>
135
89
  {% endif %}
136
90
 
137
- {# --- SYSTEM (hardcoded core pages) --- #}
91
+ {# SYSTEM: hardcoded core pages, always present (Indiekit installs them unconditionally). #}
138
92
  <div class="sidebar__group">
139
93
  <span class="sidebar__group-label">System</span>
140
94
  <ul class="sidebar__list" role="list">
@@ -87,6 +87,31 @@ async function notifyClients() {
87
87
  }
88
88
  }
89
89
 
90
+ /**
91
+ * Remove any cached auth/session pages from the pages cache.
92
+ * Called on activate to purge stale entries from before the fetch bypass was added.
93
+ */
94
+ async function clearAuthSessionEntries() {
95
+ try {
96
+ const pagesCache = await caches.open(pagesCacheName);
97
+ const keys = await pagesCache.keys();
98
+
99
+ await Promise.all(
100
+ keys
101
+ .filter((request) => {
102
+ const url = new URL(request.url);
103
+ return (
104
+ url.origin === self.location.origin &&
105
+ /^\/(auth|session)(?:\/|$)/.test(url.pathname)
106
+ );
107
+ })
108
+ .map((request) => pagesCache.delete(request)),
109
+ );
110
+ } catch (error) {
111
+ console.error("Error clearing auth/session cache entries", error);
112
+ }
113
+ }
114
+
90
115
  /**
91
116
  * Trim cache
92
117
  * @param {string} cacheName - Name of cache
@@ -120,6 +145,7 @@ self.addEventListener("activate", async (event) => {
120
145
  event.waitUntil(
121
146
  (async () => {
122
147
  await clearOldCaches();
148
+ await clearAuthSessionEntries();
123
149
  // Don't clear pages cache on activate — stale cached pages provide a
124
150
  // valuable fallback when the network is slow (e.g. right after a deploy).
125
151
  // The network-first fetch strategy naturally updates cached pages on
@@ -150,13 +176,23 @@ self.addEventListener("fetch", (event) => {
150
176
  // Cross-origin images (avatars, album covers, etc.) must be handled
151
177
  // by the browser natively — opaque responses from SW fetch are unreliable
152
178
  // and caching them wastes ~7MB each against storage quota.
179
+ const requestUrl = new URL(request.url);
153
180
  if (
154
- new URL(request.url).origin !== self.location.origin ||
181
+ requestUrl.origin !== self.location.origin ||
155
182
  request.method !== "GET"
156
183
  ) {
157
184
  return;
158
185
  }
159
186
 
187
+ // Never cache auth/session pages — always go to network.
188
+ // Stale cached auth responses break login detection (admin.js probes
189
+ // /session/login to check if owner is logged in) and can serve
190
+ // authenticated pages after session expiry.
191
+ if (/^\/(auth|session)(?:\/|$)/.test(requestUrl.pathname)) {
192
+ event.respondWith(fetch(request));
193
+ return;
194
+ }
195
+
160
196
  // For HTML requests: network-first with conditional timeout
161
197
  // - If a cached version exists: race network against timeout, serve cache on timeout
162
198
  // - If no cached version: wait for network without timeout (avoid premature "Offline")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rmdes/indiekit-frontend",
3
- "version": "1.0.0-beta.39",
3
+ "version": "1.0.0-beta.41",
4
4
  "description": "Frontend components for Indiekit (fork with floating toolbar)",
5
5
  "keywords": [
6
6
  "express",