Skip to content

Commit

Permalink
refactor: render the app an SPA and discard dynamic routing approaches (
Browse files Browse the repository at this point in the history
#145)

* Discard slugs

* Remove `ebd-form-header` component

* Add SVG integration to `ebd page`

* Add forms to `header` component

* Disable prerendering of dynamic routes

* Disable export button as long as no ebd is selected

* Move `role-select` into header

* Use URL query parameter

* Handle URL parameters and state management on client side

* Update docstrings
  • Loading branch information
OLILHR authored Dec 11, 2024
1 parent f0919e2 commit 25f2d8d
Show file tree
Hide file tree
Showing 14 changed files with 265 additions and 364 deletions.
3 changes: 2 additions & 1 deletion eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export default [
clearTimeout: "readonly",
Blob: "readonly",
URL: "readonly",
URLSearchParams: "readonly",
HTMLDivElement: "readonly",
CustomEvent: "readonly",
// DOM types
Expand All @@ -55,7 +56,7 @@ export default [
"import/first": "error",
"import/newline-after-import": "error",
"import/no-duplicates": "error",
"svelte/no-at-html-tags": "warn",
"svelte/no-at-html-tags": "off",
"no-undef": "error",
"@typescript-eslint/no-unused-expressions": [
"error",
Expand Down
95 changes: 0 additions & 95 deletions src/lib/components/features/ebd-form-header.svelte

This file was deleted.

16 changes: 10 additions & 6 deletions src/lib/components/features/ebd-navigation.svelte
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
<script lang="ts">
import { goto } from "$app/navigation";
import { base } from "$app/paths";
import type { EbdNameExtended } from "$lib/types/metadata";
import IconArrow from "../shared/icon-arrow.svelte";
export let currentEbds: EbdNameExtended[] = [];
export let currentFormatVersion: string = "";
export let selectedEbdCode: string = "";
export let onSelect: (ebdCode: string) => void;
export let isDisabled: boolean = false;
$: currentIndex = currentEbds.findIndex(
(ebd) => ebd.ebd_code === selectedEbdCode,
Expand All @@ -17,6 +17,8 @@
$: isLastEbd = currentIndex === currentEbds.length - 1;
function handleNavigation(event: MouseEvent): void {
if (isDisabled) return;
const target = event.target as HTMLElement;
const ebdListIndex = target.closest("svg")?.id;
Expand Down Expand Up @@ -44,23 +46,25 @@
return;
}
const newEbd = currentEbds[newIndex].ebd_code;
goto(`${base}/ebd/${currentFormatVersion}/${newEbd}`);
const newEbd = currentEbds[newIndex];
onSelect(newEbd.ebd_code);
}
</script>

<div class="flex flex-col gap-1">
<button
on:click={handleNavigation}
class="cursor-pointer"
class:opacity-35={isLastEbd}
class:opacity-35={isLastEbd || isDisabled}
disabled={isDisabled}
>
<IconArrow id="nextEbd" />
</button>
<button
on:click={handleNavigation}
class="cursor-pointer"
class:opacity-35={isFirstEbd}
class:opacity-35={isFirstEbd || isDisabled}
disabled={isDisabled}
>
<IconArrow orientation="rotate-180" id="previousEbd" />
</button>
Expand Down
8 changes: 6 additions & 2 deletions src/lib/components/features/export-button.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
export let currentFormatVersion: string = "";
export let currentEbd: string = "";
export let isDisabled: boolean = false;
let isExportReady = true;
let cooldownTimer: ReturnType<typeof setTimeout>;
Expand All @@ -17,7 +18,8 @@
});
async function handleExport() {
if (!isExportReady || !currentFormatVersion || !currentEbd) return;
if (isDisabled || !isExportReady || !currentFormatVersion || !currentEbd)
return;
isExportReady = false;
const ebdPath = `${base}/ebd/${currentFormatVersion}/${currentEbd}.svg`;
Expand Down Expand Up @@ -50,7 +52,9 @@

<button
on:click={handleExport}
class="flex flex-row items-center gap-2 rounded-full bg-tint text-[16px] py-3 px-5 text-secondary"
class="flex flex-row items-center gap-2 rounded-full bg-tint text-[16px] py-3 px-5 text-secondary transition-opacity duration-200"
class:opacity-30={isDisabled}
disabled={isDisabled}
>
<IconDownload /> Export SVG
</button>
27 changes: 23 additions & 4 deletions src/lib/components/features/filter-role-select.svelte
Original file line number Diff line number Diff line change
@@ -1,21 +1,40 @@
<script lang="ts">
import { onMount } from "svelte";
export let isDisabled: boolean = false; // controls whether the role filter is disabled (depending on state of <FormatVersionSelect />)
export let formatVersion: string = ""; // currently selected format version that determines available roles
export let roles: Record<string, string[]> = {}; // maps format versions to their available roles for EBD filtering
export let initialRoles: string[] = []; // initialize the roles in both the page and the component
export let onSelect: (selectedRoles: string[]) => void;
let selectedRoles: Set<string> = new Set();
let selectedRoles: Set<string> = new Set(initialRoles);
let selectElement: HTMLSelectElement;
let isSelectFocused = false;
let isInitialized = false;
$: availableRoles = formatVersion ? roles[formatVersion] || [] : [];
// initialize selectedRoles when initialRoles changes
$: if (!isInitialized && initialRoles.length > 0) {
selectedRoles = new Set(initialRoles);
isInitialized = true;
}
// reset role filter select upon changing format version
$: if (formatVersion) {
selectedRoles = new Set();
onSelect([]);
$: if (formatVersion && isInitialized) {
if (!selectedRoles.size) {
selectedRoles = new Set(initialRoles);
}
}
onMount(() => {
if (initialRoles.length > 0) {
selectedRoles = new Set(initialRoles);
onSelect([...selectedRoles]);
}
isInitialized = true;
});
function handleSelect(event: Event) {
const select = event.target as HTMLSelectElement;
const role = select.value;
Expand Down
1 change: 0 additions & 1 deletion src/lib/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ export { default as LandingpageBanner } from "$lib/components/shared/landingpage
export { default as LandingpageButton } from "$lib/components/shared/landingpage-button.svelte";

// features
export { default as EbdFormHeader } from "$lib/components/features/ebd-form-header.svelte";
export { default as EbdInput } from "$lib/components/features/ebd-input.svelte";
export { default as EbdNavigation } from "$lib/components/features/ebd-navigation.svelte";
export { default as ExportButton } from "$lib/components/features/export-button.svelte";
Expand Down
78 changes: 69 additions & 9 deletions src/lib/components/shared/header.svelte
Original file line number Diff line number Diff line change
@@ -1,15 +1,75 @@
<script>
<script lang="ts">
import { base } from "$app/paths";
import { IconLogo } from "$lib/components";
import {
EbdInput,
EbdNavigation,
FilterRoleSelect,
FormatVersionSelect,
IconLogo,
} from "$lib/components";
import type { EbdNameExtended } from "$lib/types/metadata";
export let formatVersions: Array<{
code: string;
detailedFormatVersion: string;
}> = [];
export let selectedFormatVersion: string = "";
export let onFormatVersionSelect: (version: string) => void;
export let ebdList: EbdNameExtended[] = [];
export let selectedEbd: string = "";
export let onEbdSelect: (ebdCode: string) => void;
export let roles: Record<string, string[]> = {};
export let selectedRoles: string[] = [];
export let onRoleSelect: (roles: string[]) => void;
</script>

<header class="bg-primary">
<nav class="mx-auto flex items-center px-6 py-4" aria-label="Global">
<a href="{base}/" title="landingpage" class="flex-none items-center">
<IconLogo />
</a>
<span class="text-xl text-white flex items-center me-14"
>EBD.HOCHFREQUENZ.DE</span
<div class="mx-auto">
<nav
class="flex items-center justify-between px-6 py-4 border-b border-white/10"
aria-label="Global"
>
</nav>
<div class="flex items-center w-4/5">
<a href="{base}/" title="landingpage" class="flex-none items-center">
<IconLogo />
</a>
<span class="text-xl text-white">EBD.HOCHFREQUENZ.DE</span>
<div class="-mt-2 pl-10 w-1/5">
<FormatVersionSelect
{formatVersions}
selectedVersion={selectedFormatVersion}
onSelect={onFormatVersionSelect}
/>
</div>
<div class="-mt-2 pl-5 w-1/5">
<FilterRoleSelect
isDisabled={!selectedFormatVersion}
formatVersion={selectedFormatVersion}
{roles}
onSelect={onRoleSelect}
initialRoles={selectedRoles}
/>
</div>
<div class="-mt-2 pl-5 w-1/3 mr-1">
<EbdInput
ebds={ebdList}
disabled={!selectedFormatVersion}
selectedEbdCode={selectedEbd}
formatVersionChanged={false}
onSelect={onEbdSelect}
/>
</div>
<EbdNavigation
currentEbds={ebdList}
selectedEbdCode={selectedEbd}
currentFormatVersion={selectedFormatVersion}
onSelect={onEbdSelect}
isDisabled={!selectedFormatVersion || !selectedEbd}
/>
</div>
<div class="ml-auto">
<slot name="actions" />
</div>
</nav>
</div>
</header>
4 changes: 2 additions & 2 deletions src/routes/+layout.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export const prerender = true; // requires all possible entries of [dynamic routes] to be known at build time (see src/server/prerender-entries.ts)
export const prerender = true;
export const trailingSlash = "always";

export const ssr = true;
export const ssr = false;
export const csr = true;
10 changes: 7 additions & 3 deletions src/routes/ebd/+page.server.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import { getEbdMetadata, getEbdNames, getRoles } from "$server/ebd-loader";
import { getFormatVersions } from "$server/format-version-loader";

import type { PageServerLoad } from "./$types";

export const load: PageServerLoad = async () => {
export const load = async () => {
const ebds = getEbdNames();
const formatVersions = getFormatVersions();
const metadata = getEbdMetadata();
Expand All @@ -14,5 +12,11 @@ export const load: PageServerLoad = async () => {
formatVersions,
metadata,
roles,
initialState: {
formatVersion: "",
ebd: "",
roles: [],
ebdList: [],
},
};
};
Loading

0 comments on commit 25f2d8d

Please sign in to comment.