diff --git a/CHDataManagement.xcodeproj/project.pbxproj b/CHDataManagement.xcodeproj/project.pbxproj index 685cffa..c7dc506 100644 --- a/CHDataManagement.xcodeproj/project.pbxproj +++ b/CHDataManagement.xcodeproj/project.pbxproj @@ -25,6 +25,8 @@ E218502D2CF791440090B18B /* PostImagesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E218502C2CF791440090B18B /* PostImagesView.swift */; }; E218502F2CFAF69C0090B18B /* Content+Generate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E218502E2CFAF6990090B18B /* Content+Generate.swift */; }; E21850312CFAF8880090B18B /* Content+Import.swift in Sources */ = {isa = PBXBuildFile; fileRef = E21850302CFAF8840090B18B /* Content+Import.swift */; }; + E21850332CFAFA2F0090B18B /* WebsiteData.swift in Sources */ = {isa = PBXBuildFile; fileRef = E21850322CFAFA200090B18B /* WebsiteData.swift */; }; + E21850352CFAFA5A0090B18B /* WebsiteDataFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = E21850342CFAFA570090B18B /* WebsiteDataFile.swift */; }; E24252012C50E0A40029FF16 /* HighlightedTextEditor in Frameworks */ = {isa = PBXBuildFile; productRef = E24252002C50E0A40029FF16 /* HighlightedTextEditor */; }; E24252032C5163CF0029FF16 /* Importer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E24252022C5163CF0029FF16 /* Importer.swift */; }; E24252062C51684E0029FF16 /* GenericMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = E24252052C51684E0029FF16 /* GenericMetadata.swift */; }; @@ -103,6 +105,8 @@ E218502C2CF791440090B18B /* PostImagesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostImagesView.swift; sourceTree = ""; }; E218502E2CFAF6990090B18B /* Content+Generate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Content+Generate.swift"; sourceTree = ""; }; E21850302CFAF8840090B18B /* Content+Import.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Content+Import.swift"; sourceTree = ""; }; + E21850322CFAFA200090B18B /* WebsiteData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebsiteData.swift; sourceTree = ""; }; + E21850342CFAFA570090B18B /* WebsiteDataFile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebsiteDataFile.swift; sourceTree = ""; }; E24252022C5163CF0029FF16 /* Importer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Importer.swift; sourceTree = ""; }; E24252052C51684E0029FF16 /* GenericMetadata.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenericMetadata.swift; sourceTree = ""; }; E24252072C5168750029FF16 /* GenericMetadata+Localized.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "GenericMetadata+Localized.swift"; sourceTree = ""; }; @@ -235,6 +239,7 @@ E2A37D0F2CE5375E0000979F /* Storage */ = { isa = PBXGroup; children = ( + E21850342CFAFA570090B18B /* WebsiteDataFile.swift */, E21850142CEE55D40090B18B /* FileOnDisk.swift */, E21850162CEE55FB0090B18B /* FileType.swift */, E2A37D102CE537670000979F /* PageFile.swift */, @@ -258,6 +263,7 @@ E2B85F392C428F020047CD0C /* Model */ = { isa = PBXGroup; children = ( + E21850322CFAFA200090B18B /* WebsiteData.swift */, E2E06DFA2CA4A6570019C2AF /* Content.swift */, E218502E2CFAF6990090B18B /* Content+Generate.swift */, E21850302CFAF8840090B18B /* Content+Import.swift */, @@ -511,12 +517,14 @@ E21850152CEE55D40090B18B /* FileOnDisk.swift in Sources */, E2A21C332CB5BCAC0060935B /* PageDetailView.swift in Sources */, E2A21C122CB18D560060935B /* DatePickerView.swift in Sources */, + E21850332CFAFA2F0090B18B /* WebsiteData.swift in Sources */, E21850192CEE561C0090B18B /* PageOnDisk.swift in Sources */, E2A21C4D2CBB16B50060935B /* ImagesView.swift in Sources */, E2A21C202CB28ED20060935B /* MockImage.swift in Sources */, E2A21C2C2CB2BB250060935B /* PostList.swift in Sources */, E21850112CEE17070090B18B /* Page+Storage.swift in Sources */, E218500D2CEE07180090B18B /* ColorPalette.swift in Sources */, + E21850352CFAFA5A0090B18B /* WebsiteDataFile.swift in Sources */, E21850132CEE541D0090B18B /* Post+Storage.swift in Sources */, E2B85F412C4294790047CD0C /* PageHead.swift in Sources */, E218501D2CEE6CB60090B18B /* VerticalCenter.swift in Sources */, diff --git a/CHDataManagement/Import/Importer.swift b/CHDataManagement/Import/Importer.swift index 508ffdc..34f65ec 100644 --- a/CHDataManagement/Import/Importer.swift +++ b/CHDataManagement/Import/Importer.swift @@ -76,6 +76,7 @@ final class Importer { let tag = TagFile( id: enTag.urlComponent, + isVisible: true, german: deTag, english: enTag) tags[tagId] = tag diff --git a/CHDataManagement/Model/Content.swift b/CHDataManagement/Model/Content.swift index a8cb471..508970d 100644 --- a/CHDataManagement/Model/Content.swift +++ b/CHDataManagement/Model/Content.swift @@ -79,13 +79,13 @@ final class Content: ObservableObject { .store(in: &cancellables) } - private func convert(_ tag: LocalizedTagFile) -> LocalizedTag { + private func convert(_ tag: LocalizedTagFile, images: [String : ImageResource]) -> LocalizedTag { LocalizedTag( urlComponent: tag.urlComponent, name: tag.name, subtitle: tag.subtitle, description: tag.description, - thumbnail: tag.thumbnail, + thumbnail: tag.thumbnail.map { images[$0] }, originalUrl: tag.originalURL) } @@ -122,13 +122,6 @@ final class Content: ObservableObject { let postsData = try storage.loadAllPosts() let filesData = try storage.loadAllFiles() - let tags = tagData.reduce(into: [:]) { (tags, data) in - tags[data.key] = Tag(german: convert(data.value.german), - english: convert(data.value.english)) - } - - let pages: [String : Page] = loadPages(pagesData, tags: tags) - let images: [String : ImageResource] = filesData.reduce(into: [:]) { dict, item in let (file, url) = item let ext = file.components(separatedBy: ".").last!.lowercased() @@ -145,6 +138,15 @@ final class Content: ObservableObject { } return FileResource(uniqueId: file, description: "") } + + let tags = tagData.reduce(into: [:]) { (tags, data) in + tags[data.key] = Tag( + isVisible: data.value.isVisible, + german: convert(data.value.german, images: images), + english: convert(data.value.english, images: images)) + } + + let pages: [String : Page] = loadPages(pagesData, tags: tags) let posts = postsData.map { postId, post in let linkedPage = post.linkedPageId.map { pages[$0] } diff --git a/CHDataManagement/Model/LocalizedTag.swift b/CHDataManagement/Model/LocalizedTag.swift index 3d09c1e..f5aa06c 100644 --- a/CHDataManagement/Model/LocalizedTag.swift +++ b/CHDataManagement/Model/LocalizedTag.swift @@ -17,7 +17,7 @@ final class LocalizedTag: ObservableObject { /// The image id of the thumbnail @Published - var thumbnail: String? + var thumbnail: ImageResource? /// The original url in the previous site layout let originalUrl: String? @@ -26,7 +26,7 @@ final class LocalizedTag: ObservableObject { name: String, subtitle: String? = nil, description: String? = nil, - thumbnail: String? = nil, + thumbnail: ImageResource? = nil, originalUrl: String? = nil) { self.urlComponent = urlComponent self.name = name diff --git a/CHDataManagement/Model/Tag+Storage.swift b/CHDataManagement/Model/Tag+Storage.swift index 30c2760..1dba3c0 100644 --- a/CHDataManagement/Model/Tag+Storage.swift +++ b/CHDataManagement/Model/Tag+Storage.swift @@ -4,6 +4,7 @@ extension Tag { var tagFile: TagFile { .init(id: id, + isVisible: isVisible, german: german.tagFile, english: english.tagFile) } @@ -16,7 +17,7 @@ extension LocalizedTag { name: name, subtitle: subtitle, description: description, - thumbnail: thumbnail, + thumbnail: thumbnail?.id, originalURL: originalUrl) } } diff --git a/CHDataManagement/Model/Tag.swift b/CHDataManagement/Model/Tag.swift index 5b9ba8f..e91b5d5 100644 --- a/CHDataManagement/Model/Tag.swift +++ b/CHDataManagement/Model/Tag.swift @@ -6,13 +6,17 @@ final class Tag: ObservableObject { english.urlComponent } + @Published + var isVisible: Bool + @Published var german: LocalizedTag @Published var english: LocalizedTag - init(german: LocalizedTag, english: LocalizedTag) { + init(isVisible: Bool = true, german: LocalizedTag, english: LocalizedTag) { + self.isVisible = isVisible self.german = german self.english = english } diff --git a/CHDataManagement/Model/WebsiteData.swift b/CHDataManagement/Model/WebsiteData.swift new file mode 100644 index 0000000..0d3eccb --- /dev/null +++ b/CHDataManagement/Model/WebsiteData.swift @@ -0,0 +1,5 @@ +import Foundation + +final class WebsiteData: ObservableObject { + +} diff --git a/CHDataManagement/Preview Content/Tag+Mock.swift b/CHDataManagement/Preview Content/Tag+Mock.swift index f4a392a..756687c 100644 --- a/CHDataManagement/Preview Content/Tag+Mock.swift +++ b/CHDataManagement/Preview Content/Tag+Mock.swift @@ -34,7 +34,7 @@ extension LocalizedTag { name: "Electronics", subtitle: "Projects with electronics", description: "Some description of the tag", - thumbnail: "electronic-thumbnail.jpg", + thumbnail: ImageResource(resourceName: "image1"), originalUrl: "projects/electronics") static let german = LocalizedTag( @@ -42,6 +42,6 @@ extension LocalizedTag { name: "Elektronik", subtitle: "Projekte mit Elektronik", description: "Eine Beschreibung des Tags", - thumbnail: "electronic-thumbnail.jpg", + thumbnail: ImageResource(resourceName: "image2"), originalUrl: "projects/electronics") } diff --git a/CHDataManagement/Storage/TagFile.swift b/CHDataManagement/Storage/TagFile.swift index bb64570..174421c 100644 --- a/CHDataManagement/Storage/TagFile.swift +++ b/CHDataManagement/Storage/TagFile.swift @@ -4,6 +4,8 @@ struct TagFile { let id: String + let isVisible: Bool + let german: LocalizedTagFile let english: LocalizedTagFile diff --git a/CHDataManagement/Storage/WebsiteDataFile.swift b/CHDataManagement/Storage/WebsiteDataFile.swift new file mode 100644 index 0000000..5b96926 --- /dev/null +++ b/CHDataManagement/Storage/WebsiteDataFile.swift @@ -0,0 +1,49 @@ +import Foundation + +struct WebsiteDataFile { + + let german: LocalizedWebsiteDataFile + + let english: LocalizedWebsiteDataFile +} + +extension WebsiteDataFile: Codable { + +} + +struct LocalizedWebsiteDataFile { + + let title: String + + let description: String + + let iconDescription: String + +} + +extension LocalizedWebsiteDataFile: Codable { + +} + +/* + let navigationItems: [FeedNavigationLink] = [ + .init(text: .init(en: "Projects", de: "Projekte"), + url: .init(en: "/projects", de: "/projekte")), + .init(text: .init(en: "Adventures", de: "Abenteuer"), + url: .init(en: "/adventures", de: "/abenteuer")), + .init(text: .init(en: "Services", de: "Dienste"), + url: .init(en: "/services", de: "/dienste")), + .init(text: .init(en: "Tags", de: "Kategorien"), + url: .init(en: "/tags", de: "/kategorien")), + ] + + let feed = Feed( + language: language, + title: .init(en: "Blog | CH", de: "Blog | CH"), + description: .init(en: "The latests posts, projects and adventures", + de: "Die neusten Beiträge, Projekte und Abenteuer"), + iconDescription: .init(en: "An icon consisting of the letters C and H in blue and orange", + de: "Ein Logo aus den Buchstaben C und H in Blau und Orange"), + navigationItems: navigationItems, + posts: posts) + */ diff --git a/CHDataManagement/Views/Tags/TagDetailView.swift b/CHDataManagement/Views/Tags/TagDetailView.swift index e2c8a90..c17d2ab 100644 --- a/CHDataManagement/Views/Tags/TagDetailView.swift +++ b/CHDataManagement/Views/Tags/TagDetailView.swift @@ -2,14 +2,25 @@ import SwiftUI struct TagDetailView: View { + @Binding + var tagIsVisible: Bool + @ObservedObject var tag: LocalizedTag @EnvironmentObject private var content: Content + @State + private var showImagePicker = false + var body: some View { VStack(alignment: .leading) { + Toggle("Appears in overviews", isOn: $tagIsVisible) + .toggleStyle(.switch) + .font(.callout) + .foregroundStyle(.secondary) + Text("Name") .font(.callout) .foregroundStyle(.secondary) @@ -40,14 +51,23 @@ struct TagDetailView: View { Text("Thumbnail") .font(.callout) .foregroundStyle(.secondary) - Text(tag.thumbnail ?? "-") - .padding(.top, 1) - .padding(.bottom) + Button(action: { showImagePicker = true }) { + Text(tag.thumbnail?.id ?? "Select") + } + .buttonStyle(.plain) + .foregroundStyle(.blue) } .padding() + .sheet(isPresented: $showImagePicker) { + ImagePickerView(showImagePicker: $showImagePicker) { image in + tag.thumbnail = image + } + } } } #Preview { - TagDetailView(tag: Tag.mock.english) + TagDetailView( + tagIsVisible: .constant(true), + tag: Tag.mock.english) } diff --git a/CHDataManagement/Views/Tags/TagsListView.swift b/CHDataManagement/Views/Tags/TagsListView.swift index fc02b7d..e8a3dea 100644 --- a/CHDataManagement/Views/Tags/TagsListView.swift +++ b/CHDataManagement/Views/Tags/TagsListView.swift @@ -1,5 +1,20 @@ import SwiftUI +private struct SelectedTagView: View { + + @Environment(\.language) + private var language + + @ObservedObject + var tag: Tag + + var body: some View { + TagDetailView( + tagIsVisible: $tag.isVisible, + tag: tag.localized(in: language)) + } +} + struct TagsListView: View { @Environment(\.language) @@ -20,13 +35,18 @@ struct TagsListView: View { } } detail: { if let selectedTag { - TagDetailView(tag: selectedTag.localized(in: language)) + SelectedTagView(tag: selectedTag) } else { Text("Select a tag to show the details") .font(.largeTitle) .foregroundColor(.secondary) } } + .onAppear { + if selectedTag == nil { + selectedTag = content.tags.first + } + } } }