1
0
forked from SPC/spc-site

Refactor page placement.

This commit is contained in:
Alexander Nozik 2022-06-22 12:18:35 +03:00
parent 600a9b5529
commit 4966bfc9b3
No known key found for this signature in database
GPG Key ID: F7FCF2DD25C71357
11 changed files with 189 additions and 156 deletions

View File

@ -1,7 +1,7 @@
package html5up.forty
import kotlinx.html.*
import space.kscience.snark.SiteContext
import space.kscience.snark.SiteData
import space.kscience.snark.resolveRef
@ -201,7 +201,7 @@ internal fun FlowContent.fortyFooter() {
}
}
context(SiteContext) internal fun BODY.fortyScripts() {
context(SiteData) internal fun BODY.fortyScripts() {
script {
src = resolveRef("assets/js/jquery.min.js")
}

View File

@ -1,9 +1,9 @@
package html5up.forty
import kotlinx.html.*
import space.kscience.snark.SiteContext
import space.kscience.snark.SiteData
context(SiteContext) internal fun HTML.landing(){
context(SiteData) internal fun HTML.landing(){
head {
title {
}

View File

@ -1,10 +1,10 @@
package html5up.forty
import kotlinx.html.*
import space.kscience.snark.SiteContext
import space.kscience.snark.SiteData
import space.kscience.snark.resolveRef
context(SiteContext) internal fun HTML.fortyPage(){
context(SiteData) internal fun HTML.fortyPage(){
head {
title {
}

View File

@ -80,7 +80,7 @@ private val PROGRAM_PATH: Name = CONTENT_NODE_NAME + "program"
private val RECOMMENDED_COURSES_PATH: Name = CONTENT_NODE_NAME + "recommendedCourses"
private val PARTNERS_PATH: Name = CONTENT_NODE_NAME + "partners"
context(SiteContext) private fun FlowContent.programSection() {
context(SiteData) private fun FlowContent.programSection() {
val programBlock = resolveHtml(PROGRAM_PATH)!!
val recommendedBlock = resolveHtml(RECOMMENDED_COURSES_PATH)!!
div("inner") {
@ -97,7 +97,7 @@ context(SiteContext) private fun FlowContent.programSection() {
}
}
context(SiteContext) private fun FlowContent.partners() {
context(SiteData) private fun FlowContent.partners() {
//val partnersData: Meta = resolve<Any>(PARTNERS_PATH)?.meta ?: Meta.EMPTY
val partnersData: Meta = runBlocking { data.getByType<Meta>(PARTNERS_PATH)?.await() } ?: Meta.EMPTY
div("inner") {
@ -127,7 +127,7 @@ context(SiteContext) private fun FlowContent.partners() {
// val photo: String? by meta.string()
//}
context(SiteContext) private fun FlowContent.team() {
context(SiteData) private fun FlowContent.team() {
val team = findByType("magprog_team").values.sortedBy { it.order }
div("inner") {
@ -182,7 +182,7 @@ context(SiteContext) private fun FlowContent.team() {
// }
}
context(SiteContext) private fun FlowContent.mentors() {
context(SiteData) private fun FlowContent.mentors() {
val mentors = findByType("magprog_mentor").entries.sortedBy { it.value.id }
div("inner") {
@ -219,12 +219,12 @@ context(SiteContext) private fun FlowContent.mentors() {
}
}
context(SiteContext) internal fun FlowContent.contacts() {
context(SiteData) internal fun FlowContent.contacts() {
}
context(SiteContext) internal fun HTML.magProgHead(title: String) {
context(SiteData) internal fun HTML.magProgHead(title: String) {
head {
this.title = title
meta {
@ -251,7 +251,7 @@ context(SiteContext) internal fun HTML.magProgHead(title: String) {
}
}
context(SiteContext) internal fun BODY.magProgFooter() {
context(SiteData) internal fun BODY.magProgFooter() {
footer("wrapper style1-alt") {
id = "footer"
div("inner") {
@ -296,7 +296,7 @@ internal fun Application.spcMaster(context: Context, dataPath: Path, prefix: Str
val snark = context.fetch(SnarkPlugin)
val magProgSiteContext: SiteContext = snark.read(dataPath.resolve("content"), prefix)
val magProgSiteContext: SiteData = snark.readDirectory(dataPath.resolve("content"), prefix)
routing {
route(prefix) {

View File

@ -15,7 +15,7 @@ import kotlin.collections.component1
import kotlin.collections.component2
import kotlin.collections.set
context(SiteContext) private fun FlowContent.spcSpotlightContent(
context(SiteData) private fun FlowContent.spcSpotlightContent(
landing: HtmlData,
content: Map<Name, HtmlData>,
) {
@ -88,11 +88,12 @@ context(SiteContext) private fun FlowContent.spcSpotlightContent(
}
context(SiteContext) internal fun SiteBuilder.spcSpotlight(
name: String,
context(SiteData) internal fun SiteBuilder.spcSpotlight(
address: String,
contentFilter: (Name, Meta) -> Boolean,
) {
val body = resolveHtml(name.parseAsName()) ?: error("Could not find body for $name")
val name = address.parseAsName()
val body = resolveHtml(name) ?: error("Could not find body for $name")
val content = resolveAllHtml(contentFilter)
val meta = body.meta
@ -109,7 +110,7 @@ context(SiteContext) internal fun SiteBuilder.spcSpotlight(
}
content.forEach { (name, contentBody) ->
page(name.tokens.joinToString("/")){
page(name){
spcPageContent(contentBody.meta) {
htmlData(contentBody)
}

View File

@ -9,18 +9,20 @@ import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.error
import space.kscience.dataforge.context.fetch
import space.kscience.dataforge.context.logger
import space.kscience.dataforge.data.filterByType
import space.kscience.dataforge.data.forEach
import space.kscience.dataforge.data.Data
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.get
import space.kscience.dataforge.meta.string
import space.kscience.dataforge.names.*
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.asName
import space.kscience.dataforge.names.startsWith
import space.kscience.dataforge.values.string
import space.kscience.snark.*
import java.nio.file.Path
import kotlin.reflect.typeOf
context(SiteContext) internal fun HTML.spcPageContent(
context(SiteData) internal fun HTML.spcPageContent(
meta: Meta,
title: String = meta["title"].string ?: SPC_TITLE,
fragment: FlowContent.() -> Unit,
@ -58,18 +60,18 @@ context(SiteContext) internal fun HTML.spcPageContent(
}
context(SiteContext) internal fun SiteBuilder.spcPage(subRoute: String, meta: Meta, fragment: FlowContent.() -> Unit) {
internal fun SiteBuilder.spcPage(subRoute: Name, meta: Meta, fragment: FlowContent.() -> Unit) {
page(subRoute) {
spcPageContent(meta, fragment = fragment)
}
}
context(SiteContext) internal fun SiteBuilder.spcPage(
subRoute: String,
dataPath: Name = subRoute.replace("/", ".").parseAsName(),
internal fun SiteBuilder.spcPage(
subRoute: Name,
dataPath: Name = subRoute,
more: FlowContent.() -> Unit = {},
) {
val data = resolveHtml(dataPath)
val data = data.resolveHtml(dataPath)
if (data != null) {
spcPage(subRoute, data.meta) {
htmlData(data)
@ -80,34 +82,46 @@ context(SiteContext) internal fun SiteBuilder.spcPage(
}
}
/**
* Route a directory
*/
context(SiteContext) internal fun SiteBuilder.spcDirectory(
subRoute: String,
dataPath: Name = subRoute.replace("/", ".").parseAsName(),
) {
data.filterByType<HtmlFragment> { name, _ -> name.startsWith(dataPath) }.forEach { html ->
val pageName = if (html.name.lastOrNull()?.body == SiteContext.INDEX_PAGE_NAME) {
html.name.cutLast()
} else {
html.name
@Suppress("UNCHECKED_CAST")
internal val FortyDataRenderer: SiteBuilder.(Data<*>) -> Unit = { data ->
if(data.type == typeOf<HtmlFragment>()) {
data as Data<HtmlFragment>
page {
spcPageContent(data.meta) {
htmlData(data)
}
spcPage(pageName.tokens.joinToString(separator = "/"), html.meta) {
htmlData(html)
}
}
}
context(SiteContext) internal fun SiteBuilder.spcPage(
///**
// * Route a directory
// */
//internal fun SiteBuilder.spcDirectory(
// subRoute: String,
// dataPath: Name = subRoute.replace("/", ".").parseAsName(),
//) {
// data.filterByType<HtmlFragment> { name, _ -> name.startsWith(dataPath) }.forEach { html ->
// val pageName = if (html.name.lastOrNull()?.body == SiteData.INDEX_PAGE_NAME) {
// html.name.cutLast()
// } else {
// html.name
// }
//
// spcPage(pageName.tokens.joinToString(separator = "/"), html.meta) {
// htmlData(html)
// }
// }
//}
internal fun SiteBuilder.spcPage(
name: Name,
more: FlowContent.() -> Unit = {},
) {
spcPage(name.tokens.joinToString("/"), name, more)
spcPage(name, name, more)
}
context(SiteContext, HTML) private fun HTML.spcHome() {
context(SiteData, HTML) private fun HTML.spcHome() {
spcHead()
body("is-preload") {
wrapper {
@ -298,18 +312,18 @@ internal fun Application.spcHome(context: Context, rootPath: Path, prefix: Strin
val snark = context.fetch(SnarkPlugin)
val homePageContext = snark.read(rootPath.resolve("content"), prefix)
val homePageContext = snark.readDirectory(rootPath.resolve("content"), prefix)
routing {
route(prefix) {
snarkSite(homePageContext) {
staticDirectory("assets", rootPath.resolve("assets"))
staticDirectory("images", rootPath.resolve("images"))
assetDirectory("assets", rootPath.resolve("assets"))
assetDirectory("images", rootPath.resolve("images"))
page { spcHome() }
spcDirectory("consulting")
spcDirectory("ru/consulting")
pages("consulting", dataRenderer = FortyDataRenderer)
//pages("ru.consulting".parseAsName(), dataRenderer = FortyDataRenderer)
spcSpotlight("team") { _, m -> m["type"].string == "team" }
spcSpotlight("research") { name, m -> name.startsWith("projects".asName()) && m["type"].string == "project" }

View File

@ -1,14 +1,14 @@
package ru.mipt.spc
import kotlinx.html.*
import space.kscience.snark.SiteContext
import space.kscience.snark.SiteData
import space.kscience.snark.homeRef
import space.kscience.snark.resolveRef
internal const val SPC_TITLE = "Scientific Programming Centre"
context(SiteContext) internal fun HTML.spcHead(title: String = SPC_TITLE) {
context(SiteData) internal fun HTML.spcHead(title: String = SPC_TITLE) {
head {
title {
+title
@ -27,7 +27,7 @@ context(SiteContext) internal fun HTML.spcHead(title: String = SPC_TITLE) {
}
}
context(SiteContext) internal fun FlowContent.spcHomeMenu() {
context(SiteData) internal fun FlowContent.spcHomeMenu() {
nav {
id = "menu"
ul("links") {
@ -79,7 +79,7 @@ context(SiteContext) internal fun FlowContent.spcHomeMenu() {
}
}
context(SiteContext) internal fun FlowContent.spcFooter() {
context(SiteData) internal fun FlowContent.spcFooter() {
footer {
id = "footer"
div("inner") {
@ -129,7 +129,7 @@ context(SiteContext) internal fun FlowContent.spcFooter() {
}
}
context(SiteContext) internal fun FlowContent.wrapper(contentBody: FlowContent.() -> Unit) {
context(SiteData) internal fun FlowContent.wrapper(contentBody: FlowContent.() -> Unit) {
div {
id = "wrapper"
// Header

View File

@ -9,71 +9,78 @@ import io.ktor.server.routing.get
import kotlinx.html.HTML
import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.ContextAware
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.parseAsName
import java.nio.file.Path
internal fun Name.toWebPath() = tokens.joinToString(separator = "/")
/**
* An abstraction, which is used to render sites to the different rendering engines
*/
interface SiteBuilder : ContextAware {
val siteContext: SiteContext
val data: SiteData
override val context: Context get() = siteContext.context
override val context: Context get() = data.context
fun staticFile(remotePath: String, file: Path)
fun assetFile(remotePath: String, file: Path)
fun staticDirectory(remotePath: String, directory: Path)
fun assetDirectory(remotePath: String, directory: Path)
fun staticResourceFile(remotePath: String, resourcesPath: String)
fun assetResourceFile(remotePath: String, resourcesPath: String)
fun staticResourceDirectory(resourcesPath: String)
fun assetResourceDirectory(resourcesPath: String)
fun page(route: String = "", content: context(SiteContext, HTML) () -> Unit)
fun page(route: Name = Name.EMPTY, content: context(SiteData, HTML) () -> Unit)
/**
* Create a route
*/
fun route(subRoute: String): SiteBuilder
fun route(subRoute: Name): SiteBuilder
}
public inline fun SiteBuilder.route(route: String, block: SiteBuilder.() -> Unit) {
public inline fun SiteBuilder.route(route: Name, block: SiteBuilder.() -> Unit) {
route(route).apply(block)
}
class KtorSiteRoute(override val siteContext: SiteContext, private val ktorRoute: Route) : SiteBuilder {
override fun staticFile(remotePath: String, file: Path) {
public inline fun SiteBuilder.route(route: String, block: SiteBuilder.() -> Unit) {
route(route.parseAsName()).apply(block)
}
class KtorSiteRoute(override val data: SiteData, private val ktorRoute: Route) : SiteBuilder {
override fun assetFile(remotePath: String, file: Path) {
ktorRoute.file(remotePath, file.toFile())
}
override fun staticDirectory(remotePath: String, directory: Path) {
override fun assetDirectory(remotePath: String, directory: Path) {
ktorRoute.static(remotePath) {
files(directory.toFile())
}
}
override fun page(route: String, content: context(SiteContext, HTML)() -> Unit) {
ktorRoute.get(route) {
override fun page(route: Name, content: context(SiteData, HTML)() -> Unit) {
ktorRoute.get(route.toWebPath()) {
call.respondHtml {
content(siteContext.copyWithRequestHost(call.request), this)
content(data.copyWithRequestHost(call.request), this)
}
}
}
override fun route(subRoute: String): SiteBuilder =
KtorSiteRoute(siteContext, ktorRoute.createRouteFromPath(subRoute))
override fun route(subRoute: Name): SiteBuilder =
KtorSiteRoute(data, ktorRoute.createRouteFromPath(subRoute.toWebPath()))
override fun staticResourceFile(remotePath: String, resourcesPath: String) {
override fun assetResourceFile(remotePath: String, resourcesPath: String) {
ktorRoute.resource(resourcesPath, resourcesPath)
}
override fun staticResourceDirectory(resourcesPath: String) {
override fun assetResourceDirectory(resourcesPath: String) {
ktorRoute.resources(resourcesPath)
}
}
inline fun Route.snarkSite(
siteContext: SiteContext,
block: context(SiteContext, SiteBuilder)() -> Unit,
siteContext: SiteData,
block: context(SiteData, SiteBuilder)() -> Unit,
) {
block(siteContext, KtorSiteRoute(siteContext, this@snarkSite))
}

View File

@ -15,15 +15,15 @@ import space.kscience.dataforge.meta.string
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.plus
import space.kscience.dataforge.names.startsWith
import space.kscience.snark.SiteContext.Companion.INDEX_PAGE_NAME
import space.kscience.snark.SiteData.Companion.INDEX_PAGE_NAME
import java.nio.file.Path
data class SiteContext(
data class SiteData(
val snark: SnarkPlugin,
val path: String,
val meta: Meta,
val data: DataTree<*>,
) : ContextAware {
val urlPath: String,
override val meta: Meta = data.meta
) : ContextAware, DataTree<Any> by data {
override val context: Context get() = snark.context
@ -37,15 +37,15 @@ data class SiteContext(
/**
* Resolve a resource full path by its name
*/
fun SiteContext.resolveRef(name: String): String = "${path.removeSuffix("/")}/$name"
fun SiteData.resolveRef(name: String): String = "${urlPath.removeSuffix("/")}/$name"
fun SiteContext.resolveRef(name: Name): String = "${path.removeSuffix("/")}/${name.tokens.joinToString("/")}"
fun SiteData.resolveRef(name: Name): String = "${urlPath.removeSuffix("/")}/${name.tokens.joinToString("/")}"
/**
* Resolve a Html builder by its full name
*/
fun SiteContext.resolveHtml(name: Name): HtmlData? {
val resolved = (data.getByType<HtmlFragment>(name) ?: data.getByType<HtmlFragment>(name + INDEX_PAGE_NAME))
fun DataTree<*>.resolveHtml(name: Name): HtmlData? {
val resolved = (getByType<HtmlFragment>(name) ?: getByType<HtmlFragment>(name + INDEX_PAGE_NAME))
return resolved?.takeIf {
it.published //TODO add language confirmation
@ -55,45 +55,45 @@ fun SiteContext.resolveHtml(name: Name): HtmlData? {
/**
* Find all Html blocks using given name/meta filter
*/
fun SiteContext.resolveAllHtml(predicate: (name: Name, meta: Meta) -> Boolean): Map<Name, HtmlData> =
data.filterByType<HtmlFragment> { name, meta ->
fun DataTree<*>.resolveAllHtml(predicate: (name: Name, meta: Meta) -> Boolean): Map<Name, HtmlData> =
filterByType<HtmlFragment> { name, meta ->
predicate(name, meta)
&& meta["published"].string != "false"
//TODO add language confirmation
}.asSequence().associate { it.name to it.data }
val SiteContext.homeRef get() = resolveRef("").removeSuffix("/")
val SiteData.homeRef get() = resolveRef("").removeSuffix("/")
fun SiteContext.findByType(contentType: String, baseName: Name = Name.EMPTY) = resolveAllHtml { name, meta ->
fun SiteData.findByType(contentType: String, baseName: Name = Name.EMPTY) = resolveAllHtml { name, meta ->
name.startsWith(baseName) && meta["content_type"].string == contentType
}
internal val Data<*>.published: Boolean get() = meta["published"].string != "false"
fun SnarkPlugin.siteContext(rootUrl: String, data: DataTree<*>): SiteContext =
SiteContext(this, rootUrl, data.meta, data)
fun SnarkPlugin.readData(data: DataTree<*>, rootUrl: String = "/"): SiteData =
SiteData(this, data, rootUrl)
fun SnarkPlugin.read(path: Path, rootUrl: String = "/"): SiteContext {
fun SnarkPlugin.readDirectory(path: Path, rootUrl: String = "/"): SiteData {
val parsedData: DataTree<Any> = readDirectory(path)
return siteContext(rootUrl, parsedData)
return readData(parsedData, rootUrl)
}
@PublishedApi
internal fun SiteContext.copyWithRequestHost(request: ApplicationRequest): SiteContext {
internal fun SiteData.copyWithRequestHost(request: ApplicationRequest): SiteData {
val uri = URLBuilder(
protocol = URLProtocol.createOrDefault(request.origin.scheme),
host = request.host(),
port = request.port(),
pathSegments = path.split("/"),
pathSegments = urlPath.split("/"),
)
return copy(path = uri.buildString())
return copy(urlPath = uri.buildString())
}
/**
* Substitute uri in [SiteContext] with uri in the call to properly resolve relative refs. Only host properties are substituted.
* Substitute uri in [SiteData] with uri in the call to properly resolve relative refs. Only host properties are substituted.
*/
context(SiteContext) inline fun withRequest(request: ApplicationRequest, block: context(SiteContext) () -> Unit) {
context(SiteData) inline fun withRequest(request: ApplicationRequest, block: context(SiteData) () -> Unit) {
block(copyWithRequestHost(request))
}

View File

@ -1,22 +1,25 @@
package space.kscience.snark
import kotlinx.coroutines.runBlocking
import space.kscience.dataforge.data.DataTree
import space.kscience.dataforge.data.Data
import space.kscience.dataforge.data.DataTreeItem
import space.kscience.dataforge.data.await
import space.kscience.dataforge.data.getItem
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.get
import space.kscience.dataforge.meta.getIndexed
import space.kscience.dataforge.meta.string
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.NameToken
import space.kscience.dataforge.names.asName
import space.kscience.dataforge.names.plus
import space.kscience.snark.SiteLayout.Companion.DESIGNATION_KEY
import space.kscience.dataforge.names.parseAsName
import space.kscience.snark.SiteLayout.Companion.ASSETS_KEY
import space.kscience.snark.SiteLayout.Companion.INDEX_PAGE_TOKEN
import space.kscience.snark.SiteLayout.Companion.LAYOUT_KEY
import java.nio.file.Path
import kotlin.reflect.typeOf
internal fun SiteBuilder.staticFrom(rootMeta: Meta) {
internal fun SiteBuilder.assetsFrom(rootMeta: Meta) {
rootMeta.getIndexed("resource".asName()).forEach { (_, meta) ->
val path by meta.string()
@ -25,75 +28,109 @@ internal fun SiteBuilder.staticFrom(rootMeta: Meta) {
path?.let { resourcePath ->
//If remote path provided, use a single resource
remotePath?.let {
staticResourceFile(it, resourcePath)
assetResourceFile(it, resourcePath)
return@forEach
}
//otherwise use package resources
staticResourceDirectory(resourcePath)
assetResourceDirectory(resourcePath)
}
}
rootMeta.getIndexed("file".asName()).forEach { (_, meta) ->
val remotePath by meta.string { error("File remote path is not provided") }
val path by meta.string { error("File path is not provided") }
staticFile(remotePath, Path.of(path))
assetFile(remotePath, Path.of(path))
}
rootMeta.getIndexed("directory".asName()).forEach { (_, meta) ->
val path by meta.string { error("Directory path is not provided") }
staticDirectory("", Path.of(path))
assetDirectory("", Path.of(path))
}
}
/**
* Represent pages in a [DataTree]
* Recursively renders the data items in [data]. If [LAYOUT_KEY] is defined in an item, use it to load
* layout from the context, otherwise render children nodes as name segments and individual data items using [dataRenderer].
*/
fun SiteBuilder.data(data: DataTreeItem<*>, prefix: Name = Name.EMPTY) {
fun SiteBuilder.pages(
data: DataTreeItem<*>,
dataRenderer: SiteBuilder.(Data<*>) -> Unit = SiteLayout.defaultDataRenderer,
) {
val layoutMeta = data.meta[LAYOUT_KEY]
if (layoutMeta != null) {
//use layout if it is defined
siteContext.snark.layout(layoutMeta).render(data)
this.data.snark.layout(layoutMeta).render(data)
} else {
when (data) {
is DataTreeItem.Node -> {
data.tree.items.forEach { (token, item) ->
data(item, prefix + token)
//Don't apply index token
if (token == INDEX_PAGE_TOKEN) {
pages(item, dataRenderer)
}
route(token.toString()) {
pages(item, dataRenderer)
}
}
}
is DataTreeItem.Leaf -> {
val item = data.data
if (item.type == typeOf<HtmlData>() && item.meta[DESIGNATION_KEY].string == "page") {
route(prefix.tokens.joinToString(separator = "/")) {
page {
@Suppress("UNCHECKED_CAST")
val pageFragment: HtmlFragment = runBlocking { item.await() as HtmlFragment }
pageFragment.invoke(consumer)
}
staticFrom(item.meta)
dataRenderer.invoke(this, data.data)
}
}
data.meta[ASSETS_KEY]?.let {
assetsFrom(it)
}
}
//TODO watch for changes
}
/**
* Render all pages in a node with given name
*/
fun SiteBuilder.pages(
dataPath: Name,
remotePath: Name = dataPath,
dataRenderer: SiteBuilder.(Data<*>) -> Unit = SiteLayout.defaultDataRenderer,
) {
val item = data.getItem(dataPath) ?: error("No data found by name $dataPath")
route(remotePath) {
pages(item, dataRenderer)
}
}
}
//TODO watch for changes
fun SiteBuilder.pages(
dataPath: String,
remotePath: Name = dataPath.parseAsName(),
dataRenderer: SiteBuilder.(Data<*>) -> Unit = SiteLayout.defaultDataRenderer,
) {
pages(dataPath.parseAsName(), remotePath, dataRenderer = dataRenderer)
}
fun interface SiteLayout {
context(SiteBuilder) fun render(data: DataTreeItem<*>)
context(SiteBuilder) fun render(item: DataTreeItem<*>)
companion object {
internal const val DESIGNATION_KEY = "designation"
const val LAYOUT_KEY = "layout"
const val ASSETS_KEY = "assets"
val INDEX_PAGE_TOKEN = NameToken("index")
val defaultDataRenderer: SiteBuilder.(Data<*>) -> Unit = { data ->
if (data.type == typeOf<HtmlData>()) {
page {
@Suppress("UNCHECKED_CAST")
val pageFragment: HtmlFragment = runBlocking { data.await() as HtmlFragment }
pageFragment.invoke(consumer)
}
}
}
}
}
object DefaultSiteLayout : SiteLayout {
context(SiteBuilder) override fun render(data: DataTreeItem<*>) {
data(data)
context(SiteBuilder) override fun render(item: DataTreeItem<*>) {
pages(item)
}
}

View File

@ -1,26 +0,0 @@
package ru.mipt.spc
//class SiteBuilderAction : AbstractAction<Any, HtmlFragment>(typeOf<HtmlFragment>()) {
//
// private val pageBuilders = HashMap<Name, (DataSet<*>) -> HtmlData>()
//
// fun page(name: Name, meta: Meta = Meta.EMPTY, builder: context(PageContext) TagConsumer<*>.() -> Unit) {
// val prefix = name.tokens.joinToString(separator = "/", prefix = "/")
// pageBuilders[name] = { dataset ->
// val fragment: HtmlFragment = {
// builder.invoke(PageContext(prefix, dataset), this)
// }
// Data(fragment, meta.copy {
// "name" put name.toString()
// })
// }
// }
//
//
// override fun DataSetBuilder<HtmlFragment>.generate(data: DataSet<Any>, meta: Meta) {
// pageBuilders.forEach { (name, builder) ->
// data(name, builder(data))
// }
// }
//
//}