Skip to content

feat(ui): grid/table layout toggle for tosses list#23

Merged
pseudobun merged 1 commit into
mainfrom
feat/layout-toggle
Apr 14, 2026
Merged

feat(ui): grid/table layout toggle for tosses list#23
pseudobun merged 1 commit into
mainfrom
feat/layout-toggle

Conversation

@pseudobun
Copy link
Copy Markdown
Owner

Summary

  • Adds a macOS-only segmented toolbar picker that toggles the Tosses list between the existing card grid and a new SwiftUI Table with sortable Content / Type / Created columns. The chosen layout persists across launches via @AppStorage on AppSettings.
  • Extracts the current grid rendering into a standalone TossGridView.
  • Introduces TossTableView (macOS only) with interactive header sorting via [KeyPathComparator<Toss>], selection via Set<Toss.ID>, and a selection-aware context menu (contextMenu(forSelectionType:)) whose primaryAction reuses the existing selectedToss sheet flow for double-click / Return activation.
  • New TossLayoutMode enum in TossKit, stored as a raw-string @AppStorage("layout_mode") on AppSettings with a computed enum accessor (standard SwiftUI pattern for @AppStorage enums).

Why

Card grid is great for browsing visual content (links with thumbnails), but hundreds of text tosses are easier to scan as a dense sortable list with headers. The toggle gives users both affordances on macOS without affecting the iPhone experience.

Why macOS only?

Per Apple's documented behavior and WWDC22 session 10058, SwiftUI Table on iPhone compact width hides headers and collapses all columns after the first — it's not a usable multi-column table there. The iOS target is iPhone-only (SUPPORTED_PLATFORMS = iphoneos iphonesimulator), so a Table-based layout on iOS would be strictly worse than the grid. The #if os(macOS) dispatcher gate is trivial to relax into a horizontal-size-class check later if iPad support is added.

Architecture notes

  • Table sort is in-memory (sorted(using:) on the filtered array) rather than a dynamic @Query rebuild — simpler, flexible, and fine at this data volume.
  • Table sits directly under NavigationStack, NOT inside an outer ScrollView — embedding Table in a ScrollView collapses its height to zero. The grid branch retains its ScrollView; both layouts share the same .navigationTitle / .searchable / .toolbar modifiers via a @ViewBuilder dispatcher.
  • No .sharedBackgroundVisibility(.hidden) on the picker — toolbar controls inherit reasonable Liquid Glass styling and a segmented picker is a native control; only the solo-spinner sync indicator needed the explicit opt-out.
  • Sorting by type uses \.typeRawValue (the stored String) rather than the computed type enum — the enum isn't Comparable and the raw value gives stable alphabetic ordering.

Test plan

  • Launch macOS app; toolbar shows segmented Grid/Table picker before the + button. Default is Grid (unchanged behavior).
  • Click Table segment — view swaps to three-column table sorted by Created descending.
  • Click each column header — sorting works, chevrons render on the active column.
  • Double-click a row — existing detail sheet opens with the right toss.
  • Right-click a row — Copy + Delete context menu works.
  • Search filter applies identically in both layouts; switching layouts preserves the filter.
  • Quit and relaunch — chosen layout persists.
  • Build to iPhone — no picker in toolbar, grid renders unchanged.
  • CloudKit sync: add a toss on another device in Table mode — new row appears via @Query within a couple of seconds.

🤖 Generated with Claude Code

Add a macOS-only segmented toolbar picker that toggles the Tosses list
between the existing card grid and a new SwiftUI Table with sortable
Content / Type / Created columns. The choice persists via @AppStorage on
AppSettings.

The grid rendering is extracted into a standalone TossGridView, and a new
macOS-only TossTableView drives interactive sorting via an in-memory
[KeyPathComparator<Toss>], selection via Set<Toss.ID>, and a
selection-aware context menu with a primaryAction that reuses the
existing selectedToss sheet flow for row activation.

iOS stays on the grid layout and does not show the picker. SwiftUI Table
collapses to a single header-less column at compact iPhone width per
Apple's documented behavior, so a real multi-column table is only
offered on macOS. The architecture keeps the #if os(macOS) dispatcher
trivial to relax into a horizontal-size-class check if iPad support is
added later.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@pseudobun pseudobun merged commit f485365 into main Apr 14, 2026
3 checks passed
@pseudobun pseudobun deleted the feat/layout-toggle branch April 14, 2026 09:26
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.

1 participant