import SwiftUI import SFSafeSymbols struct GenerationContentView: View { @Environment(\.language) private var language @EnvironmentObject private var content: Content @EnvironmentObject private var selection: SelectedContent @Environment(\.dismiss) private var dismiss var draftPages: Set { Set(content.pages.filter { $0.isDraft }) } var draftPosts: Set { Set(content.posts.filter { $0.isDraft }) } var body: some View { VStack(alignment: .leading) { Text("Website Generation") .font(.largeTitle) .bold() Text("Regenerate the website and monitor the output") .foregroundStyle(.secondary) .padding(.bottom, 30) HStack { Button { if content.isGeneratingWebsite { content.endCurrentGeneration() } else { content.generateWebsiteInAllLanguages() } } label: { Text(content.isGeneratingWebsite ? "Cancel" : "Generate") } .disabled(content.isGeneratingWebsite != content.shouldGenerateWebsite) if content.isGeneratingWebsite { ProgressView() .progressViewStyle(.circular) .scaleEffect(0.6) .frame(height: 16) } Spacer() } Text(content.generationStatus) .padding(.vertical, 5) GenerationStringIssuesView( text: "output files", statusWhenNonEmpty: .nominal, items: content.results.outputFiles) GenerationResultsIssueView( text: "\(content.results.imagesToGenerate.count) images", status: .nominal, items: { [] }) GenerationResultsIssueView( text: "\(content.results.resultCount) items processed", status: .nominal, items: { [] }) GenerationStringIssuesView( text: "external links", statusWhenNonEmpty: .nominal, items: content.results.externalLinks) GenerationStringIssuesView( text: "required files", statusWhenNonEmpty: .nominal, items: content.results.requiredFiles) { $0.identifier } GenerationStringIssuesView( text: "external files", statusWhenNonEmpty: .nominal, items: content.results.externalFiles) { $0.identifier } GenerationIssuesView( text: "empty pages", statusWhenNonEmpty: .warning, items: $content.results.emptyPages) { pageId in HStack { Text("\(pageId.pageId) (\(pageId.language))") Spacer() Button("Show") { show(page: pageId.pageId, language: pageId.language) } } } GenerationIssuesActionView( title: "draft pages", statusWhenNonEmpty: .warning, items: draftPages, buttonText: "Show", itemText: { $0.identifier }, action: { show($0) }) GenerationIssuesActionView( title: "draft posts", statusWhenNonEmpty: .warning, items: draftPosts, buttonText: "Show", itemText: { $0.identifier }, action: { show($0) }) GenerationIssuesView( text: "additional output files", statusWhenNonEmpty: .warning, items: $content.results.unusedFilesInOutput) { filePath in HStack { Text(filePath) Spacer() Button("Delete", action: { delete(unusedFile: filePath) }) } } GenerationStringIssuesView( text: "inaccessible files", items: content.results.inaccessibleFiles) { $0.identifier } GenerationStringIssuesView( text: "unparsable files", items: content.results.unparsableFiles) { $0.identifier } GenerationStringIssuesView( text: "unsaved output files", items: content.results.unsavedOutputFiles) GenerationStringIssuesView( text: "failed image generations", items: content.results.failedImages) { $0.outputPath } GenerationStringIssuesView( text: "missing files", items: content.results.missingFiles) GenerationStringIssuesView( text: "missing tags", items: content.results.missingTags) GenerationStringIssuesView( text: "missing pages", items: content.results.missingPages) { pageId in let sources = content.results.sources(forMissingPage: pageId) .map { "\($0.page): \($0.source)"} .joined(separator: ", ") return "\(pageId) (\(sources))" } GenerationStringIssuesView( text: "invalid commands", items: content.results.invalidCommands) GenerationStringIssuesView( text: "invalid blocks", items: content.results.invalidBlocks) GenerationStringIssuesView( text: "warnings", statusWhenNonEmpty: .warning, items: content.results.warnings) HorizontalCenter { Button(action: { dismiss() }) { Text("Close") } } }.padding() } private func delete(unusedFile: String) { guard content.storage.deleteInOutputFolder(unusedFile) else { return } content.results.unusedFilesInOutput.remove(unusedFile) } private func show(page pageId: String, language: ContentLanguage? = nil) { guard let page = content.page(pageId) else { return } show(page, language: language) } private func show(_ page: Page, language: ContentLanguage? = nil) { selection.page = page if let language { selection.language = language } selection.tab = .pages dismiss() } private func show(_ post: Post, language: ContentLanguage? = nil) { selection.post = post if let language { selection.language = language } selection.tab = .posts dismiss() } } #Preview { GenerationContentView() .environmentObject(Content.mock) .padding() }