Improve settings, sidebars
This commit is contained in:
@ -49,9 +49,9 @@ final class ImageGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
func runJobs() -> Bool {
|
||||
func runJobs(callback: (String) -> Void) -> Bool {
|
||||
for job in jobs {
|
||||
print("Generating image \(job.version)")
|
||||
callback("Generating image \(job.version)")
|
||||
guard generate(job: job) else {
|
||||
return false
|
||||
}
|
||||
@ -72,6 +72,10 @@ final class ImageGenerator {
|
||||
func generateVersion(for image: String, type: ImageType, maximumWidth: CGFloat, maximumHeight: CGFloat) -> String {
|
||||
let version = versionFileName(image: image, type: type, width: maximumWidth, height: maximumHeight)
|
||||
let fullPath = "/" + relativeImageOutputPath + "/" + version
|
||||
if exists(version) {
|
||||
hasNowGenerated(version: version, for: image)
|
||||
return fullPath
|
||||
}
|
||||
if hasPreviouslyGenerated(version: version, for: image), exists(version) {
|
||||
// Don't add job again
|
||||
return fullPath
|
||||
@ -121,6 +125,7 @@ final class ImageGenerator {
|
||||
print("Missing image \(inputPath.path())")
|
||||
return false
|
||||
}
|
||||
|
||||
let data: Data
|
||||
do {
|
||||
data = try Data(contentsOf: inputPath)
|
||||
@ -163,8 +168,16 @@ final class ImageGenerator {
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
|
||||
let result = inOutputImagesFolder { folder in
|
||||
let url = folder.appendingPathComponent(job.version)
|
||||
if job.type == .avif {
|
||||
let out = url.path()
|
||||
let input = out.replacingOccurrences(of: ".avif", with: ".jpg")
|
||||
print("avifenc -q 70 \(input) \(out)")
|
||||
return true
|
||||
}
|
||||
do {
|
||||
try data.write(to: url)
|
||||
return true
|
||||
@ -198,19 +211,20 @@ final class ImageGenerator {
|
||||
private func create(image: NSBitmapImageRep, type: ImageType, quality: CGFloat) -> Data? {
|
||||
switch type {
|
||||
case .jpg:
|
||||
return image.representation(using: .jpeg, properties: [.compressionFactor: NSNumber(value: quality)])
|
||||
return image.representation(using: .jpeg, properties: [.compressionFactor: NSNumber(value: 0.6)])
|
||||
case .png:
|
||||
return image.representation(using: .png, properties: [.compressionFactor: NSNumber(value: quality)])
|
||||
return image.representation(using: .png, properties: [.compressionFactor: NSNumber(value: 0.6)])
|
||||
case .avif:
|
||||
return createAvif(image: image, quality: quality)
|
||||
return createAvif(image: image, quality: 0.7)
|
||||
case .webp:
|
||||
return createWebp(image: image, quality: quality)
|
||||
return createWebp(image: image, quality: 0.8)
|
||||
case .gif:
|
||||
return image.representation(using: .gif, properties: [.compressionFactor: NSNumber(value: quality)])
|
||||
}
|
||||
}
|
||||
|
||||
private func createAvif(image: NSBitmapImageRep, quality: CGFloat) -> Data? {
|
||||
return Data()
|
||||
let newImage = NSImage(size: image.size)
|
||||
newImage.addRepresentation(image)
|
||||
return SDImageAVIFCoder.shared.encodedData(with: newImage, format: .AVIF, options: [.encodeCompressionQuality: quality])
|
||||
|
@ -0,0 +1,14 @@
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
extension LocalizedPostSettingsFile: Codable { }
|
@ -0,0 +1,12 @@
|
||||
|
||||
struct LocalizedSettingsFile {
|
||||
|
||||
let navigationBarIconDescription: String
|
||||
|
||||
let posts: LocalizedPostSettingsFile
|
||||
|
||||
}
|
||||
|
||||
extension LocalizedSettingsFile: Codable {
|
||||
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
|
||||
struct NavigationBarSettingsFile {
|
||||
|
||||
/// The path to the main icon in the navigation bar
|
||||
let navigationIconPath: String
|
||||
|
||||
/// The tags to show in the navigation bar
|
||||
let navigationTags: [String]
|
||||
}
|
||||
|
||||
extension NavigationBarSettingsFile: Codable { }
|
||||
|
@ -0,0 +1,12 @@
|
||||
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: CGFloat
|
||||
}
|
||||
|
||||
extension PostSettingsFile: Codable { }
|
17
CHDataManagement/Storage/Model/Settings/SettingsFile.swift
Normal file
17
CHDataManagement/Storage/Model/Settings/SettingsFile.swift
Normal file
@ -0,0 +1,17 @@
|
||||
import Foundation
|
||||
|
||||
struct SettingsFile {
|
||||
|
||||
/// The file path to the output directory
|
||||
let outputDirectoryPath: String
|
||||
|
||||
let navigationBar: NavigationBarSettingsFile
|
||||
|
||||
let posts: PostSettingsFile
|
||||
|
||||
let german: LocalizedSettingsFile
|
||||
|
||||
let english: LocalizedSettingsFile
|
||||
}
|
||||
|
||||
extension SettingsFile: Codable { }
|
@ -1,28 +0,0 @@
|
||||
import Foundation
|
||||
|
||||
struct WebsiteDataFile {
|
||||
|
||||
let navigationTags: [String]
|
||||
|
||||
let german: LocalizedWebsiteDataFile
|
||||
|
||||
let english: LocalizedWebsiteDataFile
|
||||
}
|
||||
|
||||
extension WebsiteDataFile: Codable {
|
||||
|
||||
}
|
||||
|
||||
struct LocalizedWebsiteDataFile {
|
||||
|
||||
let title: String
|
||||
|
||||
let description: String
|
||||
|
||||
let iconDescription: String
|
||||
|
||||
}
|
||||
|
||||
extension LocalizedWebsiteDataFile: Codable {
|
||||
|
||||
}
|
@ -236,17 +236,17 @@ final class Storage {
|
||||
|
||||
// MARK: Website data
|
||||
|
||||
private var websiteDataUrl: URL {
|
||||
baseFolder.appending(path: "website-data.json", directoryHint: .notDirectory)
|
||||
private var settingsDataUrl: URL {
|
||||
baseFolder.appending(path: "settings.json", directoryHint: .notDirectory)
|
||||
}
|
||||
|
||||
func loadWebsiteData() throws -> WebsiteDataFile {
|
||||
try read(at: websiteDataUrl)
|
||||
func loadSettings() throws -> SettingsFile {
|
||||
try read(at: settingsDataUrl)
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
func save(websiteData: WebsiteDataFile) -> Bool {
|
||||
write(websiteData, type: "Website Data", id: "-", to: websiteDataUrl)
|
||||
func save(settings: SettingsFile) -> Bool {
|
||||
write(settings, type: "Settings", id: "-", to: settingsDataUrl)
|
||||
}
|
||||
|
||||
// MARK: Image generation data
|
||||
|
@ -1,71 +1,61 @@
|
||||
import Foundation
|
||||
|
||||
struct WebsiteGeneratorConfiguration {
|
||||
|
||||
let language: ContentLanguage
|
||||
|
||||
let outputDirectory: URL
|
||||
|
||||
let postsPerPage: Int
|
||||
|
||||
let postFeedTitle: String
|
||||
|
||||
let postFeedDescription: String
|
||||
|
||||
let postFeedUrlPrefix: String
|
||||
|
||||
let navigationIconPath: String
|
||||
|
||||
let mainContentMaximumWidth: CGFloat
|
||||
}
|
||||
|
||||
final class WebsiteGenerator {
|
||||
|
||||
let language: ContentLanguage
|
||||
|
||||
let outputDirectory: URL
|
||||
let localizedSettings: LocalizedSettings
|
||||
|
||||
let postsPerPage: Int
|
||||
private var outputDirectory: URL {
|
||||
URL(filePath: content.settings.outputDirectoryPath)
|
||||
}
|
||||
|
||||
let postFeedTitle: String
|
||||
private var postsPerPage: Int {
|
||||
content.settings.posts.postsPerPage
|
||||
}
|
||||
|
||||
let postFeedDescription: String
|
||||
private var postFeedTitle: String {
|
||||
localizedSettings.posts.title
|
||||
}
|
||||
|
||||
let postFeedUrlPrefix: String
|
||||
private var postFeedDescription: String {
|
||||
localizedSettings.posts.description
|
||||
}
|
||||
|
||||
let navigationIconPath: String
|
||||
private var postFeedUrlPrefix: String {
|
||||
localizedSettings.posts.feedUrlPrefix
|
||||
}
|
||||
|
||||
let mainContentMaximumWidth: CGFloat
|
||||
private var navigationIconPath: String {
|
||||
content.settings.navigationBar.iconPath
|
||||
}
|
||||
|
||||
private var mainContentMaximumWidth: CGFloat {
|
||||
content.settings.posts.contentWidth
|
||||
}
|
||||
|
||||
private let content: Content
|
||||
|
||||
private let imageGenerator: ImageGenerator
|
||||
|
||||
init(content: Content, configuration: WebsiteGeneratorConfiguration) {
|
||||
self.language = configuration.language
|
||||
self.outputDirectory = configuration.outputDirectory
|
||||
self.postsPerPage = configuration.postsPerPage
|
||||
self.postFeedTitle = configuration.postFeedTitle
|
||||
self.postFeedDescription = configuration.postFeedDescription
|
||||
self.postFeedUrlPrefix = configuration.postFeedUrlPrefix
|
||||
self.navigationIconPath = configuration.navigationIconPath
|
||||
self.mainContentMaximumWidth = configuration.mainContentMaximumWidth
|
||||
|
||||
init(content: Content, language: ContentLanguage) {
|
||||
self.language = language
|
||||
self.content = content
|
||||
self.localizedSettings = content.settings.localized(in: language)
|
||||
self.imageGenerator = ImageGenerator(
|
||||
storage: content.storage,
|
||||
inputImageFolder: content.storage.filesFolder,
|
||||
relativeImageOutputPath: "images")
|
||||
}
|
||||
|
||||
func generateWebsite() -> Bool {
|
||||
func generateWebsite(callback: (String) -> Void) -> Bool {
|
||||
guard imageGenerator.prepareForGeneration() else {
|
||||
return false
|
||||
}
|
||||
guard createPostFeedPages() else {
|
||||
return false
|
||||
}
|
||||
guard imageGenerator.runJobs() else {
|
||||
guard imageGenerator.runJobs(callback: callback) else {
|
||||
return false
|
||||
}
|
||||
return imageGenerator.save()
|
||||
@ -77,7 +67,9 @@ final class WebsiteGenerator {
|
||||
return true
|
||||
}
|
||||
|
||||
let navBarData = createNavigationBarData()
|
||||
let navBarData = createNavigationBarData(
|
||||
settings: content.settings.navigationBar,
|
||||
iconDescription: localizedSettings.navigationBarIconDescription)
|
||||
|
||||
let numberOfPages = (totalCount + postsPerPage - 1) / postsPerPage // Round up
|
||||
for pageIndex in 1...numberOfPages {
|
||||
@ -91,15 +83,14 @@ final class WebsiteGenerator {
|
||||
return true
|
||||
}
|
||||
|
||||
private func createNavigationBarData() -> NavigationBarData {
|
||||
let data = content.websiteData.localized(in: language)
|
||||
let navigationItems: [NavigationBarLink] = content.websiteData.navigationTags.map {
|
||||
private func createNavigationBarData(settings: NavigationBarSettings, iconDescription: String) -> NavigationBarData {
|
||||
let navigationItems: [NavigationBarLink] = settings.tags.map {
|
||||
let localized = $0.localized(in: language)
|
||||
return .init(text: localized.name, url: localized.urlComponent)
|
||||
}
|
||||
return NavigationBarData(
|
||||
navigationIconPath: navigationIconPath,
|
||||
iconDescription: data.iconDescription,
|
||||
iconDescription: iconDescription,
|
||||
navigationItems: navigationItems)
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user