Improve tag and images view, save website settings

This commit is contained in:
Christoph Hagen
2024-12-02 13:08:52 +01:00
parent 1261ea534b
commit 4440b2ce0d
22 changed files with 576 additions and 144 deletions

View File

@ -4,26 +4,19 @@ extension Content {
func generateFeed(for language: ContentLanguage, bookmarkKey: String) {
let posts = posts.map { $0.feedEntry(for: language) }
DispatchQueue.global(qos: .userInitiated).async {
let data = websiteData.localized(in: language)
let navigationItems: [FeedNavigationLink] = websiteData.navigationTags.map {
let localized = $0.localized(in: language)
return .init(text: localized.name, url: localized.urlComponent)
}
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")),
]
DispatchQueue.global(qos: .userInitiated).async {
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"),
title: data.title,
description: data.description,
iconDescription: data.iconDescription,
navigationItems: navigationItems,
posts: posts)
let fileContent = feed.content

View File

@ -5,19 +5,22 @@ import Combine
final class Content: ObservableObject {
@Published
var posts: [Post] = []
var websiteData: WebsiteData
@Published
var pages: [Page] = []
var posts: [Post]
@Published
var tags: [Tag] = []
var pages: [Page]
@Published
var images: [ImageResource] = []
var tags: [Tag]
@Published
var files: [FileResource] = []
var images: [ImageResource]
@Published
var files: [FileResource]
@AppStorage("contentPath")
private var storedContentPath: String = ""
@ -33,12 +36,14 @@ final class Content: ObservableObject {
private var cancellables = Set<AnyCancellable>()
init(posts: [Post] = [],
pages: [Page] = [],
tags: [Tag] = [],
images: [ImageResource] = [],
files: [FileResource] = [],
init(websiteData: WebsiteData,
posts: [Post],
pages: [Page],
tags: [Tag],
images: [ImageResource],
files: [FileResource],
storedContentPath: String) {
self.websiteData = websiteData
self.posts = posts
self.pages = pages
self.tags = tags
@ -59,6 +64,13 @@ final class Content: ObservableObject {
init() {
self.storage = Storage(baseFolder: URL(filePath: ""))
self.websiteData = .mock
self.posts = []
self.pages = []
self.tags = []
self.images = []
self.files = []
contentPath = storedContentPath
do {
try storage.createFolderStructure()
@ -114,9 +126,17 @@ final class Content: ObservableObject {
linkPreviewDescription: page.linkPreviewDescription)
}
private func convert(_ websiteData: LocalizedWebsiteDataFile) -> LocalizedWebsiteData {
.init(title: websiteData.title,
description: websiteData.description,
iconDescription: websiteData.iconDescription)
}
func loadFromDisk() throws {
let storage = Storage(baseFolder: URL(filePath: contentPath))
let websiteData = try storage.loadWebsiteData()
let tagData = try storage.loadAllTags()
let pagesData = try storage.loadAllPages()
let postsData = try storage.loadAllPosts()
@ -170,6 +190,10 @@ final class Content: ObservableObject {
self.files = files.sorted { $0.uniqueId }
self.images = images.values.sorted { $0.id }
self.posts = posts.sorted(ascending: false) { $0.startDate }
self.websiteData = WebsiteData(
navigationTags: websiteData.navigationTags.map { tags[$0]! },
german: convert(websiteData.german),
english: convert(websiteData.english))
}
private func loadPages(_ pagesData: [String : PageFile], tags: [String : Tag]) -> [String : Page] {
@ -202,6 +226,8 @@ final class Content: ObservableObject {
for tag in tags {
storage.save(tagMetadata: tag.tagFile, for: tag.id)
}
storage.save(websiteData: websiteData.dataFile)
// TODO: Remove all files that are no longer in use (they belong to deleted items)
//print("Finished save")
}

View File

@ -80,7 +80,11 @@ extension ImageResource {
print("Failed to create image from \(url.path)")
return failureImage
}
self.size = loadedImage.size
if self.size == .zero && loadedImage.size != .zero {
DispatchQueue.main.async {
self.size = loadedImage.size
}
}
return .init(nsImage: loadedImage)
}

View File

@ -0,0 +1,19 @@
import Foundation
final class LocalizedWebsiteData: ObservableObject {
@Published
var title: String
@Published
var description: String
@Published
var iconDescription: String
init(title: String, description: String, iconDescription: String) {
self.title = title
self.description = description
self.iconDescription = iconDescription
}
}

View File

@ -0,0 +1,20 @@
import Foundation
extension WebsiteData {
var dataFile: WebsiteDataFile {
.init(
navigationTags: navigationTags.map { $0.id },
german: german.dataFile,
english: english.dataFile)
}
}
extension LocalizedWebsiteData {
var dataFile: LocalizedWebsiteDataFile {
.init(title: title,
description: description,
iconDescription: iconDescription)
}
}

View File

@ -1,5 +1,26 @@
import Foundation
final class WebsiteData: ObservableObject {
@Published
var navigationTags: [Tag]
@Published
var german: LocalizedWebsiteData
@Published
var english: LocalizedWebsiteData
init(navigationTags: [Tag] = [], german: LocalizedWebsiteData, english: LocalizedWebsiteData) {
self.navigationTags = navigationTags
self.german = german
self.english = english
}
func localized(in language: ContentLanguage) -> LocalizedWebsiteData {
switch language {
case .english: return english
case .german: return german
}
}
}