krz/org-swift

A dependency-free Swift library that renders org-mode to sanitized HTML. html library org-mode swift

Sources/OrgSwiftUI/OrgTableView.swift

v0.8.0
org-swift/Sources/OrgSwiftUI/OrgTableView.swift history · blame · raw

57 lines · 2275 bytes

 1import OrgSwift
 2import SwiftUI
 3
 4/// A table, in a `Grid` that scrolls sideways when it is wider than the screen.
 5///
 6/// Column alignment comes from org's `|---+:---:+---|` separator row. `Grid` takes it from
 7/// one cell per column, so it is set on the first row and inherited down.
 8struct OrgTableView: View {
 9    let table: OrgTableLayout
10    @Environment(\.orgMath) private var math
11
12    var body: some View {
13        ScrollView(.horizontal, showsIndicators: false) {
14            Grid(alignment: .topLeading, horizontalSpacing: 14, verticalSpacing: 7) {
15                ForEach(Array(table.rows.enumerated()), id: \.element.id) { index, row in
16                    GridRow {
17                        ForEach(0 ..< table.columnCount, id: \.self) { column in
18                            cell(row, column: column, isHeader: index < table.headerRowCount)
19                        }
20                    }
21                    // The rule row separating the header band from the body.
22                    if index + 1 == table.headerRowCount {
23                        Divider().gridCellColumns(table.columnCount)
24                    }
25                }
26            }
27            .padding(.vertical, 2)
28        }
29    }
30
31    @ViewBuilder
32    private func cell(_ row: OrgTableLayout.Row, column: Int, isHeader: Bool) -> some View {
33        // Org tolerates ragged rows; a missing cell is empty, not a crash.
34        let text = column < row.cells.count ? row.cells[column].text : AttributedString()
35        orgText(text, math: math)
36            .fontWeight(isHeader ? .semibold : .regular)
37            .multilineTextAlignment(Self.textAlignment(table.alignment(column: column)))
38            .fixedSize(horizontal: false, vertical: true)
39            .gridColumnAlignment(Self.gridAlignment(table.alignment(column: column)))
40    }
41
42    private static func gridAlignment(_ alignment: OrgAlignment?) -> HorizontalAlignment {
43        switch alignment {
44        case .center: .center
45        case .right: .trailing
46        case .left, nil: .leading
47        }
48    }
49
50    private static func textAlignment(_ alignment: OrgAlignment?) -> TextAlignment {
51        switch alignment {
52        case .center: .center
53        case .right: .trailing
54        case .left, nil: .leading
55        }
56    }
57}