import SwiftUI struct BookmarkRow: View { let bookmark: Bookmark var body: some View { VStack(alignment: .leading, spacing: 6) { HStack(alignment: .top, spacing: 11) { FaviconView(url: bookmark.faviconUrl) .overlay(alignment: .topLeading) { if bookmark.unread { Circle() .fill(.blue) .frame(width: 8, height: 8) .offset(x: -3, y: -3) } } .padding(.top, 1) VStack(alignment: .leading, spacing: 4) { Text(bookmark.displayTitle) .font(.system(size: 22, weight: .medium)) .foregroundStyle(.primary) .lineLimit(2) .fixedSize(horizontal: false, vertical: true) Text(bookmark.domain) .font(.system(size: 16)) .foregroundStyle(.tertiary) } } if let summary = bookmark.aiSummary { Text(summary) .font(.system(size: 15)) .foregroundStyle(.secondary) .lineLimit(2) .padding(.leading, 40) } if !effectiveTags.isEmpty { ScrollView(.horizontal, showsIndicators: false) { HStack(spacing: 6) { ForEach(effectiveTags, id: \.self) { tag in Text(tag) .font(.system(size: 12, weight: .medium)) .foregroundStyle(.blue) .padding(.horizontal, 9) .padding(.vertical, 4) .background(Color.blue.opacity(0.1)) .clipShape(Capsule()) } } } .padding(.leading, 40) } } .padding(.vertical, 14) .contentShape(Rectangle()) } private var effectiveTags: [String] { let base = bookmark.tagNames let ai = bookmark.aiTags ?? [] let extra = ai.filter { !base.contains($0) }.prefix(3) return (base + extra).prefix(6).map { $0 } } } struct FaviconView: View { let url: String? var body: some View { Group { if let urlString = url, let faviconUrl = URL(string: urlString) { AsyncImage(url: faviconUrl) { phase in switch phase { case .success(let image): image.resizable().scaledToFit() default: placeholder } } } else { placeholder } } .frame(width: 26, height: 26) .clipShape(RoundedRectangle(cornerRadius: 5)) } private var placeholder: some View { RoundedRectangle(cornerRadius: 4) .fill(Color(.systemGray5)) .overlay { Image(systemName: "bookmark") .font(.system(size: 9, weight: .medium)) .foregroundStyle(Color(.systemGray2)) } } }