2026-08-19 22:55:00 +02:00
import Elementary
import Foundation
import Infrastructure
import Localization
/// The website's landing page, with its text localized to a given locale.
struct IndexPage {
// MARK: Properties
/// The analytics tracker embedded as a deferred script in the document head, or `nil` to omit it.
let analytics : Analytics ?
/// The version token appended to the page's asset URLs, or `nil` to leave them unversioned.
let assetVersion : String ?
/// The locale the page content is localized to.
let locale : Locale
2026-09-04 13:40:35 +00:00
/// The public origin the page derives its canonical URL and language alternates from, or `nil` to omit them.
let siteOrigin : String ?
2026-08-19 22:55:00 +02:00
/// Resolves the page's text from the bundled String Catalog for the page's ``locale``.
private let localize : Localize
// MARK: Initializers
/// Creates a landing page localized to the given locale.
/// - Parameters:
/// - locale: the locale the page content is localized to.
/// - assetVersion: the version token appended to the page's asset URLs, or `nil` (the default) to leave them unversioned.
2026-09-04 13:40:35 +00:00
/// - siteOrigin: the public origin the page derives its canonical URL and language alternates from, or `nil` (the default) to omit them.
2026-08-19 22:55:00 +02:00
/// - analytics: the analytics tracker embedded in the document head, or `nil` (the default) to omit it.
init (
locale : Locale ,
assetVersion : String ? = nil ,
2026-09-04 13:40:35 +00:00
siteOrigin : String ? = nil ,
2026-08-19 22:55:00 +02:00
analytics : Analytics ? = nil
) {
self . analytics = analytics
self . assetVersion = assetVersion
self . locale = locale
2026-09-04 13:40:35 +00:00
self . siteOrigin = siteOrigin
2026-08-19 22:55:00 +02:00
self . localize = . init ( bundle : . module )
}
}
// MARK: - Page
extension IndexPage : Page {
2026-09-04 13:40:35 +00:00
// MARK: Constants
/// The path the page is served at; ``RootController`` registers its route against it, and the page builds its canonical URL from it.
static let path = "/"
// MARK: Computed
/// The canonical URL of the page's edition in its language, or `nil` when the origin is unknown.
///
/// The origin alone for the default language, since canonical URLs carry no trailing slash — `TrailingSlashRedirectMiddleware` enforces
/// that on every path but the root, which has nothing to strip.
var canonicalURL : String ? {
siteOrigin . map {
Language ( of : locale ). url (
origin : $0 ,
path : Self . path
)
}
}
/// The site-wide metadata, preceded by the `hreflang` alternates tying the page's language editions together.
@ HTMLBuilder
var metadata : some HTML {
languageAlternates (
origin : siteOrigin ,
path : Self . path
)
siteMetadata
}
2026-08-19 22:55:00 +02:00
// MARK: Properties
2026-09-21 10:22:55 +02:00
/// The hero alone, until the listings exist.
2026-08-19 22:55:00 +02:00
var content : some HTML {
2026-09-21 10:22:55 +02:00
SiteLayout {
div (. class ( "page" )) {
section (. class ( "hero" )) {
p (. class ( "type-eyebrow" )) {
"Single issues · Manga · Trades · Hardcovers"
}
h1 (. class ( "type-hero" )) {
localize ( "index.heading" , locale : locale )
}
p (. class ( "type-lead" )) {
"Search every listing by title, print and grade. Browse any seller's shop without an account — sign in with a passkey only when you're ready to buy, make an offer or message."
}
div (. class ( "hero__actions" )) {
a (
. class ( "button button--primary button--lg" ),
. href ( Format . singleIssues . path )
) {
"Browse single issues"
}
a (
. class ( "button button--outline button--lg" ),
. href (. Route . series )
) {
"Browse by series"
}
}
}
}
2026-08-19 22:55:00 +02:00
}
}
var scripts : [ any Asset ] {
[ StaticFile . index , StaticFile . shared ]
}
var stylesheets : [ any Asset ] {
[ StaticFile . shared , StaticFile . index ]
}
var title : String {
localize ( "index.title" , locale : locale )
}
}