Custom page link texts, optional post title

This commit is contained in:
Christoph Hagen 2025-01-07 10:34:36 +01:00
parent 1f7167b076
commit 2a50773e2f
16 changed files with 98 additions and 48 deletions

View File

@ -43,11 +43,10 @@ final class PostListPageGenerator {
private func makePostData(post: Post) -> FeedEntryData {
let localized: LocalizedPost = post.localized(in: language)
#warning("Add post link text to settings or to each post")
let linkUrl = post.linkedPage.map {
FeedEntryData.Link(
url: $0.absoluteUrl(in: language),
text: language == .english ? "View" : "Anzeigen")
text: localized.pageLinkText ?? post.content.settings.localized(in: language).defaultPageLinkText)
}
// Use the tags of the page if one is linked
@ -69,6 +68,7 @@ final class PostListPageGenerator {
tags: tags,
text: localized.text.components(separatedBy: "\n\n"),
images: images)
#warning("Treat post text as markdown")
}
private func createPostFeedPage(_ pageIndex: Int, pageCount: Int, posts: ArraySlice<Post>) {
@ -89,6 +89,7 @@ final class PostListPageGenerator {
totalPages: pageCount,
languageButtonUrl: languageButtonUrl,
linkPrefix: source.pageUrlPrefix(for: language))
// Includes leading slash
let filePath = pageUrl(in: language, pageNumber: pageIndex) + ".html"
guard save(fileContent, to: filePath) else {
source.results.unsavedOutput(filePath, source: .feed)

View File

@ -13,18 +13,6 @@ extension Content {
originalUrl: tag.originalURL)
}
private func convert(_ post: LocalizedPostFile, images: [String : FileResource]) -> LocalizedPost {
LocalizedPost(
content: self,
title: post.title,
text: post.content,
lastModified: post.lastModifiedDate,
images: post.images.compactMap { images[$0] },
linkPreviewImage: post.linkPreviewImage.map { images[$0] },
linkPreviewTitle: post.linkPreviewTitle,
linkPreviewDescription: post.linkPreviewDescription)
}
private func convert(_ page: LocalizedPageFile, images: [String : FileResource]) -> LocalizedPage {
LocalizedPage(
content: self,
@ -96,8 +84,8 @@ extension Content {
let posts: [String : Post] = postsData.reduce(into: [:]) { dict, data in
let (postId, post) = data
let linkedPage = post.linkedPageId.map { pages[$0] }
let german = convert(post.german, images: images)
let english = convert(post.english, images: images)
let german = LocalizedPost(content: self, file: post.german, images: images)
let english = LocalizedPost(content: self, file: post.english, images: images)
dict[postId] = Post(
content: self,

View File

@ -83,16 +83,3 @@ private extension Post {
linkedPageId: linkedPage?.id)
}
}
private extension LocalizedPost {
var postFile: LocalizedPostFile {
.init(images: images.map { $0.id },
title: title.nonEmpty,
content: text,
lastModifiedDate: lastModified,
linkPreviewImage: linkPreviewImage?.id,
linkPreviewTitle: linkPreviewTitle,
linkPreviewDescription: linkPreviewDescription)
}
}

View File

@ -12,8 +12,8 @@ extension LocalizedItem {
func localized(in language: ContentLanguage) -> Localized {
switch language {
case .german: return german
case .english: return english
case .german: german
case .english: english
}
}
}

View File

@ -6,7 +6,7 @@ final class LocalizedPost: ObservableObject {
unowned let content: Content
@Published
var title: String
var title: String?
@Published
var text: String
@ -17,6 +17,10 @@ final class LocalizedPost: ObservableObject {
@Published
var images: [FileResource]
/// The text to show for the link to the `linkedPage`
@Published
var pageLinkText: String?
@Published
var linkPreviewImage: FileResource?
@ -31,18 +35,50 @@ final class LocalizedPost: ObservableObject {
text: String,
lastModified: Date? = nil,
images: [FileResource] = [],
pageLinkText: String? = nil,
linkPreviewImage: FileResource? = nil,
linkPreviewTitle: String? = nil,
linkPreviewDescription: String? = nil) {
self.content = content
self.title = title ?? ""
self.title = title
self.text = text
self.lastModified = lastModified
self.images = images
self.pageLinkText = pageLinkText
self.linkPreviewImage = linkPreviewImage
self.linkPreviewTitle = linkPreviewTitle
self.linkPreviewDescription = linkPreviewDescription
}
init(content: Content, file: LocalizedPostFile, images: [String : FileResource]) {
self.content = content
self.title = file.title
self.text = file.content
self.lastModified = file.lastModifiedDate
self.images = file.images.compactMap { images[$0] }
self.pageLinkText = file.pageLinkText
self.linkPreviewImage = file.linkPreviewImage.map { images[$0] }
self.linkPreviewTitle = file.linkPreviewTitle
self.linkPreviewDescription = file.linkPreviewDescription
}
var postFile: LocalizedPostFile {
.init(images: images.map { $0.id },
title: title,
content: text,
lastModifiedDate: lastModified,
pageLinkText: pageLinkText,
linkPreviewImage: linkPreviewImage?.id,
linkPreviewTitle: linkPreviewTitle,
linkPreviewDescription: linkPreviewDescription)
}
func contains(_ string: String) -> Bool {
if let title, title.contains(string) {
return true
}
return text.contains(string)
}
}
extension LocalizedPost: LinkPreviewItem {

View File

@ -107,11 +107,17 @@ final class Post: Item {
tags.append(tag)
}
func localized(in language: ContentLanguage) -> LocalizedPost {
switch language {
case .english: return english
case .german: return german
}
/**
A title for the UI, not the generation.
*/
override func title(in language: ContentLanguage) -> String {
localized(in: language).title ?? id
}
func contains(_ string: String) -> Bool {
id.contains(string) ||
german.contains(string) ||
english.contains(string)
}
func isValid(id: String) -> Bool {
@ -134,3 +140,7 @@ final class Post: Item {
extension Post: DateItem {
}
extension Post: LocalizedItem {
}

View File

@ -11,10 +11,14 @@ final class LocalizedPostSettings: ObservableObject {
@Published
var feedUrlPrefix: String
init(title: String, description: String, feedUrlPrefix: String) {
@Published
var defaultPageLinkText: String
init(title: String, description: String, feedUrlPrefix: String, defaultPageLinkText: String) {
self.title = title
self.description = description
self.feedUrlPrefix = feedUrlPrefix
self.defaultPageLinkText = defaultPageLinkText
}
// MARK: Storage
@ -23,12 +27,14 @@ final class LocalizedPostSettings: ObservableObject {
self.title = file.feedTitle
self.description = file.feedDescription
self.feedUrlPrefix = file.feedUrlPrefix
self.defaultPageLinkText = file.defaultPageLinkText ?? "View"
}
var file: LocalizedPostSettingsFile {
.init(
feedTitle: title,
feedDescription: description,
feedUrlPrefix: feedUrlPrefix)
feedUrlPrefix: feedUrlPrefix,
defaultPageLinkText: defaultPageLinkText)
}
}

View File

@ -27,13 +27,15 @@ extension LocalizedPostSettings {
.init(
title: "Titel",
description: "Beschreibung",
feedUrlPrefix: "blog")
feedUrlPrefix: "blog",
defaultPageLinkText: "Anzeigen")
}
static var english: LocalizedPostSettings {
.init(
title: "A Title",
description: "Description",
feedUrlPrefix: "feed")
feedUrlPrefix: "feed",
defaultPageLinkText: "View")
}
}

View File

@ -36,6 +36,8 @@ struct LocalizedPostFile {
let lastModifiedDate: Date?
let pageLinkText: String?
let linkPreviewImage: String?
let linkPreviewTitle: String?

View File

@ -9,6 +9,13 @@ struct LocalizedPostSettingsFile {
/// The path to the feed in the final website, appended with the page number
let feedUrlPrefix: String
/**
The text to display when linking to a page
Each post may define a custom text.
*/
let defaultPageLinkText: String?
}
extension LocalizedPostSettingsFile: Codable { }
@ -18,6 +25,7 @@ extension LocalizedPostSettingsFile {
static var `default`: LocalizedPostSettingsFile {
.init(feedTitle: "A title",
feedDescription: "A description",
feedUrlPrefix: "blog")
feedUrlPrefix: "blog",
defaultPageLinkText: "View")
}
}

View File

@ -7,6 +7,11 @@ struct LocalizedPostDetailView: View {
var body: some View {
VStack(alignment: .leading) {
OptionalStringPropertyView(
title: "Custom Page Link Text",
text: $post.pageLinkText,
footer: "The custom text to show for the link to the linked page")
OptionalStringPropertyView(
title: "Preview Title",
text: $post.linkPreviewTitle,

View File

@ -38,7 +38,7 @@ private struct LocalizedTitle: View {
}
var body: some View {
TextField("", text: $post.title)
OptionalTextField("", text: $post.title)
.font(.system(size: 24, weight: .bold))
.foregroundStyle(Color.primary)
.textFieldStyle(.plain)

View File

@ -22,7 +22,7 @@ struct PostListView: View {
guard !searchString.isEmpty else {
return content.posts
}
return content.posts.filter { $0.localized(in: language).title.contains(searchString) }
return content.posts.filter { $0.contains(searchString) }
}
var body: some View {
@ -31,7 +31,7 @@ struct PostListView: View {
.textFieldStyle(.roundedBorder)
.padding(.horizontal, 8)
List(filteredPosts, selection: $selectedPost) { post in
Text(post.localized(in: language).title).tag(post)
Text(post.title(in: language)).tag(post)
}
}.onAppear {
if selectedPost == nil {

View File

@ -7,6 +7,11 @@ struct LocalizedPostFeedSettingsView: View {
var body: some View {
VStack(alignment: .leading) {
StringPropertyView(
title: "Default Page Link Text",
text: $settings.defaultPageLinkText,
footer: "The text to display when linking from a post to a page. Each post can provide a custom text.")
StringPropertyView(
title: "Title",
text: $settings.title,

View File

@ -17,7 +17,7 @@ private struct PostSelectionView: View {
let isSelected = post.contains(tag)
Image(systemSymbol: isSelected ? .checkmarkCircleFill : .circle)
.foregroundStyle(Color.blue)
Text(post.localized(in: language).title)
Text(post.title(in: language))
}
.contentShape(Rectangle())
.onTapGesture {

View File

@ -39,7 +39,7 @@ struct TagContentView: View {
}
Section("Posts") {
ForEach(selectedPosts) { post in
Text(post.localized(in: language).title)
Text(post.title(in: language))
}
Button(action: { showPostSelection = true }) {
Text("Select posts")