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.6.0
org-swift/Sources/OrgSwiftUI/OrgTableView.swift history · blame · raw

56 lines · 2215 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
11    var body: some View {
12        ScrollView(.horizontal, showsIndicators: false) {
13            Grid(alignment: .topLeading, horizontalSpacing: 14, verticalSpacing: 7) {
14                ForEach(Array(table.rows.enumerated()), id: \.element.id) { index, row in
15                    GridRow {
16                        ForEach(0 ..< table.columnCount, id: \.self) { column in
17                            cell(row, column: column, isHeader: index < table.headerRowCount)
18                        }
19                    }
20                    // The rule row separating the header band from the body.
21                    if index + 1 == table.headerRowCount {
22                        Divider().gridCellColumns(table.columnCount)
23                    }
24                }
25            }
26            .padding(.vertical, 2)
27        }
28    }
29
30    @ViewBuilder
31    private func cell(_ row: OrgTableLayout.Row, column: Int, isHeader: Bool) -> some View {
32        // Org tolerates ragged rows; a missing cell is empty, not a crash.
33        let text = column < row.cells.count ? row.cells[column].text : AttributedString()
34        Text(text)
35            .fontWeight(isHeader ? .semibold : .regular)
36            .multilineTextAlignment(Self.textAlignment(table.alignment(column: column)))
37            .fixedSize(horizontal: false, vertical: true)
38            .gridColumnAlignment(Self.gridAlignment(table.alignment(column: column)))
39    }
40
41    private static func gridAlignment(_ alignment: OrgAlignment?) -> HorizontalAlignment {
42        switch alignment {
43        case .center: .center
44        case .right: .trailing
45        case .left, nil: .leading
46        }
47    }
48
49    private static func textAlignment(_ alignment: OrgAlignment?) -> TextAlignment {
50        switch alignment {
51        case .center: .center
52        case .right: .trailing
53        case .left, nil: .leading
54        }
55    }
56}