fix(search): sort button layout + section dividers in filter panel (#981)#985
fix(search): sort button layout + section dividers in filter panel (#981)#985ericsocrat merged 1 commit intomainfrom
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
📸 PR ScreenshotsCaptured 2 screenshots (1 mobile, 1 desktop) for 1 changed page(s):
📥 Download screenshots from workflow artifacts. Captured by PR Screenshots workflow • 2026-03-19 |
Bundle Size Report
✅ Bundle size is within acceptable limits. |
There was a problem hiding this comment.
Pull request overview
This PR addresses UX issues in the search FilterPanel by improving sort button grid symmetry (odd last item spans both columns) and adding visual dividers between filter groups.
Changes:
- Update sort option rendering to apply
col-span-2to the final button when the option count is odd. - Add
<hr>separators between filter sections (Sort → Categories → Nutri-Score → NOVA → Allergens → Min Score). - Add tests for divider presence and the odd-last sort button spanning behavior.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
frontend/src/components/search/FilterPanel.tsx |
Adds odd-last grid spanning for sort buttons and inserts section divider <hr> elements. |
frontend/src/components/search/FilterPanel.test.tsx |
Adds tests asserting dividers exist and the last sort button gets col-span-2 when appropriate. |
| <hr className="border-t border-border/40" /> | ||
|
|
There was a problem hiding this comment.
The new
dividers are always rendered even when the adjacent section is conditionally absent (e.g., no categories/nutri_scores/etc.). This can result in dividers not actually separating two rendered groups (including potentially multiple consecutive dividers). Consider only rendering a divider when both the previous and next sections are present, or build a list of rendered sections and interleave separators between them.
| <hr className="border-t border-border/40" /> | ||
|
|
||
| {/* Categories */} | ||
| {data && (data.categories?.length ?? 0) > 0 && ( | ||
| <div> |
There was a problem hiding this comment.
These
elements are inserted as additional direct children inside a
space-y-5 container, which will add vertical spacing both above and below each divider (effectively doubling the gap between sections vs. before). If the intent is to keep the same spacing and just add a subtle separator, consider switching to a divide-y approach on a wrapper that only contains the filter groups (excluding the Clear button), or remove space-y-5 and explicitly control margins/padding around the divider.
| <hr className="border-t border-border/40" /> | |
| {/* Categories */} | |
| {data && (data.categories?.length ?? 0) > 0 && ( | |
| <div> | |
| {/* Categories */} | |
| {data && (data.categories?.length ?? 0) > 0 && ( | |
| <div className="border-t border-border/40 pt-5"> |
| renderPanel(); | ||
| await waitFor(() => { | ||
| expect(screen.getAllByText("Relevance").length).toBeGreaterThanOrEqual(1); | ||
| }); | ||
| const separators = document.querySelectorAll("hr"); |
There was a problem hiding this comment.
This test queries document.querySelectorAll("hr"), which isn't scoped to the rendered FilterPanel and can be influenced by other DOM content. Since renderPanel() returns the render result, prefer scoping to its container (or using Testing Library queries) to make the test deterministic; also consider asserting the expected divider count per rendered panel, since desktop+mobile may render duplicates.
| renderPanel(); | |
| await waitFor(() => { | |
| expect(screen.getAllByText("Relevance").length).toBeGreaterThanOrEqual(1); | |
| }); | |
| const separators = document.querySelectorAll("hr"); | |
| const { container } = renderPanel(); | |
| await waitFor(() => { | |
| expect(screen.getAllByText("Relevance").length).toBeGreaterThanOrEqual(1); | |
| }); | |
| const separators = container.querySelectorAll("hr"); |
| const caloriesBtn = screen.getAllByText("Calories")[0].closest("button"); | ||
| expect(caloriesBtn?.className).toContain("col-span-2"); |
There was a problem hiding this comment.
caloriesBtn?.className can become undefined if the closest button isn't found, leading to a less clear failure mode. Since the presence of the element is required for the assertion, explicitly assert that caloriesBtn is non-null (or use a role-based query that returns the button) before checking for col-span-2.
| const caloriesBtn = screen.getAllByText("Calories")[0].closest("button"); | |
| expect(caloriesBtn?.className).toContain("col-span-2"); | |
| const caloriesBtn = screen.getByRole("button", { name: /Calories/i }); | |
| expect(caloriesBtn.className).toContain("col-span-2"); |
Summary
Closes #981
Sort layout fix: The 5th sort button ("Calories") was orphaned alone in the last row of a 2-column grid. Now adds
col-span-2to the last button when the sort array has an odd count, centering it symmetrically.Section dividers: Added
<hr className="border-t border-border/40" />between all adjacent filter sections (Sort → Categories → Nutri-Score → NOVA → Allergens → Min Score). This visually separates each filter group and improves scannability in both desktop sidebar and mobile bottom sheet.Changes
.map()now receives(opt, idx, arr)and appliescol-span-2to the last item whenarr.lengthis odd. 5<hr>dividers added between sections.<hr>elements) andcol-span-2on last sort button.Verification
npx tsc --noEmit— 0 errors