Spliting site and the snark project complete

This commit is contained in:
Alexander Nozik 2022-07-03 16:28:53 +03:00
parent eb81d46238
commit 5e93f982f8
No known key found for this signature in database
GPG Key ID: F7FCF2DD25C71357
17 changed files with 90 additions and 53 deletions

View File

@ -29,6 +29,7 @@ dependencies {
implementation("io.ktor:ktor-server-netty:$ktorVersion") implementation("io.ktor:ktor-server-netty:$ktorVersion")
implementation("io.ktor:ktor-server-http-redirect:$ktorVersion") implementation("io.ktor:ktor-server-http-redirect:$ktorVersion")
implementation("ch.qos.logback:logback-classic:1.2.11")
testImplementation("io.ktor:ktor-server-tests:$ktorVersion") testImplementation("io.ktor:ktor-server-tests:$ktorVersion")
} }
@ -43,7 +44,7 @@ apiValidation{
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> { tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
kotlinOptions { kotlinOptions {
freeCompilerArgs = freeCompilerArgs + "-Xcontext-receivers" freeCompilerArgs = freeCompilerArgs + "-Xcontext-receivers"
} }
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 810 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
data/common/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -0,0 +1 @@
{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}

View File

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

View File

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

View File

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

View File

@ -5,10 +5,8 @@ import io.ktor.server.application.log
import kotlinx.css.CssBuilder import kotlinx.css.CssBuilder
import kotlinx.html.CommonAttributeGroupFacade import kotlinx.html.CommonAttributeGroupFacade
import kotlinx.html.style import kotlinx.html.style
import space.kscience.dataforge.context.Context import space.kscience.snark.SnarkEnvironment
import space.kscience.dataforge.context.fetch import space.kscience.snark.ktor.site
import space.kscience.snark.html.SnarkPlugin
import space.kscience.snark.ktor.snarkSite
import java.net.URI import java.net.URI
import java.nio.file.FileSystems import java.nio.file.FileSystems
import java.nio.file.Files import java.nio.file.Files
@ -49,11 +47,6 @@ const val BUILD_DATE_FILE = "/buildDate"
fun Application.spcModule() { fun Application.spcModule() {
// install(HttpsRedirect) // install(HttpsRedirect)
val context = Context("spc-site") {
plugin(SnarkPlugin)
}
val snark = context.fetch(SnarkPlugin)
val dataPath = Path.of("data") val dataPath = Path.of("data")
// Clear data directory if it is outdated // Clear data directory if it is outdated
@ -88,20 +81,20 @@ fun Application.spcModule() {
dataPath.resolve(DEPLOY_DATE_FILE).writeText(date) dataPath.resolve(DEPLOY_DATE_FILE).writeText(date)
} }
snarkSite(snark) { SnarkEnvironment.default.site {
val homeDataPath = resolveData( val homeDataPath = resolveData(
this@spcModule.javaClass.getResource("/home")!!.toURI(), this@spcModule.javaClass.getResource("/home")!!.toURI(),
dataPath / "home" dataPath / "home"
) )
spcHome(rootPath = homeDataPath) spcHome(dataPath = homeDataPath)
val mastersDataPath = resolveData( val mastersDataPath = resolveData(
this@spcModule.javaClass.getResource("/magprog")!!.toURI(), this@spcModule.javaClass.getResource("/magprog")!!.toURI(),
dataPath / "magprog" dataPath / "magprog"
) )
spcMaster(dataPath = mastersDataPath) spcMasters(dataPath = mastersDataPath)
} }
} }

View File

@ -15,7 +15,7 @@ import kotlin.collections.component1
import kotlin.collections.component2 import kotlin.collections.component2
import kotlin.collections.set import kotlin.collections.set
context(Page) private fun FlowContent.spcSpotlightContent( context(WebPage) private fun FlowContent.spcSpotlightContent(
landing: HtmlData, landing: HtmlData,
content: Map<Name, HtmlData>, content: Map<Name, HtmlData>,
) { ) {

View File

@ -15,7 +15,7 @@ import java.nio.file.Path
import kotlin.reflect.typeOf import kotlin.reflect.typeOf
context(Page) internal fun HTML.spcPageContent( context(WebPage) internal fun HTML.spcPageContent(
meta: Meta, meta: Meta,
title: String = meta["title"].string ?: SPC_TITLE, title: String = meta["title"].string ?: SPC_TITLE,
fragment: FlowContent.() -> Unit, fragment: FlowContent.() -> Unit,
@ -65,7 +65,7 @@ internal val FortyDataRenderer: DataRenderer = { name, data ->
} }
context(Page) private fun HTML.spcHome() { context(WebPage) private fun HTML.spcHome() {
spcHead() spcHead()
body("is-preload") { body("is-preload") {
wrapper { wrapper {
@ -252,13 +252,14 @@ context(Page) private fun HTML.spcHome() {
} }
internal fun SiteBuilder.spcHome(rootPath: Path, prefix: Name = Name.EMPTY) { internal fun SiteBuilder.spcHome(dataPath: Path, prefix: Name = Name.EMPTY) {
val homePageData = snark.readDirectory(rootPath.resolve("content")) val homePageData = snark.readDirectory(dataPath.resolve("content"))
route(prefix, homePageData, setAsRoot = true) { route(prefix, homePageData, setAsRoot = true) {
assetDirectory("assets", rootPath.resolve("assets")) file(dataPath.resolve("assets"))
assetDirectory("images", rootPath.resolve("images")) file(dataPath.resolve("images"))
file(dataPath.resolve("../common"), "")
page { spcHome() } page { spcHome() }

View File

@ -15,7 +15,7 @@ import space.kscience.dataforge.names.plus
import space.kscience.dataforge.names.withIndex import space.kscience.dataforge.names.withIndex
import space.kscience.snark.* import space.kscience.snark.*
import space.kscience.snark.html.* import space.kscience.snark.html.*
import space.kscience.snark.html.Page import space.kscience.snark.html.WebPage
import java.nio.file.Path import java.nio.file.Path
import kotlin.collections.component1 import kotlin.collections.component1
import kotlin.collections.component2 import kotlin.collections.component2
@ -37,14 +37,14 @@ import kotlin.collections.set
private val HtmlData.imagePath: String? get() = meta["image"]?.string ?: meta["image.path"].string 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 HtmlData.name: String get() = meta["name"].string ?: error("Name not found")
context(Page) class MagProgSection( context(WebPage) class MagProgSection(
val id: String, val id: String,
val title: String, val title: String,
val style: String, val style: String,
val content: FlowContent.() -> Unit, val content: FlowContent.() -> Unit,
) )
context(Page) private fun wrapSection( context(WebPage) private fun wrapSection(
id: String, id: String,
title: String, title: String,
sectionContent: FlowContent.() -> Unit, sectionContent: FlowContent.() -> Unit,
@ -55,7 +55,7 @@ context(Page) private fun wrapSection(
} }
} }
context(Page) private fun wrapSection( context(WebPage) private fun wrapSection(
block: HtmlData, block: HtmlData,
idOverride: String? = null, idOverride: String? = null,
): MagProgSection = wrapSection( ): MagProgSection = wrapSection(
@ -73,7 +73,7 @@ private val PROGRAM_PATH: Name = CONTENT_NODE_NAME + "program"
private val RECOMMENDED_COURSES_PATH: Name = CONTENT_NODE_NAME + "recommendedCourses" private val RECOMMENDED_COURSES_PATH: Name = CONTENT_NODE_NAME + "recommendedCourses"
private val PARTNERS_PATH: Name = CONTENT_NODE_NAME + "partners" private val PARTNERS_PATH: Name = CONTENT_NODE_NAME + "partners"
context(Page) private fun FlowContent.programSection() { context(WebPage) private fun FlowContent.programSection() {
val programBlock = data.resolveHtml(PROGRAM_PATH)!! val programBlock = data.resolveHtml(PROGRAM_PATH)!!
val recommendedBlock = data.resolveHtml(RECOMMENDED_COURSES_PATH)!! val recommendedBlock = data.resolveHtml(RECOMMENDED_COURSES_PATH)!!
div("inner") { div("inner") {
@ -90,7 +90,7 @@ context(Page) private fun FlowContent.programSection() {
} }
} }
context(Page) private fun FlowContent.partners() { context(WebPage) private fun FlowContent.partners() {
//val partnersData: Meta = resolve<Any>(PARTNERS_PATH)?.meta ?: Meta.EMPTY //val partnersData: Meta = resolve<Any>(PARTNERS_PATH)?.meta ?: Meta.EMPTY
val partnersData: Meta = runBlocking { data.getByType<Meta>(PARTNERS_PATH)?.await() } ?: Meta.EMPTY val partnersData: Meta = runBlocking { data.getByType<Meta>(PARTNERS_PATH)?.await() } ?: Meta.EMPTY
div("inner") { div("inner") {
@ -120,7 +120,7 @@ context(Page) private fun FlowContent.partners() {
// val photo: String? by meta.string() // val photo: String? by meta.string()
//} //}
context(Page) private fun FlowContent.team() { context(WebPage) private fun FlowContent.team() {
val team = data.findByContentType("magprog_team").values.sortedBy { it.order } val team = data.findByContentType("magprog_team").values.sortedBy { it.order }
div("inner") { div("inner") {
@ -175,7 +175,7 @@ context(Page) private fun FlowContent.team() {
// } // }
} }
context(Page) private fun FlowContent.mentors() { context(WebPage) private fun FlowContent.mentors() {
val mentors = data.findByContentType("magprog_mentor").entries.sortedBy { it.value.id } val mentors = data.findByContentType("magprog_mentor").entries.sortedBy { it.value.id }
div("inner") { div("inner") {
@ -213,7 +213,7 @@ context(Page) private fun FlowContent.mentors() {
} }
} }
context(Page) internal fun HTML.magProgHead(title: String) { context(WebPage) internal fun HTML.magProgHead(title: String) {
head { head {
this.title = title this.title = title
meta { meta {
@ -237,10 +237,31 @@ context(Page) internal fun HTML.magProgHead(title: String) {
href = resolveRef("assets/css/noscript.css") href = resolveRef("assets/css/noscript.css")
} }
} }
link {
rel = "apple-touch-icon"
sizes = "180x180"
href = "/apple-touch-icon.png"
}
link {
rel = "icon"
type = "image/png"
sizes = "32x32"
href = "/favicon-32x32.png"
}
link {
rel = "icon"
type = "image/png"
sizes = "16x16"
href = "/favicon-16x16.png"
}
link {
rel = "manifest"
href = "/site.webmanifest"
}
} }
} }
context(Page) internal fun BODY.magProgFooter() { context(WebPage) internal fun BODY.magProgFooter() {
footer("wrapper style1-alt") { footer("wrapper style1-alt") {
id = "footer" id = "footer"
div("inner") { div("inner") {
@ -281,13 +302,14 @@ context(Page) internal fun BODY.magProgFooter() {
context(SnarkContext) private val HtmlData.mentorPageId get() = "mentor-${id}" context(SnarkContext) private val HtmlData.mentorPageId get() = "mentor-${id}"
internal fun SiteBuilder.spcMaster(dataPath: Path, prefix: Name = "magprog".asName()) { internal fun SiteBuilder.spcMasters(dataPath: Path, prefix: Name = "magprog".asName()) {
val magProgData: DataTree<Any> = snark.readDirectory(dataPath.resolve("content")) val magProgData: DataTree<Any> = snark.readDirectory(dataPath.resolve("content"))
route(prefix, magProgData, setAsRoot = true) { route(prefix, magProgData, setAsRoot = true) {
assetDirectory("assets", dataPath.resolve("assets")) file(dataPath.resolve("assets"))
assetDirectory("images", dataPath.resolve("images")) file(dataPath.resolve("images"))
file(dataPath.resolve("../common"), "")
page { page {
val sections = listOf<MagProgSection>( val sections = listOf<MagProgSection>(

View File

@ -1,14 +1,14 @@
package ru.mipt.spc package ru.mipt.spc
import kotlinx.html.* import kotlinx.html.*
import space.kscience.snark.html.Page import space.kscience.snark.html.WebPage
import space.kscience.snark.html.homeRef import space.kscience.snark.html.homeRef
import space.kscience.snark.html.resolvePageRef import space.kscience.snark.html.resolvePageRef
internal const val SPC_TITLE = "Scientific Programming Centre" internal const val SPC_TITLE = "Scientific Programming Centre"
context(Page) internal fun HTML.spcHead(title: String = SPC_TITLE) { context(WebPage) internal fun HTML.spcHead(title: String = SPC_TITLE) {
head { head {
title { title {
+title +title
@ -24,10 +24,31 @@ context(Page) internal fun HTML.spcHead(title: String = SPC_TITLE) {
noScript { noScript {
link(rel = "stylesheet", href = resolveRef("assets/css/noscript.css")) link(rel = "stylesheet", href = resolveRef("assets/css/noscript.css"))
} }
link {
rel = "apple-touch-icon"
sizes = "180x180"
href = "/apple-touch-icon.png"
}
link {
rel = "icon"
type = "image/png"
sizes = "32x32"
href = "/favicon-32x32.png"
}
link {
rel = "icon"
type = "image/png"
sizes = "16x16"
href = "/favicon-16x16.png"
}
link {
rel = "manifest"
href = "/site.webmanifest"
}
} }
} }
context(Page) internal fun FlowContent.spcHomeMenu() { context(WebPage) internal fun FlowContent.spcHomeMenu() {
nav { nav {
id = "menu" id = "menu"
ul("links") { ul("links") {
@ -39,7 +60,7 @@ context(Page) internal fun FlowContent.spcHomeMenu() {
} }
li { li {
a { a {
href = resolvePageRef("magprog") href = resolvePageRef("magprog.index")
+"""Master""" +"""Master"""
} }
} }
@ -51,7 +72,7 @@ context(Page) internal fun FlowContent.spcHomeMenu() {
} }
li { li {
a { a {
href = resolvePageRef("consulting") href = resolvePageRef("consulting.index")
+"""Consulting""" +"""Consulting"""
} }
} }
@ -79,7 +100,7 @@ context(Page) internal fun FlowContent.spcHomeMenu() {
} }
} }
context(Page) internal fun FlowContent.spcFooter() { context(WebPage) internal fun FlowContent.spcFooter() {
footer { footer {
id = "footer" id = "footer"
div("inner") { div("inner") {
@ -129,7 +150,7 @@ context(Page) internal fun FlowContent.spcFooter() {
} }
} }
context(Page) internal fun FlowContent.wrapper(contentBody: FlowContent.() -> Unit) { context(WebPage) internal fun FlowContent.wrapper(contentBody: FlowContent.() -> Unit) {
div { div {
id = "wrapper" id = "wrapper"
// Header // Header

View File

@ -1,15 +1,13 @@
package ru.mipt.spc package ru.mipt.spc
import space.kscience.dataforge.context.Global import space.kscience.snark.SnarkEnvironment
import space.kscience.dataforge.context.fetch import space.kscience.snark.html.static
import space.kscience.snark.html.SnarkPlugin
import space.kscience.snark.html.renderStatic
import java.nio.file.Path import java.nio.file.Path
import kotlin.io.path.toPath import kotlin.io.path.toPath
fun main() { fun main() {
Global.fetch(SnarkPlugin).renderStatic(Path.of("build/out")) { SnarkEnvironment.default.static(Path.of("build/out")) {
spcHome(rootPath = javaClass.getResource("/home")!!.toURI().toPath()) spcHome(dataPath = javaClass.getResource("/home")!!.toURI().toPath())
spcMaster(dataPath = javaClass.getResource("/magprog")!!.toURI().toPath()) spcMasters(dataPath = javaClass.getResource("/magprog")!!.toURI().toPath())
} }
} }