Skip to content

iPad ergonomics: Escape, hover effects, context menu + docs refresh

jedmund requested to merge jedmund/geneva-v3 into main

Created by: jedmund

Summary

iPad ergonomics

  • Escape closes modal sheets (login, Settings, tag search) via .keyboardShortcut(.cancelAction) on the existing Cancel / Done buttons. Login still calls auth.cancelLogin() before dismissing.
  • Trackpad hover effects on every .buttonStyle(.plain) site that had lost default pointer feedback — feed cells (.lift), bookmark tag cards (.lift), search rows, metadata artist row, Share button (.lift), tag pills and Follow pills (.highlight), account rows.
  • Long-press context menu on feed cells with a larger image preview and four actions: Open in Safari / Copy Link / Share… / Mute…. The Mute action opens a modal sheet listing the artist (first row, with avatar) and every tag on the illust, each row showing its live mute status and a button to flip it. Reads go through MutesBridge.shared.current because feed cells sit inside the UIKit tab stack. Menu machinery extracted to a reusable .illustContextMenu(for:) modifier so the detail pedestal can adopt it later.

Docs refresh (bundled because the audit that identified the iPad gaps also turned up significant doc drift)

  • Rewrote the root CLAUDE.md layer map — had phantom files (MainTabView.swift, HomeView.swift) and omitted UIKit/, Diagnostics/, Transitions/, Storage/BookmarksIndex/, MutesStore + MutesBridge, RateLimitGate.
  • New sections: Why UIKit is at the signed-in root, Rate limiting and 429 defense, Muting (including the filteredIllusts(behavior:mutes:) cache-key contract that new feeds must call through).
  • New nested guides: pixillate/UIKit/CLAUDE.md (hero push/pop walkthroughs, HeroTransitionTarget protocol contract, lightbox differences, gotchas) and pixillate/Storage/BookmarksIndex/CLAUDE.md (schema + prune semantics, actor-boundary rule, three sync kinds, rate-limit discipline, bridge pattern).
  • Fixed stale 150 MB1 GB / 2 GB cache-size claims in ImagePipeline+Pixiv.swift (both file-header and lightbox docstring).

Build fix — The nested CLAUDE.md files were tripping the target's PBXFileSystemSynchronizedRootGroup (both copied to pixillate.app/CLAUDE.md, flat). Added a PBXFileSystemSynchronizedBuildFileExceptionSet so .md files stay as source-only docs.

Test plan

Functional (hardware-keyboard / trackpad behavior not easily exercised in simulator — please verify on device):

  • Login sheet closes on hardware-keyboard Escape and still cancels auth cleanly
  • Settings sheet closes on Escape
  • Tag-search sheet closes on Escape
  • Feed cells lift on trackpad hover
  • Bookmark tag cards lift on hover
  • Search suggestion and recent rows highlight on hover
  • Metadata artist row, Share button, tag pills, and Follow pills show hover feedback
  • Long-press on a feed cell opens the context menu with a larger image preview
  • "Open in Safari" opens https://www.pixiv.net/en/artworks/<id>
  • "Copy Link" puts the same URL on the clipboard
  • "Share…" presents the system share sheet
  • "Mute…" opens the mute sheet
  • Mute sheet shows artist (avatar + name) and every tag; each row reads correct live mute status
  • Tapping Mute / Unmute toggles state immediately; optimistic local update rolls back if the server call fails (alert shown)
  • Dismissing the mute sheet mid-round-trip doesn't cancel the operation

Compile:

  • xcodebuild succeeds for iPad Pro 13-inch (M5) iOS Simulator at every stage

🤖 Generated with Claude Code

Merge request reports

Loading