2022-05-13 17:21:06 +03:00
|
|
|
package ru.mipt.spc
|
2022-04-23 10:48:53 +03:00
|
|
|
|
2022-04-30 10:32:00 +03:00
|
|
|
import kotlinx.coroutines.runBlocking
|
2022-04-23 10:48:53 +03:00
|
|
|
import kotlinx.html.*
|
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
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
//}
|
|
|
|
|
2022-05-26 11:55:50 +03:00
|
|
|
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")
|
|
|
|
|
2022-04-23 10:48:53 +03:00
|
|
|
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-06-22 12:18:35 +03:00
|
|
|
context(SiteData) 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-06-22 12:18:35 +03:00
|
|
|
context(SiteData) 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-26 11:55:50 +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()
|
|
|
|
//}
|
2022-05-03 13:33:43 +03:00
|
|
|
|
2022-06-22 12:18:35 +03:00
|
|
|
context(SiteData) private fun FlowContent.team() {
|
2022-05-26 11:55:50 +03:00
|
|
|
val team = findByType("magprog_team").values.sortedBy { it.order }
|
2022-04-23 10:48:53 +03:00
|
|
|
|
2022-05-05 21:45:52 +03:00
|
|
|
div("inner") {
|
2022-05-24 21:39:01 +03:00
|
|
|
h2 { +"Команда" }
|
|
|
|
div("features") {
|
|
|
|
team.forEach { member ->
|
|
|
|
section {
|
|
|
|
a {
|
2022-05-26 11:55:50 +03:00
|
|
|
val imagePath = member.imagePath?.let { resolveRef(it) }
|
2022-05-24 21:39:01 +03:00
|
|
|
img(
|
|
|
|
classes = "icon major",
|
|
|
|
src = imagePath,
|
|
|
|
alt = imagePath
|
|
|
|
) {
|
|
|
|
h3 { +member.name }
|
2022-05-26 11:55:50 +03:00
|
|
|
htmlData(member)
|
2022-05-24 21:39:01 +03:00
|
|
|
}
|
2022-05-03 13:33:43 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-05-24 21:39:01 +03:00
|
|
|
|
|
|
|
// div("inner") {
|
|
|
|
// h2 {
|
|
|
|
// +"Команда"
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// team.forEach { member ->
|
|
|
|
// section {
|
|
|
|
// id = member.id
|
|
|
|
// a(classes = "image") {
|
|
|
|
// member.photo?.let { photoPath ->
|
|
|
|
// img(
|
|
|
|
// src = resolveRef(photoPath),
|
|
|
|
// alt = member.name
|
|
|
|
// ) {
|
|
|
|
// attributes["data-position"] = "center center"
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// div("content") {
|
|
|
|
// div("inner") {
|
|
|
|
// h3 {
|
|
|
|
// a(href = "#team_${member.id}") { +member.name }
|
|
|
|
// }
|
|
|
|
// htmlData(member)
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// }
|
2022-05-03 13:33:43 +03:00
|
|
|
}
|
|
|
|
|
2022-06-22 12:18:35 +03:00
|
|
|
context(SiteData) private fun FlowContent.mentors() {
|
2022-05-26 11:55:50 +03:00
|
|
|
val mentors = findByType("magprog_mentor").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-06-23 10:44:16 +03:00
|
|
|
val ref = resolvePage("mentor-${mentor.id}")
|
|
|
|
a(classes = "image", href = ref) {
|
2022-05-26 11:55:50 +03:00
|
|
|
mentor.imagePath?.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 {
|
2022-06-23 10:44:16 +03:00
|
|
|
a(href = ref) { +mentor.name }
|
2022-05-03 13:33:43 +03:00
|
|
|
}
|
|
|
|
val info = resolveHtml(name.withIndex("info"))
|
|
|
|
if (info != null) {
|
|
|
|
htmlData(info)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-22 12:18:35 +03:00
|
|
|
context(SiteData) 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-06-22 23:35:16 +03:00
|
|
|
href = resolveRef("assets/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-06-22 23:35:16 +03:00
|
|
|
href = resolveRef("assets/css/noscript.css")
|
2022-04-23 10:48:53 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-05-03 13:33:43 +03:00
|
|
|
}
|
|
|
|
|
2022-06-22 12:18:35 +03:00
|
|
|
context(SiteData) internal fun BODY.magProgFooter() {
|
2022-05-03 13:33:43 +03:00
|
|
|
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 {
|
2022-06-22 23:35:16 +03:00
|
|
|
src = resolveRef("assets/js/jquery.min.js")
|
2022-05-03 13:33:43 +03:00
|
|
|
}
|
|
|
|
script {
|
2022-06-22 23:35:16 +03:00
|
|
|
src = resolveRef("assets/js/jquery.scrollex.min.js")
|
2022-05-03 13:33:43 +03:00
|
|
|
}
|
|
|
|
script {
|
2022-06-22 23:35:16 +03:00
|
|
|
src = resolveRef("assets/js/jquery.scrolly.min.js")
|
2022-05-03 13:33:43 +03:00
|
|
|
}
|
|
|
|
script {
|
2022-06-22 23:35:16 +03:00
|
|
|
src = resolveRef("assets/js/browser.min.js")
|
2022-05-03 13:33:43 +03:00
|
|
|
}
|
|
|
|
script {
|
2022-06-22 23:35:16 +03:00
|
|
|
src = resolveRef("assets/js/breakpoints.min.js")
|
2022-05-03 13:33:43 +03:00
|
|
|
}
|
|
|
|
script {
|
2022-06-22 23:35:16 +03:00
|
|
|
src = resolveRef("assets/js/util.js")
|
2022-05-03 13:33:43 +03:00
|
|
|
}
|
|
|
|
script {
|
2022-06-22 23:35:16 +03:00
|
|
|
src = resolveRef("assets/js/main.js")
|
2022-05-03 13:33:43 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-26 11:55:50 +03:00
|
|
|
private val HtmlData.mentorPageId get() = "mentor-${id}"
|
2022-05-03 13:33:43 +03:00
|
|
|
|
2022-06-22 21:37:22 +03:00
|
|
|
internal fun SiteBuilder.spcMaster(dataPath: Path, prefix: Name = "magprog".asName()) {
|
|
|
|
|
|
|
|
val magProgSiteContext = snark.readDirectory(dataPath.resolve("content"))
|
|
|
|
|
|
|
|
mountSite(prefix, magProgSiteContext) {
|
2022-06-22 23:35:16 +03:00
|
|
|
assetDirectory("assets", dataPath.resolve("assets"))
|
2022-06-22 21:37:22 +03:00
|
|
|
assetDirectory("images", dataPath.resolve("images"))
|
|
|
|
|
|
|
|
page {
|
|
|
|
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"),
|
|
|
|
wrapSection(id = "contacts", title = "Контакты") {
|
|
|
|
htmlData(resolveHtml(CONTACTS_PATH)!!)
|
|
|
|
team()
|
2022-04-23 10:48:53 +03:00
|
|
|
}
|
2022-06-22 21:37:22 +03:00
|
|
|
)
|
|
|
|
magProgHead("Магистратура \"Научное программирование\"")
|
|
|
|
body("is-preload magprog-body") {
|
|
|
|
section {
|
|
|
|
id = "sidebar"
|
|
|
|
div("inner") {
|
|
|
|
nav {
|
|
|
|
ul {
|
|
|
|
li {
|
|
|
|
a(classes = "spc-home", href = "/") {
|
|
|
|
i("fa fa-home") {
|
|
|
|
attributes["aria-hidden"] = "true"
|
2022-05-03 13:33:43 +03:00
|
|
|
}
|
2022-06-22 21:37:22 +03:00
|
|
|
+"SPC"
|
2022-05-03 13:33:43 +03:00
|
|
|
}
|
|
|
|
}
|
2022-06-22 21:37:22 +03:00
|
|
|
sections.forEach { section ->
|
|
|
|
li {
|
|
|
|
a(href = "#${section.id}") {
|
|
|
|
+section.title
|
|
|
|
}
|
2022-05-03 13:33:43 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-04-23 10:48:53 +03:00
|
|
|
}
|
|
|
|
}
|
2022-06-22 21:37:22 +03:00
|
|
|
div {
|
|
|
|
id = "wrapper"
|
|
|
|
sections.forEach { sec ->
|
|
|
|
section(sec.style) {
|
|
|
|
id = sec.id
|
|
|
|
with(sec) { content() }
|
|
|
|
}
|
|
|
|
}
|
2022-05-03 13:33:43 +03:00
|
|
|
}
|
2022-06-22 21:37:22 +03:00
|
|
|
magProgFooter()
|
|
|
|
}
|
|
|
|
}
|
2022-05-03 13:33:43 +03:00
|
|
|
|
2022-06-22 21:37:22 +03:00
|
|
|
|
|
|
|
val mentors = data.findByType("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 {
|
2022-06-23 10:44:16 +03:00
|
|
|
href = resolvePage(it.mentorPageId)
|
2022-06-22 21:37:22 +03:00
|
|
|
+it.name.substringAfterLast(" ")
|
2022-05-03 13:33:43 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-06-22 21:37:22 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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
|
|
|
|
)
|
2022-05-03 13:33:43 +03:00
|
|
|
}
|
|
|
|
}
|
2022-06-22 21:37:22 +03:00
|
|
|
htmlData(mentor)
|
2022-05-03 13:33:43 +03:00
|
|
|
}
|
2022-04-23 10:48:53 +03:00
|
|
|
}
|
|
|
|
}
|
2022-06-22 21:37:22 +03:00
|
|
|
magProgFooter()
|
2022-04-23 10:48:53 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|