fix: recipes page wasted too much vertical space above content on mobile

Search bar forced its own full-width row (w-full), pushing Sort/Filter
to a second row below it — on mobile that's title + action buttons +
search row + sort/filter row + toolbar row before any recipe appears.

Sort/Filter now go icon-only below sm: (text labels hidden, matching the
convention already used for compact-view badges), letting Search share
one row with both instead of forcing its own. Also tightened the title
size and inter-section spacing on mobile (unchanged at sm: and up).

Verified at a real 390px mobile viewport: first recipe card now clears
with room to spare, versus barely visible at the same viewport height
before. Desktop screenshot confirms zero visual change there.
This commit is contained in:
Arnaud
2026-07-13 08:37:40 +02:00
parent e117533f6f
commit 257908da7f
2 changed files with 12 additions and 11 deletions
+1 -1
View File
@@ -104,7 +104,7 @@ export default async function RecipesPage({ searchParams }: { searchParams: Sear
};
return (
<div className="space-y-6">
<div className="space-y-4 sm:space-y-6">
<div className="flex items-center gap-2 text-sm">
<span className="rounded-full bg-accent px-3 py-1 font-medium">{m.recipes.tabMine}</span>
<Link href="/recipes/favorites" className="rounded-full px-3 py-1 text-muted-foreground hover:bg-accent">
+11 -10
View File
@@ -127,11 +127,11 @@ export function RecipesHeader({
return (
<>
<div className="space-y-4">
<div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
<div className="space-y-3 sm:space-y-4">
<div className="flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between sm:gap-3">
<div>
<h1 className="text-3xl font-bold tracking-tight">{t("title")}</h1>
<p className="text-muted-foreground mt-1">
<h1 className="text-2xl sm:text-3xl font-bold tracking-tight">{t("title")}</h1>
<p className="text-muted-foreground text-sm sm:text-base mt-0.5 sm:mt-1">
{count === 0
? t("subtitle")
: t(count !== 1 ? "resultPlural" : "resultSingular", { count })}
@@ -154,8 +154,9 @@ export function RecipesHeader({
</div>
<div className="flex flex-wrap gap-2">
{/* Search */}
<div className="relative w-full sm:flex-1 sm:min-w-[200px] sm:max-w-sm">
{/* Search — shares the row with Sort/Filter even on mobile now that
those are icon-only there, instead of forcing a whole row to itself. */}
<div className="relative flex-1 min-w-[120px] sm:min-w-[200px] sm:max-w-sm">
<Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground pointer-events-none" />
<Input
value={query}
@@ -178,11 +179,11 @@ export function RecipesHeader({
<DropdownMenuTrigger
className={cn(
buttonVariants({ variant: sortChanged ? "secondary" : "outline", size: "sm" }),
"gap-1.5"
"gap-1.5 shrink-0"
)}
>
<ArrowUpDown className="h-4 w-4" />
{SORT_KEYS[initialSort] ? t(SORT_KEYS[initialSort]) : t("sort")}
<span className="hidden sm:inline">{SORT_KEYS[initialSort] ? t(SORT_KEYS[initialSort]) : t("sort")}</span>
</DropdownMenuTrigger>
<DropdownMenuContent align="start">
<DropdownMenuGroup>
@@ -206,11 +207,11 @@ export function RecipesHeader({
<DropdownMenuTrigger
className={cn(
buttonVariants({ variant: activeFilterCount > 0 ? "secondary" : "outline", size: "sm" }),
"gap-1.5"
"gap-1.5 shrink-0"
)}
>
<SlidersHorizontal className="h-4 w-4" />
{t("filter")}
<span className="hidden sm:inline">{t("filter")}</span>
{activeFilterCount > 0 && (
<Badge variant="secondary" className="ml-1 h-4 min-w-4 px-1 text-xs">
{activeFilterCount}