Skip to content

feat: landing page, result hierarchy, and drawer transitions - #2390

Merged
felladrin merged 5 commits into
felladrin:mainfrom
uuzzrm:feat/home-page-and-results-polish
Aug 16, 2026
Merged

feat: landing page, result hierarchy, and drawer transitions#2390
felladrin merged 5 commits into
felladrin:mainfrom
uuzzrm:feat/home-page-and-results-polish

Conversation

@uuzzrm

@uuzzrm uuzzrm commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Summary

The empty state was a single search box floating in the middle of a grey page. This PR turns it into a proper landing page, gives result rows a real hierarchy, and standardizes drawer motion — while keeping the app flat, lightweight, and faster to load than before.

1. Changes — point by point

Landing page (the empty state)

  • Brand block: the existing pixel-lens logo, "MiniSearch", and the tagline "Private AI search in your browser".
  • Search form unchanged (still the center of the page).
  • Try: three suggestion links from the bundled query-suggestions.json (355 entries already in the repo). Each is a plain /?q=… link — the exact flow the smoke e2e already exercises.
  • Recent: up to five searches from history, only when history is enabled and entries exist.
  • HomePage is lazy-loaded; the critical path still renders only the search form. The suggestion fetch is deferred with requestIdleCallback.

Result rows

  • One grammar per row: title (15px/600, AA link color, single-line ellipsis) → domain (12px dimmed meta, was 16px italics) → snippet (13.5px, 3-line clamp, was unbounded).
  • Row spacing 40px → 16px. Rows are React.memo-wrapped with content-visibility; the per-row JS <Transition> state is removed.

Drawers

  • History (left) and settings (right) get explicit 250ms ease-out directional transitions, with duration 0 under prefers-reduced-motion.

2. Performance — before / after

Metric Before (main) After Delta
First-load JS 223.4 KB raw / 70.5 KB gzip 212.7 KB raw / 66.2 KB gzip −10.7 KB / −4.3 KB
New dependencies / browser requests 0 / 0 0

3. Visual effect — before / after

Screen Before After
Empty state Lone search box Brand + tagline + search form + three quiet suggestion links + recent searches
Result rows Same-size title/domain (italics), unbounded snippets, 40px gaps Source → title → snippet hierarchy, consistent rows, denser list
Drawers Default slide Deliberate directional slide, reduced-motion aware

Screenshots: docs/screenshots/home-dark.png, home-light.png, home-mobile.png, results-dark.png.

4. Actual advantages

  1. The product reads as a product on first visit (brand + tagline), important for a self-hosted tool.
  2. Results are scannable and denser (3-line clamp, 16px spacing).
  3. The critical path got ~4.3 KB gzip smaller — the landing page costs only a 2.1 KB lazy chunk.
  4. Privacy intact: no new third-party requests; suggestions and history are local.
  5. Motion is directional and fully disabled under reduced motion.
  6. No new dependencies, no new state channels, no server changes.

Validation

  • 30/30 affected component tests pass (HomePage ×3, MainPage ×10, SearchResultsList ×6, MenuDrawer, App, SearchForm).
  • tsc and biome clean. Production build measured (above). Real browser run confirms three suggestion links and the Recent row.

Screenshots

Home dark
Home light
Results dark

uuzzrm and others added 5 commits August 15, 2026 18:40
The empty state was a lone search box. It is now a page with the brand mark, tagline, three suggestion links from the bundled query-suggestions.json, and recent searches from history.

HomePage is lazy-loaded so the critical path still only renders the search form, and the suggestion fetch is deferred with requestIdleCallback so first paint is never blocked.
Title and domain shared the same 16px size (domain distinguished only by italics) and snippets had no length cap. Rows now follow one grammar: title (15px/600, AA link color) / domain (12px dimmed meta) / snippet (13.5px, 3-line clamp), spaced 16px instead of 40px.

Rows are memoized and use content-visibility, and the per-row JS Transition state is removed, which shrinks the first-load bundle.
Both drawers now use explicit 250ms ease-out transitions matching their position (history slides from the left, settings from the right), and honor prefers-reduced-motion by setting duration to 0 via useReducedMotion.
@felladrin

felladrin commented Aug 16, 2026

Copy link
Copy Markdown
Owner

I've merged main into this branch and made a small adjustment: kept all the optimizations (result row hierarchy, drawer transitions, performance gains) but removed the landing page visuals from HomePage; the brand block, "Try" suggestions, and "Recent" searches. The empty state now just shows the search input, same as before.

The changes are in HomePage.tsx, HomePage.test.tsx, and MainPage.tsx (removed the lazy() wrapper since the component is now trivial).

@felladrin
felladrin merged commit d16b623 into felladrin:main Aug 16, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants