iPad ergonomics: Escape, hover effects, context menu + docs refresh
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 callsauth.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.currentbecause 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.mdlayer map — had phantom files (MainTabView.swift,HomeView.swift) and omittedUIKit/,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,HeroTransitionTargetprotocol contract, lightbox differences, gotchas) andpixillate/Storage/BookmarksIndex/CLAUDE.md(schema + prune semantics, actor-boundary rule, three sync kinds, rate-limit discipline, bridge pattern). - Fixed stale
150 MB→1 GB/2 GBcache-size claims inImagePipeline+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:
-
xcodebuildsucceeds for iPad Pro 13-inch (M5) iOS Simulator at every stage