Skip to content

Commit

Permalink
Preserve profile in the URL. #11
Browse files Browse the repository at this point in the history
  • Loading branch information
dabreegster committed Aug 18, 2024
1 parent 9fa6639 commit 09ae5bc
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 1 deletion.
8 changes: 7 additions & 1 deletion web/src/stores.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { MapModel } from "backend";
import type { FeatureCollection } from "geojson";
import type { Map } from "maplibre-gl";
import { get, writable, type Writable } from "svelte/store";
import { urlState, enumUrl } from "./url";

export let maptilerApiKey = "MZEJTanw3WpxRvt7qDfo";

Expand All @@ -21,7 +22,12 @@ export let mode: Writable<Mode> = writable({ kind: "title" });
export let model: Writable<MapModel | null> = writable(null);
export let map: Writable<Map | null> = writable(null);
export let showAbout: Writable<boolean> = writable(true);
export let profile = writable("USA");
export let profile = urlState({
name: "profile",
defaultValue: "USA",
stringify: (x) => x,
parse: enumUrl(["USA", "SidewalksOnHighways", "SeparateWays"]),
});

export let minScore = writable(0);
export let maxScore = writable(100);
Expand Down
49 changes: 49 additions & 0 deletions web/src/url.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { writable, type Writable } from "svelte/store";

// TODO Move to svelte-utils

// Create a store to represent some state about a layer, syncing it to a URL
// query parameter. The parameter missing is equivalent to stringify returning
// null.
export function urlState<T>(params: {
name: string;
defaultValue: T;
stringify: (state: T) => string | null;
parse: (param: string) => T;
}): Writable<T> {
let initialValue = params.defaultValue;
let param = new URLSearchParams(window.location.search).get(params.name);
if (param != null) {
try {
initialValue = params.parse(param);
} catch (err) {
console.warn(
`Parsing URL parameter ${params.name}=${param} failed, using default value: ${err}`,
);
}
}

let store = writable(initialValue);
// TODO How do we avoid leaking this?
store.subscribe((state) => {
let url = new URL(window.location.href);
let value = params.stringify(state);
if (value == null) {
url.searchParams.delete(params.name);
} else {
url.searchParams.set(params.name, value);
}
window.history.replaceState(null, "", url.toString());
});
return store;
}

// Generates a `parse` function that insists the input belongs to the set of values
export function enumUrl(values: string[]): (param: string) => string {
return (param) => {
if (values.includes(param)) {
return param;
}
throw new Error(`${param} isn't in ${values}`);
};
}

0 comments on commit 09ae5bc

Please sign in to comment.