import Foundation final class PostListPageGenerator { let source: PostListPageGeneratorSource init(source: PostListPageGeneratorSource) { self.source = source } private var language: ContentLanguage { source.language } private var mainContentMaximumWidth: Int { source.content.settings.posts.contentWidth } private func pageUrl(in language: ContentLanguage, pageNumber: Int) -> String { "\(source.pageUrlPrefix(for: language))/\(pageNumber)" } func createPages(for posts: [Post]) { // Sort by newest first, filter drafts let posts = posts .filter { !$0.isDraft } .sorted(ascending: false) { $0.startDate } let totalCount = posts.count guard totalCount > 0 else { // Create one empty page createPostFeedPage(1, pageCount: 1, posts: []) return } let postsPerPage = source.postsPerPage let numberOfPages = (totalCount + postsPerPage - 1) / postsPerPage // Round up for pageIndex in 1...numberOfPages { let startIndex = (pageIndex - 1) * postsPerPage let endIndex = min(pageIndex * postsPerPage, totalCount) let postsOnPage = posts[startIndex.. FeedEntryData { let localized: LocalizedPost = post.localized(in: language) let linkUrl = post.linkedPage.map { FeedEntryData.Link( url: $0.absoluteUrl(in: language), text: localized.pageLinkText ?? post.content.settings.posts.localized(in: language).defaultPageLinkText) } // Use the tags of the page if one is linked let tags: [FeedEntryData.Tag] = post.usedTags().filter { $0.isVisible }.map { tag in .init(name: tag.localized(in: language).name, url: tag.absoluteUrl(in: language)) } let images = localized.images.map { image in image.imageSet(width: mainContentMaximumWidth, height: mainContentMaximumWidth, language: language) } images.forEach(source.results.require) return FeedEntryData( entryId: post.id, title: localized.title, textAboveTitle: post.dateText(in: language), link: linkUrl, tags: tags, text: localized.text.components(separatedBy: "\n\n"), images: images) #warning("Treat post text as markdown") } private func createPostFeedPage(_ pageIndex: Int, pageCount: Int, posts: ArraySlice) { let posts: [FeedEntryData] = posts.map(makePostData) let feedPageGenerator = FeedPageGenerator(content: source.content, results: source.results) // Includes leading slash let languageButtonUrl = pageUrl(in: language.next, pageNumber: pageIndex) let fileContent = feedPageGenerator.generatePage( language: language, posts: posts, title: source.pageTitle, description: source.pageDescription, showTitle: source.showTitle, pageNumber: pageIndex, totalPages: pageCount, languageButtonUrl: languageButtonUrl, linkPrefix: source.pageUrlPrefix(for: language)) // Includes leading slash let filePath = pageUrl(in: language, pageNumber: pageIndex) + ".html" guard save(fileContent, to: filePath) else { source.results.unsavedOutput(filePath, source: .feed) return } } private func save(_ content: String, to relativePath: String) -> Bool { source.content.storage.write(content, to: relativePath) } }