Compare commits
4 Commits
d0afbae699
...
72ac07db5a
Author | SHA1 | Date | |
---|---|---|---|
72ac07db5a | |||
f65b537255 | |||
1923a1d296 | |||
d2a31ce33e |
@ -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")
|
||||
}
|
||||
|
@ -8,11 +8,11 @@ language: ru
|
||||
|
||||
#### Организация
|
||||
|
||||
КПМ РИТМ
|
||||
Julia ORG
|
||||
|
||||
#### Биография
|
||||
|
||||
Учился и защищался в БелГУ, с 2022 года работаю в КПМ РИТМ лидом команды программирующих математиков.
|
||||
Учился и защищался в БелГУ, с 2022 года работаю в Julia ORG лидом команды программирующих математиков.
|
||||
|
||||
#### Направления исследований
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
**Лидер команды программирующих математиков КПМ РИТМ**
|
||||
**Лидер команды программирующих математиков Julia ORG**
|
||||
|
||||
Разработка и исследования методов компьютерного моделирования гибридных динамических систем.
|
||||
|
||||
|
@ -8,16 +8,16 @@ language: ru
|
||||
|
||||
#### Организация
|
||||
|
||||
КПМ РИТМ
|
||||
Julia ORG
|
||||
|
||||
#### Биография
|
||||
|
||||
2019 - к.ф.-м.н.
|
||||
* 2019 - к.ф.-м.н.
|
||||
Московский государственный университет им. М.В. Ломоносова, Москва
|
||||
2012 - Магистр
|
||||
* 2012 - Магистр
|
||||
НИУ "БелГУ"
|
||||
Инженерно физический, Кафедра теоретической и математической физики, Прикладные математика и физика
|
||||
2010 - Бакалавр
|
||||
* 2010 - Бакалавр
|
||||
НИУ БелГУ
|
||||
Инженерно физический, Кафедра теоретической и математической физики, Прикладные математика и физика
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
**CTO КПМ РИТМ**
|
||||
**Разработчик Julia ORG**
|
||||
|
||||
Разработка и исследования методов компьютерного моделирования гибридных динамических систем.
|
||||
|
||||
|
@ -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
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -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
|
||||
|
@ -3,63 +3,75 @@ package center.sciprog
|
||||
import io.ktor.server.application.Application
|
||||
import io.ktor.server.application.call
|
||||
import io.ktor.server.application.install
|
||||
import io.ktor.server.application.log
|
||||
import io.ktor.server.config.tryGetString
|
||||
import io.ktor.server.plugins.forwardedheaders.ForwardedHeaders
|
||||
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.snark.ktor.prepareSnarkDataCacheDirectory
|
||||
import space.kscience.dataforge.data.DataSourceBuilder
|
||||
import space.kscience.dataforge.io.IOPlugin
|
||||
import space.kscience.dataforge.misc.DFExperimental
|
||||
import space.kscience.dataforge.names.Name
|
||||
import space.kscience.dataforge.workspace.monitorRawDirectory
|
||||
import space.kscience.dataforge.workspace.readResources
|
||||
import space.kscience.snark.html.SnarkHtml
|
||||
import space.kscience.snark.html.fill
|
||||
import space.kscience.snark.html.readSiteData
|
||||
import space.kscience.snark.ktor.site
|
||||
import java.nio.file.FileSystems
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.createDirectories
|
||||
import kotlin.io.path.isRegularFile
|
||||
import kotlin.io.path.relativeTo
|
||||
import kotlin.io.path.toPath
|
||||
|
||||
|
||||
private fun Application.copyResource(resource: String, dataDirectory: Path) {
|
||||
val uri = javaClass.getResource("/$resource")?.toURI()
|
||||
?: error("Resource $resource not found")
|
||||
val targetPath = dataDirectory.resolve(resource)
|
||||
//private fun Application.copyResource(resource: String, dataDirectory: Path) {
|
||||
// val uri = javaClass.getResource("/$resource")?.toURI()
|
||||
// ?: error("Resource $resource not found")
|
||||
// val targetPath = dataDirectory.resolve(resource)
|
||||
//
|
||||
// if (Files.isDirectory(targetPath)) {
|
||||
// log.info("Using existing data directory at $targetPath.")
|
||||
// } else {
|
||||
// log.info("Copying data from $uri into $targetPath.")
|
||||
// targetPath.createDirectories()
|
||||
// //Copy everything into a temporary directory
|
||||
//
|
||||
// fun copyFromPath(rootPath: Path) {
|
||||
// Files.walk(rootPath).forEach { source: Path ->
|
||||
// if (source.isRegularFile()) {
|
||||
// val relative = source.relativeTo(rootPath).toString()
|
||||
// val destination: Path = targetPath.resolve(relative)
|
||||
// destination.parent.createDirectories()
|
||||
// Files.copy(source, destination)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if ("jar" == uri.scheme) {
|
||||
// FileSystems.newFileSystem(uri, emptyMap<String, Any>()).use { fs ->
|
||||
// val rootPath: Path = fs.provider().getPath(uri)
|
||||
// copyFromPath(rootPath)
|
||||
// }
|
||||
// } else {
|
||||
// val rootPath = uri.toPath()
|
||||
// copyFromPath(rootPath)
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
if (Files.isDirectory(targetPath)) {
|
||||
log.info("Using existing data directory at $targetPath.")
|
||||
} else {
|
||||
log.info("Copying data from $uri into $targetPath.")
|
||||
targetPath.createDirectories()
|
||||
//Copy everything into a temporary directory
|
||||
context(IOPlugin)
|
||||
@OptIn(DFExperimental::class)
|
||||
fun DataSourceBuilder<Any>.directory(path: Path, name: Name = Name.EMPTY) {
|
||||
node(name, monitorRawDirectory(path))
|
||||
}
|
||||
|
||||
fun copyFromPath(rootPath: Path) {
|
||||
Files.walk(rootPath).forEach { source: Path ->
|
||||
if (source.isRegularFile()) {
|
||||
val relative = source.relativeTo(rootPath).toString()
|
||||
val destination: Path = targetPath.resolve(relative)
|
||||
destination.parent.createDirectories()
|
||||
Files.copy(source, destination)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ("jar" == uri.scheme) {
|
||||
FileSystems.newFileSystem(uri, emptyMap<String, Any>()).use { fs ->
|
||||
val rootPath: Path = fs.provider().getPath(uri)
|
||||
copyFromPath(rootPath)
|
||||
}
|
||||
} else {
|
||||
val rootPath = uri.toPath()
|
||||
copyFromPath(rootPath)
|
||||
}
|
||||
}
|
||||
context(IOPlugin)
|
||||
@OptIn(DFExperimental::class)
|
||||
fun DataSourceBuilder<Any>.resource(
|
||||
resource: String,
|
||||
classLoader: ClassLoader = Thread.currentThread().contextClassLoader,
|
||||
) {
|
||||
fill(readResources(resource, classLoader = classLoader))
|
||||
}
|
||||
|
||||
|
||||
@ -69,26 +81,28 @@ 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"
|
||||
)
|
||||
|
||||
if (!prepareSnarkDataCacheDirectory(dataDirectory)) {
|
||||
copyResource("common", dataDirectory)
|
||||
copyResource("home", dataDirectory)
|
||||
copyResource("magprog", dataDirectory)
|
||||
val siteData = snark.readSiteData(context) {
|
||||
resource("common")
|
||||
resource("home")
|
||||
resource("magprog")
|
||||
//directory(dataDirectory)
|
||||
}
|
||||
|
||||
val siteData: DataTree<Any> = snark.readDirectory(dataDirectory)
|
||||
|
||||
site(snark, siteData, block = SiteBuilder::spcSite)
|
||||
|
||||
routing {
|
||||
get("magprog") {
|
||||
call.respondRedirect("education/masters")
|
||||
}
|
||||
site(context, siteData, content = spcSite)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,58 +20,55 @@ 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"))
|
||||
static("assets")
|
||||
static("images")
|
||||
static("common.assets.webfonts", "assets/webfonts")
|
||||
static("common", "")
|
||||
|
||||
site(prefix, data) {
|
||||
static("assets")
|
||||
static("images")
|
||||
static("common.assets.webfonts", "assets/webfonts")
|
||||
static("common", "")
|
||||
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() }
|
||||
|
||||
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() }
|
||||
|
||||
page {
|
||||
head {
|
||||
title = "БМК-Сервис"
|
||||
meta {
|
||||
charset = "utf-8"
|
||||
}
|
||||
meta {
|
||||
name = "viewport"
|
||||
content = "width=device-width, initial-scale=1, user-scalable=no"
|
||||
}
|
||||
page {
|
||||
head {
|
||||
title = "БМК-Сервис"
|
||||
meta {
|
||||
charset = "utf-8"
|
||||
}
|
||||
meta {
|
||||
name = "viewport"
|
||||
content = "width=device-width, initial-scale=1, user-scalable=no"
|
||||
}
|
||||
link {
|
||||
rel = "stylesheet"
|
||||
href = resolveRef("assets/css/main.css")
|
||||
}
|
||||
noScript {
|
||||
link {
|
||||
rel = "stylesheet"
|
||||
href = resolveRef("assets/css/main.css")
|
||||
}
|
||||
noScript {
|
||||
link {
|
||||
rel = "stylesheet"
|
||||
href = resolveRef("assets/css/noscript.css")
|
||||
}
|
||||
href = resolveRef("assets/css/noscript.css")
|
||||
}
|
||||
}
|
||||
body("is-preload") {
|
||||
}
|
||||
body("is-preload") {
|
||||
// Wrapper
|
||||
div {
|
||||
id = "wrapper"
|
||||
div {
|
||||
id = "wrapper"
|
||||
// Header
|
||||
header("alt") {
|
||||
id = "header"
|
||||
span("logo") {
|
||||
img {
|
||||
src = "images/logo.svg"
|
||||
alt = ""
|
||||
}
|
||||
header("alt") {
|
||||
id = "header"
|
||||
span("logo") {
|
||||
img {
|
||||
src = "images/logo.svg"
|
||||
alt = ""
|
||||
}
|
||||
h1 { +"""БМК-Сервис""" }
|
||||
}
|
||||
h1 { +"""БМК-Сервис""" }
|
||||
// p {
|
||||
// +"""Just another free, fully responsive site template"""
|
||||
// br {
|
||||
@ -90,99 +85,98 @@ internal fun SiteBuilder.bmk(data: DataTree<Any>, prefix: Name = "bmk".parseAsNa
|
||||
// }
|
||||
// +"""."""
|
||||
// }
|
||||
}
|
||||
}
|
||||
// Nav
|
||||
nav {
|
||||
id = "nav"
|
||||
ul {
|
||||
li {
|
||||
a(classes = "active") {
|
||||
href = "#${about.fragment}"
|
||||
+about.title
|
||||
nav {
|
||||
id = "nav"
|
||||
ul {
|
||||
li {
|
||||
a(classes = "active") {
|
||||
href = "#${about.fragment}"
|
||||
+about.title
|
||||
}
|
||||
}
|
||||
li {
|
||||
a {
|
||||
href = "#${team.fragment}"
|
||||
+team.title
|
||||
}
|
||||
}
|
||||
li {
|
||||
a {
|
||||
href = "#${solutions.fragment}"
|
||||
+solutions.title
|
||||
}
|
||||
}
|
||||
li {
|
||||
a {
|
||||
href = "#${partners.fragment}"
|
||||
+partners.title
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
div {
|
||||
id = "main"
|
||||
section("main") {
|
||||
id = about.fragment
|
||||
div("spotlight") {
|
||||
div("content") {
|
||||
header("major") {
|
||||
h2 { +about.title }
|
||||
}
|
||||
fragment(about)
|
||||
}
|
||||
}
|
||||
}
|
||||
section("main") {
|
||||
id = team.fragment
|
||||
header("major") {
|
||||
h2 { +team.title }
|
||||
}
|
||||
fragment(team)
|
||||
teamData.values.sortedBy { it.order }.forEach { data ->
|
||||
span("image left") {
|
||||
img {
|
||||
src = resolveRef("images/${data.meta["image"].string!!}")
|
||||
height = "120dp"
|
||||
}
|
||||
}
|
||||
li {
|
||||
a {
|
||||
href = "#${team.fragment}"
|
||||
+team.title
|
||||
}
|
||||
}
|
||||
li {
|
||||
a {
|
||||
href = "#${solutions.fragment}"
|
||||
+solutions.title
|
||||
}
|
||||
}
|
||||
li {
|
||||
a {
|
||||
href = "#${partners.fragment}"
|
||||
+partners.title
|
||||
h3 { +data.title }
|
||||
fragment(data)
|
||||
}
|
||||
}
|
||||
section("main") {
|
||||
id = solutions.fragment
|
||||
header("major") {
|
||||
h2 { +solutions.title }
|
||||
fragment(solutions)
|
||||
span("image fit") {
|
||||
img {
|
||||
src = resolveRef("images/fresnel_lands_critdepth2.png")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
div {
|
||||
id = "main"
|
||||
section("main") {
|
||||
id = about.fragment
|
||||
div("spotlight") {
|
||||
div("content") {
|
||||
header("major") {
|
||||
h2 { +about.title }
|
||||
}
|
||||
htmlData(about)
|
||||
}
|
||||
}
|
||||
}
|
||||
section("main") {
|
||||
id = team.fragment
|
||||
header("major") {
|
||||
h2 { +team.title }
|
||||
}
|
||||
htmlData(team)
|
||||
teamData.values.sortedBy { it.order }.forEach { data ->
|
||||
span("image left") {
|
||||
img {
|
||||
src = resolveRef("images/${data.meta["image"].string!!}")
|
||||
height = "120dp"
|
||||
}
|
||||
}
|
||||
h3 { +data.title }
|
||||
htmlData(data)
|
||||
}
|
||||
}
|
||||
section("main") {
|
||||
id = solutions.fragment
|
||||
header("major") {
|
||||
h2 { +solutions.title }
|
||||
htmlData(solutions)
|
||||
span("image fit") {
|
||||
img {
|
||||
src = resolveRef("images/fresnel_lands_critdepth2.png")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
section("main") {
|
||||
id = partners.fragment
|
||||
header("major") {
|
||||
h2 { +partners.title }
|
||||
htmlData(partners)
|
||||
table {
|
||||
partnersData.getIndexed("content").values.forEach {
|
||||
tr {
|
||||
td {
|
||||
span("image right") {
|
||||
img {
|
||||
src = resolveRef(it["image"].string!!)
|
||||
height = "120dp"
|
||||
width = "auto"
|
||||
}
|
||||
section("main") {
|
||||
id = partners.fragment
|
||||
header("major") {
|
||||
h2 { +partners.title }
|
||||
fragment(partners)
|
||||
table {
|
||||
partnersData.getIndexed("content").values.forEach {
|
||||
tr {
|
||||
td {
|
||||
span("image right") {
|
||||
img {
|
||||
src = resolveRef(it["image"].string!!)
|
||||
height = "120dp"
|
||||
width = "auto"
|
||||
}
|
||||
h3 {
|
||||
a(href = it["target"].string!!) {
|
||||
+it["title"].string!!
|
||||
}
|
||||
}
|
||||
h3 {
|
||||
a(href = it["target"].string!!) {
|
||||
+it["title"].string!!
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -191,8 +185,9 @@ internal fun SiteBuilder.bmk(data: DataTree<Any>, prefix: Name = "bmk".parseAsNa
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Footer
|
||||
footer {
|
||||
footer {
|
||||
// id = "footer"
|
||||
// section {
|
||||
// h2 { +"""Aliquam sed mauris""" }
|
||||
@ -254,38 +249,37 @@ internal fun SiteBuilder.bmk(data: DataTree<Any>, prefix: Name = "bmk".parseAsNa
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
p("copyright") {
|
||||
+"""SPC. Design:"""
|
||||
a {
|
||||
href = "https://html5up.net"
|
||||
+"""HTML5 UP"""
|
||||
}
|
||||
+"""."""
|
||||
p("copyright") {
|
||||
+"""SPC. Design:"""
|
||||
a {
|
||||
href = "https://html5up.net"
|
||||
+"""HTML5 UP"""
|
||||
}
|
||||
+"""."""
|
||||
}
|
||||
}
|
||||
}
|
||||
// Scripts
|
||||
script {
|
||||
src = resolveRef("assets/js/jquery.min.js")
|
||||
}
|
||||
script {
|
||||
src = resolveRef("assets/js/jquery.scrollex.min.js")
|
||||
}
|
||||
script {
|
||||
src = resolveRef("assets/js/jquery.scrolly.min.js")
|
||||
}
|
||||
script {
|
||||
src = resolveRef("assets/js/browser.min.js")
|
||||
}
|
||||
script {
|
||||
src = resolveRef("assets/js/breakpoints.min.js")
|
||||
}
|
||||
script {
|
||||
src = resolveRef("assets/js/util.js")
|
||||
}
|
||||
script {
|
||||
src = resolveRef("assets/js/main.js")
|
||||
}
|
||||
script {
|
||||
src = resolveRef("assets/js/jquery.min.js")
|
||||
}
|
||||
script {
|
||||
src = resolveRef("assets/js/jquery.scrollex.min.js")
|
||||
}
|
||||
script {
|
||||
src = resolveRef("assets/js/jquery.scrolly.min.js")
|
||||
}
|
||||
script {
|
||||
src = resolveRef("assets/js/browser.min.js")
|
||||
}
|
||||
script {
|
||||
src = resolveRef("assets/js/breakpoints.min.js")
|
||||
}
|
||||
script {
|
||||
src = resolveRef("assets/js/util.js")
|
||||
}
|
||||
script {
|
||||
src = resolveRef("assets/js/main.js")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
@ -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,32 +233,88 @@ context(WebPage) private fun HTML.spcHomePage() {
|
||||
}
|
||||
}
|
||||
|
||||
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"
|
||||
}
|
||||
}
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal val spcHome: HtmlSite = HtmlSite {
|
||||
static("assets")
|
||||
static("images")
|
||||
static("common", "")
|
||||
|
||||
multiLanguageSite(
|
||||
siteData,
|
||||
mapOf(
|
||||
"en" to Language(""),
|
||||
"ru" to Language("ru"),
|
||||
)
|
||||
) {
|
||||
page(content = spcHomePage)
|
||||
|
||||
allPagesIn("consulting")
|
||||
|
||||
allPagesIn("education")
|
||||
|
||||
spcSpotlight("team") { _, meta ->
|
||||
meta["type"].string == "team"
|
||||
}
|
||||
|
||||
spcSpotlight("research") { name, meta ->
|
||||
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"
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
@ -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,72 +303,110 @@ 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"))
|
||||
internal val spcMasters = HtmlSite {
|
||||
static("assets")
|
||||
static("images")
|
||||
static("common", "")
|
||||
|
||||
site(prefix, magProgData) {
|
||||
static("assets")
|
||||
static("images")
|
||||
static("common", "")
|
||||
page{
|
||||
val sections = listOf(
|
||||
wrapSection(data.resolveHtmlOrNull(INTRO_PATH)!!, "intro"),
|
||||
MagProgSection(
|
||||
id = "partners",
|
||||
title = "Партнеры",
|
||||
style = "wrapper style3 fullscreen fade-up"
|
||||
) {
|
||||
fragment(partners)
|
||||
},
|
||||
// section(props.data.partners),
|
||||
MagProgSection(
|
||||
id = "mentors",
|
||||
title = "Научные руководители",
|
||||
style = "wrapper style2 spotlights",
|
||||
) {
|
||||
fragment(mentors)
|
||||
},
|
||||
MagProgSection(
|
||||
id = "program",
|
||||
title = "Учебная программа",
|
||||
style = "wrapper style3 fullscreen fade-up"
|
||||
) {
|
||||
fragment(programSection)
|
||||
},
|
||||
wrapSection(data.resolveHtmlOrNull(ENROLL_PATH)!!, "enroll"),
|
||||
wrapSection(id = "contacts", title = "Контакты") {
|
||||
fragment(data.resolveHtmlOrNull(CONTACTS_PATH)!!)
|
||||
fragment(team)
|
||||
}
|
||||
)
|
||||
|
||||
page {
|
||||
val sections = listOf<MagProgSection>(
|
||||
wrapSection(page.data.resolveHtmlOrNull(INTRO_PATH)!!, "intro"),
|
||||
MagProgSection(
|
||||
id = "partners",
|
||||
title = "Партнеры",
|
||||
style = "wrapper style3 fullscreen fade-up"
|
||||
) {
|
||||
partners()
|
||||
},
|
||||
// section(props.data.partners),
|
||||
MagProgSection(
|
||||
id = "mentors",
|
||||
title = "Научные руководители",
|
||||
style = "wrapper style2 spotlights",
|
||||
) {
|
||||
mentors()
|
||||
},
|
||||
MagProgSection(
|
||||
id = "program",
|
||||
title = "Учебная программа",
|
||||
style = "wrapper style3 fullscreen fade-up"
|
||||
) {
|
||||
programSection()
|
||||
},
|
||||
wrapSection(page.data.resolveHtmlOrNull(ENROLL_PATH)!!, "enroll"),
|
||||
wrapSection(id = "contacts", title = "Контакты") {
|
||||
htmlData(page.data.resolveHtmlOrNull(CONTACTS_PATH)!!)
|
||||
team()
|
||||
}
|
||||
)
|
||||
|
||||
magProgHead("Магистратура \"Научное программирование\"")
|
||||
body("is-preload magprog-body") {
|
||||
section {
|
||||
id = "sidebar"
|
||||
div("inner") {
|
||||
nav {
|
||||
ul {
|
||||
magProgHead("Магистратура \"Научное программирование\"")
|
||||
body("is-preload magprog-body") {
|
||||
section {
|
||||
id = "sidebar"
|
||||
div("inner") {
|
||||
nav {
|
||||
ul {
|
||||
li {
|
||||
a(
|
||||
classes = "spc-home",
|
||||
href = "/" //TODO provide a way to navigate out-of-site
|
||||
) {
|
||||
i("fa fa-home") {
|
||||
attributes["aria-hidden"] = "true"
|
||||
}
|
||||
+"SPC"
|
||||
}
|
||||
}
|
||||
sections.forEach { section ->
|
||||
li {
|
||||
a(
|
||||
classes = "spc-home",
|
||||
href = "/" //TODO provide a way to navigate out-of-site
|
||||
) {
|
||||
i("fa fa-home") {
|
||||
attributes["aria-hidden"] = "true"
|
||||
}
|
||||
+"SPC"
|
||||
a(href = "#${section.id}") {
|
||||
+section.title
|
||||
}
|
||||
}
|
||||
sections.forEach { section ->
|
||||
li {
|
||||
a(href = "#${section.id}") {
|
||||
+section.title
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
div {
|
||||
id = "wrapper"
|
||||
sections.forEach { sec ->
|
||||
section(sec.style) {
|
||||
id = sec.id
|
||||
with(sec) { content() }
|
||||
}
|
||||
}
|
||||
}
|
||||
magProgFooter()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
val mentors = siteData.findHtmlByContentType("magprog_mentor").values.sortedBy {
|
||||
it.order
|
||||
}
|
||||
|
||||
mentors.forEach { mentor ->
|
||||
page(mentor.mentorPageId.asName(), siteData) {
|
||||
magProgHead("Научное программирование: ${mentor.name}")
|
||||
body("is-preload") {
|
||||
header {
|
||||
id = "header"
|
||||
a(classes = "title") {
|
||||
href = "${page.homeRef}#mentors"
|
||||
+"Научные руководители"
|
||||
}
|
||||
nav {
|
||||
ul {
|
||||
mentors.forEach {
|
||||
li {
|
||||
a {
|
||||
href = page.resolvePageRef(it.mentorPageId)
|
||||
+it.name.substringAfterLast(" ")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -371,68 +415,25 @@ internal fun SiteBuilder.spcMasters(magProgData: DataTree<Any>, prefix: Name = "
|
||||
}
|
||||
div {
|
||||
id = "wrapper"
|
||||
sections.forEach { sec ->
|
||||
section(sec.style) {
|
||||
id = sec.id
|
||||
with(sec) { content() }
|
||||
section("wrapper") {
|
||||
id = "main"
|
||||
div("inner") {
|
||||
h1("major") { +mentor.name }
|
||||
val imageClass = mentor.meta["image.position"].string ?: "left"
|
||||
span("image $imageClass") {
|
||||
mentor.imagePath?.let { photoPath ->
|
||||
img(
|
||||
src = page.resolveRef(photoPath),
|
||||
alt = mentor.name
|
||||
)
|
||||
}
|
||||
}
|
||||
fragment(mentor)
|
||||
}
|
||||
}
|
||||
}
|
||||
magProgFooter()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
val mentors = data.findByContentType("magprog_mentor").values.sortedBy {
|
||||
it.order
|
||||
}
|
||||
|
||||
mentors.forEach { mentor ->
|
||||
page(mentor.mentorPageId.asName()) {
|
||||
|
||||
magProgHead("Научное программирование: ${mentor.name}")
|
||||
body("is-preload") {
|
||||
header {
|
||||
id = "header"
|
||||
a(classes = "title") {
|
||||
href = "$homeRef#mentors"
|
||||
+"Научные руководители"
|
||||
}
|
||||
nav {
|
||||
ul {
|
||||
mentors.forEach {
|
||||
li {
|
||||
a {
|
||||
href = resolvePageRef(it.mentorPageId)
|
||||
+it.name.substringAfterLast(" ")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
div {
|
||||
id = "wrapper"
|
||||
section("wrapper") {
|
||||
id = "main"
|
||||
div("inner") {
|
||||
h1("major") { +mentor.name }
|
||||
val imageClass = mentor.meta["image.position"].string ?: "left"
|
||||
span("image $imageClass") {
|
||||
mentor.imagePath?.let { photoPath ->
|
||||
img(
|
||||
src = resolveRef(photoPath),
|
||||
alt = mentor.name
|
||||
)
|
||||
}
|
||||
}
|
||||
htmlData(mentor)
|
||||
}
|
||||
}
|
||||
}
|
||||
magProgFooter()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
@ -1,18 +1,27 @@
|
||||
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.SnarkHtml
|
||||
import space.kscience.snark.html.readSiteData
|
||||
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 siteData = snark.readResources("common", "home", "magprog")
|
||||
val snark = context.request(SnarkHtml)
|
||||
val siteData = snark.readSiteData(context) {
|
||||
resource("common")
|
||||
resource("home")
|
||||
resource("magprog")
|
||||
|
||||
snark.static(siteData, Path.of(destinationPath), block = SiteBuilder::spcSite)
|
||||
}
|
||||
|
||||
snark.staticSite(siteData, Path.of(destinationPath), content = spcSite)
|
||||
}
|
@ -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")
|
||||
}
|
||||
|
@ -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 {
|
||||
}
|
||||
@ -30,7 +31,7 @@ context(WebPage) internal fun HTML.landing(){
|
||||
div {
|
||||
id = "wrapper"
|
||||
// Header
|
||||
// Note: The "styleN" class below should match that of the banner element. -->
|
||||
// Note: The "styleN" class below should match that of the banner element. -->
|
||||
|
||||
header("alt style2") {
|
||||
id = "header"
|
||||
@ -48,7 +49,7 @@ context(WebPage) internal fun HTML.landing(){
|
||||
}
|
||||
fortyMenu()
|
||||
// Banner
|
||||
// Note: The "styleN" class below should match that of the header element.
|
||||
// Note: The "styleN" class below should match that of the header element.
|
||||
section("style2") {
|
||||
id = "banner"
|
||||
div("inner") {
|
||||
|
@ -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 {
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user