Add image rendering

This commit is contained in:
Alexander Nozik 2024-05-01 13:26:19 +03:00
parent 7a2b5c1768
commit 21a85b4501
9 changed files with 60 additions and 64 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

@ -1,6 +1,5 @@
--- ---
type: markdown contentType: markdown
order: 2
--- ---
## Chapter ${section(1)} ## Chapter ${section(1)}

View File

@ -4,11 +4,19 @@ authors:
- name: Alexander Nozik - name: Alexander Nozik
affiliation: MIPT affiliation: MIPT
fragments: fragments:
- name: chapter1 - type: image
type: data ref: SPC-logo.png
- name: chapter2 meta:
type: data caption: SPC logo
- name: chapter3 - type: data
type: data name: chapter1
- type: data
name: chapter2
- type: image
ref: SPC-logo.png
meta:
caption: Another SPC logo
- type: data
name: chapter3
documentMeta: documentMeta:
metaValue: Hello world! metaValue: Hello world!

View File

@ -35,7 +35,6 @@ fun Application.renderAllDocuments() = snarkApplication {
fun main() { fun main() {
embeddedServer(CIO) { embeddedServer(CIO) {
renderAllDocuments() renderAllDocuments()
}.start(true) }.start(true)

View File

@ -6,6 +6,7 @@ import io.ktor.http.ContentType
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.io.readByteArray import kotlinx.io.readByteArray
import space.kscience.dataforge.actions.Action import space.kscience.dataforge.actions.Action
import space.kscience.dataforge.actions.mapping
import space.kscience.dataforge.actions.transform import space.kscience.dataforge.actions.transform
import space.kscience.dataforge.context.Context import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.PluginFactory import space.kscience.dataforge.context.PluginFactory
@ -107,6 +108,10 @@ public class SnarkHtml : WorkspacePlugin() {
public val parseAction: Action<Binary, Any> = ParseAction(this) public val parseAction: Action<Binary, Any> = ParseAction(this)
public val layoutAction: Action<Any, Any> = Action.mapping {
}
private val allDataNotNull: DataSelector<Any> private val allDataNotNull: DataSelector<Any>
get() = DataSelector { workspace, _ -> workspace.data.filterByType() } get() = DataSelector { workspace, _ -> workspace.data.filterByType() }

View File

@ -7,14 +7,12 @@ import space.kscience.dataforge.context.info
import space.kscience.dataforge.context.logger import space.kscience.dataforge.context.logger
import space.kscience.dataforge.context.request import space.kscience.dataforge.context.request
import space.kscience.dataforge.data.* import space.kscience.dataforge.data.*
import space.kscience.dataforge.io.Binary
import space.kscience.dataforge.meta.Laminate import space.kscience.dataforge.meta.Laminate
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.get import space.kscience.dataforge.meta.get
import space.kscience.dataforge.meta.string import space.kscience.dataforge.meta.string
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.*
import space.kscience.dataforge.names.cutLast
import space.kscience.dataforge.names.endsWith
import space.kscience.dataforge.names.parseAsName
import space.kscience.snark.SnarkBuilder import space.kscience.snark.SnarkBuilder
import space.kscience.snark.SnarkContext import space.kscience.snark.SnarkContext
import space.kscience.snark.html.* import space.kscience.snark.html.*
@ -26,7 +24,7 @@ import kotlin.reflect.typeOf
@SnarkBuilder @SnarkBuilder
public interface DocumentBuilder : SnarkContext { public interface DocumentBuilder : SnarkContext {
public val documentName: Name public val route: Name
public val documentMeta: Meta public val documentMeta: Meta
@ -51,7 +49,7 @@ private class PageBasedDocumentBuilder(
val page: PageContextWithData, val page: PageContextWithData,
private val dataRootName: Name, private val dataRootName: Name,
) : DocumentBuilder { ) : DocumentBuilder {
override val documentName: Name get() = page.pageRoute override val route: Name get() = page.pageRoute
override val documentMeta: Meta get() = page.pageMeta override val documentMeta: Meta get() = page.pageMeta
override val data: DataTree<*> = page.data.branch(dataRootName) ?: DataTree.EMPTY 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?) { override suspend fun fragment(fragment: DocumentFragment, overrideMeta: Meta?) {
when (fragment) { when (fragment) {
is ImageDocumentFragment -> fragment { is ImageDocumentFragment -> fragment {
figure("snark-figure") { figure("snark-figure") {
img(classes = "snark-image") { img(classes = "snark-image") {
src = fragment.path src = resolveRef(this@PageBasedDocumentBuilder.route.toWebPath() + "/" + fragment.ref)
alt = fragment.meta["alt"].string ?: "" alt = fragment.meta["alt"].string ?: ""
} }
fragment.meta["caption"].string?.let { caption -> fragment.meta["caption"].string?.let { caption ->
@ -115,53 +112,41 @@ private class PageBasedDocumentBuilder(
} }
public fun SiteContextWithData.document( 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, dataName: Name,
descriptor: DocumentDescriptor, descriptor: DocumentDescriptor = DocumentDescriptor.empty(),
route: Name = dataName,
headers: MetaDataContent.() -> Unit = {}, headers: MetaDataContent.() -> Unit = {},
): Unit = page(route, descriptor.documentMeta ?: Meta.EMPTY) { documentBlock: DocumentBuilder.() -> Unit = {},
val documentBuilder = runBlocking { ): Unit {
PageBasedDocumentBuilder(page, dataName).apply { siteData.branch(dataName)?.filterByType<Binary>()?.forEach {
descriptor.fragments.forEach { static(route + it.name.last(), it.data)
fragment(it) }
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 {
head { title(descriptor.title ?: "Snark document")
title(descriptor.title ?: "Snark document") headers()
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 } }
}
} }
postprocess(FtlDocumentProcessor(this@document.context, documentBuilder)) { body {
documentBuilder.fragments.forEach { h1("title") { +(descriptor.title ?: dataName.toString()) }
fragment(it) 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 val route = descriptor.route?.parseAsName(false) ?: directory
context.logger.info { "Loading document $route" } context.logger.info { "Loading document $route" }
document( document(
route = route,
dataName = directory, dataName = directory,
descriptor = descriptor, descriptor = descriptor,
route = route,
headers = headers headers = headers
) )
} }

View File

@ -20,7 +20,7 @@ public class MarkupDocumentFragment(
@Serializable @Serializable
@SerialName("image") @SerialName("image")
public class ImageDocumentFragment( public class ImageDocumentFragment(
public val path: String, public val ref: String,
override val meta: Meta = Meta.EMPTY, override val meta: Meta = Meta.EMPTY,
) : DocumentFragment ) : DocumentFragment

View File

@ -59,7 +59,7 @@ public class FtlDocumentProcessor(
} }
private val data = mapOf( private val data = mapOf(
"documentName" to document.documentName.toStringUnescaped(), "documentName" to document.route.toStringUnescaped(),
"label" to TemplateMethodModelEx { args: List<Any?> -> "label" to TemplateMethodModelEx { args: List<Any?> ->
val counter = args.getOrNull(0)?.toString() ?: "@default" val counter = args.getOrNull(0)?.toString() ?: "@default"

View File

@ -42,7 +42,7 @@ public class RegexDocumentProcessor(public val document: DocumentBuilder) : Text
when (match.groups["function"]?.value) { when (match.groups["function"]?.value) {
"documentName" -> { "documentName" -> {
document.documentName.toStringUnescaped() document.route.toStringUnescaped()
} }
"label" -> { "label" -> {
@ -77,7 +77,7 @@ public class RegexDocumentProcessor(public val document: DocumentBuilder) : Text
}.replace(attributeRegex) { match -> }.replace(attributeRegex) { match ->
val uri = URI(match.groups["uri"]!!.value) val uri = URI(match.groups["uri"]!!.value)
val snarkUrl = when (uri.authority) { val snarkUrl = when (uri.authority) {
"documentName" -> document.documentName.toStringUnescaped() "documentName" -> document.route.toStringUnescaped()
// "ref" -> page.resolveRef(uri.path) // "ref" -> page.resolveRef(uri.path)
"meta" -> document.documentMeta[uri.path.parseAsName()].string ?: "@null" "meta" -> document.documentMeta[uri.path.parseAsName()].string ?: "@null"
else -> match.value else -> match.value