Simplify images, tag overview
This commit is contained in:
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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)'\">"
|
||||
|
@ -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
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user