@sprig-and-prose/sprig-ui-csr 0.1.1 → 0.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.
package/package.json
CHANGED
package/src/App.svelte
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
import { onMount, onDestroy } from 'svelte';
|
|
3
|
-
import { loadUniverseGraph } from './lib/data/universeStore.js';
|
|
3
|
+
import { loadUniverseGraph, autoSelectFirstUniverse, universeGraph } from './lib/data/universeStore.js';
|
|
4
4
|
import { getCurrentRoute, navigate } from './lib/router.js';
|
|
5
5
|
import { theme } from './lib/stores/theme.js';
|
|
6
6
|
import { describeRenderMode } from './lib/stores/describeRenderMode.js';
|
|
@@ -14,6 +14,12 @@
|
|
|
14
14
|
let error = null;
|
|
15
15
|
let currentRoute = getCurrentRoute();
|
|
16
16
|
|
|
17
|
+
// Reactively auto-select first universe when on home route and graph is loaded
|
|
18
|
+
// This runs whenever universeGraph or currentRoute changes
|
|
19
|
+
$: if ($universeGraph && currentRoute?.route === 'home') {
|
|
20
|
+
autoSelectFirstUniverse($universeGraph);
|
|
21
|
+
}
|
|
22
|
+
|
|
17
23
|
function toggleTheme() {
|
|
18
24
|
theme.update((t) => {
|
|
19
25
|
if (t === 'light') return 'dark';
|
|
@@ -35,6 +41,9 @@
|
|
|
35
41
|
loading = true;
|
|
36
42
|
error = null;
|
|
37
43
|
const { describeRenderMode: mode } = await loadUniverseGraph('/api/manifest');
|
|
44
|
+
|
|
45
|
+
// Auto-selection is handled reactively above
|
|
46
|
+
|
|
38
47
|
if (mode === 'lists' || mode === 'plain') {
|
|
39
48
|
describeRenderMode.set(mode);
|
|
40
49
|
}
|
|
@@ -48,6 +57,7 @@
|
|
|
48
57
|
|
|
49
58
|
function handleRouteChange() {
|
|
50
59
|
currentRoute = getCurrentRoute();
|
|
60
|
+
// Auto-selection will happen reactively when route changes
|
|
51
61
|
}
|
|
52
62
|
|
|
53
63
|
// Intercept link clicks for client-side navigation
|
|
@@ -56,6 +56,32 @@
|
|
|
56
56
|
return null;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
if (node.kind === 'concept') {
|
|
60
|
+
if (!node.parent) return null;
|
|
61
|
+
|
|
62
|
+
const ancestors = getAncestorChain(graph, node);
|
|
63
|
+
const parent = graph.nodes[node.parent];
|
|
64
|
+
|
|
65
|
+
if (!parent) return null;
|
|
66
|
+
|
|
67
|
+
// Check if concept is in a book or chapter
|
|
68
|
+
const book = ancestors.find(a => a.kind === 'book');
|
|
69
|
+
const series = ancestors.find(a => a.kind === 'series');
|
|
70
|
+
|
|
71
|
+
if (book && series) {
|
|
72
|
+
return `in ${getDisplayTitle(book)} (in ${getDisplayTitle(series)})`;
|
|
73
|
+
} else if (book) {
|
|
74
|
+
return `in ${getDisplayTitle(book)}`;
|
|
75
|
+
} else if (series) {
|
|
76
|
+
return `in ${getDisplayTitle(series)}`;
|
|
77
|
+
} else if (parent.kind === 'series') {
|
|
78
|
+
return `in ${getDisplayTitle(parent)}`;
|
|
79
|
+
} else if (parent.kind === 'anthology') {
|
|
80
|
+
return `in ${getDisplayTitle(parent)}`;
|
|
81
|
+
}
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
|
|
59
85
|
return null;
|
|
60
86
|
}
|
|
61
87
|
|
|
@@ -68,7 +94,7 @@
|
|
|
68
94
|
if (!graph || !graph.nodes) return [];
|
|
69
95
|
|
|
70
96
|
const items = [];
|
|
71
|
-
const searchableKinds = ['series', 'book', 'chapter'];
|
|
97
|
+
const searchableKinds = ['series', 'book', 'chapter', 'concept'];
|
|
72
98
|
|
|
73
99
|
for (const node of Object.values(graph.nodes)) {
|
|
74
100
|
if (!node || !searchableKinds.includes(node.kind)) continue;
|
|
@@ -259,7 +285,7 @@
|
|
|
259
285
|
<input
|
|
260
286
|
bind:this={searchInput}
|
|
261
287
|
type="text"
|
|
262
|
-
placeholder="Search Series, Books, Chapters… (Press / to focus)"
|
|
288
|
+
placeholder="Search Series, Books, Chapters, Concepts… (Press / to focus)"
|
|
263
289
|
bind:value={query}
|
|
264
290
|
class="search-input"
|
|
265
291
|
role="combobox"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { writable, derived } from 'svelte/store';
|
|
1
|
+
import { writable, derived, get } from 'svelte/store';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* @typedef {{ line:number, col:number, offset:number }} Pos
|
|
@@ -12,7 +12,7 @@ import { writable, derived } from 'svelte/store';
|
|
|
12
12
|
|
|
13
13
|
export const universeGraph = writable(/** @type {UniverseGraph|null} */ (null));
|
|
14
14
|
|
|
15
|
-
export const currentUniverseName = writable(
|
|
15
|
+
export const currentUniverseName = writable(/** @type {string|null} */ (null));
|
|
16
16
|
|
|
17
17
|
export const currentUniverse = derived(
|
|
18
18
|
[universeGraph, currentUniverseName],
|
|
@@ -223,6 +223,22 @@ export function getNodeRoute(node) {
|
|
|
223
223
|
return `/universes/${universe}/concept/${encodeURIComponent(node.id)}`;
|
|
224
224
|
}
|
|
225
225
|
|
|
226
|
+
/**
|
|
227
|
+
* Auto-select the first universe if current universe is null or doesn't exist
|
|
228
|
+
* @param {UniverseGraph} graph - The loaded universe graph
|
|
229
|
+
*/
|
|
230
|
+
export function autoSelectFirstUniverse(graph) {
|
|
231
|
+
if (!graph || !graph.universes) return;
|
|
232
|
+
|
|
233
|
+
const currentName = get(currentUniverseName);
|
|
234
|
+
const universeNames = Object.keys(graph.universes);
|
|
235
|
+
|
|
236
|
+
// If no universe is selected, or the selected one doesn't exist, select the first one
|
|
237
|
+
if (universeNames.length > 0 && (!currentName || !graph.universes[currentName])) {
|
|
238
|
+
currentUniverseName.set(universeNames[0]);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
226
242
|
/**
|
|
227
243
|
* Fetch UniverseGraph JSON from a static path.
|
|
228
244
|
* @param {string} url
|