Keep icon touch targets full-size; shrink logo instead; fluid nav gap

Revert the 40px icon-shrink below 375px (hard to tap accurately) and reclaim that space from the logo instead (76-130px depending on width, vs the always-181px controls). Re-verified overflow-free at 320px via Playwright with all 4 icons at full 44px.

Also: wishlist heart's touch-friendly smaller/subtler size now applies to already-wishlisted (filled) hearts too, not just not-yet-wishlisted ones. The wishlist page's login redirect now returns to the wishlist instead of the generic account/orders overview. Desktop nav-link gap now scales fluidly between 1024-1300px instead of a fixed 48px that felt too wide right where nav labels have the least room.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Marco
2026-07-31 21:20:01 +00:00
parent 1a3a8ba20e
commit 92727ff22a
4 changed files with 51 additions and 27 deletions
+36 -22
View File
@@ -113,7 +113,7 @@ function AccountLink() {
<Link
href={href}
aria-label={loggedIn ? "Mein Konto (eingeloggt)" : "Anmelden"}
className="relative flex h-11 w-11 max-[375px]:h-10 max-[375px]:w-10 items-center justify-center shrink-0 active:scale-[0.9] transition-transform"
className="relative flex h-11 w-11 items-center justify-center shrink-0 active:scale-[0.9] transition-transform"
>
{/* -translate-y-0.5 — the glyph's own bounding box centers fine
mathematically, but the round head (light, isolated) versus the
@@ -135,10 +135,11 @@ function AccountLink() {
// Wishlist icon + count badge — only rendered by the caller when
// `wishlistEnabled` (CompanySettings). Visible at every width, alongside
// Search/Account/Cart — confirmed by an actual 320px-viewport check (see
// this file's git history) that all 4 icons fit without wrapping/overflow
// once sized down slightly on the smallest screens (see the h-11/w-11 →
// h-10/w-10 max-[375px] override below and on the sibling icon buttons).
// Search/Account/Cart — all 4 stay full 44px touch targets even on the
// smallest phones (shrinking them was tried and reverted: it made them
// hard to hit accurately). The logo shrinks further below 375px instead
// to make room — confirmed via an actual Playwright viewport sweep down
// to 320px that this fits without wrapping/overflow (see git history).
function WishlistLink() {
const { count } = useWishlist();
@@ -146,7 +147,7 @@ function WishlistLink() {
<Link
href="/konto/merkliste"
aria-label={count > 0 ? `Merkliste, ${count} Artikel` : "Merkliste"}
className="relative flex h-11 w-11 max-[375px]:h-10 max-[375px]:w-10 items-center justify-center shrink-0 active:scale-[0.9] transition-transform"
className="relative flex h-11 w-11 items-center justify-center shrink-0 active:scale-[0.9] transition-transform"
>
<svg viewBox="0 0 20 18" className="h-6 w-6 text-text-primary" fill="none" aria-hidden="true">
<path
@@ -212,7 +213,7 @@ function CartLink() {
}
}}
aria-label={visibleCount > 0 ? `Warenkorb, ${visibleCount} Artikel` : "Warenkorb"}
className="relative flex h-11 w-11 max-[375px]:h-10 max-[375px]:w-10 items-center justify-center shrink-0 active:scale-[0.9] transition-transform"
className="relative flex h-11 w-11 items-center justify-center shrink-0 active:scale-[0.9] transition-transform"
>
<svg
viewBox="0 0 32 30"
@@ -441,7 +442,7 @@ export function Navbar({
: "bg-bg-base"
}`}
>
<div className="flex h-[6.25rem] w-full shrink-0 items-center px-4 sm:px-8">
<div className="flex h-[6.25rem] w-full shrink-0 items-center px-2 min-[375px]:px-4 sm:px-8">
<div className="w-full flex items-center justify-between">
{/* Logo — real navigation to "/" from anywhere else; only when
@@ -453,7 +454,7 @@ export function Navbar({
while leaving that page's content on screen. */}
<Link
href="/"
className="shrink-0 w-[130px] sm:w-[181px]"
className="shrink-0 w-[76px] min-[375px]:w-[130px] sm:w-[181px]"
onClick={
pathname === "/"
? (e) => {
@@ -467,11 +468,13 @@ export function Navbar({
>
{/* Fixed width/height are the real file dimensions (Next Image
needs them for optimization/layout); the wrapping Link's own
w-[130px] sm:w-[181px] + h-auto here is what actually shrinks
the rendered logo below 640px — there wasn't enough header
width for 4 icons + hamburger otherwise (confirmed via an
actual Playwright viewport sweep down to 320px, not
assumed). */}
w-[112px] min-[375px]:w-[130px] sm:w-[181px] + h-auto here is
what actually shrinks the rendered logo below 640px — there
wasn't enough header width for 4 full-44px icons + hamburger
otherwise (confirmed via an actual Playwright viewport sweep
down to 320px, not assumed) — the icons themselves are never
shrunk (see WishlistLink's own comment on why), so the logo
is what gives on the very smallest phones instead. */}
<Image
src="/logo.png"
alt="einfach produktiv"
@@ -498,8 +501,17 @@ export function Navbar({
the vertical grid/flex reflows the rest of the site has —
there's no fluid token that shrinks link text to make a full
inline nav fit at 640px, and nothing here was ever tied to
the fluid token scale the way Hero/About/etc. were. */}
<nav className="hidden lg:flex items-center gap-12">
the fluid token scale the way Hero/About/etc. were.
The gap itself, though, does scale fluidly — just on its own
1024-1300px range (this nav's own floor/ceiling, only ever
relevant while it's actually visible), not the site-wide
640-1440px scale: clamp(1.5rem, 8.696vw - 4.065rem, 3rem) is
gap-6 (1.5rem) at exactly 1024px, gap-12 (3rem) from 1300px
up, and eases linearly between — the fixed 48px gap read as
too wide right where the nav labels themselves have the
least room (just above 1024px). */}
<nav className="hidden lg:flex items-center gap-[clamp(1.5rem,8.696vw_-_4.065rem,3rem)]">
{navLinks.map((link) => {
const isActive = isNavLinkActive(link.href, pathname, activeSection);
const underline = (
@@ -549,11 +561,13 @@ export function Navbar({
{/* Trailing controls — CTA buttons (md+), cart (always), hamburger
(below lg). Grouped so spacing stays consistent as individual
children hide/show across the three breakpoint tiers. */}
<div className="flex items-center gap-2">
{/* No gap between these — each is already a 44px (40px below
375px, see max-[375px]:h-10/w-10 on each icon button) touch
target with the icon centered inside, so even gap-0 here
still leaves visual space between the actual glyphs. All 4
<div className="flex items-center gap-1 min-[375px]:gap-2">
{/* No gap between these — each is a full 44px touch target
(never shrunk, even on the smallest phones — a smaller
target was tried and reverted for being hard to tap
accurately) with the icon centered inside, so even gap-0
here still leaves visual space between the actual glyphs.
All 4
icons (Search/Account/Wishlist/Cart) are visible at every
width, including true mobile — the 375px-and-below size
step exists specifically so all 4 plus the hamburger fit
@@ -604,7 +618,7 @@ export function Navbar({
e.stopPropagation();
setMobileOpen((v) => !v);
}}
className="lg:hidden flex h-11 w-11 max-[375px]:h-10 max-[375px]:w-10 items-center justify-center shrink-0"
className="lg:hidden flex h-11 w-11 items-center justify-center shrink-0"
>
<span className="relative block h-4 w-6">
<span
+1 -1
View File
@@ -29,7 +29,7 @@ export function SearchButton() {
type="button"
onClick={() => setOpen(true)}
aria-label="Suche öffnen"
className="flex h-11 w-11 max-[375px]:h-10 max-[375px]:w-10 items-center justify-center shrink-0 active:scale-[0.9] transition-transform"
className="flex h-11 w-11 items-center justify-center shrink-0 active:scale-[0.9] transition-transform"
>
<svg viewBox="0 0 24 24" className="h-6 w-6 text-text-primary" fill="none" aria-hidden="true">
<circle cx="11" cy="11" r="7" stroke="currentColor" strokeWidth="1.8" />
+8 -3
View File
@@ -36,7 +36,10 @@ export function WishlistButton({
* exists to avoid), touch devices get a smaller variant with a lighter
* (not removed — fully transparent made it invisible against some
* product photos) background instead — present and tappable everywhere,
* but visually quieter than the full-size default. */
* but visually quieter than the full-size default. Applies to
* already-wishlisted hearts too (not just the hover-revealed ones) —
* consistent sizing across every heart on a touch device, rather than
* only the not-yet-wishlisted ones shrinking. */
revealOnHover?: boolean;
}) {
const { isWishlisted, toggle } = useWishlist();
@@ -68,8 +71,10 @@ export function WishlistButton({
aria-pressed={wishlisted}
disabled={pending}
className={`flex h-9 w-9 items-center justify-center rounded-full bg-bg-base/90 backdrop-blur-sm transition-all active:scale-90 disabled:opacity-60 ${
revealOnHover ? "pointer-coarse:h-7 pointer-coarse:w-7 pointer-coarse:bg-bg-base/60" : ""
} ${
revealOnHover && !wishlisted
? "opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 focus-visible:opacity-100 pointer-coarse:opacity-100 pointer-coarse:h-7 pointer-coarse:w-7 pointer-coarse:bg-bg-base/60"
? "opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 focus-visible:opacity-100 pointer-coarse:opacity-100"
: ""
} ${className}`}
>
@@ -78,7 +83,7 @@ export function WishlistButton({
height="18"
viewBox="0 0 20 18"
fill={wishlisted ? "currentColor" : "none"}
className={`${wishlisted ? "text-brand" : "text-text-primary"} ${revealOnHover && !wishlisted ? "pointer-coarse:scale-75" : ""}`}
className={`${wishlisted ? "text-brand" : "text-text-primary"} ${revealOnHover ? "pointer-coarse:scale-75" : ""}`}
>
<path
d="M10 17S1 11.5 1 5.8C1 2.6 3.4 1 5.8 1c1.6 0 3.2.9 4.2 2.4C11 1.9 12.6 1 14.2 1 16.6 1 19 2.6 19 5.8 19 11.5 10 17 10 17Z"
+6 -1
View File
@@ -19,7 +19,12 @@ export const metadata: Metadata = {
export default async function KontoMerklistePage() {
const session = await getSessionCustomer();
if (!session) redirect("/konto/login");
// ?redirect= back to this page — landing on the generic account/orders
// overview after logging in from the wishlist icon (the common entry
// point, unlike most other /konto/* pages that are only ever reached
// once already logged in) would silently lose the wishlist context the
// customer actually came here for.
if (!session) redirect("/konto/login?redirect=%2Fkonto%2Fmerkliste");
// The feature can be switched off after a customer already had rows in
// their wishlist — 404 rather than showing a stale page for a feature