diff --git a/web/src/hooks/use-param.ts b/web/src/hooks/use-param.ts new file mode 100644 index 0000000..8e9b3c6 --- /dev/null +++ b/web/src/hooks/use-param.ts @@ -0,0 +1,48 @@ +import { useCallback, useEffect, useState } from "react" + +/** Uses the URL search params to store a value in addition to React state. */ +export const useParam = ( + key: string, + convert: (input: string | T) => T, + defaultValue: T +): [T, (input: T) => void] => { + /** Get value from URL search param or use `defaultValue`. */ + const getParam = useCallback( + () => + convert( + new URLSearchParams(window.location.search).get(key) ?? + defaultValue + ), + [convert, defaultValue, key] + ) + + const [value, setValue] = useState(getParam) + + /** Set value in URL search param *and* React state. */ + const setParam = useCallback( + (input: T) => { + const url = new URL(window.location.href) + + url.searchParams.set(key, String(input)) + window.history.pushState(null, "", url) + + setValue(input) + }, + [key] + ) + + /** Update React state on browser navigation `popstate` events. */ + useEffect(() => { + const popParam = () => { + setValue(getParam()) + } + + window.addEventListener("popstate", popParam) + + return () => { + window.removeEventListener("popstate", popParam) + } + }, [getParam]) + + return [value, setParam] +} diff --git a/web/src/sections/LandingPage/index.stories.tsx b/web/src/sections/LandingPage/index.stories.tsx new file mode 100644 index 0000000..b1e602a --- /dev/null +++ b/web/src/sections/LandingPage/index.stories.tsx @@ -0,0 +1,23 @@ +import type { Meta, StoryObj } from "@storybook/react" + +import { LandingPage } from "./index" + +const meta = { + /** Only required props should be in the default export */ + args: {}, + component: LandingPage, + tags: ["autodocs"] + // title: "Sections/LandingPage" +} satisfies Meta + +type Story = StoryObj + +export default meta + +/** + The default look of the Component, only with simple required props. + We're hiding the panel to allow a full view of the Component. + */ +export const Default: Story = { + args: {} +}