71 lines
2.7 KiB
Swift
71 lines
2.7 KiB
Swift
import ByreAPI
|
|||
|
|
import SwiftUI
|
||
|
|
|
||
|
|
struct BoardView: View {
|
||
|
|
@Environment(Store.self) private var store
|
||
|
|
|
||
|
|
var body: some View {
|
||
|
|
let taskId = store.selectedTaskId
|
||
|
|
let posts = store.transcript.filter { $0.kind == "board.posted" }
|
||
|
|
VStack(spacing: 0) {
|
||
|
|
HStack(spacing: 10) {
|
||
|
|
Text("Board").font(Fonts.font(13, weight: 700))
|
||
|
|
Text(taskId.map { store.team($0).map(\.member).joined(separator: ", ") } ?? "")
|
||
|
|
.foregroundStyle(Palette.muted)
|
||
|
|
.lineLimit(1)
|
||
|
|
.truncationMode(.tail)
|
||
|
|
}
|
||
|
|
.modifier(HeaderBar())
|
||
|
|
if posts.isEmpty {
|
||
|
|
EmptyText(text: taskId == nil ? "No task selected." : "No posts yet. Post from the Transcript tab's composer.")
|
||
|
|
} else {
|
||
|
|
ScrollViewReader { proxy in
|
||
|
|
ScrollView {
|
||
|
|
LazyVStack(alignment: .leading, spacing: 12) {
|
||
|
|
ForEach(posts, id: \.seq) { ev in
|
||
|
|
PostView(ev: ev, taskId: taskId)
|
||
|
|
.id(ev.seq)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
.padding(.horizontal, 16)
|
||
|
|
.padding(.vertical, 12)
|
||
|
|
}
|
||
|
|
.onAppear {
|
||
|
|
proxy.scrollTo(posts.last?.seq, anchor: .bottom)
|
||
|
|
}
|
||
|
|
.onChange(of: posts.count) {
|
||
|
|
proxy.scrollTo(posts.last?.seq, anchor: .bottom)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
.frame(maxHeight: .infinity, alignment: .top)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private struct PostView: View {
|
||
|
|
let ev: ByreEvent
|
||
|
|
let taskId: String?
|
||
|
|
|
||
|
|
var body: some View {
|
||
|
|
let p = ev.payload.value
|
||
|
|
let member = str(p, "member") ?? ""
|
||
|
|
VStack(alignment: .leading, spacing: 4) {
|
||
|
|
HStack(spacing: 6) {
|
||
|
|
Text(member.isEmpty ? ev.actor : member).font(Fonts.font(12, weight: 700))
|
||
|
|
if !member.isEmpty {
|
||
|
|
Text(str(p, "model") ?? "").foregroundStyle(Palette.muted)
|
||
|
|
}
|
||
|
|
WhenText(when: ev.createdAt).foregroundStyle(Palette.muted)
|
||
|
|
}
|
||
|
|
.font(Fonts.font(11))
|
||
|
|
MarkdownView(blocks: parseMarkdown(str(p, "text") ?? ""), ctx: MDContext(taskId: taskId))
|
||
|
|
}
|
||
|
|
.padding(.horizontal, 12)
|
||
|
|
.padding(.vertical, 8)
|
||
|
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||
|
|
.background(member.isEmpty ? Palette.accentTint : Palette.raised, in: RoundedRectangle(cornerRadius: 10))
|
||
|
|
.overlay(RoundedRectangle(cornerRadius: 10).stroke(Palette.border))
|
||
|
|
}
|
||
|
|
}
|