Files
linkding-ios/Marks/Views/Library/LibraryGridView.swift
T
Krishna KumarandClaude Opus 5 cdbec4aaf8
CI / build-and-deploy (pull_request) Successful in 19s
CI / build-and-deploy (push) Successful in 21s
Scale library type up 50%
Every font size in the library design multiplied by 1.5 — card title and
stamp, list title, meta, excerpt and tags, filter tabs, and the
prototype's header.

Geometry had to follow, or the larger type would have broken the layout
it sits in:

- The card grid drops from three columns to two. At 16.5pt in a 95pt
  column a card gets about nine characters per line and every title
  truncates; the text size is what sets the column count.
- Filter tabs grow 30pt -> 42pt tall, the card gains padding and a
  slightly squarer aspect, and the list's color chip, unread dot and tag
  chips scale with the text they sit beside.

Verified in both layouts against the live server. Suite passes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JgLHztZGaEHvS3KNeGQmRM
2026-07-26 01:54:51 -05:00

86 lines
3.0 KiB
Swift

import SwiftUI
/// The library's card presentation of `viewModel.bookmarks`. Drops into
/// BookmarksView's content area in place of the List and carries the same
/// actions — tap to open, long press for the full menu. The filter strip above
/// it belongs to BookmarksView, since both layouts share it.
struct LibraryGridView: View {
@Bindable var viewModel: BookmarksViewModel
let onOpen: (Bookmark) -> Void
let onEdit: (Bookmark) -> Void
@Environment(\.openURL) private var openURL
@State private var showFullPlayer = false
@State private var episodePicker: Bookmark?
private var items: [LibraryItem] {
viewModel.bookmarks.map(LibraryItem.init(bookmark:))
}
var body: some View {
ScrollView {
LazyVGrid(
// Two columns, not three: at the scaled-up type a third
// column leaves ~9 characters per line and every title
// truncates. The text size sets the column count.
columns: Array(repeating: GridItem(.flexible(), spacing: 10), count: 2),
spacing: 10
) {
ForEach(items) { item in
card(item)
}
}
.padding(.horizontal, 18)
.padding(.top, 16)
.padding(.bottom, 40)
if viewModel.isLoadingMore {
ProgressView().padding(.bottom, 28)
}
}
.scrollBounceBehavior(.basedOnSize)
.background(Paper.sheet)
.podcastSheets(
viewModel: viewModel,
showFullPlayer: $showFullPlayer,
episodePicker: $episodePicker
)
}
@ViewBuilder
private func card(_ item: LibraryItem) -> some View {
// The grid renders LibraryItems, but every action needs the Bookmark it
// came from. Ids are linkding's, so this is a direct lookup.
if let bookmark = viewModel.bookmarks.first(where: { $0.id == item.id }) {
Button { onOpen(bookmark) } label: {
LibraryCard(item: item)
}
.buttonStyle(RowPressStyle())
.contextMenu {
bookmarkMenuItems(
bookmark: bookmark,
viewModel: viewModel,
openURL: openURL,
onOpen: { onOpen(bookmark) },
onEdit: { onEdit(bookmark) },
onPodcast: {
launchPodcast(
for: bookmark,
viewModel: viewModel,
showFullPlayer: $showFullPlayer,
episodePicker: $episodePicker
)
}
)
}
.onAppear { maybeLoadMore(bookmark) }
}
}
private func maybeLoadMore(_ bookmark: Bookmark) {
guard let last = viewModel.bookmarks.last, last.id == bookmark.id,
viewModel.nextPageUrl != nil, !viewModel.isLoadingMore else { return }
Task { await viewModel.loadMore() }
}
}