krz/orgstar

A native macOS editor for org-mode files. editor org-mode swift

Sources/Orgstar/ExportSheet.swift

main
orgstar/Sources/Orgstar/ExportSheet.swift history · blame · raw

57 lines · 2345 bytes

2 symbols in this file
 1import AppKit
 2import SwiftUI
 3
 4/// Export… (`app.export-dialog`): the format, where the file goes, and whether to open it after.
 5struct ExportSheet: View {
 6    let source: URL
 7    let export: (_ format: String, _ destination: URL, _ open: Bool) -> Void
 8    @AppStorage("exportFormat") private var format = "html"
 9    @AppStorage("exportOpenAfter") private var openAfter = false
10    @State private var destination: URL?
11    @Environment(\.dismiss) private var dismiss
12
13    static let formats: [(id: String, title: String, ext: String)] = [
14        ("html", "HTML", "html"), ("markdown", "Markdown", "md"), ("pdf", "PDF (Emacs)", "pdf"),
15        ("odt", "ODT (Emacs)", "odt"), ("latex", "LaTeX (Emacs)", "tex"), ("text", "Plain text (Emacs)", "txt"),
16    ]
17
18    private var ext: String { Self.formats.first { $0.id == format }?.ext ?? "html" }
19    private var target: URL { destination ?? source.deletingPathExtension().appendingPathExtension(ext) }
20
21    var body: some View {
22        Form {
23            Picker("Format", selection: $format) {
24                ForEach(Self.formats, id: \.id) { Text($0.title).tag($0.id) }
25            }
26            .onChange(of: format) { destination = destination.map { $0.deletingPathExtension().appendingPathExtension(ext) } }
27            LabeledContent("Destination") {
28                HStack {
29                    Text(target.path(percentEncoded: false)).lineLimit(1).truncationMode(.middle).foregroundStyle(.secondary)
30                    Button("Choose…") { choose() }
31                }
32            }
33            Toggle("Open after export", isOn: $openAfter)
34        }
35        .formStyle(.grouped)
36        .safeAreaInset(edge: .bottom) {
37            HStack {
38                Spacer()
39                Button("Cancel") { dismiss() }.keyboardShortcut(.cancelAction)
40                Button("Export") {
41                    export(format, target, openAfter)
42                    dismiss()
43                }
44                .keyboardShortcut(.defaultAction)
45            }
46            .padding()
47        }
48        .frame(width: 520)
49    }
50
51    private func choose() {
52        let panel = NSSavePanel()
53        panel.directoryURL = target.deletingLastPathComponent()
54        panel.nameFieldStringValue = target.lastPathComponent
55        if panel.runModal() == .OK, let url = panel.url { destination = url }
56    }
57}