Custom page link texts, optional post title
This commit is contained in:
parent
1f7167b076
commit
2a50773e2f
@ -43,11 +43,10 @@ final class PostListPageGenerator {
|
|||||||
private func makePostData(post: Post) -> FeedEntryData {
|
private func makePostData(post: Post) -> FeedEntryData {
|
||||||
let localized: LocalizedPost = post.localized(in: language)
|
let localized: LocalizedPost = post.localized(in: language)
|
||||||
|
|
||||||
#warning("Add post link text to settings or to each post")
|
|
||||||
let linkUrl = post.linkedPage.map {
|
let linkUrl = post.linkedPage.map {
|
||||||
FeedEntryData.Link(
|
FeedEntryData.Link(
|
||||||
url: $0.absoluteUrl(in: language),
|
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
|
// Use the tags of the page if one is linked
|
||||||
@ -69,6 +68,7 @@ final class PostListPageGenerator {
|
|||||||
tags: tags,
|
tags: tags,
|
||||||
text: localized.text.components(separatedBy: "\n\n"),
|
text: localized.text.components(separatedBy: "\n\n"),
|
||||||
images: images)
|
images: images)
|
||||||
|
#warning("Treat post text as markdown")
|
||||||
}
|
}
|
||||||
|
|
||||||
private func createPostFeedPage(_ pageIndex: Int, pageCount: Int, posts: ArraySlice<Post>) {
|
private func createPostFeedPage(_ pageIndex: Int, pageCount: Int, posts: ArraySlice<Post>) {
|
||||||
@ -89,6 +89,7 @@ final class PostListPageGenerator {
|
|||||||
totalPages: pageCount,
|
totalPages: pageCount,
|
||||||
languageButtonUrl: languageButtonUrl,
|
languageButtonUrl: languageButtonUrl,
|
||||||
linkPrefix: source.pageUrlPrefix(for: language))
|
linkPrefix: source.pageUrlPrefix(for: language))
|
||||||
|
// Includes leading slash
|
||||||
let filePath = pageUrl(in: language, pageNumber: pageIndex) + ".html"
|
let filePath = pageUrl(in: language, pageNumber: pageIndex) + ".html"
|
||||||
guard save(fileContent, to: filePath) else {
|
guard save(fileContent, to: filePath) else {
|
||||||
source.results.unsavedOutput(filePath, source: .feed)
|
source.results.unsavedOutput(filePath, source: .feed)
|
||||||
|
@ -13,18 +13,6 @@ extension Content {
|
|||||||
originalUrl: tag.originalURL)
|
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 {
|
private func convert(_ page: LocalizedPageFile, images: [String : FileResource]) -> LocalizedPage {
|
||||||
LocalizedPage(
|
LocalizedPage(
|
||||||
content: self,
|
content: self,
|
||||||
@ -96,8 +84,8 @@ extension Content {
|
|||||||
let posts: [String : Post] = postsData.reduce(into: [:]) { dict, data in
|
let posts: [String : Post] = postsData.reduce(into: [:]) { dict, data in
|
||||||
let (postId, post) = data
|
let (postId, post) = data
|
||||||
let linkedPage = post.linkedPageId.map { pages[$0] }
|
let linkedPage = post.linkedPageId.map { pages[$0] }
|
||||||
let german = convert(post.german, images: images)
|
let german = LocalizedPost(content: self, file: post.german, images: images)
|
||||||
let english = convert(post.english, images: images)
|
let english = LocalizedPost(content: self, file: post.english, images: images)
|
||||||
|
|
||||||
dict[postId] = Post(
|
dict[postId] = Post(
|
||||||
content: self,
|
content: self,
|
||||||
|
@ -83,16 +83,3 @@ private extension Post {
|
|||||||
linkedPageId: linkedPage?.id)
|
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -12,8 +12,8 @@ extension LocalizedItem {
|
|||||||
|
|
||||||
func localized(in language: ContentLanguage) -> Localized {
|
func localized(in language: ContentLanguage) -> Localized {
|
||||||
switch language {
|
switch language {
|
||||||
case .german: return german
|
case .german: german
|
||||||
case .english: return english
|
case .english: english
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ final class LocalizedPost: ObservableObject {
|
|||||||
unowned let content: Content
|
unowned let content: Content
|
||||||
|
|
||||||
@Published
|
@Published
|
||||||
var title: String
|
var title: String?
|
||||||
|
|
||||||
@Published
|
@Published
|
||||||
var text: String
|
var text: String
|
||||||
@ -17,6 +17,10 @@ final class LocalizedPost: ObservableObject {
|
|||||||
@Published
|
@Published
|
||||||
var images: [FileResource]
|
var images: [FileResource]
|
||||||
|
|
||||||
|
/// The text to show for the link to the `linkedPage`
|
||||||
|
@Published
|
||||||
|
var pageLinkText: String?
|
||||||
|
|
||||||
@Published
|
@Published
|
||||||
var linkPreviewImage: FileResource?
|
var linkPreviewImage: FileResource?
|
||||||
|
|
||||||
@ -31,18 +35,50 @@ final class LocalizedPost: ObservableObject {
|
|||||||
text: String,
|
text: String,
|
||||||
lastModified: Date? = nil,
|
lastModified: Date? = nil,
|
||||||
images: [FileResource] = [],
|
images: [FileResource] = [],
|
||||||
|
pageLinkText: String? = nil,
|
||||||
linkPreviewImage: FileResource? = nil,
|
linkPreviewImage: FileResource? = nil,
|
||||||
linkPreviewTitle: String? = nil,
|
linkPreviewTitle: String? = nil,
|
||||||
linkPreviewDescription: String? = nil) {
|
linkPreviewDescription: String? = nil) {
|
||||||
self.content = content
|
self.content = content
|
||||||
self.title = title ?? ""
|
self.title = title
|
||||||
self.text = text
|
self.text = text
|
||||||
self.lastModified = lastModified
|
self.lastModified = lastModified
|
||||||
self.images = images
|
self.images = images
|
||||||
|
self.pageLinkText = pageLinkText
|
||||||
self.linkPreviewImage = linkPreviewImage
|
self.linkPreviewImage = linkPreviewImage
|
||||||
self.linkPreviewTitle = linkPreviewTitle
|
self.linkPreviewTitle = linkPreviewTitle
|
||||||
self.linkPreviewDescription = linkPreviewDescription
|
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 {
|
extension LocalizedPost: LinkPreviewItem {
|
||||||
|
@ -107,11 +107,17 @@ final class Post: Item {
|
|||||||
tags.append(tag)
|
tags.append(tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
func localized(in language: ContentLanguage) -> LocalizedPost {
|
/**
|
||||||
switch language {
|
A title for the UI, not the generation.
|
||||||
case .english: return english
|
*/
|
||||||
case .german: return german
|
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 {
|
func isValid(id: String) -> Bool {
|
||||||
@ -134,3 +140,7 @@ final class Post: Item {
|
|||||||
extension Post: DateItem {
|
extension Post: DateItem {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension Post: LocalizedItem {
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -11,10 +11,14 @@ final class LocalizedPostSettings: ObservableObject {
|
|||||||
@Published
|
@Published
|
||||||
var feedUrlPrefix: String
|
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.title = title
|
||||||
self.description = description
|
self.description = description
|
||||||
self.feedUrlPrefix = feedUrlPrefix
|
self.feedUrlPrefix = feedUrlPrefix
|
||||||
|
self.defaultPageLinkText = defaultPageLinkText
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Storage
|
// MARK: Storage
|
||||||
@ -23,12 +27,14 @@ final class LocalizedPostSettings: ObservableObject {
|
|||||||
self.title = file.feedTitle
|
self.title = file.feedTitle
|
||||||
self.description = file.feedDescription
|
self.description = file.feedDescription
|
||||||
self.feedUrlPrefix = file.feedUrlPrefix
|
self.feedUrlPrefix = file.feedUrlPrefix
|
||||||
|
self.defaultPageLinkText = file.defaultPageLinkText ?? "View"
|
||||||
}
|
}
|
||||||
|
|
||||||
var file: LocalizedPostSettingsFile {
|
var file: LocalizedPostSettingsFile {
|
||||||
.init(
|
.init(
|
||||||
feedTitle: title,
|
feedTitle: title,
|
||||||
feedDescription: description,
|
feedDescription: description,
|
||||||
feedUrlPrefix: feedUrlPrefix)
|
feedUrlPrefix: feedUrlPrefix,
|
||||||
|
defaultPageLinkText: defaultPageLinkText)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,13 +27,15 @@ extension LocalizedPostSettings {
|
|||||||
.init(
|
.init(
|
||||||
title: "Titel",
|
title: "Titel",
|
||||||
description: "Beschreibung",
|
description: "Beschreibung",
|
||||||
feedUrlPrefix: "blog")
|
feedUrlPrefix: "blog",
|
||||||
|
defaultPageLinkText: "Anzeigen")
|
||||||
}
|
}
|
||||||
|
|
||||||
static var english: LocalizedPostSettings {
|
static var english: LocalizedPostSettings {
|
||||||
.init(
|
.init(
|
||||||
title: "A Title",
|
title: "A Title",
|
||||||
description: "Description",
|
description: "Description",
|
||||||
feedUrlPrefix: "feed")
|
feedUrlPrefix: "feed",
|
||||||
|
defaultPageLinkText: "View")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,8 @@ struct LocalizedPostFile {
|
|||||||
|
|
||||||
let lastModifiedDate: Date?
|
let lastModifiedDate: Date?
|
||||||
|
|
||||||
|
let pageLinkText: String?
|
||||||
|
|
||||||
let linkPreviewImage: String?
|
let linkPreviewImage: String?
|
||||||
|
|
||||||
let linkPreviewTitle: String?
|
let linkPreviewTitle: String?
|
||||||
|
@ -9,6 +9,13 @@ struct LocalizedPostSettingsFile {
|
|||||||
|
|
||||||
/// The path to the feed in the final website, appended with the page number
|
/// The path to the feed in the final website, appended with the page number
|
||||||
let feedUrlPrefix: String
|
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 { }
|
extension LocalizedPostSettingsFile: Codable { }
|
||||||
@ -18,6 +25,7 @@ extension LocalizedPostSettingsFile {
|
|||||||
static var `default`: LocalizedPostSettingsFile {
|
static var `default`: LocalizedPostSettingsFile {
|
||||||
.init(feedTitle: "A title",
|
.init(feedTitle: "A title",
|
||||||
feedDescription: "A description",
|
feedDescription: "A description",
|
||||||
feedUrlPrefix: "blog")
|
feedUrlPrefix: "blog",
|
||||||
|
defaultPageLinkText: "View")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,11 @@ struct LocalizedPostDetailView: View {
|
|||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(alignment: .leading) {
|
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(
|
OptionalStringPropertyView(
|
||||||
title: "Preview Title",
|
title: "Preview Title",
|
||||||
text: $post.linkPreviewTitle,
|
text: $post.linkPreviewTitle,
|
||||||
|
@ -38,7 +38,7 @@ private struct LocalizedTitle: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
TextField("", text: $post.title)
|
OptionalTextField("", text: $post.title)
|
||||||
.font(.system(size: 24, weight: .bold))
|
.font(.system(size: 24, weight: .bold))
|
||||||
.foregroundStyle(Color.primary)
|
.foregroundStyle(Color.primary)
|
||||||
.textFieldStyle(.plain)
|
.textFieldStyle(.plain)
|
||||||
|
@ -22,7 +22,7 @@ struct PostListView: View {
|
|||||||
guard !searchString.isEmpty else {
|
guard !searchString.isEmpty else {
|
||||||
return content.posts
|
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 {
|
var body: some View {
|
||||||
@ -31,7 +31,7 @@ struct PostListView: View {
|
|||||||
.textFieldStyle(.roundedBorder)
|
.textFieldStyle(.roundedBorder)
|
||||||
.padding(.horizontal, 8)
|
.padding(.horizontal, 8)
|
||||||
List(filteredPosts, selection: $selectedPost) { post in
|
List(filteredPosts, selection: $selectedPost) { post in
|
||||||
Text(post.localized(in: language).title).tag(post)
|
Text(post.title(in: language)).tag(post)
|
||||||
}
|
}
|
||||||
}.onAppear {
|
}.onAppear {
|
||||||
if selectedPost == nil {
|
if selectedPost == nil {
|
||||||
|
@ -7,6 +7,11 @@ struct LocalizedPostFeedSettingsView: View {
|
|||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(alignment: .leading) {
|
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(
|
StringPropertyView(
|
||||||
title: "Title",
|
title: "Title",
|
||||||
text: $settings.title,
|
text: $settings.title,
|
||||||
|
@ -17,7 +17,7 @@ private struct PostSelectionView: View {
|
|||||||
let isSelected = post.contains(tag)
|
let isSelected = post.contains(tag)
|
||||||
Image(systemSymbol: isSelected ? .checkmarkCircleFill : .circle)
|
Image(systemSymbol: isSelected ? .checkmarkCircleFill : .circle)
|
||||||
.foregroundStyle(Color.blue)
|
.foregroundStyle(Color.blue)
|
||||||
Text(post.localized(in: language).title)
|
Text(post.title(in: language))
|
||||||
}
|
}
|
||||||
.contentShape(Rectangle())
|
.contentShape(Rectangle())
|
||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
|
@ -39,7 +39,7 @@ struct TagContentView: View {
|
|||||||
}
|
}
|
||||||
Section("Posts") {
|
Section("Posts") {
|
||||||
ForEach(selectedPosts) { post in
|
ForEach(selectedPosts) { post in
|
||||||
Text(post.localized(in: language).title)
|
Text(post.title(in: language))
|
||||||
}
|
}
|
||||||
Button(action: { showPostSelection = true }) {
|
Button(action: { showPostSelection = true }) {
|
||||||
Text("Select posts")
|
Text("Select posts")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user