Simplify images, tag overview

This commit is contained in:
Christoph Hagen
2025-01-04 08:44:26 +01:00
parent 4d4275e072
commit 22e7d9a05a
49 changed files with 603 additions and 509 deletions

View File

@ -1,39 +1,32 @@
struct RelatedPageLink {
/**
An element showing a box with info about a related page.
struct Image {
let url: String
let description: String
let size: Int
}
Contains an optional thumbnail image, a title and a description.
*/
struct RelatedPageLink: HtmlProducer {
/// The title of the linked page
let title: String
/// A short description of the linked page
let description: String
/// The url to the linked page
let url: String
let image: Image?
/// The optional thumbnail image to display
let image: ImageSet?
var content: String {
var result = ""
func populate(_ result: inout String) {
result += "<a href='\(url)' class='related-box-wrapper'>"
result += "<div class='related-box'>"
if let image {
result += WebsiteImage(
rawImagePath: image.url,
width: image.size,
height: image.size,
altText: image.description)
.content
result += image.content
}
result += "<div class='related-content'>"
result += "<h3>\(title)</h3>"
result += "<p>\(description)</p>"
result += "</div></div></a>" // Close related-box-wrapper, related-box
return result
}
}

View File

@ -14,8 +14,7 @@ struct FeedEntry {
var content: String {
var result = "<article><div class='card\(cardLinkClassText)'>"
ImageGallery(id: data.entryId, images: data.images)
.addContent(to: &result)
ImageGallery(id: data.entryId, images: data.images).populate(&result)
if let url = data.link?.url {
result += "<div class='card-content' onclick=\"window.location.href='\(url)'\">"

View File

@ -13,9 +13,9 @@ struct FeedEntryData {
let text: [String]
let images: [Image]
let images: [ImageSet]
init(entryId: String, title: String?, textAboveTitle: String, link: Link?, tags: [Tag], text: [String], images: [Image]) {
init(entryId: String, title: String?, textAboveTitle: String, link: Link?, tags: [Tag], text: [String], images: [ImageSet]) {
self.entryId = entryId
self.title = title
self.textAboveTitle = textAboveTitle
@ -40,16 +40,4 @@ struct FeedEntryData {
let url: String
}
struct Image {
let rawImagePath: String
let width: Int
let height: Int
let altText: String
}
}

View File

@ -1,49 +1,50 @@
import Foundation
struct ImageGallery {
/**
An element showing a selection of images one by one using navigation buttons.
*/
struct ImageGallery: HtmlProducer {
/// The unique id to distinguish different galleries in HTML and JavaScript
let id: String
let images: [FeedEntryData.Image]
/// The images to display
let images: [ImageSet]
/// A version of the id that is safe to use in HTML and JavaScript
private var htmlSafeId: String {
ImageGallery.htmlSafe(id)
}
init(id: String, images: [FeedEntryData.Image]) {
init(id: String, images: [ImageSet]) {
self.id = id
self.images = images
}
func addContent(to result: inout String) {
func populate(_ result: inout String) {
guard !images.isEmpty else {
return
}
result += "<div id='\(htmlSafeId)' class='swiper'><div class='swiper-wrapper'>"
guard images.count > 1 else {
result += "<div class='swiper-slide'>"
result += WebsiteImage(image: images[0]).content
result += "</div></div></div>" // Close swiper-slide, swiper, swiper-wrapper
return
}
let needsPagination = images.count > 1
for image in images {
// TODO: Use different images based on device
result += "<div class='swiper-slide'>"
result += WebsiteImage(image: image).content
result += "<div class='swiper-lazy-preloader swiper-lazy-preloader-white'></div>"
result += image.content
if needsPagination {
result += "<div class='swiper-lazy-preloader swiper-lazy-preloader-white'></div>"
}
result += "</div>" // Close swiper-slide
}
result += "</div>" // Close swiper-wrapper
result += "<div class='swiper-button-next'></div>"
result += "<div class='swiper-button-prev'></div>"
result += "<div class='swiper-pagination'></div>"
if needsPagination {
result += "<div class='swiper-button-next'></div>"
result += "<div class='swiper-button-prev'></div>"
result += "<div class='swiper-pagination'></div>"
}
result += "</div>" // Close swiper
}

View File

@ -1,27 +1,34 @@
import Foundation
struct PageImage {
/**
An image that is part of the page content.
A tap/click on the image shows a fullscreen version of the image, including an optional caption.
*/
struct PageImage: HtmlProducer {
/// The HTML id attribute used to enable fullscreen images
let imageId: String
let thumbnail: FeedEntryData.Image
/// The small version of the image visible on the page
let thumbnail: ImageSet
let largeImage: FeedEntryData.Image
/// The large version of the image for fullscreen view
let largeImage: ImageSet
/// The optional caption text below the fullscreen image
let caption: String?
var content: String {
var result = ""
func populate(_ result: inout String) {
result += "<div class='content-image' onclick=\"document.getElementById('\(imageId)').classList.add('active')\">"
result += WebsiteImage(image: thumbnail).content
result += thumbnail.content
result += "</div>"
result += "<div id='\(imageId)' class='fullscreen-image' onclick=\"document.getElementById('\(imageId)').classList.remove('active')\">"
result += WebsiteImage(image: largeImage).content
result += largeImage.content
if let caption {
result += "<div class='caption'>\(caption)</div>"
}
result += "<div class='close'></div>"
result += "</div>"
return result
}
}

View File

@ -2,30 +2,20 @@ import Foundation
struct PostFeedPageNavigation {
let language: ContentLanguage
let linkPrefix: String
let currentPage: Int
let numberOfPages: Int
init(currentPage: Int, numberOfPages: Int, language: ContentLanguage) {
init(linkPrefix: String, currentPage: Int, numberOfPages: Int) {
self.linkPrefix = linkPrefix
self.currentPage = currentPage
self.numberOfPages = numberOfPages
self.language = language
}
private func pageLink(_ page: Int) -> String {
guard page > 1 else { return "href='/feed'" }
return "href='/feed-\(page)'"
}
private func previousText() -> String {
switch language {
case .english:
return "Previous"
case .german:
return "Zurück"
}
"href='\(linkPrefix)\(page)'"
}
private func addPreviousButton(to result: inout String) {

View File

@ -1,48 +0,0 @@
struct WebsiteImage {
static func imagePath(prefix: String, width: Int, height: Int) -> String {
"\(prefix)@\(width)x\(height)"
}
static func imagePath(prefix: String, extension fileExtension: String, width: Int, height: Int) -> String {
"\(prefix)@\(width)x\(height).\(fileExtension)"
}
static func imagePath(source: String, width: Int, height: Int) -> String {
let (prefix, ext) = source.fileNameAndExtension
return imagePath(prefix: prefix, extension: ext ?? ".jpg", width: width, height: height)
}
private let prefix1x: String
private let prefix2x: String
private let altText: String
private let ext: String
init(image: FeedEntryData.Image) {
self.init(rawImagePath: image.rawImagePath,
width: image.width,
height: image.height,
altText: image.altText)
}
init(rawImagePath: String, width: Int, height: Int, altText: String) {
let (prefix, ext) = rawImagePath.fileNameAndExtension
self.prefix1x = WebsiteImage.imagePath(prefix: prefix, width: width, height: height)
self.prefix2x = WebsiteImage.imagePath(prefix: prefix, width: 2*width, height: 2*height)
self.altText = altText.htmlEscaped()
self.ext = ext ?? "jpg"
}
var content: String {
var result = "<picture>"
result += "<source type='image/avif' srcset='\(prefix1x).avif 1x, \(prefix2x).avif 2x'/>"
result += "<source type='image/webp' srcset='\(prefix1x).webm 1x, \(prefix1x).webm 2x'/>"
result += "<img srcset='\(prefix2x).\(ext) 2x' src='\(prefix1x).\(ext)' loading='lazy' alt='\(altText)'/>"
result += "</picture>"
return result
}
}