Add tag command

This commit is contained in:
Christoph Hagen 2024-12-14 19:02:01 +01:00
parent cdaaa36303
commit 657f8c4ef4
8 changed files with 77 additions and 14 deletions

View File

@ -252,9 +252,8 @@ final class PageContentParser {
return handleSvg(arguments, markdown: markdown) return handleSvg(arguments, markdown: markdown)
case .audioPlayer: case .audioPlayer:
return audioPlayer.process(arguments, markdown: markdown) return audioPlayer.process(arguments, markdown: markdown)
default: case .tagLink:
results.invalid(command: nil, markdown) return handleTagLink(arguments, markdown: markdown)
return ""
} }
} }
@ -439,6 +438,45 @@ final class PageContentParser {
.content .content
} }
/**
Format: `![tag](<tagId>)`
*/
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](<file>)` Format: `![model](<file>)`
*/ */

View File

@ -5,10 +5,6 @@ import Foundation
*/ */
enum ShorthandMarkdownKey: String { enum ShorthandMarkdownKey: String {
/// A standard url
/// Format: `![url](<url>;<text>)`
case url
/// An image /// An image
/// Format: `![image](<imageId>;<caption?>]` /// Format: `![image](<imageId>;<caption?>]`
case image case image
@ -37,6 +33,10 @@ enum ShorthandMarkdownKey: String {
/// Format: `![page](<pageId>)` /// Format: `![page](<pageId>)`
case pageLink = "page" case pageLink = "page"
/// A pretty link to a tag list on the site.
/// Format: `![tag](<tagId>)`
case tagLink = "tag"
/// Additional HTML code include verbatim into the page. /// Additional HTML code include verbatim into the page.
/// Format: `![html](<fileId>)` /// Format: `![html](<fileId>)`
case includedHtml = "html" case includedHtml = "html"

View File

@ -1,6 +1,7 @@
import SwiftUI import SwiftUI
import SFSafeSymbols import SFSafeSymbols
#warning("Button to delete file")
#warning("Fix podcast") #warning("Fix podcast")
#warning("Allow selection of pages as navigation bar items") #warning("Allow selection of pages as navigation bar items")
#warning("Add link to other language") #warning("Add link to other language")

View File

@ -76,6 +76,7 @@ extension Content {
let tags = tagData.reduce(into: [:]) { (tags, data) in let tags = tagData.reduce(into: [:]) { (tags, data) in
tags[data.key] = Tag( tags[data.key] = Tag(
content: self,
isVisible: data.value.isVisible, isVisible: data.value.isVisible,
german: convert(data.value.german, images: images), german: convert(data.value.german, images: images),
english: convert(data.value.english, images: images)) english: convert(data.value.english, images: images))

View File

@ -1,6 +1,6 @@
import Foundation import Foundation
final class Tag: ObservableObject { final class Tag: Item {
var id: String { var id: String {
english.urlComponent english.urlComponent
@ -15,17 +15,19 @@ final class Tag: ObservableObject {
@Published @Published
var english: LocalizedTag var english: LocalizedTag
init(id: String) { init(content: Content, id: String) {
self.isVisible = true self.isVisible = true
self.english = .init(urlComponent: id, name: id) self.english = .init(urlComponent: id, name: id)
let deId = id + "-" + ContentLanguage.german.rawValue let deId = id + "-" + ContentLanguage.german.rawValue
self.german = .init(urlComponent: deId, name: deId) 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.isVisible = isVisible
self.german = german self.german = german
self.english = english self.english = english
super.init(content: content)
} }
var linkName: String { var linkName: String {
@ -42,6 +44,20 @@ final class Tag: ObservableObject {
case .german: return german 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 { extension Tag: Identifiable {

View File

@ -3,25 +3,30 @@ import Foundation
extension Tag { extension Tag {
static let mock = Tag( static let mock = Tag(
content: .mock,
german: .german, german: .german,
english: .english) english: .english)
static let nature = Tag( static let nature = Tag(
content: .mock,
german: .init(urlComponent: "natur", name: "Natur"), german: .init(urlComponent: "natur", name: "Natur"),
english: .init(urlComponent: "nature", name: "Nature") english: .init(urlComponent: "nature", name: "Nature")
) )
static let sports = Tag( static let sports = Tag(
content: .mock,
german: .init(urlComponent: "sport", name: "Sport"), german: .init(urlComponent: "sport", name: "Sport"),
english: .init(urlComponent: "sports", name: "Sports") english: .init(urlComponent: "sports", name: "Sports")
) )
static let hiking = Tag( static let hiking = Tag(
content: .mock,
german: .init(urlComponent: "wandern", name: "Wandern"), german: .init(urlComponent: "wandern", name: "Wandern"),
english: .init(urlComponent: "hiking", name: "Hiking") english: .init(urlComponent: "hiking", name: "Hiking")
) )
static let mountains = Tag( static let mountains = Tag(
content: .mock,
german: .init(urlComponent: "berge", name: "Berge"), german: .init(urlComponent: "berge", name: "Berge"),
english: .init(urlComponent: "mountains", name: "Mountains") english: .init(urlComponent: "mountains", name: "Mountains")
) )

View File

@ -248,7 +248,7 @@ struct PageIssueView: View {
return return
} }
let tag = Tag(id: tagId) let tag = Tag(content: content, id: tagId)
content.tags.append(tag) content.tags.append(tag)
retryPageCheck() retryPageCheck()

View File

@ -24,7 +24,9 @@ struct AddTagView: View {
} }
private func addNewTag() { private func addNewTag() {
let newTag = Tag(isVisible: true, let newTag = Tag(
content: content,
isVisible: true,
german: .init(urlComponent: "tag", name: "Neuer Tag"), german: .init(urlComponent: "tag", name: "Neuer Tag"),
english: .init(urlComponent: "tag-en", name: "New Tag")) english: .init(urlComponent: "tag-en", name: "New Tag"))
// Add to top of the list, and resort when changing the name // Add to top of the list, and resort when changing the name