From c48504de1674d1fc9e6afbb4ae4cf47635354846 Mon Sep 17 00:00:00 2001 From: Gabriele Battimelli Date: Fri, 24 Apr 2026 00:41:22 +0200 Subject: [PATCH 1/3] Address browse page feedback: persist filters, responsive layout, scrollable sidebar - Sidebar: independently scrollable with thin scrollbar so filter stays reachable - Filter persistence: kinds query preserved across sidebar nav, breadcrumb, submodule, and root /browse links - Mobile: add MobileKindFilter chip bar (sidebar is hidden on small screens) - DeclarationItem: break long informal names, descriptions, and module paths so they no longer overflow narrow viewports - Module/submodule rows: truncate long names and pin counts with shrink-0 - Fix double := when expanding declarations whose stored value already starts with := - Rename filter Clear -> Reset --- frontend/src/app/browse/[...slug]/page.tsx | 177 +++++++++------ frontend/src/app/browse/page.tsx | 81 ++++--- frontend/src/app/globals.css | 15 ++ frontend/src/components/BrowseSidebar.tsx | 227 +++++++++++++++++++ frontend/src/components/DeclarationItem.tsx | 18 +- frontend/src/components/MobileKindFilter.tsx | 83 +++++++ 6 files changed, 490 insertions(+), 111 deletions(-) create mode 100644 frontend/src/components/BrowseSidebar.tsx create mode 100644 frontend/src/components/MobileKindFilter.tsx diff --git a/frontend/src/app/browse/[...slug]/page.tsx b/frontend/src/app/browse/[...slug]/page.tsx index 70f7e19..509785c 100644 --- a/frontend/src/app/browse/[...slug]/page.tsx +++ b/frontend/src/app/browse/[...slug]/page.tsx @@ -5,10 +5,13 @@ import { getModuleDeclarations, listModules } from "@/lib/api"; import DeclarationItem from "@/components/DeclarationItem"; import Header from "@/components/Header"; import Footer from "@/components/Footer"; -import type { ModuleInfo } from "@/types"; +import BrowseSidebar from "@/components/BrowseSidebar"; +import MobileKindFilter from "@/components/MobileKindFilter"; +import type { ModuleInfo, DeclarationKind } from "@/types"; interface Props { params: Promise<{ slug: string[] }>; + searchParams: Promise<{ kinds?: string }>; } function getDirectChildren( @@ -32,10 +35,16 @@ function getDirectChildren( .sort((a, b) => a.name.localeCompare(b.name)); } -export default async function ModulePage({ params }: Props) { +export default async function ModulePage({ params, searchParams }: Props) { const { slug } = await params; + const { kinds: kindsParam } = await searchParams; const moduleName = slug; + const selectedKinds = kindsParam + ? (kindsParam.split(",").filter(Boolean) as DeclarationKind[]) + : []; + const kindsQuery = kindsParam ? `?kinds=${kindsParam}` : ""; + const [declarations, allModules] = await Promise.all([ getModuleDeclarations(moduleName), listModules(), @@ -43,85 +52,113 @@ export default async function ModulePage({ params }: Props) { const subModules = getDirectChildren(allModules, moduleName); + const filteredDeclarations = + selectedKinds.length > 0 + ? declarations.filter((d) => selectedKinds.includes(d.kind)) + : declarations; + return (
-
- - -
-

- {moduleName.join(".")} -

-

- {declarations.length} declaration{declarations.length !== 1 ? "s" : ""} - {subModules.length > 0 && - ` · ${subModules.length} submodule${subModules.length !== 1 ? "s" : ""}`} -

-
+
+
+ - {subModules.length > 0 && ( -
-

- Submodules -

-
- {subModules.map((sub, i) => ( - - - {sub.name} - - - {sub.count} - - +
+ + + + +
+

+ {moduleName.join(".")} +

+

+ {filteredDeclarations.length} declaration + {filteredDeclarations.length !== 1 ? "s" : ""} + {selectedKinds.length > 0 && + ` (filtered from ${declarations.length})`} + {subModules.length > 0 && + ` · ${subModules.length} submodule${subModules.length !== 1 ? "s" : ""}`} +

-
- )} - {declarations.length > 0 && ( -
{subModules.length > 0 && ( -

- Declarations -

+
+

+ Submodules +

+
+ {subModules.map((sub, i) => ( + + + {sub.name} + + + {sub.count} + + + ))} +
+
+ )} + + {filteredDeclarations.length > 0 && ( +
+ {subModules.length > 0 && ( +

+ Declarations +

+ )} + {filteredDeclarations.map((decl, i) => ( + + ))} +
)} - {declarations.map((decl, i) => ( - - ))} -
- )} - {subModules.length === 0 && declarations.length === 0 && ( -

- No declarations found in this module. -

- )} + {subModules.length === 0 && filteredDeclarations.length === 0 && ( +

+ {selectedKinds.length > 0 + ? "No declarations match the current filter." + : "No declarations found in this module."} +

+ )} +
+