diff --git a/src/components/FieldCatalog.tsx b/src/components/FieldCatalog.tsx index 983ca174b4dd626..c9ea7fc9dd56ffb 100644 --- a/src/components/FieldCatalog.tsx +++ b/src/components/FieldCatalog.tsx @@ -2,20 +2,19 @@ import { useEffect, useState, type ChangeEvent } from "react"; import FieldBadges from "./fields/FieldBadges"; import Markdown from "react-markdown"; import type { CollectionEntry } from "astro:content"; +import { setSearchParams } from "~/util/url"; type Fields = CollectionEntry<"fields">["data"]["entries"]; type Filters = { search: string; categories: string[]; - keywords: string[]; }; const FieldCatalog = ({ fields }: { fields: Fields }) => { const [filters, setFilters] = useState({ search: "", categories: [], - keywords: [], }); const mapped = fields.sort((f1, f2) => { @@ -58,7 +57,6 @@ const FieldCatalog = ({ fields }: { fields: Fields }) => { }); useEffect(() => { - // On component load, check for deep-links to categories in the query param const params = new URLSearchParams(window.location.search); const categories = params.getAll("field-category"); const searchTerm = params.get("search-term") ?? ""; @@ -72,6 +70,22 @@ const FieldCatalog = ({ fields }: { fields: Fields }) => { }); }, []); + useEffect(() => { + const params = new URLSearchParams(); + + if (filters.search) { + params.set("search-term", filters.search); + } + + if (filters.categories.length > 0) { + filters.categories.forEach((category) => + params.append("field-category", category), + ); + } + + setSearchParams(params); + }, [filters]); + return (
diff --git a/src/components/LearningPathCatalog.tsx b/src/components/LearningPathCatalog.tsx index a96aead5e702ba1..cbb6482837c5c3c 100644 --- a/src/components/LearningPathCatalog.tsx +++ b/src/components/LearningPathCatalog.tsx @@ -1,7 +1,8 @@ -import { useState, type ChangeEvent } from "react"; +import { useEffect, useState, type ChangeEvent } from "react"; import Markdown from "react-markdown"; import type { CollectionEntry } from "astro:content"; import type { IconifyIconBuildResult } from "@iconify/utils"; +import { setSearchParams } from "~/util/url"; type LearningPaths = CollectionEntry<"learning-paths">["data"][]; type Icons = Record; @@ -23,6 +24,34 @@ const LearningPathCatalog = ({ groups: [], }); + useEffect(() => { + const params = new URLSearchParams(window.location.search); + const products = params.getAll("products"); + const groups = params.getAll("groups"); + + if (!products && !groups) return; + + setFilters({ + ...filters, + products, + groups, + }); + }, []); + + useEffect(() => { + const params = new URLSearchParams(); + + if (filters.products.length > 0) { + filters.products.forEach((product) => params.append("products", product)); + } + + if (filters.groups.length > 0) { + filters.groups.forEach((group) => params.append("groups", group)); + } + + setSearchParams(params); + }, [filters]); + const sorted = paths.sort((lp1, lp2) => { return lp1.priority < lp2.priority ? -1 : 1; }); diff --git a/src/components/ModelCatalog.tsx b/src/components/ModelCatalog.tsx index 285c989be6c9d0f..f5a068ab79955fe 100644 --- a/src/components/ModelCatalog.tsx +++ b/src/components/ModelCatalog.tsx @@ -3,6 +3,7 @@ import ModelInfo from "./models/ModelInfo"; import ModelBadges from "./models/ModelBadges"; import { authorData } from "./models/data"; import type { WorkersAIModelsSchema } from "~/schemas"; +import { setSearchParams } from "~/util/url"; type Filters = { search: string; @@ -67,6 +68,30 @@ const ModelCatalog = ({ models }: { models: WorkersAIModelsSchema[] }) => { }); }, []); + useEffect(() => { + const params = new URLSearchParams(); + + if (filters.search) { + params.set("search", filters.search); + } + + if (filters.authors.length > 0) { + filters.authors.forEach((author) => params.append("authors", author)); + } + + if (filters.tasks.length > 0) { + filters.tasks.forEach((task) => params.append("tasks", task)); + } + + if (filters.capabilities.length > 0) { + filters.capabilities.forEach((capability) => + params.append("capabilities", capability), + ); + } + + setSearchParams(params); + }, [filters]); + const mapped = sortedModels.map((model) => ({ model: { ...model, diff --git a/src/components/ProductCatalog.tsx b/src/components/ProductCatalog.tsx index ac8d20f4f32ab45..7d405883ec48e2d 100644 --- a/src/components/ProductCatalog.tsx +++ b/src/components/ProductCatalog.tsx @@ -1,6 +1,7 @@ import { useEffect, useState, type ChangeEvent } from "react"; import type { CollectionEntry } from "astro:content"; import type { IconifyIconBuildResult } from "@iconify/utils"; +import { setSearchParams } from "~/util/url"; export type ProductData = CollectionEntry<"products"> & { icon?: IconifyIconBuildResult; @@ -42,7 +43,6 @@ const ProductCatalog = ({ products }: { products: ProductData[] }) => { }); useEffect(() => { - // On component load, check for deep-links to groups in the query param const params = new URLSearchParams(window.location.search); const groups = params.get("product-group")?.split(","); @@ -54,6 +54,20 @@ const ProductCatalog = ({ products }: { products: ProductData[] }) => { }); }, []); + useEffect(() => { + const params = new URLSearchParams(); + + if (filters.search) { + params.set("search", filters.search); + } + + if (filters.groups.length > 0) { + filters.groups.forEach((group) => params.append("product-group", group)); + } + + setSearchParams(params); + }, [filters]); + return (
diff --git a/src/components/search/InstantSearch.tsx b/src/components/search/InstantSearch.tsx index cbb40dfc21de44b..40c4ec1cb76fdfa 100644 --- a/src/components/search/InstantSearch.tsx +++ b/src/components/search/InstantSearch.tsx @@ -21,6 +21,7 @@ import { FloatingPortal, } from "@floating-ui/react"; import { PiCaretDownBold } from "react-icons/pi"; +import { setSearchParams } from "~/util/url"; function SearchBox(props: UseSearchBoxProps) { const { query, refine } = useSearchBox(props); @@ -43,11 +44,7 @@ function SearchBox(props: UseSearchBoxProps) { params.delete("q"); } - history.pushState( - null, - "", - `${window.location.pathname}?${params.toString()}`, - ); + setSearchParams(params); }, [query]); return ( @@ -143,11 +140,7 @@ function FilterDropdown({ params.set(attribute, refined.join(",")); } - history.pushState( - null, - "", - `${window.location.pathname}?${params.toString()}`, - ); + setSearchParams(params); }, [items]); const { refs, floatingStyles, context } = useFloating({ diff --git a/src/util/url.ts b/src/util/url.ts new file mode 100644 index 000000000000000..17a84c6c4f77847 --- /dev/null +++ b/src/util/url.ts @@ -0,0 +1,12 @@ +export function setSearchParams(params: URLSearchParams) { + if (params.size === 0) { + history.pushState(null, "", window.location.pathname); + return; + } + + history.pushState( + null, + "", + `${window.location.pathname}?${params.toString()}`, + ); +}