211 lines
4.8 KiB
Swift
211 lines
4.8 KiB
Swift
import Plot
|
|
import Publish
|
|
|
|
public extension Theme {
|
|
static var minimal: Self {
|
|
Theme(
|
|
htmlFactory: FoundationHTMLFactory(),
|
|
resourcePaths: ["Resources/styles.css"]
|
|
)
|
|
}
|
|
}
|
|
|
|
private struct FoundationHTMLFactory<Site: Website>: HTMLFactory {
|
|
func makeIndexHTML(for index: Index, context: PublishingContext<Site>) throws -> HTML {
|
|
HTML(
|
|
.lang(context.site.language),
|
|
.head(for: index, on: context.site),
|
|
.body {
|
|
SiteHeader(context: context, selectedSelectionID: nil)
|
|
Wrapper {
|
|
H1(index.title)
|
|
Paragraph(context.site.description)
|
|
.class("description")
|
|
H2("Latest content")
|
|
ItemList(
|
|
items: context.allItems(
|
|
sortedBy: \.date,
|
|
order: .descending
|
|
),
|
|
site: context.site
|
|
)
|
|
}
|
|
SiteFooter()
|
|
}
|
|
)
|
|
}
|
|
|
|
func makeSectionHTML(for section: Section<Site>, context: PublishingContext<Site>) throws -> HTML {
|
|
HTML(
|
|
.lang(context.site.language),
|
|
.head(for: section, on: context.site),
|
|
.body {
|
|
SiteHeader(context: context, selectedSelectionID: section.id)
|
|
Wrapper {
|
|
H1(section.title)
|
|
ItemList(items: section.items, site: context.site)
|
|
}
|
|
SiteFooter()
|
|
}
|
|
)
|
|
}
|
|
|
|
func makeItemHTML(for item: Item<Site>, context: PublishingContext<Site>) throws -> HTML {
|
|
HTML(
|
|
.lang(context.site.language),
|
|
.head(for: item, on: context.site),
|
|
.body(
|
|
.class("item-page"),
|
|
.components {
|
|
SiteHeader(context: context, selectedSelectionID: item.sectionID)
|
|
Wrapper {
|
|
Article {
|
|
Div(item.content.body).class("content")
|
|
Span("Tagged with: ")
|
|
ItemTagList(item: item, site: context.site)
|
|
}
|
|
}
|
|
SiteFooter()
|
|
}
|
|
)
|
|
)
|
|
}
|
|
|
|
func makePageHTML(for page: Page, context: PublishingContext<Site>) throws -> HTML {
|
|
HTML(.lang(context.site.language),
|
|
.head(for: page, on: context.site),
|
|
.body {
|
|
SiteHeader(context: context, selectedSelectionID: nil)
|
|
Wrapper(page.body)
|
|
SiteFooter()
|
|
})
|
|
}
|
|
|
|
func makeTagListHTML(for page: TagListPage, context: PublishingContext<Site>) throws -> HTML? {
|
|
HTML(.lang(context.site.language),
|
|
.head(for: page, on: context.site),
|
|
.body {
|
|
SiteHeader(context: context, selectedSelectionID: nil)
|
|
Wrapper {
|
|
H1("Browse all tags")
|
|
List(page.tags.sorted()) { tag in
|
|
ListItem {
|
|
Link(tag.string,
|
|
url: context.site.path(for: tag).absoluteString)
|
|
}
|
|
.class("tag")
|
|
}
|
|
.class("all-tags")
|
|
}
|
|
SiteFooter()
|
|
})
|
|
}
|
|
|
|
func makeTagDetailsHTML(for page: TagDetailsPage, context: PublishingContext<Site>) throws -> HTML? {
|
|
HTML(.lang(context.site.language),
|
|
.head(for: page, on: context.site),
|
|
.body {
|
|
SiteHeader(context: context, selectedSelectionID: nil)
|
|
Wrapper {
|
|
H1 {
|
|
Text("Tagged with ")
|
|
Span(page.tag.string).class("tag")
|
|
}
|
|
|
|
Link("Browse all tags",
|
|
url: context.site.tagListPath.absoluteString)
|
|
.class("browse-all")
|
|
|
|
ItemList(
|
|
items: context.items(
|
|
taggedWith: page.tag,
|
|
sortedBy: \.date,
|
|
order: .descending
|
|
),
|
|
site: context.site
|
|
)
|
|
}
|
|
SiteFooter()
|
|
})
|
|
}
|
|
}
|
|
|
|
private struct Wrapper: ComponentContainer {
|
|
@ComponentBuilder var content: ContentProvider
|
|
|
|
var body: Component {
|
|
Div(content: content).class("wrapper")
|
|
}
|
|
}
|
|
|
|
private struct SiteHeader<Site: Website>: Component {
|
|
var context: PublishingContext<Site>
|
|
var selectedSelectionID: Site.SectionID?
|
|
|
|
var body: Component {
|
|
Header {
|
|
Wrapper {
|
|
Link(context.site.name, url: "/")
|
|
.class("site-name")
|
|
|
|
if Site.SectionID.allCases.count > 1 {
|
|
navigation
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private var navigation: Component {
|
|
Navigation {
|
|
List(Site.SectionID.allCases) { sectionID in
|
|
let section = context.sections[sectionID]
|
|
|
|
return Link(section.title,
|
|
url: section.path.absoluteString)
|
|
.class(sectionID == selectedSelectionID ? "selected" : "")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private struct ItemList<Site: Website>: Component {
|
|
var items: [Item<Site>]
|
|
var site: Site
|
|
|
|
var body: Component {
|
|
List(items) { item in
|
|
Article {
|
|
H1(Link(item.title, url: item.path.absoluteString))
|
|
ItemTagList(item: item, site: site)
|
|
Paragraph(item.description)
|
|
}
|
|
}
|
|
.class("item-list")
|
|
}
|
|
}
|
|
|
|
private struct ItemTagList<Site: Website>: Component {
|
|
var item: Item<Site>
|
|
var site: Site
|
|
|
|
var body: Component {
|
|
List(item.tags) { tag in
|
|
Link(tag.string, url: site.path(for: tag).absoluteString)
|
|
}
|
|
.class("tag-list")
|
|
}
|
|
}
|
|
|
|
private struct SiteFooter: Component {
|
|
var body: Component {
|
|
Footer {
|
|
Paragraph {
|
|
Text("Minimal Theme")
|
|
}
|
|
Paragraph {
|
|
Link("RSS feed", url: "/feed.rss")
|
|
}
|
|
}
|
|
}
|
|
}
|