import SwiftUI import SFSafeSymbols struct GenerationContentView: View { @Environment(\.language) private var language @EnvironmentObject private var content: Content @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.id } GenerationStringIssuesView( text: "external files", statusWhenNonEmpty: .nominal, items: content.results.externalFiles) { $0.id } GenerationStringIssuesView( text: "empty pages", statusWhenNonEmpty: .warning, items: content.results.emptyPages) { "\($0.pageId) (\($0.language))" } GenerationStringIssuesView( text: "draft pages", statusWhenNonEmpty: .warning, items: draftPages) { $0.id } GenerationStringIssuesView( text: "draft posts", statusWhenNonEmpty: .warning, items: draftPosts) { $0.id } 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.id } GenerationStringIssuesView( text: "unparsable files", items: content.results.unparsableFiles) { $0.id } 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) } } #Preview { GenerationContentView() .environmentObject(Content.mock) .padding() }