1
0
forked from SPC/spc-site

409 lines
14 KiB
Kotlin
Raw Normal View History

2022-05-13 17:21:06 +03:00
package ru.mipt.spc
2022-04-23 10:48:53 +03:00
2022-05-03 13:33:43 +03:00
import io.ktor.server.application.Application
import io.ktor.server.application.call
import io.ktor.server.html.respondHtml
import io.ktor.server.http.content.files
import io.ktor.server.http.content.static
import io.ktor.server.routing.get
import io.ktor.server.routing.route
import io.ktor.server.routing.routing
2022-04-30 10:32:00 +03:00
import kotlinx.coroutines.runBlocking
2022-04-23 10:48:53 +03:00
import kotlinx.html.*
2022-05-03 13:33:43 +03:00
import space.kscience.dataforge.context.Context
2022-05-04 19:29:29 +03:00
import space.kscience.dataforge.context.fetch
2022-04-30 10:32:00 +03:00
import space.kscience.dataforge.data.await
2022-05-13 17:21:06 +03:00
import space.kscience.dataforge.data.getByType
2022-04-23 10:48:53 +03:00
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.get
2022-05-01 21:14:00 +03:00
import space.kscience.dataforge.meta.getIndexed
2022-04-23 10:48:53 +03:00
import space.kscience.dataforge.meta.string
import space.kscience.dataforge.names.Name
2022-05-01 21:14:00 +03:00
import space.kscience.dataforge.names.asName
2022-04-23 10:48:53 +03:00
import space.kscience.dataforge.names.plus
2022-05-03 13:33:43 +03:00
import space.kscience.dataforge.names.withIndex
import space.kscience.snark.*
import java.nio.file.Path
import kotlin.collections.component1
import kotlin.collections.component2
import kotlin.collections.set
2022-05-03 17:15:07 +03:00
2022-04-23 10:48:53 +03:00
2022-04-30 10:32:00 +03:00
//fun CssBuilder.magProgCss() {
2022-04-23 10:48:53 +03:00
// rule(".magprog-body") {
// rule(".magprog-header") {
// display = Display.flex
// alignItems = Align.center
// justifyContent = JustifyContent.center
// marginTop = 90.pt
// marginLeft = 40.pt
// }
// }
//}
class MagProgSection(
val id: String,
val title: String,
val style: String,
2022-05-01 21:14:00 +03:00
val content: FlowContent.() -> Unit,
2022-05-05 21:17:26 +03:00
)
2022-04-23 10:48:53 +03:00
private fun wrapSection(
id: String,
title: String,
sectionContent: FlowContent.() -> Unit,
): MagProgSection = MagProgSection(id, title, "wrapper style1 fullscreen fade-up") {
div("inner") {
h2 { +title }
sectionContent()
}
}
2022-04-30 10:32:00 +03:00
private fun wrapSection(
2022-05-01 21:14:00 +03:00
block: HtmlData,
2022-04-30 10:32:00 +03:00
idOverride: String? = null,
): MagProgSection = wrapSection(
idOverride ?: block.id,
block.meta["section_title"]?.string ?: error("Section without title"),
2022-05-03 13:33:43 +03:00
) {
2022-05-01 21:14:00 +03:00
htmlData(block)
}
2022-04-23 10:48:53 +03:00
2022-04-30 10:32:00 +03:00
private val CONTENT_NODE_NAME = Name.EMPTY//"content".asName()
private val INTRO_PATH: Name = CONTENT_NODE_NAME + "intro"
private val ENROLL_PATH: Name = CONTENT_NODE_NAME + "enroll"
private val CONTACTS_PATH: Name = CONTENT_NODE_NAME + "contacts"
private val PROGRAM_PATH: Name = CONTENT_NODE_NAME + "program"
private val RECOMMENDED_COURSES_PATH: Name = CONTENT_NODE_NAME + "recommendedCourses"
2022-04-23 10:48:53 +03:00
private val PARTNERS_PATH: Name = CONTENT_NODE_NAME + "partners"
2022-05-02 09:49:18 +03:00
context(PageContext) private fun FlowContent.programSection() {
2022-04-23 10:48:53 +03:00
val programBlock = resolveHtml(PROGRAM_PATH)!!
val recommendedBlock = resolveHtml(RECOMMENDED_COURSES_PATH)!!
div("inner") {
h2 { +"Учебная программа" }
2022-05-01 21:14:00 +03:00
htmlData(programBlock)
2022-05-03 13:33:43 +03:00
button(classes = "fit collapsible") {
attributes["data-target"] = "recommended-courses-content"
2022-04-23 10:48:53 +03:00
+"Рекомендованные курсы"
}
2022-05-03 13:33:43 +03:00
div(classes = "collapsible-content") {
id = "recommended-courses-content"
htmlData(recommendedBlock)
2022-04-23 10:48:53 +03:00
}
}
}
2022-05-02 09:49:18 +03:00
context(PageContext) private fun FlowContent.partners() {
2022-04-30 10:32:00 +03:00
//val partnersData: Meta = resolve<Any>(PARTNERS_PATH)?.meta ?: Meta.EMPTY
2022-05-13 17:21:06 +03:00
val partnersData: Meta = runBlocking { data.getByType<Meta>(PARTNERS_PATH)?.await() } ?: Meta.EMPTY
2022-04-23 10:48:53 +03:00
div("inner") {
h2 { +"Партнеры" }
div("features") {
2022-05-01 21:14:00 +03:00
partnersData.getIndexed("content".asName()).values.forEach { partner ->
2022-04-23 10:48:53 +03:00
section {
a(href = partner["link"].string, target = "_blank") {
rel = "noreferrer"
2022-05-13 17:21:06 +03:00
val imagePath = partner["logo"].string?.let { resolveRef(it) }
2022-04-23 10:48:53 +03:00
img(
classes = "icon major",
src = imagePath,
alt = imagePath
) {
h3 { +(partner["title"].string ?: "") }
}
}
}
}
}
}
}
2022-05-03 13:33:43 +03:00
class Person(val data: HtmlData) : HtmlData by data {
val name: String by meta.string { error("Mentor name is not defined") }
val photo: String? by meta.string()
}
context(PageContext) private fun FlowContent.team() {
val team = findByType("magprog_team").map { Person(it.value) }.sortedBy { it.order }
2022-04-23 10:48:53 +03:00
2022-05-05 21:45:52 +03:00
div("inner") {
h2 {
2022-05-03 13:33:43 +03:00
+"Команда"
}
}
team.forEach { member ->
section {
id = member.id
2022-05-03 17:15:07 +03:00
a(classes = "image", href = resolveRef("mentor-${member.id}")) {
2022-05-03 13:33:43 +03:00
member.photo?.let { photoPath ->
img(
src = resolveRef(photoPath),
alt = member.name
2022-05-03 17:15:07 +03:00
) {
attributes["data-position"] = "center center"
}
2022-05-03 13:33:43 +03:00
}
}
div("content") {
div("inner") {
2022-05-05 21:45:52 +03:00
h3 {
2022-05-03 13:33:43 +03:00
a(href = "#team_${member.id}") { +member.name }
}
htmlData(member)
}
}
}
}
}
context(PageContext) private fun FlowContent.mentors() {
2022-05-05 21:17:26 +03:00
val mentors = findByType("magprog_mentor").mapValues { Person(it.value) }.entries.sortedBy { it.value.id }
2022-05-03 13:33:43 +03:00
2022-05-05 21:45:52 +03:00
div("inner") {
h2 {
2022-05-03 13:33:43 +03:00
+"Научные руководители"
}
}
mentors.forEach { (name, mentor) ->
section {
id = mentor.id
2022-05-03 17:15:07 +03:00
a(classes = "image", href = resolveRef("mentor-${mentor.id}")) {
2022-05-03 13:33:43 +03:00
mentor.photo?.let { photoPath ->
2022-05-03 17:15:07 +03:00
img(
src = resolveRef(photoPath),
alt = mentor.name
) {
attributes["data-position"] = "center center"
2022-05-03 13:33:43 +03:00
}
}
}
div("content") {
div("inner") {
h2 {
a(href = resolveRef("mentor-${mentor.id}")) { +mentor.name }
}
val info = resolveHtml(name.withIndex("info"))
if (info != null) {
htmlData(info)
}
}
}
}
}
}
context(PageContext) internal fun HTML.magProgHead(title: String) {
2022-04-23 10:48:53 +03:00
head {
2022-05-03 13:33:43 +03:00
this.title = title
2022-04-23 10:48:53 +03:00
meta {
charset = "utf-8"
}
meta {
name = "viewport"
content = "width=device-width, initial-scale=1, user-scalable=no"
}
2022-05-02 09:49:18 +03:00
link {
rel = "stylesheet"
2022-05-03 13:33:43 +03:00
href = resolveRef("css/main.css")
2022-04-23 10:48:53 +03:00
}
2022-05-06 15:54:59 +03:00
link {
rel = "shortcut icon"
href = resolveRef("images/favicon-32x32.png")
}
2022-04-23 10:48:53 +03:00
noScript {
link {
rel = "stylesheet"
2022-05-03 13:33:43 +03:00
href = resolveRef("css/noscript.css")
2022-04-23 10:48:53 +03:00
}
}
}
2022-05-03 13:33:43 +03:00
}
context(PageContext) internal fun BODY.magProgFooter() {
footer("wrapper style1-alt") {
id = "footer"
div("inner") {
ul("menu") {
li { +"""SPC. All rights reserved.""" }
li {
+"""Design:"""
a {
href = "http://html5up.net"
+"""HTML5 UP"""
2022-04-23 10:48:53 +03:00
}
}
}
}
2022-05-03 13:33:43 +03:00
}
script {
src = resolveRef("js/jquery.min.js")
}
script {
src = resolveRef("js/jquery.scrollex.min.js")
}
script {
src = resolveRef("js/jquery.scrolly.min.js")
}
script {
src = resolveRef("js/browser.min.js")
}
script {
src = resolveRef("js/breakpoints.min.js")
}
script {
src = resolveRef("js/util.js")
}
script {
src = resolveRef("js/main.js")
}
}
internal val Person.mentorPageId get() = "mentor-${id}"
2022-05-13 17:21:06 +03:00
internal fun Application.spcMaster(context: Context, dataPath: Path, prefix: String = "/magprog") {
2022-05-03 13:33:43 +03:00
2022-05-04 19:29:29 +03:00
val snark = context.fetch(SnarkPlugin)
2022-05-03 13:33:43 +03:00
2022-05-21 13:38:15 +03:00
val magProgPageContext: PageContext = snark.parse(prefix, dataPath.resolve("content"))
2022-05-03 13:33:43 +03:00
routing {
route(prefix) {
2022-05-04 19:29:29 +03:00
with(magProgPageContext) {
2022-05-22 16:52:36 +03:00
static{
2022-05-13 17:21:06 +03:00
files(dataPath.resolve("assets").toFile())
2022-05-22 16:52:36 +03:00
static("images") {
files(dataPath.resolve("images").toFile())
}
2022-04-23 10:48:53 +03:00
}
2022-05-03 13:33:43 +03:00
2022-05-22 16:52:36 +03:00
2022-05-03 13:33:43 +03:00
get {
call.respondHtml {
val sections = listOf<MagProgSection>(
wrapSection(resolveHtml(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(resolveHtml(ENROLL_PATH)!!, "enroll"),
MagProgSection(
id = "team",
title = "Команда",
style = "wrapper style2 spotlights",
) {
team()
},
wrapSection(resolveHtml(CONTACTS_PATH)!!, "contacts"),
)
magProgHead("Магистратура \"Научное программирование\"")
body("is-preload magprog-body") {
section {
id = "sidebar"
div("inner") {
nav {
ul {
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()
}
2022-04-23 10:48:53 +03:00
}
}
2022-05-03 13:33:43 +03:00
val mentors = findByType("magprog_mentor").map {
Person(it.value)
}.sortedBy {
it.order
}
mentors.forEach { mentor ->
get(mentor.mentorPageId) {
call.respondHtml {
magProgHead("Научное программирование: ${mentor.name}")
body("is-preload") {
header {
id = "header"
a(classes = "title") {
href = "$homeRef#mentors"
+"Научные руководители"
}
2022-05-05 21:45:52 +03:00
nav() {
2022-05-03 13:33:43 +03:00
ul {
mentors.forEach {
li {
a {
href = resolveRef(it.mentorPageId)
+it.name
}
}
}
}
}
}
div {
id = "wrapper"
section("wrapper") {
id = "main"
div("inner") {
h1("major") { +mentor.name }
span("image left") {
mentor.photo?.let { photoPath ->
img(
src = resolveRef(photoPath),
alt = mentor.name
)
}
}
htmlData(mentor)
}
}
}
magProgFooter()
}
2022-04-23 10:48:53 +03:00
}
}
}
}
}
}
}