Files
Outpost/Outpost/Features/Collections/CollectionDocumentsOutline.swift
T
Puranjay Savar Mattas 4bec511b62 feat(collections): add sidebar collection context menu (macOS)
Star, New Document, Rename, Sort in Sidebar (client-side only —
Outline's own spec leaves persisted sort order as a frontend concern),
Export, Search in Collection, and Delete. Omits Subscribe and Archive
(no such endpoints exist for collections in Outline's public API),
and Import/Edit/Permissions/New Template (need infra not built yet:
multipart upload, membership UI, template flow).
2026-08-14 00:56:33 +01:00

73 lines
2.6 KiB
Swift

#if os(macOS)
import SwiftUI
import OutlineKit
/// Flat document list nested under an expanded collection in the sidebar tree.
/// Documents can themselves have children (`parentDocumentId`) in Outline — not
/// represented here yet, this is a first pass at the collection-level expansion.
struct CollectionDocumentsOutline: View {
@State private var viewModel: DocumentsViewModel
let sortOption: SidebarSortOption
let refreshToken: Int
let onSelectDocument: (OutlineDocument) -> Void
private var sortedDocuments: [OutlineDocument] {
sortOption.sorted(viewModel.documents)
}
init(
apiClient: OutlineAPIClient,
collection: OutlineCollection,
sortOption: SidebarSortOption,
refreshToken: Int,
onSelectDocument: @escaping (OutlineDocument) -> Void
) {
_viewModel = State(initialValue: DocumentsViewModel(apiClient: apiClient, collection: collection))
self.sortOption = sortOption
self.refreshToken = refreshToken
self.onSelectDocument = onSelectDocument
}
var body: some View {
Group {
if viewModel.isLoading && viewModel.documents.isEmpty {
ProgressView()
.controlSize(.small)
.padding(.vertical, 6)
} else if viewModel.documents.isEmpty {
Text("No documents")
.font(.callout)
.foregroundStyle(.secondary)
.padding(.vertical, 6)
} else {
ForEach(sortedDocuments) { document in
Button {
onSelectDocument(document)
} label: {
HStack(spacing: 8) {
if let emoji = document.emoji {
Text(emoji)
.font(.body)
} else {
Image(systemName: "doc.text")
.font(.callout)
.foregroundStyle(.secondary)
}
Text(document.title.isEmpty ? "Untitled" : document.title)
.font(.body)
.lineLimit(1)
Spacer(minLength: 0)
}
.contentShape(Rectangle())
}
.buttonStyle(.plain)
.padding(.vertical, 6)
}
}
}
.task(id: refreshToken) { await viewModel.load() }
}
}
#endif