import SwiftUI struct SheetPanels: View { @Bindable var model: SheetModel let panel: String var openImported: ((UInt64, String) -> Void)? = nil @Environment(\.dismiss) private var dismiss @State private var title = "" @State private var width = 110 @State private var height = 32 @State private var mode = "auto" var body: some View { NavigationStack { Form { if !model.error.isEmpty { Text(model.error).foregroundStyle(.red) } switch panel { case "Rename": TextField("Sheet title", text: $title) Button("Rename") { Task { guard await model.command("/rename", ["title": title]) else { return } await model.loadList() if let sheet = model.sheets.first(where: { $0.ID == model.page?.Sheet.ID }) { await model.open(sheet) } dismiss() } } case "Sizes": TextField("Column width", value: $width, format: .number) Button("Set column width") { Task { await model.resize(axis: "col", size: width) } } .disabled(!(16...2000).contains(width)) TextField("Row height", value: $height, format: .number) Button("Set row height") { Task { await model.resize(axis: "row", size: height) } } .disabled(!(16...2000).contains(height)) Text("Formatting and size changes do not have undo.").font(.caption) case "History": ForEach(model.history) { entry in VStack(alignment: .leading) { Text(entry.Ref).font(.headline) Text(entry.Who).font(.caption) Text("Before: " + entry.Old).textSelection(.enabled) Text("After: " + entry.New).textSelection(.enabled) if model.mayWrite { Button("Restore before this edit") { Task { await model.command("/restore", ["event": String(entry.ID)]) await model.loadHistory() } } } } } case "Data": Picker("Sort column", selection: $model.view.sortCol) { Text("None").tag(-1) ForEach(0..<26, id: \.self) { Text(Coordinate(r: 0, c: $0).ref.dropLast()).tag($0) } } Toggle("Descending", isOn: $model.view.sortDesc) Picker("Filter column", selection: $model.view.filterCol) { Text("None").tag(-1) ForEach(0..<26, id: \.self) { Text(Coordinate(r: 0, c: $0).ref.dropLast()).tag($0) } } Picker("Comparison", selection: $model.view.filterOp) { ForEach(["contains", "equals", "gt", "lt", "nonempty"], id: \.self) { Text($0).tag($0) } } TextField("Filter value", text: $model.view.filterVal) Button("Apply and open table") { Task { guard await model.saveView() else { return } model.showTable = true dismiss() } }.disabled(!model.mayWrite) Button("Open table") { model.showTable = true dismiss() } Text("Sorting changes display order. Cell references stay in their original positions.") .font(.caption) case "Comments": SheetComments(model: model) case "Share": SheetSharing(model: model) case "Import", "Export": SheetFiles(model: model, importing: panel == "Import", openImported: openImported) default: EmptyView() } }.formStyle(.grouped).navigationTitle(panel) .toolbar { ToolbarItem(placement: .confirmationAction) { Button("Done") { dismiss() } } } } #if os(macOS) .frame(minWidth: 480, minHeight: 500) #endif .task { title = model.page?.Sheet.Title ?? "" if panel == "History" { await model.loadHistory() } if panel == "Data" { await model.loadTable() } } } }