mirror of
https://github.com/yattee/yattee.git
synced 2026-02-20 01:39:46 +00:00
Yattee v2 rewrite
This commit is contained in:
94
Yattee/Views/Components/CommentsPillView.swift
Normal file
94
Yattee/Views/Components/CommentsPillView.swift
Normal file
@@ -0,0 +1,94 @@
|
||||
//
|
||||
// CommentsPillView.swift
|
||||
// Yattee
|
||||
//
|
||||
// A rounded pill showing a comment preview that slides in from the bottom.
|
||||
// Tapping expands to full comments view.
|
||||
// Collapses to just avatar when isCollapsed is true.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import NukeUI
|
||||
|
||||
struct CommentsPillView: View {
|
||||
let comment: Comment
|
||||
let isCollapsed: Bool
|
||||
var fillWidth: Bool = false
|
||||
/// When true, uses smaller sizing for the collapsed state (e.g. on narrow devices).
|
||||
var compact: Bool = false
|
||||
let onTap: () -> Void
|
||||
|
||||
var body: some View {
|
||||
Button(action: onTap) {
|
||||
HStack(spacing: isCollapsed ? 0 : 12) {
|
||||
// Show icon when collapsed, avatar when expanded
|
||||
if isCollapsed {
|
||||
collapsedIconView
|
||||
} else {
|
||||
avatarView
|
||||
}
|
||||
|
||||
// Text content - only in layout when expanded
|
||||
if !isCollapsed {
|
||||
textContent
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: (!isCollapsed && fillWidth) ? .infinity : nil, alignment: .leading)
|
||||
.padding(.horizontal, isCollapsed ? (compact ? 6 : 10) : 16)
|
||||
.padding(.vertical, isCollapsed ? (compact ? 6 : 10) : 12)
|
||||
.contentShape(Rectangle())
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.contentShape(Capsule())
|
||||
.glassBackground(.regular, in: .capsule, fallback: .thinMaterial)
|
||||
.shadow(color: .black.opacity(0.1), radius: 8, y: 2)
|
||||
}
|
||||
|
||||
private var collapsedIconView: some View {
|
||||
let size: CGFloat = compact ? 28 : 32
|
||||
return Image(systemName: "bubble.left.and.bubble.right")
|
||||
.font(.system(size: compact ? 16 : 18, weight: .medium))
|
||||
.foregroundStyle(.primary)
|
||||
.frame(width: size, height: size)
|
||||
}
|
||||
|
||||
private var avatarView: some View {
|
||||
LazyImage(url: comment.author.thumbnailURL) { state in
|
||||
if let image = state.image {
|
||||
image
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fill)
|
||||
} else {
|
||||
Circle()
|
||||
.fill(.quaternary)
|
||||
.overlay {
|
||||
Text(String(comment.author.name.prefix(1)))
|
||||
.font(.caption2)
|
||||
.fontWeight(.medium)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
}
|
||||
}
|
||||
.frame(width: 32, height: 32)
|
||||
.clipShape(Circle())
|
||||
}
|
||||
|
||||
private var textContent: some View {
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
// Author name
|
||||
Text(comment.author.name)
|
||||
.font(.caption2)
|
||||
.fontWeight(.semibold)
|
||||
.foregroundStyle(.primary)
|
||||
.lineLimit(1)
|
||||
|
||||
// 2-line excerpt of comment
|
||||
Text(comment.content)
|
||||
.font(.footnote)
|
||||
.foregroundStyle(.secondary)
|
||||
.lineLimit(2)
|
||||
.multilineTextAlignment(.leading)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user