Skip to content

Search tab + sort menu fix (and tag feeds carried from #4)

jedmund requested to merge claude/search-tab-ui into main

Created by: jedmund

Summary

Three things rolled up: the tag-feeds work from PR #4 (which merged into claude/illust-detail-view, not main, so it needs to come along), plus a new Search tab in the main tab bar, plus a fix for the stacked-segmented-control visual collision in TagFeedView on iPadOS 26.

Search tab

  • MainTabView gains a third tab between Home and Profile — magnifyingglass SF Symbol. The TabView { Tab(...) } syntax already produces the iOS 26 floating pill tab bar for free (bottom on iPhone, top on iPad).
  • New SearchViewNavigationStack + .searchable in the nav bar drawer. Submitting the search replaces the NavigationPath with a single PixivIllust.Tag rather than appending, so five searches in a row don't leave the user five pages deep.
  • Empty state is a magnifyingglass icon and a "Search for a tag" prompt. No history / trending / suggestions yet — those would each be their own feature.
  • Reads isPremium from @Environment(AuthSession.self) and threads it into TagFeedView the same way HomeView does, so the paginated sort=popular_desc endpoint routes correctly.
  • Re-registers PixivIllust and PixivIllust.Tag destinations locally because each tab has its own NavigationStack and destinations are per-stack.

Sort-menu redesign in TagFeedView

The .principal toolbar slot held a segmented Picker for Popular / Recent. On iPadOS 26 that sat directly under the top-placed tab bar, so two horizontal segmented-style controls ended up stacked on top of each other and read as one giant button bar. Moving sort to a Menu button in .topBarTrailing (alongside the gear) frees up the principal slot for the nav title and makes the control unambiguously a dropdown.

  • The Menu wraps a Picker so selection renders with iOS's standard checkmark on the current mode.
  • Each dropdown row has a per-mode SF Symbol via a new systemImage computed on TagSearchOptions.SortModeflame for Popular, clock for Recent.
  • Toolbar button label is a fixed arrow.up.arrow.down — users learn the shape fast and the current mode is always one tap away.

Tag feeds (from PR #4, carried along)

This diff also includes everything from PR #4 — PR #4 merged into claude/illust-detail-view rather than main, so the tag-feed commits never actually landed on main. Summary:

  • PixivEndpoint split into .tagSearchRecent(word:timeRange:), .tagSearchPopular(word:timeRange:) (premium-gated, paginated), and .tagSearchPopularPreview(word:) (free top-30 fallback). Both /v1/search/illust cases funnel through a private searchIllustURL helper.
  • TagSearchOptions model (sort mode + time range) with SearchTimeRange owning the native durationstart_date/end_date translation for ranges Pixiv's duration param doesn't cover.
  • MasonryFeed extracted from HomeView as a reusable component so both feed surfaces share one implementation.
  • TagFeedView pushes from tag pills in IllustDetailView; rebuilds its IllustFeedViewModel on onChange(of: options) with a fresh endpoint.
  • TagSearchSettingsView — modal sheet with a time-range picker; footer copy switches based on premium status.
  • Profile premium badge — golden-gradient pill with crown.fill under the user's @handle when is_premium == true.

Known limitations carried over

  • Black-cell-on-next-tap bug (from PR #3's follow-ups) affects any view that uses the zoom navigation transition — so HomeView, TagFeedView, and now SearchView → TagFeedView. Still tracked as a follow-up.
  • "All / male / female" demographic filter still not wired — Pixiv's tag search API doesn't expose it, and the ranking endpoint that does isn't tag-filtered. The settings sheet has a placeholder section documenting the gap.
  • Non-premium popular results capped at ~30popular-preview isn't paginated. Pixiv limitation.

Test plan

  • Tap the new Search tab → empty state shows with search field.
  • Type a tag name + return → pushes a TagFeedView with the typed term as the tag.
  • Back to the search tab → type a different tag + return → previous tag feed is replaced (not stacked) in the path.
  • TagFeedView nav bar: tag name in the center, sort menu + gear on the right, no segmented control. Sort menu dropdown shows Popular (with flame) and Recent (with clock) with a checkmark on the current mode.
  • On a premium account: flipping sort to Popular paginates with the current time range; flipping time range via the gear reloads correctly.
  • iPad: confirm the top-placed tab bar and the tag-feed nav bar no longer look like stacked segmented controls.
  • iPhone: confirm the floating bottom tab bar still has all three tabs (Home / Search / Profile) and the pill look.

https://claude.ai/code/session_01RDp8iEpHQ3GgpvDesCBR3s

Merge request reports

Loading