From 6174aef09891b1562969095b7b608150a99305b2 Mon Sep 17 00:00:00 2001 From: Victor Date: Sun, 19 Jul 2026 00:15:30 +0200 Subject: [PATCH 1/3] fix: resolve breadcrumb overlap on mobile --- src/components/PageHeader/ItemPage.astro | 2 +- .../ReferenceDirectoryWithFilter/index.tsx | 82 ++++++++++++++--- src/components/SearchForm/index.astro | 2 +- src/layouts/ReferenceLayout.astro | 1 + src/pages/_utils.ts | 12 +-- .../ReferenceDirectoryWithFilter.test.tsx | 91 +++++++++++++++++++ 6 files changed, 171 insertions(+), 19 deletions(-) create mode 100644 test/components/ReferenceDirectoryWithFilter.test.tsx diff --git a/src/components/PageHeader/ItemPage.astro b/src/components/PageHeader/ItemPage.astro index 6213d90494..96c8481678 100644 --- a/src/components/PageHeader/ItemPage.astro +++ b/src/components/PageHeader/ItemPage.astro @@ -19,7 +19,7 @@ if (titleAuthor) { } --- -
+
{topic.name} + value.replace(/<[^>]*>/g, " ").replace(/\s+/g, " ").trim().toLowerCase(); + /** * Convert Reference description to one-line description * @param description String description @@ -51,6 +59,34 @@ const getOneLineDescription = (description: string): string => { export const ReferenceDirectoryWithFilter = ({ categoryData, }: ReferenceDirectoryProps) => { + const [searchTerm, setSearchTerm] = useState(""); + + const filteredCategoryData = useMemo(() => { + const normalizedQuery = normalizeSearchText(searchTerm); + + if (!normalizedQuery) { + return categoryData; + } + + return categoryData + .map((category) => ({ + ...category, + subcats: category.subcats + .map((subcat) => ({ + ...subcat, + entries: subcat.entries.filter((entry) => { + const searchableText = `${entry.data.title} ${entry.data.description}`; + + return normalizeSearchText(searchableText).includes( + normalizedQuery, + ); + }), + })) + .filter((subcat) => subcat.entries.length > 0), + })) + .filter((category) => category.subcats.length > 0); + }, [categoryData, searchTerm]); + const renderEntries = (entries: ReferenceDirectoryEntry[]) => entries.length === 0 ? null : (
@@ -95,8 +131,8 @@ export const ReferenceDirectoryWithFilter = ({ }; const getSubcatHeading = ( - subcat: { name: string; entry?: any }, - category: { name: string }, + subcat: ReferenceDirectorySubcategory, + category: ReferenceDirectoryCategory, ) => { if (!subcatShouldHaveHeading(subcat, category)) { return null; @@ -121,7 +157,15 @@ export const ReferenceDirectoryWithFilter = ({ }; const renderCategoryData = () => { - return categoryData.map((category) => ( + if (filteredCategoryData.length === 0) { + return ( +

+ No matching references found. +

+ ); + } + + return filteredCategoryData.map((category) => (

+
+ + { + setSearchTerm(event.currentTarget.value); + }} + placeholder="Search references" + aria-label="Search references" + class="w-full rounded-[20px] border border-sidebar-type-color bg-body-color px-md py-3 text-body-large placeholder-sidebar-type-color focus:outline-0" + /> +
{renderCategoryData()}

); diff --git a/src/components/SearchForm/index.astro b/src/components/SearchForm/index.astro index 36107a1944..6c5629c5cb 100644 --- a/src/components/SearchForm/index.astro +++ b/src/components/SearchForm/index.astro @@ -20,7 +20,7 @@ const t = await getUiTranslator(currentLocale); type="search" placeholder={t("Search") as string} name="term" - class="border-accent-type-color border outline-offset-0 placeholder-accent-type-color bg-transparent pl-gutter-md py-[6px] md:py-[4px] lg:py-[8px] h-full w-full rounded-[20px] peer text-base" + class="border-accent-type-color border outline-offset-0 placeholder-accent-type-color bg-transparent pl-gutter-md py-[6px] md:py-[4px] lg:py-[8px] h-full w-full rounded-[20px] peer text-3xl" aria-label="Search through site content" required /> diff --git a/src/layouts/ReferenceLayout.astro b/src/layouts/ReferenceLayout.astro index 021d338f01..ca9e945aca 100644 --- a/src/layouts/ReferenceLayout.astro +++ b/src/layouts/ReferenceLayout.astro @@ -153,6 +153,7 @@ const pageJumpToState: JumpToState = { diff --git a/src/pages/_utils.ts b/src/pages/_utils.ts index 00e56bde05..a10e405e58 100644 --- a/src/pages/_utils.ts +++ b/src/pages/_utils.ts @@ -283,17 +283,17 @@ export type PageTopic = export const getTopicInfo = (topic?: PageTopic) => { switch (topic) { case "community": - return { name: "Community", url: "/community" }; + return { name: "Community", url: "/community/" }; case "reference": - return { name: "Reference", url: "/reference" }; + return { name: "Reference", url: "/reference/" }; case "contribute": - return { name: "Contribute", url: "/contribute" }; + return { name: "Contribute", url: "/contribute/" }; case "about": - return { name: "About", url: "/about" }; + return { name: "About", url: "/about/" }; case "examples": - return { name: "Examples", url: "/examples" }; + return { name: "Examples", url: "/examples/" }; case "tutorials": - return { name: "Tutorials", url: "/tutorials" }; + return { name: "Tutorials", url: "/tutorials/" }; default: return { name: "p5.js", url: "/" }; } diff --git a/test/components/ReferenceDirectoryWithFilter.test.tsx b/test/components/ReferenceDirectoryWithFilter.test.tsx new file mode 100644 index 0000000000..6aa2d3b7f3 --- /dev/null +++ b/test/components/ReferenceDirectoryWithFilter.test.tsx @@ -0,0 +1,91 @@ +import { cleanup, fireEvent, render, screen } from "@testing-library/preact"; +import { expect, it, suite } from "vitest"; +import { ReferenceDirectoryWithFilter } from "@components/ReferenceDirectoryWithFilter"; + +suite("ReferenceDirectoryWithFilter", () => { + it("filters by title and description, case-insensitively", () => { + render( + Loads and plays a video element.

", + }, + }, + ], + }, + { + name: "audio", + entries: [ + { + id: "2", + slug: "volume", + body: "", + collection: "reference", + data: { + path: "p5/volume", + title: "volume()", + description: "

Controls the media volume for video playback.

", + }, + }, + ], + }, + ], + }, + { + name: "p5.Graphics", + subcats: [ + { + name: "misc", + entries: [ + { + id: "3", + slug: "alpha", + body: "", + collection: "reference", + data: { + path: "p5/alpha", + title: "alpha()", + description: "

No matching term here.

", + }, + }, + ], + }, + ], + }, + ]} + />, + ); + + const searchInput = screen.getByLabelText("Search references"); + + expect(screen.getByText("p5.MediaElement")).toBeTruthy(); + expect(screen.getByText("p5.Graphics")).toBeTruthy(); + expect(screen.getByText("video")).toBeTruthy(); + expect(screen.getByText("audio")).toBeTruthy(); + + fireEvent.input(searchInput, { target: { value: "VIDEO" } }); + + expect(screen.getByText("p5.MediaElement")).toBeTruthy(); + expect(screen.queryByText("p5.Graphics")).toBeNull(); + expect(screen.getByText("video")).toBeTruthy(); + expect(screen.getByText("audio")).toBeTruthy(); + expect(screen.getByText("createVideo()")).toBeTruthy(); + expect(screen.getByText("volume()")).toBeTruthy(); + expect(screen.queryByText("alpha()")).toBeNull(); + + cleanup(); + }); +}); \ No newline at end of file From f560a31b6058a1d2b15e9f07853b28a1b3b686ca Mon Sep 17 00:00:00 2001 From: Victor Date: Sun, 19 Jul 2026 00:22:34 +0200 Subject: [PATCH 2/3] fix: resolve build and typecheck errors --- src/pages/_utils.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/pages/_utils.ts b/src/pages/_utils.ts index a10e405e58..00e56bde05 100644 --- a/src/pages/_utils.ts +++ b/src/pages/_utils.ts @@ -283,17 +283,17 @@ export type PageTopic = export const getTopicInfo = (topic?: PageTopic) => { switch (topic) { case "community": - return { name: "Community", url: "/community/" }; + return { name: "Community", url: "/community" }; case "reference": - return { name: "Reference", url: "/reference/" }; + return { name: "Reference", url: "/reference" }; case "contribute": - return { name: "Contribute", url: "/contribute/" }; + return { name: "Contribute", url: "/contribute" }; case "about": - return { name: "About", url: "/about/" }; + return { name: "About", url: "/about" }; case "examples": - return { name: "Examples", url: "/examples/" }; + return { name: "Examples", url: "/examples" }; case "tutorials": - return { name: "Tutorials", url: "/tutorials/" }; + return { name: "Tutorials", url: "/tutorials" }; default: return { name: "p5.js", url: "/" }; } From dd97130750319dc4d910db378d6a653d4638f294 Mon Sep 17 00:00:00 2001 From: Victor Date: Sun, 19 Jul 2026 00:28:20 +0200 Subject: [PATCH 3/3] :wqfix: update test data to match type definition:wq --- .../ReferenceDirectoryWithFilter.test.tsx | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/components/ReferenceDirectoryWithFilter.test.tsx b/test/components/ReferenceDirectoryWithFilter.test.tsx index 6aa2d3b7f3..ddbfc4c1eb 100644 --- a/test/components/ReferenceDirectoryWithFilter.test.tsx +++ b/test/components/ReferenceDirectoryWithFilter.test.tsx @@ -19,6 +19,12 @@ suite("ReferenceDirectoryWithFilter", () => { body: "", collection: "reference", data: { + module: "Shape", + submodule: "video", + file: "createVideo.mdx", + line: 1, + deprecated: "", + params: [], path: "p5/createVideo", title: "createVideo()", description: "

Loads and plays a video element.

", @@ -35,6 +41,12 @@ suite("ReferenceDirectoryWithFilter", () => { body: "", collection: "reference", data: { + module: "Shape", + submodule: "audio", + file: "volume.mdx", + line: 1, + deprecated: "", + params: [], path: "p5/volume", title: "volume()", description: "

Controls the media volume for video playback.

", @@ -56,6 +68,12 @@ suite("ReferenceDirectoryWithFilter", () => { body: "", collection: "reference", data: { + module: "Shape", + submodule: "misc", + file: "alpha.mdx", + line: 1, + deprecated: "", + params: [], path: "p5/alpha", title: "alpha()", description: "

No matching term here.

",