initial commit

This commit is contained in:
mae
2026-03-17 03:28:37 -05:00
commit 8972a90b6c
34 changed files with 1068 additions and 0 deletions

View File

@@ -0,0 +1,15 @@
package online.maestoso.cofront
import io.ktor.server.application.*
import io.ktor.server.engine.*
import io.ktor.server.netty.*
import online.maestoso.cofront.frontend.configureFrontend
fun main() {
embeddedServer(Netty, port = 8080, host = "0.0.0.0", module = Application::module)
.start(wait = true)
}
fun Application.module() {
configureSecurity()
configureFrontend()
}

View File

@@ -0,0 +1,25 @@
package online.maestoso.cofront
import io.ktor.server.application.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
import io.ktor.server.sessions.*
import kotlinx.serialization.Serializable
fun Application.configureSecurity() {
install(Sessions) {
cookie<MySession>("MY_SESSION") {
cookie.extensions["SameSite"] = "lax"
}
}
routing {
get("/session/increment") {
val session = call.sessions.get<MySession>() ?: MySession()
call.sessions.set(session.copy(count = session.count + 1))
call.respondText("Counter is ${session.count}. Refresh to increment.")
}
}
}
@Serializable
data class MySession(val count: Int = 0)

View File

@@ -0,0 +1,11 @@
@file:OptIn(ExperimentalUuidApi::class)
package online.maestoso.cofront.api
import online.maestoso.cofront.Identifier
import kotlin.uuid.ExperimentalUuidApi
import kotlin.uuid.Uuid
fun test() {
val i = Identifier(Uuid.generateV7(), "localhost")
}

View File

@@ -0,0 +1,30 @@
package online.maestoso.cofront.frontend
import io.ktor.server.application.Application
import io.ktor.server.response.respondResource
import io.ktor.server.routing.get
import io.ktor.server.routing.routing
import kotlinx.html.FlowOrMetaDataOrPhrasingContent
import kotlinx.html.link
import kotlinx.html.meta
const val FAVICON_ROOT: String = "/static/favicon"
fun FlowOrMetaDataOrPhrasingContent.favicon() {
link(rel = "icon", type = "image/png", href= "$FAVICON_ROOT/favicon-96x96.png") {
attributes["sizes"] = "96x96"
}
link(rel = "icon", type = "image/svg+xml", href="$FAVICON_ROOT/favicon.svg")
link(rel = "shortcut icon", href="$FAVICON_ROOT/favicon.ico")
link(rel = "apple-touch-icon", href="$FAVICON_ROOT/apple-touch-icon.png") {
attributes["sizes"] = "180x180"
}
meta(name = "apple-mobile-web-app-tile", content="Cofront")
link(rel = "manifest", href="$FAVICON_ROOT/site.webmanifest")
}
fun Application.configureFavicon() {
routing {
get("/favicon.ico") {
call.respondResource("static/favicon/favicon.ico")
}
}
}

View File

@@ -0,0 +1,8 @@
package online.maestoso.cofront.frontend
import io.ktor.server.application.Application
fun Application.configureFrontend() {
configureResources()
addAllPages()
}

View File

@@ -0,0 +1,19 @@
package online.maestoso.cofront.frontend
import io.ktor.http.ContentType
import io.ktor.server.application.Application
import io.ktor.server.http.content.staticResources
import io.ktor.server.routing.get
import io.ktor.server.routing.routing
import kotlinx.html.FlowOrMetaDataOrPhrasingContent
import kotlinx.html.script
fun Application.configureJavascript() {
routing {
staticResources("/js", "js")
}
}
fun FlowOrMetaDataOrPhrasingContent.js() {
script(type = ContentType.Text.JavaScript.toString(), src = "js/Cofront.js") {}
}

View File

@@ -0,0 +1,50 @@
package online.maestoso.cofront.frontend
import io.ktor.http.*
import io.ktor.server.application.*
import io.ktor.server.html.*
import io.ktor.server.routing.*
import kotlinx.css.CssBuilder
import kotlinx.html.BODY
import kotlinx.html.HEAD
import kotlinx.html.body
import kotlinx.html.head
import kotlinx.html.meta
import kotlinx.html.style
import kotlinx.html.unsafe
import online.maestoso.cofront.frontend.pages.Index
import kotlin.String
import kotlin.Unit
abstract class Page(val path: String) {
open val style: CssBuilder.() -> Unit = {}
open val head: HEAD.() -> Unit = {}
open val body: BODY.() -> Unit = {}
fun addPage(app: Application) {
app.routing {
get(this@Page.path) {
call.respondHtml {
head {
meta(charset = Charsets.UTF_8.toString())
stylesheet()
favicon()
js()
apply(this@Page.head)
val css = CssBuilder().apply(this@Page.style)
unsafe {
this@head.style(type = ContentType.Text.CSS.toString(), content = css.toString())
}
}
body {
apply(this@Page.body)
}
}
}
}
}
}
fun Application.addAllPages() {
Index.addPage(this)
}

View File

@@ -0,0 +1,20 @@
package online.maestoso.cofront.frontend
import io.ktor.server.application.*
import io.ktor.server.http.content.*
import io.ktor.server.response.respondRedirect
import io.ktor.server.routing.*
fun Application.configureResources() {
configureFavicon()
configureJavascript()
routing {
get("/res/{path}") {
when(call.parameters["path"]) {
"index.css" -> call.configureStylesheet()
else -> call.respondRedirect("/static/${call.parameters["path"]}", true)
}
}
staticResources("/static", "static")
}
}

View File

@@ -0,0 +1,35 @@
package online.maestoso.cofront.frontend
import io.ktor.http.ContentType
import io.ktor.server.application.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
import kotlinx.css.*
import kotlinx.html.FlowOrMetaDataOrPhrasingContent
import kotlinx.html.link
suspend fun RoutingCall.configureStylesheet() {
css {
media("(prefers-color-scheme: dark)") {
html {
backgroundColor = Color("#222")
color = Color.white
}
}
media("not (prefers-color-scheme: dark)") {
html {
backgroundColor = Color.ghostWhite
color = Color.black
}
}
html {
}
}
}
suspend inline fun ApplicationCall.css(builder: CssBuilder.() -> Unit) {
this.respondText(CssBuilder().apply(builder).toString(), ContentType.Text.CSS)
}
fun FlowOrMetaDataOrPhrasingContent.stylesheet() {
link(rel = "stylesheet", href = "/res/index.css")
}

View File

@@ -0,0 +1,13 @@
package online.maestoso.cofront.frontend.pages
import kotlinx.html.BODY
import kotlinx.html.h1
import online.maestoso.cofront.frontend.Page
object Index : Page("/") {
override val body: BODY.() -> Unit = {
h1 {
+"Cofront"
}
}
}