Add note containers
This commit is contained in:
@ -79,6 +79,17 @@ public extension LinkedItem {
|
||||
(labels?.count ?? 0) > 0
|
||||
}
|
||||
|
||||
var noteText: String? {
|
||||
if let highlights = highlights?.compactMap({ $0 as? Highlight }) {
|
||||
let result = highlights
|
||||
.filter { $0.type == "NOTE" }
|
||||
.sorted(by: { $0.updatedAt ?? Date() < $1.updatedAt ?? Date() })
|
||||
.first
|
||||
return result?.annotation
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var isUnread: Bool {
|
||||
readingProgress <= 0
|
||||
}
|
||||
|
||||
@ -50,6 +50,7 @@ public extension Color {
|
||||
static var extensionPanelBackground: Color { Color("_extensionPanelBackground", bundle: .module) }
|
||||
static var extensionTextSubtle: Color { Color("_extensionTextSubtle", bundle: .module) }
|
||||
|
||||
static var noteContainer: Color { Color("_noteContainer", bundle: .module) }
|
||||
static var textFieldBackground: Color { Color("_textFieldBackground", bundle: .module) }
|
||||
|
||||
// Apple system UIColor equivalents
|
||||
|
||||
@ -0,0 +1,38 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0xED",
|
||||
"green" : "0xED",
|
||||
"red" : "0xED"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0x2A",
|
||||
"green" : "0x2A",
|
||||
"red" : "0x2A"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@ -1,117 +0,0 @@
|
||||
import Models
|
||||
import SwiftUI
|
||||
import Utils
|
||||
|
||||
public struct FeedCard: View {
|
||||
let viewer: Viewer?
|
||||
let tapHandler: () -> Void
|
||||
@ObservedObject var item: LinkedItem
|
||||
|
||||
public init(item: LinkedItem, viewer: Viewer?, tapHandler: @escaping () -> Void = {}) {
|
||||
self.item = item
|
||||
self.viewer = viewer
|
||||
self.tapHandler = tapHandler
|
||||
}
|
||||
|
||||
public var body: some View {
|
||||
VStack {
|
||||
HStack(alignment: .top, spacing: 10) {
|
||||
VStack(alignment: .leading, spacing: 1) {
|
||||
Text(item.unwrappedTitle)
|
||||
.font(.appCallout)
|
||||
.lineSpacing(1.25)
|
||||
.foregroundColor(.appGrayTextContrast)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.padding(EdgeInsets(top: 0, leading: 0, bottom: 2, trailing: 0))
|
||||
|
||||
if let author = item.author {
|
||||
Text("By \(author)")
|
||||
.font(.appCaption)
|
||||
.foregroundColor(.appGrayText)
|
||||
.lineLimit(1)
|
||||
}
|
||||
|
||||
if let publisherDisplayName = item.publisherDisplayName {
|
||||
Text(publisherDisplayName)
|
||||
.font(.appCaption)
|
||||
.foregroundColor(.appGrayText)
|
||||
.lineLimit(1)
|
||||
}
|
||||
}
|
||||
.frame(
|
||||
minWidth: 0,
|
||||
maxWidth: .infinity,
|
||||
minHeight: 0,
|
||||
maxHeight: .infinity,
|
||||
alignment: .topLeading
|
||||
)
|
||||
.multilineTextAlignment(.leading)
|
||||
.padding(0)
|
||||
|
||||
Group {
|
||||
if let imageURL = item.imageURL {
|
||||
AsyncImage(url: imageURL) { phase in
|
||||
if let image = phase.image {
|
||||
image
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fill)
|
||||
.frame(width: 80, height: 80)
|
||||
.cornerRadius(6)
|
||||
} else {
|
||||
Color.systemBackground
|
||||
.frame(width: 80, height: 80)
|
||||
.cornerRadius(6)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if item.hasLabels {
|
||||
// Category Labels
|
||||
ScrollView(.horizontal, showsIndicators: false) {
|
||||
HStack {
|
||||
ForEach(item.sortedLabels, id: \.self) {
|
||||
TextChip(feedItemLabel: $0)
|
||||
}
|
||||
Spacer()
|
||||
}
|
||||
}.introspectScrollView { scrollView in
|
||||
#if os(iOS)
|
||||
scrollView.bounces = false
|
||||
#endif
|
||||
}
|
||||
.padding(.top, 0)
|
||||
#if os(macOS)
|
||||
.onTapGesture {
|
||||
tapHandler()
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
let recs = Recommendation.notViewers(viewer: viewer, item.recommendations)
|
||||
if recs.count > 0 {
|
||||
let byStr = Recommendation.byline(recs)
|
||||
let inStr = Recommendation.groupsLine(recs)
|
||||
HStack {
|
||||
Image(systemName: "sparkles")
|
||||
Text("Recommended by \(byStr) in \(inStr)")
|
||||
.font(.appCaption)
|
||||
.frame(alignment: .leading)
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding(.top, 0)
|
||||
.padding(.bottom, 8)
|
||||
.frame(
|
||||
minWidth: nil,
|
||||
idealWidth: nil,
|
||||
maxWidth: nil,
|
||||
minHeight: 70,
|
||||
idealHeight: nil,
|
||||
maxHeight: nil,
|
||||
alignment: .topLeading
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -47,6 +47,7 @@ public extension View {
|
||||
public struct LibraryItemCard: View {
|
||||
let viewer: Viewer?
|
||||
@ObservedObject var item: LinkedItem
|
||||
@State var noteLineLimit: Int? = 3
|
||||
|
||||
public init(item: LinkedItem, viewer: Viewer?) {
|
||||
self.item = item
|
||||
@ -64,6 +65,30 @@ public struct LibraryItemCard: View {
|
||||
if item.hasLabels {
|
||||
labels
|
||||
}
|
||||
|
||||
if let note = item.noteText {
|
||||
HStack(alignment: .top, spacing: 10) {
|
||||
avatarImage
|
||||
.frame(width: 20, height: 20)
|
||||
.padding(.vertical, 10)
|
||||
.padding(.leading, 10)
|
||||
|
||||
Text(note)
|
||||
.font(Font.system(size: 12))
|
||||
.multilineTextAlignment(.leading)
|
||||
.lineLimit(noteLineLimit)
|
||||
.padding(.vertical, 10)
|
||||
.padding(.trailing, 10)
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
.frame(alignment: .topLeading)
|
||||
.background(Color.noteContainer)
|
||||
.cornerRadius(5)
|
||||
.allowsHitTesting(noteLineLimit != nil)
|
||||
.onTapGesture {
|
||||
noteLineLimit = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding(5)
|
||||
.padding(.top, 10)
|
||||
@ -79,6 +104,16 @@ public struct LibraryItemCard: View {
|
||||
Int(item.readingProgress) > 0
|
||||
}
|
||||
|
||||
var avatarImage: some View {
|
||||
ZStack(alignment: .center) {
|
||||
Circle()
|
||||
.foregroundColor(Color.appCtaYellow)
|
||||
Text((viewer?.name ?? "O").prefix(1))
|
||||
.font(Font.system(size: 10))
|
||||
.foregroundColor(Color.black)
|
||||
}
|
||||
}
|
||||
|
||||
var readIndicator: some View {
|
||||
HStack {
|
||||
Circle()
|
||||
|
||||
Reference in New Issue
Block a user