Rework storage structs, link preview

This commit is contained in:
Christoph Hagen
2025-01-08 14:59:04 +01:00
parent b99c064d10
commit a7197b9628
75 changed files with 1365 additions and 1454 deletions

View File

@ -1,13 +0,0 @@
struct FileDescriptions {
let fileId: String
let german: String?
let english: String?
}
extension FileDescriptions: Codable {
}

View File

@ -1,36 +0,0 @@
import Foundation
/**
This struct holds metadata about a file resource that is stored in the content folder.
*/
struct FileResourceFile {
/// The file/image description in German
let englishDescription: String?
/// The file/image description in English
let germanDescription: String?
/// The list of generated image versions for this image
let generatedImages: [String]?
/// A custom file path in the output folder where this file is located
let customOutputPath: String?
/// A version string of this resource, mostly for assets
let version: String?
/// A URL where the resource was copied/downloaded from
let sourceUrl: String?
/// The date when the file was added
let addedDate: Date
/// The date when the file was last modified
let modifiedDate: Date
}
extension FileResourceFile: Codable {
}

View File

@ -1,58 +0,0 @@
import Foundation
struct PageFile {
let isDraft: Bool
let externalLink: String?
let tags: [String]
let hideDate: Bool?
let createdDate: Date
let startDate: Date
let endDate: Date?
let german: LocalizedPageFile
let english: LocalizedPageFile
/**
Specifies additional files which should be copied to the destination when generating the content.
- Note: This property defaults to an empty set.
*/
let requiredFiles: [String]?
}
extension PageFile: Codable {
}
/**
The structure to store the metadata of a localized page
*/
struct LocalizedPageFile {
let url: String
let title: String
let linkPreviewImage: String?
let linkPreviewTitle: String?
let linkPreviewDescription: String?
let lastModifiedDate: Date?
let originalURL: String?
let hideTitle: Bool?
}
extension LocalizedPageFile: Codable {
}

View File

@ -1,50 +0,0 @@
import Foundation
struct PostFile {
let isDraft: Bool
let createdDate: Date
let startDate: Date
let endDate: Date?
let tags: [String]
let german: LocalizedPostFile
let english: LocalizedPostFile
let linkedPageId: String?
}
extension PostFile: Codable {
}
/**
The structure to store the metadata of a localized post
*/
struct LocalizedPostFile {
let images: [String]
let title: String?
let content: String
let lastModifiedDate: Date?
let pageLinkText: String?
let linkPreviewImage: String?
let linkPreviewTitle: String?
let linkPreviewDescription: String?
}
extension LocalizedPostFile: Codable {
}

View File

@ -1,24 +0,0 @@
struct AudioPlayerSettingsFile: Codable {
let playlistCoverImageSize: Int
let smallCoverImageSize: Int
let audioPlayerJsFile: String?
let audioPlayerCssFile: String?
let german: LocalizedAudioPlayerSettingsFile
let english: LocalizedAudioPlayerSettingsFile
}
struct LocalizedAudioPlayerSettingsFile: Codable {
let playlistText: String
}
extension AudioPlayerSettingsFile: LocalizedItem {
}

View File

@ -1,17 +0,0 @@
import Foundation
struct LocalizedNavigationSettingsFile {
let rootUrl: String
}
extension LocalizedNavigationSettingsFile: Codable {
}
extension LocalizedNavigationSettingsFile {
static var `default`: LocalizedNavigationSettingsFile {
.init(rootUrl: "/")
}
}

View File

@ -1,23 +0,0 @@
struct LocalizedPageSettingsFile {
let emptyPageTitle: String
let emptyPageText: String
init(emptyPageTitle: String, emptyPageText: String) {
self.emptyPageTitle = emptyPageTitle
self.emptyPageText = emptyPageText
}
}
extension LocalizedPageSettingsFile: Codable {
}
extension LocalizedPageSettingsFile {
static var `default`: LocalizedPageSettingsFile {
.init(emptyPageTitle: "Empty Page", emptyPageText: "This page is empty.")
}
}

View File

@ -1,31 +0,0 @@
struct LocalizedPostSettingsFile {
/// The page title for the post feed
let feedTitle: String
/// The page description for the post feed
let feedDescription: String
/// 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 { }
extension LocalizedPostSettingsFile {
static var `default`: LocalizedPostSettingsFile {
.init(feedTitle: "A title",
feedDescription: "A description",
feedUrlPrefix: "blog",
defaultPageLinkText: "View")
}
}

View File

@ -1,25 +0,0 @@
import Foundation
struct NavigationSettingsFile {
/// The tags to show in the navigation bar
let navigationItems: [String]
let german: LocalizedNavigationSettingsFile
let english: LocalizedNavigationSettingsFile
}
extension NavigationSettingsFile: Codable {
}
extension NavigationSettingsFile {
static var `default`: NavigationSettingsFile {
.init(
navigationItems: [],
german: .default,
english: .default)
}
}

View File

@ -1,47 +0,0 @@
struct PageSettingsFile {
let contentWidth: Int
let largeImageWidth: Int
let pageLinkImageSize: Int
let defaultCssFile: String?
let codeHighlightingJsFile: String?
let modelViewerJsFile: String?
let imageCompareJsFile: String?
let imageCompareCssFile: String?
let german: LocalizedPageSettingsFile
let english: LocalizedPageSettingsFile
}
extension PageSettingsFile: Codable {
}
extension PageSettingsFile {
static var `default`: PageSettingsFile {
.init(contentWidth: 600,
largeImageWidth: 1200,
pageLinkImageSize: 180,
defaultCssFile: nil,
codeHighlightingJsFile: nil,
modelViewerJsFile: nil,
imageCompareJsFile: nil,
imageCompareCssFile: nil,
german: .default,
english: .default)
}
}
extension PageSettingsFile: LocalizedItem {
}

View File

@ -1,52 +0,0 @@
struct PathSettingsFile {
let assetsOutputFolderPath: String
let pagesOutputFolderPath: String
let imagesOutputFolderPath: String
let filesOutputFolderPath: String
let videosOutputFolderPath: String
let tagsOutputFolderPath: String
let audioOutputFolderPath: String
init(assetsOutputFolderPath: String,
pagesOutputFolderPath: String,
imagesOutputFolderPath: String,
filesOutputFolderPath: String,
videosOutputFolderPath: String,
tagsOutputFolderPath: String,
audioOutputFolderPath: String) {
self.assetsOutputFolderPath = assetsOutputFolderPath
self.pagesOutputFolderPath = pagesOutputFolderPath
self.imagesOutputFolderPath = imagesOutputFolderPath
self.filesOutputFolderPath = filesOutputFolderPath
self.videosOutputFolderPath = videosOutputFolderPath
self.tagsOutputFolderPath = tagsOutputFolderPath
self.audioOutputFolderPath = audioOutputFolderPath
}
}
extension PathSettingsFile: Codable {
}
extension PathSettingsFile {
static var `default`: PathSettingsFile {
PathSettingsFile(
assetsOutputFolderPath: "asset",
pagesOutputFolderPath: "page",
imagesOutputFolderPath: "image",
filesOutputFolderPath: "file",
videosOutputFolderPath: "video",
tagsOutputFolderPath: "tag",
audioOutputFolderPath: "audio")
}
}

View File

@ -1,35 +0,0 @@
import Foundation
struct PostSettingsFile {
/// The number of posts to show in a single page of the news feed
let postsPerPage: Int
/// The maximum width of the main content
let contentWidth: Int
let swiperCssFile: String?
let swiperJsFile: String?
let defaultCssFile: String?
let german: LocalizedPostSettingsFile
let english: LocalizedPostSettingsFile
}
extension PostSettingsFile: Codable { }
extension PostSettingsFile {
static var `default`: PostSettingsFile {
.init(postsPerPage: 25,
contentWidth: 600,
swiperCssFile: nil,
swiperJsFile: nil,
defaultCssFile: nil,
german: .default,
english: .default)
}
}

View File

@ -1,33 +0,0 @@
import Foundation
struct SettingsFile {
let paths: PathSettingsFile
/// The tags to show in the navigation bar
let navigation: NavigationSettingsFile
let posts: PostSettingsFile
let pages: PageSettingsFile
let audioPlayer: AudioPlayerSettingsFile
let tagOverview: TagOverviewFile?
}
extension SettingsFile: Codable { }
extension SettingsFile {
static var `default`: SettingsFile {
.init(
paths: .default,
navigation: .default,
posts: .default,
pages: .default,
audioPlayer: AudioPlayerSettings.default.file,
tagOverview: nil
)
}
}

View File

@ -1,31 +0,0 @@
struct TagOverviewFile {
let german: LocalizedTagOverviewFile
let english: LocalizedTagOverviewFile
}
extension TagOverviewFile: Codable {
}
/**
The structure to store the metadata of a localized page
*/
struct LocalizedTagOverviewFile {
let url: String
let title: String
let linkPreviewImage: String?
let linkPreviewTitle: String?
let linkPreviewDescription: String?
}
extension LocalizedTagOverviewFile: Codable {
}

View File

@ -1,41 +0,0 @@
import Foundation
struct TagFile {
let id: String
let isVisible: Bool
let german: LocalizedTagFile
let english: LocalizedTagFile
}
extension TagFile: Codable {
}
struct LocalizedTagFile {
/// The id of the tag, used also as a url component
let urlComponent: String
/// A custom name, different from the tag id
let name: String
let linkPreviewTitle: String?
let linkPreviewDescription: String?
/// The image id of the thumbnail
let linkPreviewImage: String?
/// The original url in the previous site layout
let originalURL: String?
}
extension LocalizedTagFile: Codable {
}

View File

@ -312,6 +312,7 @@ struct SecurityBookmark {
do {
data = try Data(contentsOf: url)
} catch {
#warning("Get these errors")
print("Storage: Failed to read file \(url.path()): \(error)")
return
}

View File

@ -34,6 +34,7 @@ final class Storage: ObservableObject {
// MARK: Properties
#warning("Rework to make this non-optional by creating a wrapper class")
@Published
var contentScope: SecurityBookmark?
@ -72,13 +73,13 @@ final class Storage: ObservableObject {
return contentScope.write(pageContent, to: path)
}
func save(pageMetadata: PageFile, for pageId: String) -> Bool {
func save(pageMetadata: Page.Data, for pageId: String) -> Bool {
guard let contentScope else { return false }
let path = pageMetadataPath(page: pageId)
return contentScope.encode(pageMetadata, to: path)
}
func loadAllPages() -> [String : PageFile]? {
func loadAllPages() -> [String : Page.Data]? {
contentScope?.decodeJsonFiles(in: pagesFolderName)
}
@ -144,13 +145,13 @@ final class Storage: ObservableObject {
postsFolderName + "/" + postFileName(postId)
}
func save(post: PostFile, for postId: String) -> Bool {
func save(post: Post.Data, for postId: String) -> Bool {
guard let contentScope else { return false }
let path = postFilePath(post: postId)
return contentScope.encode(post, to: path)
}
func loadAllPosts() -> [String : PostFile]? {
func loadAllPosts() -> [String : Post.Data]? {
contentScope?.decodeJsonFiles(in: postsFolderName)
}
@ -183,13 +184,13 @@ final class Storage: ObservableObject {
tagsFolderName + "/" + tagFileName(tagId: tagId)
}
func save(tagMetadata: TagFile, for tagId: String) -> Bool {
func save(tagMetadata: Tag.Data, for tagId: String) -> Bool {
guard let contentScope else { return false }
let path = tagFilePath(tag: tagId)
return contentScope.encode(tagMetadata, to: path)
}
func loadAllTags() -> [String : TagFile]? {
func loadAllTags() -> [String : Tag.Data]? {
contentScope?.decodeJsonFiles(in: tagsFolderName)
}
@ -311,9 +312,9 @@ final class Storage: ObservableObject {
- Returns: A dictionary with the file ids as keys and the metadata file as a value.
*/
func loadAllFiles() -> [String : (data: FileResourceFile, isExternal: Bool)]? {
func loadAllFiles() -> [String : (data: FileResource.Data, isExternal: Bool)]? {
guard let contentScope else { return nil }
guard let list: [String : FileResourceFile] = contentScope.decodeJsonFiles(in: fileInfoFolderName) else {
guard let list: [String : FileResource.Data] = contentScope.decodeJsonFiles(in: fileInfoFolderName) else {
return nil
}
guard let existingFiles = contentScope.fileNames(inRelativeFolder: filesFolderName).map(Set.init) else {
@ -326,7 +327,7 @@ final class Storage: ObservableObject {
}
@discardableResult
func save(fileInfo: FileResourceFile, for fileId: String) -> Bool {
func save(fileInfo: FileResource.Data, for fileId: String) -> Bool {
guard let contentScope else { return false }
let path = fileInfoPath(file: fileId)
return contentScope.encode(fileInfo, to: path)
@ -359,12 +360,12 @@ final class Storage: ObservableObject {
// MARK: Settings
func loadSettings() -> SettingsFile? {
func loadSettings() -> Settings.Data? {
guard let contentScope else { return nil }
return contentScope.decode(at: settingsDataFileName)
}
func save(settings: SettingsFile) -> Bool {
func save(settings: Settings.Data) -> Bool {
guard let contentScope else { return false }
return contentScope.encode(settings, to: settingsDataFileName)
}