Generate tag overview, add file action
This commit is contained in:
@ -11,6 +11,7 @@ extension Content {
|
||||
|
||||
self.copyRequiredFiles()
|
||||
self.generateRequiredImages()
|
||||
self.results.recalculate()
|
||||
self.status("Generation completed")
|
||||
}
|
||||
}
|
||||
@ -61,9 +62,6 @@ extension Content {
|
||||
}
|
||||
|
||||
private func generateRequiredImages() {
|
||||
let imageGenerator = ImageGenerator(
|
||||
storage: storage,
|
||||
settings: settings)
|
||||
|
||||
let images = results.imagesToGenerate.sorted()
|
||||
let count = images.count
|
||||
@ -255,7 +253,7 @@ extension Content {
|
||||
guard shouldGenerateWebsite else { return }
|
||||
let results = results.makeResults(for: .tagOverview, in: language)
|
||||
let generator = TagOverviewGenerator(content: self, language: language, results: results)
|
||||
generator.generatePage(tags: tags, overview: tagOverview)
|
||||
generator.generatePages(tags: tags, overview: tagOverview)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@ extension Content {
|
||||
subtitle: tag.subtitle,
|
||||
description: tag.description,
|
||||
thumbnail: tag.thumbnail.map { images[$0] },
|
||||
linkPreviewTitle: tag.linkPreviewTitle,
|
||||
originalUrl: tag.originalURL)
|
||||
}
|
||||
|
||||
|
@ -129,6 +129,7 @@ private extension LocalizedTag {
|
||||
name: name,
|
||||
subtitle: subtitle,
|
||||
description: description,
|
||||
linkPreviewTitle: linkPreviewTitle,
|
||||
thumbnail: linkPreviewImage?.id,
|
||||
originalURL: originalUrl)
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ extension Content {
|
||||
private static let disallowedCharactersInFileIds = CharacterSet.alphanumerics.union(CharacterSet(charactersIn: "-.")).inverted
|
||||
|
||||
func isNewIdForTag(_ id: String) -> Bool {
|
||||
!tags.contains { $0.id == id }
|
||||
tagOverview?.id != id && !tags.contains { $0.id == id }
|
||||
}
|
||||
|
||||
func isNewIdForPage(_ id: String) -> Bool {
|
||||
|
@ -37,6 +37,8 @@ final class Content: ObservableObject {
|
||||
@Published
|
||||
private(set) var shouldGenerateWebsite = false
|
||||
|
||||
let imageGenerator: ImageGenerator
|
||||
|
||||
init(settings: Settings,
|
||||
posts: [Post],
|
||||
pages: [Page],
|
||||
@ -53,6 +55,9 @@ final class Content: ObservableObject {
|
||||
|
||||
let storage = Storage()
|
||||
self.storage = storage
|
||||
self.imageGenerator = ImageGenerator(
|
||||
storage: storage,
|
||||
settings: settings)
|
||||
}
|
||||
|
||||
init() {
|
||||
@ -67,6 +72,9 @@ final class Content: ObservableObject {
|
||||
|
||||
let storage = Storage()
|
||||
self.storage = storage
|
||||
self.imageGenerator = ImageGenerator(
|
||||
storage: storage,
|
||||
settings: settings)
|
||||
}
|
||||
|
||||
private func clear() {
|
||||
@ -112,4 +120,9 @@ final class Content: ObservableObject {
|
||||
print("Failed to reload content: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
func remove(_ file: FileResource) {
|
||||
files.remove(file)
|
||||
#warning("Remove file from required files, thumbnails, post images, etc.")
|
||||
}
|
||||
}
|
||||
|
@ -14,8 +14,13 @@ final class FileResource: Item {
|
||||
@Published
|
||||
var english: String
|
||||
|
||||
/// The dimensions of the image
|
||||
@Published
|
||||
var size: CGSize = .zero
|
||||
var imageDimensions: CGSize? = nil
|
||||
|
||||
/// The size of the file in bytes
|
||||
@Published
|
||||
var fileSize: Int? = nil
|
||||
|
||||
init(content: Content, id: String, isExternallyStored: Bool, en: String, de: String) {
|
||||
self.type = FileType(fileExtension: id.fileExtension)
|
||||
@ -49,10 +54,13 @@ final class FileResource: Item {
|
||||
// MARK: Images
|
||||
|
||||
var aspectRatio: CGFloat {
|
||||
guard size.height > 0 else {
|
||||
guard let imageDimensions else {
|
||||
return 0
|
||||
}
|
||||
return size.width / size.height
|
||||
guard imageDimensions.height > 0 else {
|
||||
return 0
|
||||
}
|
||||
return imageDimensions.width / imageDimensions.height
|
||||
}
|
||||
|
||||
var imageToDisplay: Image {
|
||||
@ -60,18 +68,58 @@ final class FileResource: Item {
|
||||
print("Failed to load data for image \(id)")
|
||||
return failureImage
|
||||
}
|
||||
if fileSize == nil {
|
||||
DispatchQueue.main.async {
|
||||
self.fileSize = imageData.count
|
||||
}
|
||||
}
|
||||
guard let loadedImage = NSImage(data: imageData) else {
|
||||
print("Failed to create image \(id)")
|
||||
return failureImage
|
||||
}
|
||||
if self.size == .zero && loadedImage.size != .zero {
|
||||
if loadedImage.size != imageDimensions {
|
||||
DispatchQueue.main.async {
|
||||
self.size = loadedImage.size
|
||||
self.imageDimensions = loadedImage.size
|
||||
}
|
||||
}
|
||||
return .init(nsImage: loadedImage)
|
||||
}
|
||||
|
||||
func determineImageDimensions() {
|
||||
let size = getImageDimensions()
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.imageDimensions = size
|
||||
}
|
||||
}
|
||||
|
||||
private func getImageDimensions() -> CGSize? {
|
||||
guard type.isImage else {
|
||||
return nil
|
||||
}
|
||||
guard let imageData = content.storage.fileData(for: id) else {
|
||||
return nil
|
||||
}
|
||||
guard let loadedImage = NSImage(data: imageData) else {
|
||||
return nil
|
||||
}
|
||||
return loadedImage.size
|
||||
}
|
||||
|
||||
func determineFileSize() {
|
||||
DispatchQueue.global(qos: .userInitiated).async {
|
||||
let size = self.content.storage.size(of: self.id)
|
||||
DispatchQueue.main.async {
|
||||
self.fileSize = size
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func removeGeneratedImages() {
|
||||
content.imageGenerator.removeVersions(of: id)
|
||||
content.storage.deleteInOutputFolder(path: outputImageFolder)
|
||||
}
|
||||
|
||||
private var failureImage: Image {
|
||||
Image(systemSymbol: .exclamationmarkTriangle)
|
||||
}
|
||||
@ -105,6 +153,13 @@ final class FileResource: Item {
|
||||
|
||||
// MARK: Paths
|
||||
|
||||
func removeFileFromOutputFolder() {
|
||||
content.storage.deleteInOutputFolder(path: absoluteUrl)
|
||||
if type.isImage {
|
||||
removeGeneratedImages()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Get the url path to a file in the output folder.
|
||||
The result is an absolute path from the output folder for use in HTML.
|
||||
|
@ -4,6 +4,10 @@ class Item: ObservableObject, Identifiable {
|
||||
|
||||
unowned let content: Content
|
||||
|
||||
/// A dummy property to force views to update when properties change
|
||||
@Published
|
||||
private var changeToggle = false
|
||||
|
||||
@Published
|
||||
var id: String
|
||||
|
||||
@ -12,6 +16,10 @@ class Item: ObservableObject, Identifiable {
|
||||
self.id = id
|
||||
}
|
||||
|
||||
func didChange() {
|
||||
changeToggle.toggle()
|
||||
}
|
||||
|
||||
func makeCleanAbsolutePath(_ path: String) -> String {
|
||||
"/" + makeCleanRelativePath(path)
|
||||
}
|
||||
|
@ -21,6 +21,9 @@ final class LocalizedTag: ObservableObject {
|
||||
@Published
|
||||
var linkPreviewImage: FileResource?
|
||||
|
||||
@Published
|
||||
var linkPreviewTitle: String?
|
||||
|
||||
/// The original url in the previous site layout
|
||||
let originalUrl: String?
|
||||
|
||||
@ -30,6 +33,7 @@ final class LocalizedTag: ObservableObject {
|
||||
subtitle: String? = nil,
|
||||
description: String? = nil,
|
||||
thumbnail: FileResource? = nil,
|
||||
linkPreviewTitle: String? = nil,
|
||||
originalUrl: String? = nil) {
|
||||
self.content = content
|
||||
self.urlComponent = urlComponent
|
||||
@ -37,6 +41,7 @@ final class LocalizedTag: ObservableObject {
|
||||
self.subtitle = subtitle
|
||||
self.description = description
|
||||
self.linkPreviewImage = thumbnail
|
||||
self.linkPreviewTitle = linkPreviewTitle
|
||||
self.originalUrl = originalUrl
|
||||
}
|
||||
|
||||
@ -48,10 +53,6 @@ final class LocalizedTag: ObservableObject {
|
||||
|
||||
extension LocalizedTag: LinkPreviewItem {
|
||||
|
||||
var linkPreviewTitle: String? {
|
||||
self.name
|
||||
}
|
||||
|
||||
var linkPreviewDescription: String? {
|
||||
description
|
||||
}
|
||||
|
@ -26,12 +26,19 @@ final class Tag: Item {
|
||||
super.init(content: content, id: id)
|
||||
}
|
||||
|
||||
var linkName: String {
|
||||
id.lowercased().replacingOccurrences(of: " ", with: "-")
|
||||
func isValid(id: String) -> Bool {
|
||||
content.isValidIdForTagOrPageOrPost(id) &&
|
||||
content.isNewIdForTag(id)
|
||||
}
|
||||
|
||||
var url: String {
|
||||
"/tags/\(linkName).html"
|
||||
@discardableResult
|
||||
func update(id newId: String) -> Bool {
|
||||
guard content.storage.move(tag: id, to: newId) else {
|
||||
print("Failed to move files of tag \(id)")
|
||||
return false
|
||||
}
|
||||
id = newId
|
||||
return true
|
||||
}
|
||||
|
||||
// MARK: Paths
|
||||
|
Reference in New Issue
Block a user