83 lines
2.4 KiB
Swift
83 lines
2.4 KiB
Swift
|
|
import SwiftUI
|
||
|
|
import SaplingCore
|
||
|
|
|
||
|
|
public struct WorkspaceTreeView: View {
|
||
|
|
private let workspace: Workspace
|
||
|
|
private let onSelectFile: (WorkspaceFile) -> Void
|
||
|
|
private let onSelectProject: (Project) -> Void
|
||
|
|
|
||
|
|
public init(
|
||
|
|
workspace: Workspace,
|
||
|
|
onSelectFile: @escaping (WorkspaceFile) -> Void,
|
||
|
|
onSelectProject: @escaping (Project) -> Void
|
||
|
|
) {
|
||
|
|
self.workspace = workspace
|
||
|
|
self.onSelectFile = onSelectFile
|
||
|
|
self.onSelectProject = onSelectProject
|
||
|
|
}
|
||
|
|
|
||
|
|
public var body: some View {
|
||
|
|
List {
|
||
|
|
Section(workspace.name) {
|
||
|
|
ForEach(workspace.items) { item in
|
||
|
|
WorkspaceItemRow(
|
||
|
|
item: item,
|
||
|
|
onSelectFile: onSelectFile,
|
||
|
|
onSelectProject: onSelectProject
|
||
|
|
)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
.listStyle(.sidebar)
|
||
|
|
.navigationTitle("Workspace")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private struct WorkspaceItemRow: View {
|
||
|
|
let item: WorkspaceItem
|
||
|
|
let onSelectFile: (WorkspaceFile) -> Void
|
||
|
|
let onSelectProject: (Project) -> Void
|
||
|
|
|
||
|
|
var body: some View {
|
||
|
|
switch item {
|
||
|
|
case .folder(let folder):
|
||
|
|
DisclosureGroup {
|
||
|
|
ForEach(folder.children) { child in
|
||
|
|
WorkspaceItemRow(
|
||
|
|
item: child,
|
||
|
|
onSelectFile: onSelectFile,
|
||
|
|
onSelectProject: onSelectProject
|
||
|
|
)
|
||
|
|
}
|
||
|
|
} label: {
|
||
|
|
Label(folder.name, systemImage: "folder")
|
||
|
|
}
|
||
|
|
case .file(let file):
|
||
|
|
Button {
|
||
|
|
onSelectFile(file)
|
||
|
|
} label: {
|
||
|
|
Label(file.name, systemImage: iconName(for: file.kind))
|
||
|
|
}
|
||
|
|
.buttonStyle(.plain)
|
||
|
|
case .project(let project):
|
||
|
|
Button {
|
||
|
|
onSelectProject(project)
|
||
|
|
} label: {
|
||
|
|
Label(project.name, systemImage: "point.3.connected.trianglepath.dotted")
|
||
|
|
}
|
||
|
|
.buttonStyle(.plain)
|
||
|
|
case .subproject(let subproject):
|
||
|
|
Label(subproject.name, systemImage: "rectangle.connected.to.line.below")
|
||
|
|
.foregroundStyle(.secondary)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private func iconName(for kind: WorkspaceFileKind) -> String {
|
||
|
|
switch kind {
|
||
|
|
case .markdown: "doc.plaintext"
|
||
|
|
case .attachment: "paperclip"
|
||
|
|
case .other: "doc"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|