From 657f8c4ef41d97e0b84bc2694b9fd844c06944b7 Mon Sep 17 00:00:00 2001 From: Christoph Hagen Date: Sat, 14 Dec 2024 19:02:01 +0100 Subject: [PATCH] Add tag command --- .../Generator/PageContentGenerator.swift | 44 +++++++++++++++++-- .../Generator/ShorthandMarkdownKey.swift | 8 ++-- CHDataManagement/Main/MainView.swift | 1 + CHDataManagement/Model/Content+Load.swift | 1 + CHDataManagement/Model/Tag.swift | 22 ++++++++-- .../Preview Content/Tag+Mock.swift | 5 +++ .../Content/Pages/PageIssueView.swift | 2 +- CHDataManagement/Views/Tags/AddTagView.swift | 8 ++-- 8 files changed, 77 insertions(+), 14 deletions(-) diff --git a/CHDataManagement/Generator/PageContentGenerator.swift b/CHDataManagement/Generator/PageContentGenerator.swift index 81908d9..ec52a47 100644 --- a/CHDataManagement/Generator/PageContentGenerator.swift +++ b/CHDataManagement/Generator/PageContentGenerator.swift @@ -252,9 +252,8 @@ final class PageContentParser { return handleSvg(arguments, markdown: markdown) case .audioPlayer: return audioPlayer.process(arguments, markdown: markdown) - default: - results.invalid(command: nil, markdown) - return "" + case .tagLink: + return handleTagLink(arguments, markdown: markdown) } } @@ -439,6 +438,45 @@ final class PageContentParser { .content } + /** + Format: `![tag]()` + */ + private func handleTagLink(_ arguments: [String], markdown: Substring) -> String { + guard arguments.count == 1 else { + results.invalid(command: .tagLink, markdown) + return "" + } + let tagId = arguments[0] + + guard let tag = content.tag(tagId) else { + results.missing(tag: tagId, markdown: markdown) + return "" + } + + let localized = tag.localized(in: language) + let url = tag.absoluteUrl(for: language) + let title = localized.name + let description = localized.description ?? "" + + let image = localized.linkPreviewImage.map { image in + let size = content.settings.pages.pageLinkImageSize + results.files.insert(image) + results.imagesToGenerate.insert(.init(size: size, image: image)) + + return RelatedPageLink.Image( + url: image.absoluteUrl, + description: image.getDescription(for: language), + size: size) + } + + return RelatedPageLink( + title: title, + description: description, + url: url, + image: image) + .content + } + /** Format: `![model]()` */ diff --git a/CHDataManagement/Generator/ShorthandMarkdownKey.swift b/CHDataManagement/Generator/ShorthandMarkdownKey.swift index 5ffdaa6..f3c7b7b 100644 --- a/CHDataManagement/Generator/ShorthandMarkdownKey.swift +++ b/CHDataManagement/Generator/ShorthandMarkdownKey.swift @@ -5,10 +5,6 @@ import Foundation */ enum ShorthandMarkdownKey: String { - /// A standard url - /// Format: `![url](;)` - case url - /// An image /// Format: `![image](;]` case image @@ -37,6 +33,10 @@ enum ShorthandMarkdownKey: String { /// Format: `![page]()` case pageLink = "page" + /// A pretty link to a tag list on the site. + /// Format: `![tag]()` + case tagLink = "tag" + /// Additional HTML code include verbatim into the page. /// Format: `![html]()` case includedHtml = "html" diff --git a/CHDataManagement/Main/MainView.swift b/CHDataManagement/Main/MainView.swift index 19dfd46..7ff13f7 100644 --- a/CHDataManagement/Main/MainView.swift +++ b/CHDataManagement/Main/MainView.swift @@ -1,6 +1,7 @@ import SwiftUI import SFSafeSymbols +#warning("Button to delete file") #warning("Fix podcast") #warning("Allow selection of pages as navigation bar items") #warning("Add link to other language") diff --git a/CHDataManagement/Model/Content+Load.swift b/CHDataManagement/Model/Content+Load.swift index 4784653..d57cd6f 100644 --- a/CHDataManagement/Model/Content+Load.swift +++ b/CHDataManagement/Model/Content+Load.swift @@ -76,6 +76,7 @@ extension Content { let tags = tagData.reduce(into: [:]) { (tags, data) in tags[data.key] = Tag( + content: self, isVisible: data.value.isVisible, german: convert(data.value.german, images: images), english: convert(data.value.english, images: images)) diff --git a/CHDataManagement/Model/Tag.swift b/CHDataManagement/Model/Tag.swift index 459efa0..4cd93ce 100644 --- a/CHDataManagement/Model/Tag.swift +++ b/CHDataManagement/Model/Tag.swift @@ -1,6 +1,6 @@ import Foundation -final class Tag: ObservableObject { +final class Tag: Item { var id: String { english.urlComponent @@ -15,17 +15,19 @@ final class Tag: ObservableObject { @Published var english: LocalizedTag - init(id: String) { + init(content: Content, id: String) { self.isVisible = true self.english = .init(urlComponent: id, name: id) let deId = id + "-" + ContentLanguage.german.rawValue self.german = .init(urlComponent: deId, name: deId) + super.init(content: content) } - init(isVisible: Bool = true, german: LocalizedTag, english: LocalizedTag) { + init(content: Content, isVisible: Bool = true, german: LocalizedTag, english: LocalizedTag) { self.isVisible = isVisible self.german = german self.english = english + super.init(content: content) } var linkName: String { @@ -42,6 +44,20 @@ final class Tag: ObservableObject { case .german: return german } } + + // MARK: Paths + + func absoluteUrl(for language: ContentLanguage) -> String { + makeCleanAbsolutePath(internalPath(for: language)) + } + + func filePathRelativeToOutputFolder(for language: ContentLanguage) -> String { + makeCleanRelativePath(internalPath(for: language)) + } + + private func internalPath(for language: ContentLanguage) -> String { + content.settings.pages.pageUrlPrefix + "/" + localized(in: language).urlComponent + } } extension Tag: Identifiable { diff --git a/CHDataManagement/Preview Content/Tag+Mock.swift b/CHDataManagement/Preview Content/Tag+Mock.swift index c4eeb87..a51e670 100644 --- a/CHDataManagement/Preview Content/Tag+Mock.swift +++ b/CHDataManagement/Preview Content/Tag+Mock.swift @@ -3,25 +3,30 @@ import Foundation extension Tag { static let mock = Tag( + content: .mock, german: .german, english: .english) static let nature = Tag( + content: .mock, german: .init(urlComponent: "natur", name: "Natur"), english: .init(urlComponent: "nature", name: "Nature") ) static let sports = Tag( + content: .mock, german: .init(urlComponent: "sport", name: "Sport"), english: .init(urlComponent: "sports", name: "Sports") ) static let hiking = Tag( + content: .mock, german: .init(urlComponent: "wandern", name: "Wandern"), english: .init(urlComponent: "hiking", name: "Hiking") ) static let mountains = Tag( + content: .mock, german: .init(urlComponent: "berge", name: "Berge"), english: .init(urlComponent: "mountains", name: "Mountains") ) diff --git a/CHDataManagement/Views/Settings/Content/Pages/PageIssueView.swift b/CHDataManagement/Views/Settings/Content/Pages/PageIssueView.swift index 44da6cb..d2505ba 100644 --- a/CHDataManagement/Views/Settings/Content/Pages/PageIssueView.swift +++ b/CHDataManagement/Views/Settings/Content/Pages/PageIssueView.swift @@ -248,7 +248,7 @@ struct PageIssueView: View { return } - let tag = Tag(id: tagId) + let tag = Tag(content: content, id: tagId) content.tags.append(tag) retryPageCheck() diff --git a/CHDataManagement/Views/Tags/AddTagView.swift b/CHDataManagement/Views/Tags/AddTagView.swift index c297797..a3f9614 100644 --- a/CHDataManagement/Views/Tags/AddTagView.swift +++ b/CHDataManagement/Views/Tags/AddTagView.swift @@ -24,9 +24,11 @@ struct AddTagView: View { } private func addNewTag() { - let newTag = Tag(isVisible: true, - german: .init(urlComponent: "tag", name: "Neuer Tag"), - english: .init(urlComponent: "tag-en", name: "New Tag")) + let newTag = Tag( + content: content, + isVisible: true, + german: .init(urlComponent: "tag", name: "Neuer Tag"), + english: .init(urlComponent: "tag-en", name: "New Tag")) // Add to top of the list, and resort when changing the name content.tags.insert(newTag, at: 0) dismiss()