feat: Moves core functionality into it's own library.

This commit is contained in:
2024-12-05 09:59:30 -05:00
parent 33356d8648
commit e7bbbec7c2
24 changed files with 464 additions and 387 deletions

View File

@@ -0,0 +1,96 @@
// TODO: Add vertical spacing.
public struct Section<Header: TextNode, Content: TextNode, Footer: TextNode>: TextNode {
@usableFromInline
let header: Header
@usableFromInline
let content: Content
@usableFromInline
let footer: Footer
@inlinable
public init(
@TextBuilder content: () -> Content,
@TextBuilder header: () -> Header,
@TextBuilder footer: () -> Footer
) {
self.header = header()
self.content = content()
self.footer = footer()
}
public var body: some TextNode {
style(.default)
}
}
public extension Section where Footer == Empty {
@inlinable
init(
@TextBuilder content: () -> Content,
@TextBuilder header: () -> Header
) {
self.init(content: content, header: header) { Empty() }
}
}
public extension Section where Header == Empty {
@inlinable
init(
@TextBuilder content: () -> Content,
@TextBuilder footer: () -> Footer
) {
self.init(content: content, header: { Empty() }, footer: footer)
}
}
public extension Section where Header == Empty, Footer == Empty {
@inlinable
init(
@TextBuilder content: () -> Content
) {
self.init(content: content, header: { Empty() }, footer: { Empty() })
}
}
// MARK: - Style
public extension Section {
@inlinable
func style<S: SectionStyle>(_ style: S) -> some TextNode {
style.render(content: .init(header: header, content: content, footer: footer))
}
}
public struct SectionConfiguration {
public let header: any TextNode
public let content: any TextNode
public let footer: any TextNode
@usableFromInline
init(header: any TextNode, content: any TextNode, footer: any TextNode) {
self.header = header
self.content = content
self.footer = footer
}
}
public protocol SectionStyle: NodeModifier where Content == SectionConfiguration {}
public extension SectionStyle where Self == DefaultSectionStyle {
static var `default`: Self { DefaultSectionStyle() }
}
public struct DefaultSectionStyle: SectionStyle {
public func render(content: SectionConfiguration) -> some TextNode {
VStack(spacing: 2) {
content.header
content.content
content.footer
}
}
}