- {#if isSearching}
-
-
- {copy.searching}
-
- {:else if showInitialHint || showHint}
-
- {copy.hint}
-
- {:else if showEmpty}
-
-
-
-
- {copy.noResults}
-
- {:else}
- {#each groups as group, groupIndex (group.type)}
- {@const Icon = groupIcons[group.type]}
- {#if groupIndex > 0}
-
- {/if}
-
-
- {copy.groups[group.type]}
-
-
- {#each group.items as item (item.id)}
- -
-
-
- {/each}
-
-
- {/each}
- {/if}
+
+
+
+ {#each groups as group, groupIndex (group.type)}
+ {@const Icon = groupIcons[group.type]}
+ {#if groupIndex > 0}
+
+ {/if}
+
+
+ {copy.groups[group.type]}
+
+
+ {#each group.items as item (item.id)}
+ {@const itemIndex = flatItems.findIndex(
+ (candidate) => candidate.id === item.id,
+ )}
+ {@const isActive = activeItemId === item.id}
+ -
+
+
+ {/each}
+
+
+ {/each}
+
+{/if}
diff --git a/src/lib/metrics/analytics-engine.ts b/src/lib/metrics/analytics-engine.ts
index e3771b396..9e71aa5a8 100644
--- a/src/lib/metrics/analytics-engine.ts
+++ b/src/lib/metrics/analytics-engine.ts
@@ -73,6 +73,7 @@ export type PublicRuntimeCacheAnalyticsNamespace =
| "sitemap"
| `page:section-detail:overview:${AppLocale}`
| `search:catalog:${AppLocale}`
+ | `search:catalog:v2:${AppLocale}`
| `bus:timetable:${AppLocale}`
| `${
| "api:courses"
diff --git a/src/routes/search/+page.server.ts b/src/routes/search/+page.server.ts
new file mode 100644
index 000000000..77a613927
--- /dev/null
+++ b/src/routes/search/+page.server.ts
@@ -0,0 +1,8 @@
+import type { PageServerLoad } from "./$types";
+
+export const load: PageServerLoad = async (event) => {
+ const layoutData = await event.parent();
+ return {
+ copy: layoutData.copy.globalSearch,
+ };
+};
diff --git a/src/routes/search/+page.svelte b/src/routes/search/+page.svelte
new file mode 100644
index 000000000..9c5c4fa55
--- /dev/null
+++ b/src/routes/search/+page.svelte
@@ -0,0 +1,245 @@
+
+
+