import SwiftUI struct SettingsView: View { @Environment(\.language) var language @AppStorage("contentPath") var contentPath: String = "" @AppStorage("outputPath") var outputPath: String = "" @EnvironmentObject var content: Content @State private var folderSelection: SecurityScopeBookmark = .contentPath @State private var showTagPicker = false @State private var isGeneratingWebsite = false var body: some View { ScrollView { VStack(alignment: .leading) { Text("Content Folder") .font(.headline) TextField("Content Folder", text: $contentPath) Button(action: selectContentFolder) { Text("Select folder") } Text("Output Folder") .font(.headline) TextField("Output Folder", text: $outputPath) Button(action: selectOutputFolder) { Text("Select folder") } Text("Navigation Bar Items") .font(.headline) FlowHStack { ForEach(content.websiteData.navigationTags, id: \.id) { tag in TagView(tag: .init( en: tag.english.name, de: tag.german.name) ) .foregroundStyle(.white) } Button(action: { showTagPicker = true }) { Image(systemSymbol: .squareAndPencilCircleFill) .resizable() .aspectRatio(1, contentMode: .fit) .frame(height: 22) .foregroundColor(Color.gray) .background(Circle() .fill(Color.white) .padding(1)) } .buttonStyle(.plain) } LocalizedSettingsView(settings: content.websiteData.localized(in: language)) Text("Feed") .font(.headline) HStack { Button(action: generateFeed) { Text("Generate") } .disabled(isGeneratingWebsite) if isGeneratingWebsite { ProgressView() .progressViewStyle(.circular) .frame(height: 25) } Spacer() } } .padding() } .sheet(isPresented: $showTagPicker) { TagSelectionView( presented: $showTagPicker, selected: $content.websiteData.navigationTags, tags: $content.tags) } } // MARK: Folder selection private func selectContentFolder() { folderSelection = .contentPath guard let url = savePanelUsingOpenPanel() else { return } self.contentPath = url.path() } private func selectOutputFolder() { folderSelection = .outputPath guard let url = savePanelUsingOpenPanel() else { return } self.outputPath = url.path() } // MARK: Feed private func generateFeed() { guard outputPath != "" else { print("Invalid output path") return } let url = URL(fileURLWithPath: outputPath) guard FileManager.default.fileExists(atPath: url.path) else { print("Missing output folder") return } isGeneratingWebsite = true DispatchQueue.global(qos: .userInitiated).async { let generator = WebsiteGenerator( content: content, configuration: configuration) _ = generator.generateWebsite() DispatchQueue.main.async { isGeneratingWebsite = false } } } private var configuration: WebsiteGeneratorConfiguration { return .init( language: language, outputDirectory: URL(filePath: outputPath, directoryHint: .isDirectory), postsPerPage: 20, postFeedTitle: "Posts", postFeedDescription: "The most recent posts on christophhagen.de", postFeedUrlPrefix: "feed", navigationIconPath: "/assets/icons/ch.svg", mainContentMaximumWidth: 600) } func savePanelUsingOpenPanel() -> URL? { let panel = NSOpenPanel() // Sets up so user can only select a single directory panel.canChooseFiles = false panel.canChooseDirectories = true panel.allowsMultipleSelection = false panel.showsHiddenFiles = false panel.title = "Select Save Directory" panel.prompt = "Select Save Directory" let response = panel.runModal() guard response == .OK else { return nil } guard let url = panel.url else { return nil } content.storage.save(folderUrl: url, in: folderSelection) return url } } #Preview { SettingsView() .environmentObject(Content.mock) }