Skip to content

Commit 4a4118e

Browse files
committed
Add redirect routes and version selector to overview pages
- Create /[package]/api redirect to /[package]/[version]/api - Create /[package]/examples redirect to /[package]/[version]/examples - Add layout load functions for pathsim/chem/vehicle to load manifest - Show version selector in sidebar on overview pages - Update sidebar selectVersion to handle overview page (invalidateAll)
1 parent a307cb8 commit 4a4118e

9 files changed

Lines changed: 199 additions & 19 deletions

File tree

src/lib/components/layout/Sidebar.svelte

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@
5252
);
5353
let isVersionedPage = $derived(isApiPage || $page.url.pathname.includes('/examples'));
5454
55+
// Check if we're on an overview page (no /api or /examples in path)
56+
let isOverviewPage = $derived(!isApiPage && !$page.url.pathname.includes('/examples'));
57+
5558
function isActive(path: string): boolean {
5659
return $page.url.pathname === `${base}/${path}`;
5760
}
@@ -100,30 +103,33 @@
100103
versionDropdownOpen = !versionDropdownOpen;
101104
}
102105
103-
function selectVersion(tag: string) {
106+
async function selectVersion(tag: string) {
104107
versionDropdownOpen = false;
105108
106-
if (!currentTag) return;
109+
// Update stored version preference
110+
const { versionStore } = await import('$lib/stores/versionStore');
111+
versionStore.setVersion(packageId, tag);
107112
108113
// Preserve current hash if it exists
109114
const hash = typeof window !== 'undefined' ? window.location.hash : '';
110115
111-
// Get current page type (api or examples)
116+
// Get current page type (api or examples or overview)
112117
const pathname = $page.url.pathname;
113-
let pageType = 'api';
114-
let subPath = '';
115118
116119
if (pathname.includes('/examples/')) {
117120
// We're on a specific example page
118-
pageType = 'examples';
119121
const match = pathname.match(/\/examples\/(.+)$/);
120-
subPath = match ? `/${match[1]}` : '';
122+
const subPath = match ? `/${match[1]}` : '';
123+
goto(`${base}/${packageId}/${tag}/examples${subPath}${hash}`);
121124
} else if (pathname.includes('/examples')) {
122-
pageType = 'examples';
125+
goto(`${base}/${packageId}/${tag}/examples${hash}`);
126+
} else if (pathname.includes('/api')) {
127+
goto(`${base}/${packageId}/${tag}/api${hash}`);
128+
} else {
129+
// On overview page - reload to pick up new version
130+
const { invalidateAll } = await import('$app/navigation');
131+
await invalidateAll();
123132
}
124-
125-
// Navigate to the same page with new version
126-
goto(`${base}/${packageId}/${tag}/${pageType}${subPath}${hash}`);
127133
}
128134
129135
function handleVersionClickOutside(event: MouseEvent) {
@@ -188,8 +194,8 @@
188194
{/if}
189195
</nav>
190196
{:else}
191-
<!-- Version selector - only show on versioned pages -->
192-
{#if isVersionedPage && manifest && currentTag}
197+
<!-- Version selector - show whenever manifest is available -->
198+
{#if manifest && currentTag}
193199
<div class="version-selector-container" bind:this={versionDropdownRef}>
194200
<button
195201
class="version-selector-trigger"

src/routes/[package]/api/+page.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { redirect } from '@sveltejs/kit';
2+
import type { PageLoad } from './$types';
3+
import { packages, type PackageId } from '$lib/config/packages';
4+
import { getPackageManifest } from '$lib/api/versions';
5+
import { versionStore } from '$lib/stores/versionStore';
6+
7+
const validPackageIds = new Set<string>(Object.keys(packages));
8+
9+
/**
10+
* Redirect /[package]/api to /[package]/[version]/api
11+
* Uses stored version or latest if none stored.
12+
*/
13+
export const load: PageLoad = async ({ params, fetch }) => {
14+
const { package: packageId } = params;
15+
16+
if (!validPackageIds.has(packageId)) {
17+
throw redirect(307, '/');
18+
}
19+
20+
try {
21+
const manifest = await getPackageManifest(packageId, fetch);
22+
23+
// Check for stored version preference
24+
const storedVersion = versionStore.getVersionSync(packageId as PackageId);
25+
const targetTag = storedVersion || manifest.latestTag;
26+
27+
throw redirect(307, `/${packageId}/${targetTag}/api`);
28+
} catch (e) {
29+
// If redirect was thrown, re-throw it
30+
if (e && typeof e === 'object' && 'status' in e) {
31+
throw e;
32+
}
33+
// Fallback to package overview if manifest fails
34+
throw redirect(307, `/${packageId}`);
35+
}
36+
};
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { redirect } from '@sveltejs/kit';
2+
import type { PageLoad } from './$types';
3+
import { packages, type PackageId } from '$lib/config/packages';
4+
import { getPackageManifest } from '$lib/api/versions';
5+
import { versionStore } from '$lib/stores/versionStore';
6+
7+
const validPackageIds = new Set<string>(Object.keys(packages));
8+
9+
/**
10+
* Redirect /[package]/examples to /[package]/[version]/examples
11+
* Uses stored version or latest if none stored.
12+
*/
13+
export const load: PageLoad = async ({ params, fetch }) => {
14+
const { package: packageId } = params;
15+
16+
if (!validPackageIds.has(packageId)) {
17+
throw redirect(307, '/');
18+
}
19+
20+
try {
21+
const manifest = await getPackageManifest(packageId, fetch);
22+
23+
// Check for stored version preference
24+
const storedVersion = versionStore.getVersionSync(packageId as PackageId);
25+
const targetTag = storedVersion || manifest.latestTag;
26+
27+
throw redirect(307, `/${packageId}/${targetTag}/examples`);
28+
} catch (e) {
29+
// If redirect was thrown, re-throw it
30+
if (e && typeof e === 'object' && 'status' in e) {
31+
throw e;
32+
}
33+
// Fallback to package overview if manifest fails
34+
throw redirect(307, `/${packageId}`);
35+
}
36+
};

src/routes/chem/+layout.svelte

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
<script lang="ts">
22
import { DocLayout } from '$lib/components/layout';
33
import type { Snippet } from 'svelte';
4+
import type { LayoutData } from './$types';
45
56
interface Props {
7+
data: LayoutData;
68
children: Snippet;
79
}
810
9-
let { children }: Props = $props();
11+
let { data, children }: Props = $props();
1012
</script>
1113

12-
<DocLayout packageId="chem">
14+
<DocLayout packageId="chem" manifest={data.manifest} currentTag={data.selectedTag}>
1315
{@render children()}
1416
</DocLayout>

src/routes/chem/+layout.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import type { LayoutLoad } from './$types';
2+
import { getPackageManifest } from '$lib/api/versions';
3+
import { versionStore } from '$lib/stores/versionStore';
4+
5+
const PACKAGE_ID = 'chem';
6+
7+
/**
8+
* Load manifest for the chem package overview.
9+
* This allows the version selector to appear in the sidebar.
10+
*/
11+
export const load: LayoutLoad = async ({ fetch }) => {
12+
try {
13+
const manifest = await getPackageManifest(PACKAGE_ID, fetch);
14+
15+
// Get stored version or use latest
16+
const storedVersion = versionStore.getVersionSync(PACKAGE_ID);
17+
const selectedTag = storedVersion || manifest.latestTag;
18+
19+
return {
20+
packageId: PACKAGE_ID,
21+
manifest,
22+
selectedTag
23+
};
24+
} catch (e) {
25+
// Manifest not available, continue without version selector
26+
return {
27+
packageId: PACKAGE_ID,
28+
manifest: null,
29+
selectedTag: null
30+
};
31+
}
32+
};

src/routes/pathsim/+layout.svelte

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
<script lang="ts">
22
import { DocLayout } from '$lib/components/layout';
33
import type { Snippet } from 'svelte';
4+
import type { LayoutData } from './$types';
45
56
interface Props {
7+
data: LayoutData;
68
children: Snippet;
79
}
810
9-
let { children }: Props = $props();
11+
let { data, children }: Props = $props();
1012
</script>
1113

12-
<DocLayout packageId="pathsim">
14+
<DocLayout packageId="pathsim" manifest={data.manifest} currentTag={data.selectedTag}>
1315
{@render children()}
1416
</DocLayout>

src/routes/pathsim/+layout.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import type { LayoutLoad } from './$types';
2+
import { getPackageManifest } from '$lib/api/versions';
3+
import { versionStore } from '$lib/stores/versionStore';
4+
5+
const PACKAGE_ID = 'pathsim';
6+
7+
/**
8+
* Load manifest for the pathsim package overview.
9+
* This allows the version selector to appear in the sidebar.
10+
*/
11+
export const load: LayoutLoad = async ({ fetch }) => {
12+
try {
13+
const manifest = await getPackageManifest(PACKAGE_ID, fetch);
14+
15+
// Get stored version or use latest
16+
const storedVersion = versionStore.getVersionSync(PACKAGE_ID);
17+
const selectedTag = storedVersion || manifest.latestTag;
18+
19+
return {
20+
packageId: PACKAGE_ID,
21+
manifest,
22+
selectedTag
23+
};
24+
} catch (e) {
25+
// Manifest not available, continue without version selector
26+
return {
27+
packageId: PACKAGE_ID,
28+
manifest: null,
29+
selectedTag: null
30+
};
31+
}
32+
};

src/routes/vehicle/+layout.svelte

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
<script lang="ts">
22
import { DocLayout } from '$lib/components/layout';
33
import type { Snippet } from 'svelte';
4+
import type { LayoutData } from './$types';
45
56
interface Props {
7+
data: LayoutData;
68
children: Snippet;
79
}
810
9-
let { children }: Props = $props();
11+
let { data, children }: Props = $props();
1012
</script>
1113

12-
<DocLayout packageId="vehicle">
14+
<DocLayout packageId="vehicle" manifest={data.manifest} currentTag={data.selectedTag}>
1315
{@render children()}
1416
</DocLayout>

src/routes/vehicle/+layout.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import type { LayoutLoad } from './$types';
2+
import { getPackageManifest } from '$lib/api/versions';
3+
import { versionStore } from '$lib/stores/versionStore';
4+
5+
const PACKAGE_ID = 'vehicle';
6+
7+
/**
8+
* Load manifest for the vehicle package overview.
9+
* This allows the version selector to appear in the sidebar.
10+
*/
11+
export const load: LayoutLoad = async ({ fetch }) => {
12+
try {
13+
const manifest = await getPackageManifest(PACKAGE_ID, fetch);
14+
15+
// Get stored version or use latest
16+
const storedVersion = versionStore.getVersionSync(PACKAGE_ID);
17+
const selectedTag = storedVersion || manifest.latestTag;
18+
19+
return {
20+
packageId: PACKAGE_ID,
21+
manifest,
22+
selectedTag
23+
};
24+
} catch (e) {
25+
// Manifest not available, continue without version selector
26+
return {
27+
packageId: PACKAGE_ID,
28+
manifest: null,
29+
selectedTag: null
30+
};
31+
}
32+
};

0 commit comments

Comments
 (0)