1
0
forked from SPC/spc-site

[WIP] refactor in progress

This commit is contained in:
Alexander Nozik 2024-01-04 11:26:23 +03:00
parent d2a31ce33e
commit 1923a1d296
14 changed files with 455 additions and 426 deletions

View File

@ -35,7 +35,7 @@ dependencies {
implementation("io.ktor:ktor-server-netty:$ktorVersion")
implementation("io.ktor:ktor-server-http-redirect:$ktorVersion")
implementation("io.ktor:ktor-server-forwarded-header:$ktorVersion")
implementation("ch.qos.logback:logback-classic:1.2.11")
implementation("ch.qos.logback:logback-classic:1.4.12")
testImplementation("io.ktor:ktor-server-tests:$ktorVersion")
}

View File

@ -1,4 +1,4 @@
kotlin.code.style=official
toolsVersion=0.14.9-kotlin-1.8.20
toolsVersion=0.15.2-kotlin-1.9.21
snarkVersion=0.1.0-dev-1

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@ -10,12 +10,11 @@ import io.ktor.server.plugins.forwardedheaders.XForwardedHeaders
import io.ktor.server.response.respondRedirect
import io.ktor.server.routing.get
import io.ktor.server.routing.routing
import space.kscience.dataforge.context.Global
import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.request
import space.kscience.dataforge.data.DataTree
import space.kscience.snark.html.SiteBuilder
import space.kscience.snark.html.SnarkHtmlPlugin
import space.kscience.snark.html.readDirectory
import space.kscience.dataforge.workspace.readDataDirectory
import space.kscience.snark.html.*
import space.kscience.snark.ktor.prepareSnarkDataCacheDirectory
import space.kscience.snark.ktor.site
import java.nio.file.FileSystems
@ -69,7 +68,11 @@ fun Application.spcModule() {
install(ForwardedHeaders)
install(XForwardedHeaders)
val snark = Global.request(SnarkHtmlPlugin)
val context = Context {
plugin(SnarkHtml)
}
val snark = context.request(SnarkHtml)
val dataDirectory = Path.of(
environment.config.tryGetString("ktor.environment.dataDirectory") ?: "data"
@ -81,14 +84,13 @@ fun Application.spcModule() {
copyResource("magprog", dataDirectory)
}
val siteData: DataTree<Any> = snark.readDirectory(dataDirectory)
site(snark, siteData, block = SiteBuilder::spcSite)
val siteData: DataTree<Any> = snark.io.readDataDirectory(dataDirectory)
routing {
get("magprog") {
call.respondRedirect("education/masters")
}
site(context, siteData, content = spcSite)
}
}

View File

@ -3,7 +3,6 @@ package center.sciprog
import kotlinx.coroutines.runBlocking
import kotlinx.html.*
import space.kscience.dataforge.data.Data
import space.kscience.dataforge.data.DataTree
import space.kscience.dataforge.data.await
import space.kscience.dataforge.data.getByType
import space.kscience.dataforge.meta.Meta
@ -11,7 +10,6 @@ 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.parseAsName
import space.kscience.snark.html.*
@ -22,22 +20,19 @@ private val Data<*>.fragment: String
get() = meta["fragment"].string ?: ""
internal fun SiteBuilder.bmk(data: DataTree<Any>, prefix: Name = "bmk".parseAsName()) {
internal val bmk = HtmlSite {
// val data: DataTree<Any> = snark.readDirectory(dataPath.resolve("content"))
site(prefix, data) {
static("assets")
static("images")
static("common.assets.webfonts", "assets/webfonts")
static("common", "")
val about: Data<HtmlFragment> = data.resolveHtml("about")
val team: Data<HtmlFragment> = data.resolveHtml("team.index")
val teamData: Map<Name, Data<HtmlFragment>> = data.resolveAllHtml { _, meta -> meta["type"].string == "team" }
val solutions: Data<HtmlFragment> = data.resolveHtml("lotSeis")
val partners: Data<HtmlFragment> = data.resolveHtml("partners")
val partnersData = runBlocking { data.getByType<Meta>("partnersData")!!.await() }
val about: Data<PageFragment> = siteData.resolveHtml("about")
val team: Data<PageFragment> = siteData.resolveHtml("team.index")
val teamData: Map<Name, Data<PageFragment>> = siteData.resolveAllHtml { _, meta -> meta["type"].string == "team" }
val solutions: Data<PageFragment> = siteData.resolveHtml("lotSeis")
val partners: Data<PageFragment> = siteData.resolveHtml("partners")
val partnersData = runBlocking { siteData.getByType<Meta>("partnersData")!!.await() }
page {
head {
@ -139,7 +134,7 @@ internal fun SiteBuilder.bmk(data: DataTree<Any>, prefix: Name = "bmk".parseAsNa
header("major") {
h2 { +team.title }
}
htmlData(team)
fragment(team)
teamData.values.sortedBy { it.order }.forEach { data ->
span("image left") {
img {
@ -148,14 +143,14 @@ internal fun SiteBuilder.bmk(data: DataTree<Any>, prefix: Name = "bmk".parseAsNa
}
}
h3 { +data.title }
htmlData(data)
fragment(data)
}
}
section("main") {
id = solutions.fragment
header("major") {
h2 { +solutions.title }
htmlData(solutions)
fragment(solutions)
span("image fit") {
img {
src = resolveRef("images/fresnel_lands_critdepth2.png")
@ -167,7 +162,7 @@ internal fun SiteBuilder.bmk(data: DataTree<Any>, prefix: Name = "bmk".parseAsNa
id = partners.fragment
header("major") {
h2 { +partners.title }
htmlData(partners)
fragment(partners)
table {
partnersData.getIndexed("content").values.forEach {
tr {
@ -289,4 +284,3 @@ internal fun SiteBuilder.bmk(data: DataTree<Any>, prefix: Name = "bmk".parseAsNa
}
}
}
}

View File

@ -13,9 +13,11 @@ import kotlin.collections.component1
import kotlin.collections.component2
import kotlin.collections.set
context(WebPage) private fun FlowContent.spcSpotlightContent(
landing: HtmlData,
content: Map<Name, HtmlData>,
context(PageContextWithData)
private fun FlowContent.spcSpotlightContent(
landing: Data<PageFragment>,
content: Map<Name, Data<PageFragment>>,
) {
// Banner
// Note: The "styleN" class below should match that of the header element.
@ -32,7 +34,7 @@ context(WebPage) private fun FlowContent.spcSpotlightContent(
h1 { +(landing.meta["title"].string ?: "???") }
}
div("content") {
htmlData(landing)
fragment(landing)
}
}
}
@ -63,8 +65,9 @@ context(WebPage) private fun FlowContent.spcSpotlightContent(
header("major") {
h3 { +(entry.meta["title"].string ?: "???") }
}
val infoData = data.resolveHtmlOrNull(name.replaceLast { NameToken(it.body + "[info]") }) ?: entry
htmlData(infoData)
val infoData =
data.resolveHtmlOrNull(name.replaceLast { NameToken(it.body + "[info]") }) ?: entry
fragment(infoData)
ul("actions") {
li {
a(classes = "button") {
@ -82,16 +85,16 @@ context(WebPage) private fun FlowContent.spcSpotlightContent(
}
internal fun SiteBuilder.spcSpotlight(
internal fun SiteContextWithData.spcSpotlight(
address: String,
contentFilter: (Name, Meta) -> Boolean,
) {
val pageName = address.parseAsName()
val languagePrefix = languagePrefix
val body = data.resolveHtmlOrNull(languagePrefix + pageName)
?: data.resolveHtmlOrNull(pageName) ?: error("Could not find body for $pageName")
val content: Map<Name, Data<HtmlFragment>> =
data.resolveAllHtml { name, meta -> name.startsWith(languagePrefix) && contentFilter(name, meta) }
val body = siteData.resolveHtmlOrNull(languagePrefix + pageName)
?: siteData.resolveHtmlOrNull(pageName) ?: error("Could not find body for $pageName")
val content: Map<Name, Data<PageFragment>> =
siteData.resolveAllHtml { name, meta -> name.startsWith(languagePrefix) && contentFilter(name, meta) }
val meta = body.meta
page(pageName) {
@ -107,10 +110,6 @@ internal fun SiteBuilder.spcSpotlight(
}
content.forEach { (name, contentBody) ->
page(name, contentBody.meta) {
spcPageContent {
htmlData(contentBody)
}
}
page(name, contentBody.meta, spcPage(contentBody))
}
}

View File

@ -2,19 +2,15 @@ package center.sciprog
import html5up.forty.fortyScripts
import kotlinx.html.*
import space.kscience.dataforge.data.Data
import space.kscience.dataforge.data.DataTree
import space.kscience.dataforge.meta.*
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.data.*
import space.kscience.dataforge.meta.get
import space.kscience.dataforge.meta.string
import space.kscience.dataforge.names.asName
import space.kscience.dataforge.names.startsWith
import space.kscience.snark.html.*
import kotlin.reflect.typeOf
context(WebPage) internal fun HTML.spcPageContent(
fragment: FlowContent.() -> Unit,
) {
internal fun spcPage(content: Data<PageFragment>) = HtmlPage {
val title by pageMeta.string { SPC_TITLE }
val pageName by pageMeta.string { title }
spcHead(pageName)
@ -30,7 +26,8 @@ context(WebPage) internal fun HTML.spcPageContent(
}
pageMeta["image"]?.let { imageMeta ->
val imagePath =
imageMeta.value?.string ?: imageMeta["path"].string ?: error("Image path not provided")
imageMeta.value?.string ?: imageMeta["path"].string
?: error("Image path not provided")
val imageClass = imageMeta["position"].string ?: "main"
span("image $imageClass") {
img {
@ -39,7 +36,7 @@ context(WebPage) internal fun HTML.spcPageContent(
}
}
}
fragment()
fragment(content)
}
}
}
@ -49,34 +46,7 @@ context(WebPage) internal fun HTML.spcPageContent(
}
}
@Suppress("UNCHECKED_CAST")
internal val FortyDataRenderer: DataRenderer = object : DataRenderer {
context(SiteBuilder)
override fun invoke(name: Name, data: Data<Any>) {
if (data.type == typeOf<HtmlFragment>()) {
data as Data<HtmlFragment>
val languageMeta: Meta = Language.forName(name)
val dataMeta: Meta = if (languageMeta.isEmpty()) {
data.meta
} else {
data.meta.toMutableMeta().apply {
Language.LANGUAGES_KEY put languageMeta
}
}
page(name, dataMeta) {
spcPageContent {
htmlData(data)
}
}
}
}
}
context(WebPage) private fun HTML.spcHomePage() {
internal val spcHomePage = HtmlPage {
spcHead()
body("is-preload") {
wrapper {
@ -156,14 +126,14 @@ context(WebPage) private fun HTML.spcHomePage() {
article {
span("image") {
img {
src = resolveRef("images/pic01.jpg")
src = page.resolveRef("images/pic01.jpg")
alt = ""
}
}
header("major") {
h3 {
a(classes = "link") {
href = resolvePageRef("education")
href = page.resolvePageRef("education")
+"""Education"""
}
}
@ -173,14 +143,14 @@ context(WebPage) private fun HTML.spcHomePage() {
article {
span("image") {
img {
src = resolveRef("images/pic02.jpg")
src = page.resolveRef("images/pic02.jpg")
alt = ""
}
}
header("major") {
h3 {
a(classes = "link") {
href = resolvePageRef("research")
href = page.resolvePageRef("research")
+"""Research"""
}
}
@ -192,14 +162,14 @@ context(WebPage) private fun HTML.spcHomePage() {
article {
span("image") {
img {
src = resolveRef("images/pic03.jpg")
src = page.resolveRef("images/pic03.jpg")
alt = ""
}
}
header("major") {
h3 {
a(classes = "link") {
href = resolvePageRef("consulting.index")
href = page.resolvePageRef("consulting.index")
+"""Consulting"""
}
}
@ -209,14 +179,14 @@ context(WebPage) private fun HTML.spcHomePage() {
article {
span("image") {
img {
src = resolveRef("images/pic04.jpg")
src = page.resolveRef("images/pic04.jpg")
alt = ""
}
}
header("major") {
h3 {
a(classes = "link") {
href = resolvePageRef("team")
href = page.resolvePageRef("team")
+"""Team"""
}
}
@ -263,24 +233,32 @@ context(WebPage) private fun HTML.spcHomePage() {
}
}
internal fun SiteBuilder.spcHome(homePageData: DataTree<Any>, prefix: Name = Name.EMPTY) {
private fun SiteContextWithData.allPagesIn(location: String){
siteData.filterByType<PageFragment> { name, meta ->
name.startsWith(location) && meta["type"].string == "page"
}.forEach { (name, content) ->
page(name, content = spcPage(content))
}
}
//val homePageData: DataTree<Any> = snark.readDirectory(dataPath.resolve("content"))
site(prefix, homePageData) {
internal val spcHome: HtmlSite = HtmlSite {
static("assets")
static("images")
static("common", "")
withLanguages(
"en" to "",
"ru" to "ru"
multiLanguageSite(
siteData,
mapOf(
"en" to Language(""),
"ru" to Language("ru"),
)
) {
page { spcHomePage() }
page(content = spcHomePage)
localizedPages("consulting", dataRenderer = FortyDataRenderer)
allPagesIn("consulting")
localizedPages("education", dataRenderer = FortyDataRenderer)
allPagesIn("education")
spcSpotlight("team") { _, meta ->
meta["type"].string == "team"
@ -290,5 +268,53 @@ internal fun SiteBuilder.spcHome(homePageData: DataTree<Any>, prefix: Name = Nam
name.startsWith("projects".asName()) && meta["type"].string == "project"
}
}
// withLanguages(
// "en" to "",
// "ru" to "ru"
// ) {
// page { spcHomePage() }
//
// localizedPages("consulting", dataRenderer = FortyDataRenderer)
//
// localizedPages("education", dataRenderer = FortyDataRenderer)
//
// spcSpotlight("team") { _, meta ->
// meta["type"].string == "team"
// }
//
// spcSpotlight("research") { name, meta ->
// name.startsWith("projects".asName()) && meta["type"].string == "project"
// }
// }
}
}
//
//internal fun SiteBuilder.spcHome(homePageData: DataTree<Any>, prefix: Name = Name.EMPTY) {
//
// //val homePageData: DataTree<Any> = snark.readDirectory(dataPath.resolve("content"))
//
// site(prefix, homePageData) {
// static("assets")
// static("images")
// static("common", "")
//
// withLanguages(
// "en" to "",
// "ru" to "ru"
// ) {
// page { spcHomePage() }
//
// localizedPages("consulting", dataRenderer = FortyDataRenderer)
//
// localizedPages("education", dataRenderer = FortyDataRenderer)
//
// spcSpotlight("team") { _, meta ->
// meta["type"].string == "team"
// }
//
// spcSpotlight("research") { name, meta ->
// name.startsWith("projects".asName()) && meta["type"].string == "project"
// }
// }
// }
//}

View File

@ -2,7 +2,7 @@ package center.sciprog
import kotlinx.coroutines.runBlocking
import kotlinx.html.*
import space.kscience.dataforge.data.DataTree
import space.kscience.dataforge.data.Data
import space.kscience.dataforge.data.await
import space.kscience.dataforge.data.getByType
import space.kscience.dataforge.meta.Meta
@ -29,17 +29,19 @@ import kotlin.collections.set
// }
//}
private val HtmlData.imagePath: String? get() = meta["image"]?.string ?: meta["image.path"].string
private val HtmlData.name: String get() = meta["name"].string ?: error("Name not found")
private val Data<PageFragment>.imagePath: String? get() = meta["image"]?.string ?: meta["image.path"].string
private val Data<PageFragment>.name: String get() = meta["name"].string ?: error("Name not found")
context(WebPage) class MagProgSection(
context(PageContext)
class MagProgSection(
val id: String,
val title: String,
val style: String,
val content: FlowContent.() -> Unit,
)
context(WebPage) private fun wrapSection(
context(PageContext)
private fun wrapSection(
id: String,
title: String,
sectionContent: FlowContent.() -> Unit,
@ -50,14 +52,15 @@ context(WebPage) private fun wrapSection(
}
}
context(WebPage) private fun wrapSection(
block: HtmlData,
context(PageContextWithData)
private fun wrapSection(
section: Data<PageFragment>,
idOverride: String? = null,
): MagProgSection = wrapSection(
idOverride ?: block.id,
block.meta["section_title"]?.string ?: error("Section without title"),
idOverride ?: section.id,
section.meta["section_title"]?.string ?: error("Section without title"),
) {
htmlData(block)
fragment(section)
}
private val CONTENT_NODE_NAME = Name.EMPTY//"content".asName()
@ -68,24 +71,25 @@ 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(WebPage) private fun FlowContent.programSection() {
private val programSection = PageFragment {
val programBlock = data.resolveHtmlOrNull(PROGRAM_PATH)!!
val recommendedBlock = data.resolveHtmlOrNull(RECOMMENDED_COURSES_PATH)!!
div("inner") {
h2 { +"Учебная программа" }
htmlData(programBlock)
fragment(programBlock)
button(classes = "fit collapsible") {
attributes["data-target"] = "recommended-courses-content"
+"Рекомендованные курсы"
}
div(classes = "collapsible-content") {
id = "recommended-courses-content"
htmlData(recommendedBlock)
fragment(recommendedBlock)
}
}
}
context(WebPage) private fun FlowContent.partners() {
private val partners = PageFragment {
//val partnersData: Meta = resolve<Any>(PARTNERS_PATH)?.meta ?: Meta.EMPTY
val partnersData: Meta = runBlocking { data.getByType<Meta>(PARTNERS_PATH)?.await() } ?: Meta.EMPTY
div("inner") {
@ -115,8 +119,8 @@ context(WebPage) private fun FlowContent.partners() {
// val photo: String? by meta.string()
//}
context(WebPage) private fun FlowContent.team() {
val team = data.findByContentType("magprog_team").values.sortedBy { it.order }
private val team = PageFragment {
val team = data.findHtmlByContentType("magprog_team").values.sortedBy { it.order }
div("inner") {
h2 { +"Команда" }
@ -131,7 +135,7 @@ context(WebPage) private fun FlowContent.team() {
alt = imagePath
) {
h3 { +member.name }
htmlData(member)
fragment(member)
}
}
}
@ -170,8 +174,8 @@ context(WebPage) private fun FlowContent.team() {
// }
}
context(WebPage) private fun FlowContent.mentors() {
val mentors = data.findByContentType("magprog_mentor").entries.sortedBy { it.value.id }
val mentors = PageFragment {
val mentors = data.findHtmlByContentType("magprog_mentor").entries.sortedBy { it.value.id }
div("inner") {
h2 {
@ -200,7 +204,7 @@ context(WebPage) private fun FlowContent.mentors() {
}
val info = data.resolveHtmlOrNull(name.replaceLast { NameToken(it.body + "[info]") })
if (info != null) {
htmlData(info)
fragment(info)
}
}
}
@ -208,7 +212,8 @@ context(WebPage) private fun FlowContent.mentors() {
}
}
context(WebPage) internal fun HTML.magProgHead(title: String) {
context(PageContext)
internal fun HTML.magProgHead(title: String) {
head {
title {
+title
@ -258,7 +263,8 @@ context(WebPage) internal fun HTML.magProgHead(title: String) {
}
}
context(WebPage) internal fun BODY.magProgFooter() {
context(PageContext)
internal fun BODY.magProgFooter() {
footer("wrapper style1-alt") {
id = "footer"
div("inner") {
@ -297,26 +303,23 @@ context(WebPage) internal fun BODY.magProgFooter() {
}
}
context(SnarkContext) private val HtmlData.mentorPageId get() = "mentor-${id}"
context(SnarkContext) private val Data<PageFragment>.mentorPageId get() = "mentor-${id}"
internal fun SiteBuilder.spcMasters(magProgData: DataTree<Any>, prefix: Name = "education.masters".parseAsName()) {
//val magProgData: DataTree<Any> = snark.readDirectory(dataPath.resolve("content"))
site(prefix, magProgData) {
internal val spcMasters = HtmlSite {
static("assets")
static("images")
static("common", "")
page{
val sections = listOf<MagProgSection>(
wrapSection(page.data.resolveHtmlOrNull(INTRO_PATH)!!, "intro"),
val sections = listOf(
wrapSection(data.resolveHtmlOrNull(INTRO_PATH)!!, "intro"),
MagProgSection(
id = "partners",
title = "Партнеры",
style = "wrapper style3 fullscreen fade-up"
) {
partners()
fragment(partners)
},
// section(props.data.partners),
MagProgSection(
@ -324,19 +327,19 @@ internal fun SiteBuilder.spcMasters(magProgData: DataTree<Any>, prefix: Name = "
title = "Научные руководители",
style = "wrapper style2 spotlights",
) {
mentors()
fragment(mentors)
},
MagProgSection(
id = "program",
title = "Учебная программа",
style = "wrapper style3 fullscreen fade-up"
) {
programSection()
fragment(programSection)
},
wrapSection(page.data.resolveHtmlOrNull(ENROLL_PATH)!!, "enroll"),
wrapSection(data.resolveHtmlOrNull(ENROLL_PATH)!!, "enroll"),
wrapSection(id = "contacts", title = "Контакты") {
htmlData(page.data.resolveHtmlOrNull(CONTACTS_PATH)!!)
team()
fragment(data.resolveHtmlOrNull(CONTACTS_PATH)!!)
fragment(team)
}
)
@ -383,19 +386,18 @@ internal fun SiteBuilder.spcMasters(magProgData: DataTree<Any>, prefix: Name = "
}
val mentors = data.findByContentType("magprog_mentor").values.sortedBy {
val mentors = siteData.findHtmlByContentType("magprog_mentor").values.sortedBy {
it.order
}
mentors.forEach { mentor ->
page(mentor.mentorPageId.asName()) {
page(mentor.mentorPageId.asName(), siteData) {
magProgHead("Научное программирование: ${mentor.name}")
body("is-preload") {
header {
id = "header"
a(classes = "title") {
href = "$homeRef#mentors"
href = "${page.homeRef}#mentors"
+"Научные руководители"
}
nav {
@ -403,7 +405,7 @@ internal fun SiteBuilder.spcMasters(magProgData: DataTree<Any>, prefix: Name = "
mentors.forEach {
li {
a {
href = resolvePageRef(it.mentorPageId)
href = page.resolvePageRef(it.mentorPageId)
+it.name.substringAfterLast(" ")
}
}
@ -421,12 +423,12 @@ internal fun SiteBuilder.spcMasters(magProgData: DataTree<Any>, prefix: Name = "
span("image $imageClass") {
mentor.imagePath?.let { photoPath ->
img(
src = resolveRef(photoPath),
src = page.resolveRef(photoPath),
alt = mentor.name
)
}
}
htmlData(mentor)
fragment(mentor)
}
}
}
@ -435,4 +437,3 @@ internal fun SiteBuilder.spcMasters(magProgData: DataTree<Any>, prefix: Name = "
}
}
}
}

View File

@ -3,16 +3,16 @@ package center.sciprog
import kotlinx.html.*
import space.kscience.dataforge.meta.get
import space.kscience.dataforge.meta.string
import space.kscience.snark.html.WebPage
import space.kscience.snark.html.PageContext
import space.kscience.snark.html.getLanguageMap
import space.kscience.snark.html.homeRef
import space.kscience.snark.html.languages
import space.kscience.snark.html.resolvePageRef
import java.time.LocalDate
internal const val SPC_TITLE = "Scientific Programming Centre"
context(WebPage)
context(PageContext)
internal fun HTML.spcHead(title: String = SPC_TITLE) {
head {
title {
@ -53,7 +53,7 @@ internal fun HTML.spcHead(title: String = SPC_TITLE) {
}
}
context(WebPage)
context(PageContext)
internal fun FlowContent.spcHomeMenu() {
nav {
id = "menu"
@ -106,7 +106,7 @@ internal fun FlowContent.spcHomeMenu() {
}
}
context(WebPage)
context(PageContext)
internal fun FlowContent.spcFooter() {
footer {
id = "footer"
@ -158,7 +158,7 @@ internal fun FlowContent.spcFooter() {
}
}
context(WebPage)
context(PageContext)
internal fun FlowContent.wrapper(contentBody: FlowContent.() -> Unit) {
div {
id = "wrapper"
@ -172,9 +172,9 @@ internal fun FlowContent.wrapper(contentBody: FlowContent.() -> Unit) {
}
if (languages.isNotEmpty()) {
getLanguageMap().takeIf { it.isNotEmpty() }?.let { languageMap->
div {
languages.forEach { (key, meta) ->
languageMap.forEach { (key, meta) ->
a(classes = "button primary small") {
href = resolvePageRef(meta["target"].string ?: "#")
+key

View File

@ -3,18 +3,19 @@ package center.sciprog
import space.kscience.dataforge.data.*
import space.kscience.dataforge.misc.DFExperimental
import space.kscience.dataforge.names.Name
import space.kscience.snark.html.SiteBuilder
import space.kscience.snark.html.HtmlSite
import space.kscience.snark.html.site
@OptIn(DFExperimental::class)
private fun <T : Any> DataSet<T>.siteData(branchName: String): DataTree<T> = DataTree(dataType) {
private fun <T : Any> DataSet<T>.contentFor(branchName: String): DataTree<T> = DataTree(dataType) {
populateFrom(branch(Name.of(branchName, "content")))
node("common", branch("common"))
node("assets", branch(Name.of(branchName, "assets")))
node("images", branch(Name.of(branchName, "images")))
}
fun SiteBuilder.spcSite() {
spcHome(data.siteData("home"))
spcMasters(data.siteData("magprog"))
val spcSite = HtmlSite {
route(Name.EMPTY, siteData.contentFor("home"), content = spcHome)
site("education.masters", siteData.contentFor("magprog"), content = spcMasters)
// bmk(data.branch("bmk").withBranch("common", commonData))
}

View File

@ -1,18 +1,21 @@
package center.sciprog
import space.kscience.dataforge.context.Global
import kotlinx.coroutines.coroutineScope
import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.request
import space.kscience.snark.html.SiteBuilder
import space.kscience.snark.html.SnarkHtmlPlugin
import space.kscience.snark.html.readResources
import space.kscience.snark.html.static
import space.kscience.snark.html.*
import space.kscience.snark.html.static.staticSite
import java.nio.file.Path
fun main(args: Array<String>) {
suspend fun main(args: Array<String>) = coroutineScope{
val context = Context{
plugin(SnarkHtml)
}
val destinationPath = args.firstOrNull() ?: "build/public"
val snark = Global.request(SnarkHtmlPlugin)
val snark = context.request(SnarkHtml)
val siteData = snark.readResources("common", "home", "magprog")
snark.static(siteData, Path.of(destinationPath), block = SiteBuilder::spcSite)
snark.staticSite(siteData, Path.of(destinationPath), content = spcSite)
}

View File

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

View File

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

View File

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