diff --git a/examples/document/data/loremIpsum/SPC-logo.png b/examples/document/data/loremIpsum/SPC-logo.png new file mode 100644 index 0000000..953de16 Binary files /dev/null and b/examples/document/data/loremIpsum/SPC-logo.png differ diff --git a/examples/document/data/loremIpsum/chapter2.md b/examples/document/data/loremIpsum/chapter2.md index 07fedc5..49b6057 100644 --- a/examples/document/data/loremIpsum/chapter2.md +++ b/examples/document/data/loremIpsum/chapter2.md @@ -1,6 +1,5 @@ --- -type: markdown -order: 2 +contentType: markdown --- ## Chapter ${section(1)} diff --git a/examples/document/data/loremIpsum/document.yaml b/examples/document/data/loremIpsum/document.yaml index a8f3771..9913ed0 100644 --- a/examples/document/data/loremIpsum/document.yaml +++ b/examples/document/data/loremIpsum/document.yaml @@ -4,11 +4,19 @@ authors: - name: Alexander Nozik affiliation: MIPT fragments: - - name: chapter1 - type: data - - name: chapter2 - type: data - - name: chapter3 - type: data + - type: image + ref: SPC-logo.png + meta: + caption: SPC logo + - type: data + name: chapter1 + - type: data + name: chapter2 + - type: image + ref: SPC-logo.png + meta: + caption: Another SPC logo + - type: data + name: chapter3 documentMeta: metaValue: Hello world! \ No newline at end of file diff --git a/examples/document/src/jvmMain/kotlin/main.kt b/examples/document/src/jvmMain/kotlin/main.kt index 4ffb9c3..b6c01cd 100644 --- a/examples/document/src/jvmMain/kotlin/main.kt +++ b/examples/document/src/jvmMain/kotlin/main.kt @@ -35,7 +35,6 @@ fun Application.renderAllDocuments() = snarkApplication { fun main() { - embeddedServer(CIO) { renderAllDocuments() }.start(true) diff --git a/snark-html/src/jvmMain/kotlin/space/kscience/snark/html/SnarkHtml.kt b/snark-html/src/jvmMain/kotlin/space/kscience/snark/html/SnarkHtml.kt index 533e29c..893dfa9 100644 --- a/snark-html/src/jvmMain/kotlin/space/kscience/snark/html/SnarkHtml.kt +++ b/snark-html/src/jvmMain/kotlin/space/kscience/snark/html/SnarkHtml.kt @@ -6,6 +6,7 @@ import io.ktor.http.ContentType import kotlinx.coroutines.CoroutineScope import kotlinx.io.readByteArray import space.kscience.dataforge.actions.Action +import space.kscience.dataforge.actions.mapping import space.kscience.dataforge.actions.transform import space.kscience.dataforge.context.Context import space.kscience.dataforge.context.PluginFactory @@ -107,6 +108,10 @@ public class SnarkHtml : WorkspacePlugin() { public val parseAction: Action = ParseAction(this) + public val layoutAction: Action = Action.mapping { + + } + private val allDataNotNull: DataSelector get() = DataSelector { workspace, _ -> workspace.data.filterByType() } diff --git a/snark-html/src/jvmMain/kotlin/space/kscience/snark/html/document/DocumentBuilder.kt b/snark-html/src/jvmMain/kotlin/space/kscience/snark/html/document/DocumentBuilder.kt index 6b7fa68..cb7aedb 100644 --- a/snark-html/src/jvmMain/kotlin/space/kscience/snark/html/document/DocumentBuilder.kt +++ b/snark-html/src/jvmMain/kotlin/space/kscience/snark/html/document/DocumentBuilder.kt @@ -7,14 +7,12 @@ import space.kscience.dataforge.context.info import space.kscience.dataforge.context.logger import space.kscience.dataforge.context.request import space.kscience.dataforge.data.* +import space.kscience.dataforge.io.Binary import space.kscience.dataforge.meta.Laminate import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.get import space.kscience.dataforge.meta.string -import space.kscience.dataforge.names.Name -import space.kscience.dataforge.names.cutLast -import space.kscience.dataforge.names.endsWith -import space.kscience.dataforge.names.parseAsName +import space.kscience.dataforge.names.* import space.kscience.snark.SnarkBuilder import space.kscience.snark.SnarkContext import space.kscience.snark.html.* @@ -26,7 +24,7 @@ import kotlin.reflect.typeOf @SnarkBuilder public interface DocumentBuilder : SnarkContext { - public val documentName: Name + public val route: Name public val documentMeta: Meta @@ -51,7 +49,7 @@ private class PageBasedDocumentBuilder( val page: PageContextWithData, private val dataRootName: Name, ) : DocumentBuilder { - override val documentName: Name get() = page.pageRoute + override val route: Name get() = page.pageRoute override val documentMeta: Meta get() = page.pageMeta override val data: DataTree<*> = page.data.branch(dataRootName) ?: DataTree.EMPTY @@ -63,11 +61,10 @@ private class PageBasedDocumentBuilder( override suspend fun fragment(fragment: DocumentFragment, overrideMeta: Meta?) { when (fragment) { - is ImageDocumentFragment -> fragment { figure("snark-figure") { img(classes = "snark-image") { - src = fragment.path + src = resolveRef(this@PageBasedDocumentBuilder.route.toWebPath() + "/" + fragment.ref) alt = fragment.meta["alt"].string ?: "" } fragment.meta["caption"].string?.let { caption -> @@ -115,53 +112,41 @@ private class PageBasedDocumentBuilder( } public fun SiteContextWithData.document( - documentName: Name, - documentMeta: Meta = Meta.EMPTY, - headers: MetaDataContent.() -> Unit = {}, - block: suspend DocumentBuilder.() -> Unit, -): Unit = page(documentName, documentMeta) { - val documentBuilder = runBlocking { PageBasedDocumentBuilder(page, documentName).apply { block() } } - head { - title(documentMeta["title"].string ?: "Snark document") - headers() - } - body { - postprocess(FtlDocumentProcessor(this@document.context, documentBuilder)) { - documentBuilder.fragments.forEach { - fragment(it) - } - } - } -} - -public fun SiteContextWithData.document( - route: Name, dataName: Name, - descriptor: DocumentDescriptor, + descriptor: DocumentDescriptor = DocumentDescriptor.empty(), + route: Name = dataName, headers: MetaDataContent.() -> Unit = {}, -): Unit = page(route, descriptor.documentMeta ?: Meta.EMPTY) { - val documentBuilder = runBlocking { - PageBasedDocumentBuilder(page, dataName).apply { - descriptor.fragments.forEach { - fragment(it) + documentBlock: DocumentBuilder.() -> Unit = {}, +): Unit { + siteData.branch(dataName)?.filterByType()?.forEach { + static(route + it.name.last(), it.data) + } + page(route, descriptor.documentMeta ?: Meta.EMPTY) { + //TODO think about avoiding blocking + val documentBuilder = runBlocking { + PageBasedDocumentBuilder(page, dataName).apply { + descriptor.fragments.forEach { + fragment(it) + } + documentBlock() } } - } - head { - title(descriptor.title ?: "Snark document") - headers() - } - body { - h1("title") { +(descriptor.title ?: dataName.toString()) } - descriptor.authors.forEach { - div("author") { - div("author-name") { +it.name } - it.affiliation?.let { affiliation -> div("author-affiliation") { +affiliation } } - } + head { + title(descriptor.title ?: "Snark document") + headers() } - postprocess(FtlDocumentProcessor(this@document.context, documentBuilder)) { - documentBuilder.fragments.forEach { - fragment(it) + body { + h1("title") { +(descriptor.title ?: dataName.toString()) } + descriptor.authors.forEach { + div("author") { + div("author-name") { +it.name } + it.affiliation?.let { affiliation -> div("author-affiliation") { +affiliation } } + } + } + postprocess(FtlDocumentProcessor(this@document.context, documentBuilder)) { + documentBuilder.fragments.forEach { + fragment(it) + } } } } @@ -178,9 +163,9 @@ public fun SiteContextWithData.allDocuments( val route = descriptor.route?.parseAsName(false) ?: directory context.logger.info { "Loading document $route" } document( - route = route, dataName = directory, descriptor = descriptor, + route = route, headers = headers ) } diff --git a/snark-html/src/jvmMain/kotlin/space/kscience/snark/html/document/DocumentFragment.kt b/snark-html/src/jvmMain/kotlin/space/kscience/snark/html/document/DocumentFragment.kt index 998c642..87a81f3 100644 --- a/snark-html/src/jvmMain/kotlin/space/kscience/snark/html/document/DocumentFragment.kt +++ b/snark-html/src/jvmMain/kotlin/space/kscience/snark/html/document/DocumentFragment.kt @@ -20,7 +20,7 @@ public class MarkupDocumentFragment( @Serializable @SerialName("image") public class ImageDocumentFragment( - public val path: String, + public val ref: String, override val meta: Meta = Meta.EMPTY, ) : DocumentFragment diff --git a/snark-html/src/jvmMain/kotlin/space/kscience/snark/html/document/FtlDocumentProcessor.kt b/snark-html/src/jvmMain/kotlin/space/kscience/snark/html/document/FtlDocumentProcessor.kt index 12a5b9c..b55672f 100644 --- a/snark-html/src/jvmMain/kotlin/space/kscience/snark/html/document/FtlDocumentProcessor.kt +++ b/snark-html/src/jvmMain/kotlin/space/kscience/snark/html/document/FtlDocumentProcessor.kt @@ -59,7 +59,7 @@ public class FtlDocumentProcessor( } private val data = mapOf( - "documentName" to document.documentName.toStringUnescaped(), + "documentName" to document.route.toStringUnescaped(), "label" to TemplateMethodModelEx { args: List -> val counter = args.getOrNull(0)?.toString() ?: "@default" diff --git a/snark-html/src/jvmMain/kotlin/space/kscience/snark/html/document/RegexDocumentProcessor.kt b/snark-html/src/jvmMain/kotlin/space/kscience/snark/html/document/RegexDocumentProcessor.kt index 944a952..c72d26e 100644 --- a/snark-html/src/jvmMain/kotlin/space/kscience/snark/html/document/RegexDocumentProcessor.kt +++ b/snark-html/src/jvmMain/kotlin/space/kscience/snark/html/document/RegexDocumentProcessor.kt @@ -42,7 +42,7 @@ public class RegexDocumentProcessor(public val document: DocumentBuilder) : Text when (match.groups["function"]?.value) { "documentName" -> { - document.documentName.toStringUnescaped() + document.route.toStringUnescaped() } "label" -> { @@ -77,7 +77,7 @@ public class RegexDocumentProcessor(public val document: DocumentBuilder) : Text }.replace(attributeRegex) { match -> val uri = URI(match.groups["uri"]!!.value) val snarkUrl = when (uri.authority) { - "documentName" -> document.documentName.toStringUnescaped() + "documentName" -> document.route.toStringUnescaped() // "ref" -> page.resolveRef(uri.path) "meta" -> document.documentMeta[uri.path.parseAsName()].string ?: "@null" else -> match.value