Replace the Tags tab with a tag picker sheet
The tab bar drops from five to four; Tags now opens as a sheet from the + in the library's filter strip, which is the control that was already about adding a tag. Picking a tag pins it as a filter tab rather than pushing to a separate per-tag list. That made TagBookmarksView redundant — the filter tab shows the same thing, in whichever layout you're already using — so it's gone. This also fixes what the + could reach. The old inline menu listed tags found on the loaded page, so it offered 21 of 96 tags, and once a tag filter was active it collapsed to just the tags co-occurring with that one — pinning a second unrelated tag was impossible. The sheet sources names from the tags endpoint via a new BookmarksViewModel.loadAllTags(), and counts still come from loaded bookmarks, so a tag we haven't paged in shows no number rather than a wrong one. The sheet is searchable, marks already-pinned tags with a check, and picking a pinned tag selects that tab instead of duplicating it. Verified by driving the UI: the tab bar is now Bookmarks/Sources/ Podcasts/Search, + opens the sheet with 42 rows where the old menu had 21, and picking "ai" pinned an "ai" tab. Suite passes. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JgLHztZGaEHvS3KNeGQmRM
This commit is contained in:
co-authored by
Claude Opus 5
parent
69c2bc7514
commit
8a777ffc83
@@ -11,6 +11,9 @@ final class BookmarksViewModel {
|
||||
var searchQuery = ""
|
||||
var nextPageUrl: String?
|
||||
var smartCollections: [SmartCollection] = []
|
||||
/// Every tag name on the server. The loaded bookmark page only ever
|
||||
/// exposes the tags of the most recent 50, which is not the vocabulary.
|
||||
var allTags: [String] = []
|
||||
var isGeneratingCollections = false
|
||||
var enrichmentProgress: Double = 0
|
||||
var unreadFilter = false
|
||||
@@ -200,6 +203,14 @@ final class BookmarksViewModel {
|
||||
}
|
||||
}
|
||||
|
||||
/// Best-effort: an empty tag list just means the picker falls back to the
|
||||
/// tags it can see on loaded bookmarks, so a failure here isn't worth an
|
||||
/// error alert.
|
||||
func loadAllTags() async {
|
||||
guard let tags = try? await api.fetchTags() else { return }
|
||||
allTags = tags
|
||||
}
|
||||
|
||||
func generateSmartCollections() async {
|
||||
guard !bookmarks.isEmpty else { return }
|
||||
isGeneratingCollections = true
|
||||
|
||||
Reference in New Issue
Block a user