Home hero: one column, search first (handoff 14, variants 3a/3b)
📝 TLDR
The home page hero is a two-column block: search on the left, “Przepis dnia” on the right, with the voice button inside the field (from lg), a small grey 18 px label (bold only for members), “Często szukane” far below the fold for guests only, and a “N przepisów wymaga uwagi” banner in the signed-in hero. Handoff 14 (accepted by the owner for desktop, variants 3a guest and 3b signed in) proposes a single centered column where searching is the only task at the top, with “Przepis dnia” as its own block under a rule. This spec describes that future layout; it is a layout and copy change, not a logic change.
📝 Problem Statement
The audience is mostly older adults. Observed on master (3796761):
src/app/page.tsx:Herois a two-column grid (repeat(auto-fit,minmax(min(100%,25rem),1fr))) with the search and greeting on the left andRecipeOfTheDayon the right;GuestHomerendersPopularSearchesbelow the hero;MemberHomeputsAttentionBannerunder the field.src/app/components/home/home-search.tsx: theattachedfield puts “Powiedz” inside the pill fromlgand below it only on a phone; the label is visible but small and grey (text-[18px] text-ink-soft), bold only for members (strongLabel).src/lib/home.ts:homeGreetingreturns “Dzień dobry, {wołacz}!”;POPULAR_SEARCHEShas 6 terms (sernik, pierogi, rosół, szarlotka, naleśniki, zupa pomidorowa).
The handoff’s own claim is that a visible label, search as the single task and “Często szukane” next to the field are easier for older users; no usage data exists in the repo to confirm it (it is the owner’s design decision).
Limitation: the handoff files (design_handoff_hero_wyszukiwarka/README.md, Hero - propozycje.dc.html) are not in the repository. This spec transcribes the README as quoted in issue #426. The README also names files that do not exist: notification-bell.tsx (today the notifications entry is the “Powiadomienia” row and counter in app-menu.tsx, and the Menu-button dot) and recipe-search.tsx (the field is home-search.tsx).
📝 Proposed Solution
Rework Hero into a one-column, centered composition and move “Często szukane” into it; keep every behaviour component as is.
Alternatives considered:
- Keep two columns, only add the label/voice row — rejected: the owner accepted 3a/3b, whose point is one task at the top.
- A new search component — rejected:
HomeSearchalready owns the form, the voice flow (useVoiceField,ListeningScreen) andcompact/attachedmodes used on/szukajand “Moje przepisy”. A newlayoutvariant ofattachedis smaller and keeps one voice implementation. - Change
POPULAR_SEARCHESto the handoff’s 5 terms — rejected: the list also feeds the header search panel and the/szukajquick bar viapopularMinusRecent; the hero shows a slice instead.
📝 Architecture
- Primary modules:
src/app/page.tsx(Hero,GuestHome,MemberHome),home/home-search.tsx,home/popular-searches.tsx,home/recipe-of-the-day.tsx,src/lib/home.ts(greeting). - Reused as is:
useVoiceField,ListeningScreen,SEARCH_PATH/searchPath,getRecipeOfTheDay,formatSource/SourceBadge,buttonClasses,CardCarouselrows below the hero. - Hero (
page.tsx): a single centered column; it no longer receivesrecipeOfDay. “Przepis dnia” is rendered by the page after the hero, under its own rule, so the hero contains only heading, subtitle, search block, voice row and “Często szukane”. HomeSearch: theattachedfield loses the in-field “Powiedz” at every width; a new voice row (“albo” + “Powiedz, czego szukasz”) renders under it whenmicSupported./szukajand “Moje przepisy” (non-attached) are untouched. The label becomes 19 px bold#111827at both access levels.PopularSearches: gains a hero presentation (centered, under a 1 px#d1d5dbrule, lead-in text, 52 px pills with a 2 px#6b7280frame, 5 pills on desktop and 4 on a phone via amax-sm:hiddenfifth pill). The standalone section under the hero is removed. It now shows for both guest and member homes.RecipeOfTheDay: becomes a two-column block (7fr/5fr, gap 40) frommd: 360 px photo left, text right with an explicit “Zobacz przepis →” link; one column belowmd.AttentionBanner: no longer rendered on the home page. The component,failedSharesdata and the notification entries stay (menu row + counter, Menu-button dot); only the hero render is dropped, and with it the now-unused prop plumbing onMemberHomeif nothing else reads it.- Cross-system effects: none outside the home page, except
homeGreeting’s copy. No query, schema or route changes; the page already loads the vocative and the recipe of the day.
📝 UI/UX
Values are the handoff README’s, checked against CLAUDE.md where noted.
Desktop, guest (3a) and signed in (3b)
- Hero: white,
padding: 64px 28px 52px, centered column,gap: 18px. - H1 64 px / 800 / 1.02,
#111827. Guest “Czego dziś szukasz?”; signed in “Czego dziś szukasz, {wołacz}?”, falling back to “Czego dziś szukasz?” when the vocative is missing (homeGreetingchanges copy only). - Subtitle 20 px
#374151. Guest: “Przepisy z internetu w jednym miejscu. Zawsze pod ręką, kiedy gotujesz.” Signed in: “Szukaj w swoich przepisach i ulubionych albo we wszystkich.” - Field block max 780 px: visible
<label for>“Wpisz nazwę dania lub składnik” (19 px bold); formrole="search"; field 68 px, 2 px#111827frame, pill,padding: 0 5px 0 24px; input 19 px, placeholder#4b5563(“np. sernik, zupa z dyni, kurczak” for guests, “np. zupa z dyni” for members); submit “Szukaj” (text only, 56 px,bg-action+ white, 19 px bold; hover#9a3412). - Voice row: “albo” (18 px
#374151) + “Powiedz, czego szukasz” (52 px, 2 px#111827pill,Mic22 px). Same handler as today’s “Powiedz”. - “Często szukane”: rule
1px #d1d5db, lead-in “Nie wiesz, co wpisać? Kliknij jedno z najczęściej szukanych:” (18 px bold), pills 52 px / 2 px#6b7280/ 18 px bold; click = search for that term (existingsearchPathlink). - “Przepis dnia”:
margin: 0 28px,border-top: 1px solid #111827,padding: 32px 0 48px, grid 7fr/5fr; whole block is a link (aria-label="Przepis dnia: {tytuł}"); photo 360 px, 4 px radius, no shadow, source tab as on cards (already built in Phase 2 of style 1b); label “PRZEPIS DNIA” (16 px bold, uppercase via CSS,#9a3412), title 40 px / 800, subtitle 20 px, “Zobacz przepis →” 19 px bold#9a3412, underlined; hoveropacity: .92. - Signed in: no attention banner in the hero.
Phone (3c/3d) — proposal, not accepted. Left-aligned, padding 28px 16px 24px, H1 36 px, 60 px field with a 50 px “Szukaj”, full-width 52 px voice button, 4 popular pills, “Przepis dnia” with a full-bleed 220 px photo and a 28 px title. Default in this spec: keep today’s phone layout except the changes that are not layout-specific (visible label, voice button outside the field — already the phone behaviour — “Często szukane” in the hero for both audiences, banner removed). Adopting 3c/3d is a one-phase follow-up.
Accessibility. WCAG 2.2 AA: the 2 px #6b7280 pill frame is 4.8:1 on white (≥ 3:1); #9a3412 text on white is 7.3:1; #c2410c only as a background with white text; every control ≥ 48 px (pills 52 px, field 68 px); focus 3px solid #1d4ed8, offset 2 px; links underlined (“Zobacz przepis →”); the “Przepis dnia” block is one link whose accessible name carries the title. The label stays associated with the input through htmlFor/id.
Suggestions panel. The handoff says the suggestions panel “opens under the field at the block width”. On master the home field has no suggestions: header-search.tsx / header-search-panel.tsx serve the signed-in desktop header on pages other than / (the header search is hidden on /). Showing suggestions on the hero field would be a new feature; this spec does not add it (see Q4).
Prototype: not in the repository (see Problem Statement).
📝 Edge Cases & Failure Scenarios
- No Web Speech API:
micSupportedis false → no voice row and no “albo”; the layout does not leave a gap (the row is rendered conditionally). - No recipe of the day (
getRecipeOfTheDayreturns null): the “Przepis dnia” block and its rule are omitted entirely; the hero still ends with “Często szukane”. - Long recipe title: 40 px title wraps (
break-words); on 7fr/5fr belowlgthe grid collapses to one column frommd. - Vocative missing or uncertain: H1 falls back to “Czego dziś szukasz?”; the comma and name are never shown for a nominative or guessed form (existing rule in
homeGreeting). - Large system font / text scale: the centered column and 780 px block shrink with
width: 100%; pills wrap (flex-wrap); the 320 px reflow check (pnpm test:reflow) must pass with the 64 px H1 reduced on small screens (text-[36px] lg:text-[64px]). - Failed imports are no longer announced on the home page. The notifications menu row, its counter and the Menu-button dot remain. Anyone who relied on the banner now has to open the menu; see Risks.
- JS disabled: the search form is a plain GET form and the popular pills are links, so both work without JS (as today).
📝 Risks & Impact Review
- Reversibility: high — markup and copy only, no data or contract changes; a revert restores the previous hero.
- Removing the attention banner is a product trade-off.
attention-banner.tsxwas added in E01-S15/E01-S31 because “older users often miss the badge alone”. The handoff removes it and points to the notifications menu; a dedicated error channel for the administrator is out of scope. Impact: members with failed imports see no prompt on the home page. Mitigation: none in this change; the owner has accepted it in the handoff. Recorded as Q3. - Shared list.
POPULAR_SEARCHESalso feeds the header search panel and the/szukajquick bar; this spec leaves it untouched and slices it in the hero. - Unrelated screens.
HomeSearchis also used on/szukaj(compact) and “Moje przepisy”; changes are scoped to theattachedpath and covered by existing tests. - Layout shift. “Przepis dnia” moves from the hero’s right column to a block below; images load lazily so the hero’s first paint is text only (a plus for LCP, not measured here).
- Handoff accuracy. File names and the suggestions-panel claim in the README do not match the repo; implementation follows the repository.
📋 Phasing
Each phase is its own PR, green on pnpm typecheck && pnpm lint && pnpm test && pnpm test:reflow, and leaves the page usable.
- Phase 1 — Hero copy, label, voice row. New heading/subtitle copy, visible label, in-field “Powiedz” removed with the new voice row, 68 px field and text “Szukaj” button. Interim look: the hero keeps two columns.
- Phase 2 — “Często szukane” into the hero; banner out. Hero presentation of
PopularSearchesfor both audiences, standalone section removed,AttentionBannerremoved from the home page. - Phase 3 — One column and “Przepis dnia” block. Hero becomes one column;
RecipeOfTheDayis rendered after it as a 7fr/5fr block with the new typography and link. - Phase 4 (optional, needs owner confirmation). Phone layout 3c/3d.
📋 Implementation Plan
Phase 1 — Hero copy, label, voice row
src/lib/home.ts:homeGreeting→ “Czego dziś szukasz, {wołacz}?” / “Czego dziś szukasz?”. Updatehome.test.ts. Test: both cases and a blank/undefined vocative.home-search.tsx(attached): visible label for both audiences (19 px bold), 68 px pill field (lg) with the text “Szukaj” (no icon), remove the in-field “Powiedz” and add the voice row (“albo” + 52 px “Powiedz, czego szukasz”), rendered only whenmicSupported. Updatehome-visuals.test.ts/home-search.test.ts. Test: labelformatches the input id; nolg:inline-flexvoice button inside the field; the voice row exists once.page.tsx: pass the new subtitle/placeholder copy for guest and member. Test: snapshot-style assertions on the strings.
Phase 2 — “Często szukane” into the hero; banner out
popular-searches.tsx:variant="hero"— rule, lead-in text, 5 pills (4 on a phone), 52 px / 2 px#6b7280pills; keep the default variant if another caller needs it, else delete it. Test: renders the first five terms; the fifth carriesmax-sm:hidden; every pill is a link tosearchPath(term).GuestHomeandMemberHomerender it inside the hero; remove the standalone<PopularSearches />fromGuestHome. Test:PopularSearchesappears exactly once per home.- Remove
AttentionBannerfromMemberHome(and any deadfailedSharesplumbing); keep the component file only if tests or other screens use it, otherwise delete it with its test. Test: the signed-in home markup contains no “wymaga uwagi”.
Phase 3 — One column and “Przepis dnia” block
Hero→ single centered column (flex-col items-center text-center, field blockmax-w-[780px] text-left); drop therecipeOfDayslot. Test: no grid template in the hero markup.RecipeOfTheDay: rule + 7fr/5fr block, 360 px photo, 40/20 px text, “Zobacz przepis →”;page.tsxrenders it between the hero and the card rows only when a recipe exists. Test: linkaria-label, absence when null, underlined “Zobacz przepis”.- Visual and keyboard check as guest and as
qa-free/qa-fullvia/api/dev/login(no recipes added as QA);pnpm test:reflowat 320 px.
Phase 4 — Phone layout (only after confirmation)
- Left-aligned hero below
md, H1 36 px, 60/50 px field, full-width voice button, 4 pills, full-bleed 220 px “Przepis dnia” photo. Test: class assertions andpnpm test:reflow.
Resolved assumptions (autonomous defaults)
| # | Question | Applied default | Why | Confirm? |
|---|---|---|---|---|
| Q1 | Adopt the phone layout 3c/3d? | No — keep today’s phone layout; Phase 4 is optional | The handoff calls it a proposal “to be confirmed” and says the current phone layout may stay | reversible |
| Q2 | Which popular terms does the hero show? | The first 5 of the existing POPULAR_SEARCHES (4 on a phone); the list itself is unchanged | The list also feeds the header panel and /szukaj; the handoff allows “data from the current source” | reversible |
| Q3 | Remove the attention banner from the member hero? | Yes, as the handoff states; notification entries in the menu stay | Explicit owner decision in the handoff; the banner’s removal is a product trade-off recorded under Risks | reversible |
| Q4 | Add suggestions under the hero field? | No — the home field has none today; adding them is a new feature | The “no logic changes” rule; the handoff’s wording assumes a panel that is not on the home page | reversible |
| Q5 | Show “Często szukane” to signed-in users too? | Yes | Handoff 3b says “ta sama sekcja co u gościa” | reversible |
| Q6 | Handoff files are not in the repo | Treat the issue’s transcription as authoritative; repo file names win over the README’s | Values were quoted in #426; two README file names do not exist | reversible |