@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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sprig-and-prose/sprig-ui-csr",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "sprig-ui-csr": "./src/cli.js"
@@ -26,4 +26,3 @@
26
26
  "vite": "^6.0.0"
27
27
  }
28
28
  }
29
-
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('Amaranthine');
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