Compare commits

...

2 commits

Author SHA1 Message Date
Lars Westermann
2b29093086
V1 von Brett her 2019-06-08 18:12:01 +02:00
Lars Westermann
17f81e8952
Split account pages 2019-06-08 14:56:47 +02:00
15 changed files with 257 additions and 253 deletions

View file

@ -99,10 +99,6 @@ kotlin {
implementation "com.soywiz:klock-jvm:$klockVersion" implementation "com.soywiz:klock-jvm:$klockVersion"
implementation "com.soywiz:klock-locale-jvm:$klockVersion" implementation "com.soywiz:klock-locale-jvm:$klockVersion"
//implementation 'com.twitter:hbc-core:2.2.0'
//implementation 'com.twitter:hbc-twitter4j:2.2.0'
api 'org.twitter4j:twitter4j-stream:4.0.1'
implementation 'com.github.uchuhimo:konf:master-SNAPSHOT' implementation 'com.github.uchuhimo:konf:master-SNAPSHOT'
implementation 'com.vladsch.flexmark:flexmark-all:0.42.10' implementation 'com.vladsch.flexmark:flexmark-all:0.42.10'
api 'io.github.microutils:kotlin-logging:1.6.23' api 'io.github.microutils:kotlin-logging:1.6.23'

View file

@ -1,5 +1,6 @@
$background-primary-color: #fff; $background-primary-color: #fff;
$background-secondary-color: #fcfcfc; $background-secondary-color: #f5f5f5;
$background-card-color: #fff;
$text-primary-color: #333; $text-primary-color: #333;
$text-secondary-color: rgba($text-primary-color, 0.5); $text-secondary-color: rgba($text-primary-color, 0.5);
@ -15,7 +16,7 @@ $input-border-color: #888;
$table-border-color: rgba($text-primary-color, 0.1); $table-border-color: rgba($text-primary-color, 0.1);
$table-header-color: rgba($text-primary-color, 0.06); $table-header-color: rgba($text-primary-color, 0.06);
$shadow-color: rgba($text-primary-color, 0.8); $shadow-color: rgba(#000, 0.3);
$icon-color-focused: rgba($text-primary-color, 0.87); $icon-color-focused: rgba($text-primary-color, 0.87);
$icon-color: rgba($text-primary-color, 0.54); $icon-color: rgba($text-primary-color, 0.54);
@ -30,6 +31,7 @@ $lever-enabled-color: $primary-color;
:root { :root {
--background-primary-color: $background-primary-color; --background-primary-color: $background-primary-color;
--background-secondary-color: $background-secondary-color; --background-secondary-color: $background-secondary-color;
--background-card-color: $background-card-color;
--text-primary-color: $text-primary-color; --text-primary-color: $text-primary-color;
--text-secondary-color: $text-secondary-color; --text-secondary-color: $text-secondary-color;

View file

@ -0,0 +1 @@

View file

@ -1,73 +1,124 @@
@import "../config"; @import "../config";
.board-header { .board-header {
line-height: 6rem; line-height: 3rem;
display: flex; flex-grow: 1;
padding: 0 2rem; font-family: "Bungee", sans-serif;
font-weight: normal;
font-size: 1.1rem;
padding-left: 0.3rem;
}
& > div { .board-card {
flex-grow: 1; background-color: var(--background-card-color);
font-family: "Bungee", sans-serif; box-shadow: 0 0.1rem 0.2rem var(--shadow-color);
font-weight: normal; border-radius: $border-radius;
font-size: 1.1rem; overflow: hidden;
text-align: center;
&:first-child {
text-align: left;
}
&:last-child {
text-align: right;
}
}
} }
.board { .board {
padding: 1rem 1rem 2rem; padding: 1rem 0.4rem 2rem;
display: flex; display: flex;
overflow: hidden; overflow: hidden;
height: calc(100vh - 6rem); height: calc(100vh - 0.5rem);
& > div { & > div {
flex-grow: 1; flex-grow: 1;
flex-basis: 0; flex-basis: 0;
padding: 0 0.4rem;
&:nth-child(1) {
flex-grow: 4;
padding-left: 0.15rem;
padding-right: 0.15rem;
}
&:nth-child(2) {
flex-grow: 3;
}
&:nth-child(3) {
flex-grow: 3;
}
} }
} }
.board-schedule { .board-twitter {
width: 100%; .board-card {
position: relative; height: calc(100% - 1.3rem);
padding: 1rem 1rem; & > * {
margin-top: -1px !important;
}
}
}
.board-post {
margin-bottom: 0.5rem;
.post-name {
top: 0.5rem;
}
padding-top: 2.5rem;
padding-bottom: 0.5rem;
}
.board-schedule-box {
display: flex;
flex-wrap: wrap;
}
.board-schedule {
position: relative;
flex-grow: 1;
flex-basis: 0;
min-width: 15rem;
padding: 0.6rem;
margin: 0 0.25rem 0.5rem;
&:not(:last-child) { &:not(:last-child) {
border-bottom: solid 1px var(--table-border-color) border-bottom: solid 1px var(--table-border-color)
} }
} }
.board-schedule-room { .board-schedule-bottom {
display: block; display: block;
padding-left: 1rem; padding-left: 1rem;
line-height: 2rem; padding-right: 0.5rem;
} line-height: 1rem;
clear: both;
.board-schedule-time { & > span {
position: absolute;
top: 1rem; &:first-child {
right: 1rem; float: left;
line-height: 2rem; }
&:last-child {
float: right;
}
}
} }
.board-schedule-color { .board-schedule-color {
background-color: var(--primary-color); background-color: var(--primary-color);
position: absolute; position: absolute;
top: 3.25rem; top: 1.25rem;
left: 1rem; left: 0.6rem;
width: 0.5rem; width: 0.8rem;
height: 1.5rem; height: 0.8rem;
border-radius: 100%;
} }
.board-schedule-name { .board-schedule-name {
display: block; display: block;
padding-left: 1rem; padding-left: 1rem;
line-height: 2rem; line-height: 1.3rem;
font-family: 'Montserrat', sans-serif;
font-weight: 600;
padding-top: 0.35rem;
padding-bottom: 0.35rem;
} }

View file

@ -12,12 +12,10 @@
} }
.overview-side { .overview-side {
min-width: 20%; min-width: 30%;
} }
.overview-twitter { .overview-twitter {
height: 20rem;
background-color: #b3e6f9;
} }
.post { .post {
@ -34,6 +32,8 @@
color: var(--primary-color); color: var(--primary-color);
line-height: 2rem; line-height: 2rem;
padding: 0 1rem; padding: 0 1rem;
font-weight: bold;
font-family: 'Montserrat', sans-serif;
&:empty::before { &:empty::before {
display: block; display: block;

View file

@ -2,11 +2,12 @@
$background-primary-color: #2d2d2d; $background-primary-color: #2d2d2d;
$background-secondary-color: #373737; $background-secondary-color: #373737;
$background-card-color: rgba($text-primary-color, 0.06);
$text-primary-color: #fff; $text-primary-color: #fff;
$text-secondary-color: rgba($text-primary-color, 0.5); $text-secondary-color: rgba($text-primary-color, 0.5);
$primary-color: #dd213d; $primary-color: #ef5350;
$primary-text-color: #fff; $primary-text-color: #fff;
$error-color: #F00; $error-color: #F00;
@ -17,7 +18,7 @@ $input-border-color: #888;
$table-border-color: rgba($text-primary-color, 0.1); $table-border-color: rgba($text-primary-color, 0.1);
$table-header-color: rgba($text-primary-color, 0.06); $table-header-color: rgba($text-primary-color, 0.06);
$shadow-color: rgba($text-primary-color, 0.8); $shadow-color: rgba(#000, 0.3);
$icon-color-focused: rgba($text-primary-color, 1.0); $icon-color-focused: rgba($text-primary-color, 1.0);
$icon-color: rgba($text-primary-color, 0.7); $icon-color: rgba($text-primary-color, 0.7);

View file

@ -2,6 +2,7 @@
$background-primary-color: #ffc3e1; $background-primary-color: #ffc3e1;
$background-secondary-color: #ffa5d2; $background-secondary-color: #ffa5d2;
$background-card-color: rgba($text-primary-color, 0.06);
$text-primary-color: #333; $text-primary-color: #333;
$text-secondary-color: rgba($text-primary-color, 0.5); $text-secondary-color: rgba($text-primary-color, 0.5);
@ -17,7 +18,7 @@ $input-border-color: #888;
$table-border-color: rgba($text-primary-color, 0.1); $table-border-color: rgba($text-primary-color, 0.1);
$table-header-color: rgba($text-primary-color, 0.06); $table-header-color: rgba($text-primary-color, 0.06);
$shadow-color: rgba($text-primary-color, 0.8); $shadow-color: rgba(#000, 0.3);
$icon-color-focused: rgba($text-primary-color, 0.87); $icon-color-focused: rgba($text-primary-color, 0.87);
$icon-color: rgba($text-primary-color, 0.54); $icon-color: rgba($text-primary-color, 0.54);

View file

@ -14,8 +14,8 @@ body, html {
color: var(--text-primary-color); color: var(--text-primary-color);
background: var(--background-secondary-color); background: var(--background-secondary-color);
font-family: 'Montserrat', Roboto, Arial, sans-serif; font-family: 'Raleway', 'Montserrat', Roboto, Arial, sans-serif;
font-weight: 600; font-weight: 500;
width: 100%; width: 100%;
height: 100%; height: 100%;

View file

@ -91,13 +91,11 @@ object Configuration {
} }
private object TwitterSpec : ConfigSpec("twitter") { private object TwitterSpec : ConfigSpec("twitter") {
val username by required<String>("username") val timeline by required<String>("timeline")
val password by required<String>("password")
} }
object Twitter { object Twitter {
val username by c(TwitterSpec.username) val timeline by c(TwitterSpec.timeline)
val password by c(TwitterSpec.password)
} }
init { init {

View file

@ -1,142 +0,0 @@
package de.kif.backend
import twitter4j.*
import twitter4j.conf.ConfigurationBuilder
/*
fun twitter() {
val msgQueue = LinkedBlockingQueue<String>(100000)
val eventQueue = LinkedBlockingQueue<Event>(1000)
val hosts = HttpHosts(Constants.STREAM_HOST)
val filterEndpoint = StatusesFilterEndpoint()
filterEndpoint.trackTerms(listOf("kif"))
println(Configuration.Twitter.username)
println(Configuration.Twitter.password)
val authentication = BasicAuth(
Configuration.Twitter.username,
Configuration.Twitter.password
)
val builder = ClientBuilder()
.name("kif-portal")
.hosts(hosts)
.authentication(authentication)
.endpoint(filterEndpoint)
.processor(StringDelimitedProcessor(msgQueue))
.eventMessageQueue(eventQueue)
val client = builder.build()
val listener = object: StatusStreamHandler {
override fun onUnknownMessageType(msg: String?) {
println("onUnknownMessageType")
println(msg)
}
override fun onDisconnectMessage(message: DisconnectMessage?) {
println("onDisconnectMessage")
println(message?.disconnectReason)
}
override fun onStallWarningMessage(warning: StallWarningMessage?) {
println("onStallWarningMessage")
println(warning?.message)
}
override fun onTrackLimitationNotice(numberOfLimitedStatuses: Int) {
println("onTrackLimitationNotice")
println(numberOfLimitedStatuses)
}
override fun onStallWarning(warning: StallWarning?) {
println("onStallWarning")
println(warning?.message)
}
override fun onException(ex: Exception?) {
println("onException")
ex?.printStackTrace()
}
override fun onDeletionNotice(statusDeletionNotice: StatusDeletionNotice?) {
println("onDeletionNotice")
println(statusDeletionNotice?.statusId)
}
override fun onStatus(status: Status?) {
println("onStatus")
println(status?.text)
}
override fun onScrubGeo(userId: Long, upToStatusId: Long) {
println("onScrubGeo")
}
}
val t4jClient = Twitter4jStatusClient(
client,
msgQueue,
listOf(listener),
Executors.newFixedThreadPool(4)
)
t4jClient.connect()
t4jClient.process()
while (true) {
}
}
*/
fun twitter() {
val cb = ConfigurationBuilder()
cb.setDebugEnabled(true)
.setUser(Configuration.Twitter.username)
.setPassword(Configuration.Twitter.password)
val listener = object : StatusListener {
override fun onTrackLimitationNotice(numberOfLimitedStatuses: Int) {
println("onTrackLimitationNotice")
println(numberOfLimitedStatuses)
}
override fun onStallWarning(warning: StallWarning?) {
println("onStallWarning")
println(warning?.message)
}
override fun onException(ex: Exception?) {
println("onException")
ex?.printStackTrace()
}
override fun onDeletionNotice(statusDeletionNotice: StatusDeletionNotice?) {
println("onDeletionNotice")
println(statusDeletionNotice?.statusId)
}
override fun onStatus(status: Status?) {
println("onStatus")
println(status?.text)
}
override fun onScrubGeo(userId: Long, upToStatusId: Long) {
println("onScrubGeo")
}
}
val twitterStream = TwitterStreamFactory(cb.build()).instance
addTwitterStreamListener(twitterStream, listener)
twitterStream.sample()
}

View file

@ -2,18 +2,15 @@ package de.kif.backend.route
import de.kif.backend.authenticate import de.kif.backend.authenticate
import de.kif.backend.authenticateOrRedirect import de.kif.backend.authenticateOrRedirect
import de.kif.backend.util.Backup
import de.kif.backend.repository.TrackRepository import de.kif.backend.repository.TrackRepository
import de.kif.backend.repository.WorkGroupRepository import de.kif.backend.repository.WorkGroupRepository
import de.kif.backend.route.api.error import de.kif.backend.route.api.error
import de.kif.backend.util.Backup
import de.kif.backend.util.WikiImporter import de.kif.backend.util.WikiImporter
import de.kif.backend.view.MainTemplate
import de.kif.backend.view.MenuTemplate
import de.kif.backend.view.respondMain import de.kif.backend.view.respondMain
import de.kif.common.RepositoryType import de.kif.common.RepositoryType
import de.kif.common.model.Permission import de.kif.common.model.Permission
import io.ktor.application.call import io.ktor.application.call
import io.ktor.html.respondHtmlTemplate
import io.ktor.http.ContentType import io.ktor.http.ContentType
import io.ktor.http.HttpStatusCode import io.ktor.http.HttpStatusCode
import io.ktor.http.content.PartData import io.ktor.http.content.PartData
@ -35,10 +32,6 @@ private val logger = KotlinLogging.logger {}
fun Route.account() { fun Route.account() {
get("/account") { get("/account") {
authenticateOrRedirect { user -> authenticateOrRedirect { user ->
val tracks = TrackRepository.all()
val wikiSections = WikiImporter.loadSections()
respondMain { respondMain {
content { content {
h1 { +"Account" } h1 { +"Account" }
@ -54,6 +47,26 @@ fun Route.account() {
} }
} }
a(href = "/account/backup", classes = "form-btn") {
+"Backup"
}
if (user.checkPermission(Permission.ADMIN)) {
a(href = "/account/import", classes = "form-btn") {
+"Import wiki"
}
}
}
}
}
}
get("/account/backup") {
authenticateOrRedirect { user ->
respondMain {
content {
h1 { +"Backup" }
div("account-backup") { div("account-backup") {
if (user.checkPermission(Permission.ROOM)) { if (user.checkPermission(Permission.ROOM)) {
a("/account/backup/rooms.json", classes = "form-btn") { a("/account/backup/rooms.json", classes = "form-btn") {
@ -99,9 +112,11 @@ fun Route.account() {
} }
if (user.checkPermission(Permission.ADMIN)) { if (user.checkPermission(Permission.ADMIN)) {
h1 { +"Restore" }
div("account-import") { div("account-import") {
form( form(
action = "/account/import", action = "/account/restore",
method = FormMethod.post, method = FormMethod.post,
encType = FormEncType.multipartFormData encType = FormEncType.multipartFormData
) { ) {
@ -146,12 +161,25 @@ fun Route.account() {
} }
} }
} }
}
}
}
}
get("/account/import") {
authenticateOrRedirect(Permission.ADMIN) { user ->
val tracks = TrackRepository.all()
val wikiSections = WikiImporter.loadSections()
respondMain {
content {
h1 { +"Import wiki" }
if (user.checkPermission(Permission.ADMIN)) { if (user.checkPermission(Permission.ADMIN)) {
div("account-import-wiki") { div("account-import-wiki") {
span { +"Import work group data from the kif wiki" } span { +"Import work group data from the kif wiki" }
form(action = "/account/import-wiki", method = FormMethod.post) { form(action = "/account/import", method = FormMethod.post) {
for ((index, section) in wikiSections.withIndex()) { for ((index, section) in wikiSections.withIndex()) {
div("form-group") { div("form-group") {
label { label {
@ -277,7 +305,7 @@ fun Route.account() {
} }
} }
post("/account/import") { post("/account/restore") {
authenticate(Permission.ADMIN) { authenticate(Permission.ADMIN) {
var reset = false var reset = false
var import = "" var import = ""
@ -308,7 +336,7 @@ fun Route.account() {
} }
} }
post("/account/import-wiki") { post("/account/import") {
authenticate(Permission.ADMIN) { authenticate(Permission.ADMIN) {
val params = call.receiveParameters().toMap().mapValues { (_, list) -> val params = call.receiveParameters().toMap().mapValues { (_, list) ->
list.firstOrNull() list.firstOrNull()

View file

@ -4,7 +4,6 @@ import de.kif.backend.Configuration
import de.kif.backend.repository.PostRepository import de.kif.backend.repository.PostRepository
import de.kif.backend.repository.ScheduleRepository import de.kif.backend.repository.ScheduleRepository
import de.kif.backend.view.respondMain import de.kif.backend.view.respondMain
import de.kif.common.formatDateTime
import de.kif.common.model.Schedule import de.kif.common.model.Schedule
import io.ktor.routing.Route import io.ktor.routing.Route
import io.ktor.routing.get import io.ktor.routing.get
@ -12,10 +11,11 @@ import kotlinx.css.CSSBuilder
import kotlinx.css.Color import kotlinx.css.Color
import kotlinx.html.div import kotlinx.html.div
import kotlinx.html.span import kotlinx.html.span
import kotlinx.html.unsafe
import java.util.* import java.util.*
fun Route.board() { fun Route.board() {
get("/board") { get("/brett") {
val postList = PostRepository.all().asReversed() val postList = PostRepository.all().asReversed()
val scheduleList = ScheduleRepository.all().map { val scheduleList = ScheduleRepository.all().map {
it to it.getAbsoluteStartTime() * 60 it to it.getAbsoluteStartTime() * 60
@ -24,8 +24,9 @@ fun Route.board() {
val referenceTime = Configuration.Schedule.referenceDate.time / 1000 val referenceTime = Configuration.Schedule.referenceDate.time / 1000
val now = referenceTime - (Date().time / 1000) val now = referenceTime - (Date().time / 1000)
respondMain(true, true) { respondMain(true, true) { theme ->
content { content {
/*
div("board-header") { div("board-header") {
div { div {
+"KIF 47.0" +"KIF 47.0"
@ -34,46 +35,96 @@ fun Route.board() {
+formatDateTime(Date().time) +formatDateTime(Date().time)
} }
} }
*/
div("board") { div("board") {
div("board-schedules") { div("board-schedules") {
attributes["data-reference"] = referenceTime.toString() attributes["data-reference"] = referenceTime.toString()
for ((schedule, time) in scheduleList) { div("board-header") {
div("board-schedule") { +"AKs"
attributes["data-id"] = schedule.id.toString() }
span("board-schedule-room") { div("board-schedule-box") {
+schedule.room.name for ((schedule, time) in scheduleList) {
} div("board-card board-schedule") {
span("board-schedule-time") { attributes["data-id"] = schedule.id.toString()
attributes["data-time"] = time.toString()
attributes["data-duration"] = schedule.workGroup.length.toString()
+Schedule.timeDifferenceToString(time + now) span("board-schedule-color") {
} attributes["style"] = CSSBuilder().apply {
span("board-schedule-color") { val c = schedule.workGroup.track?.color
attributes["style"] = CSSBuilder().apply { if (c != null) {
val c = schedule.workGroup.track?.color backgroundColor = Color(c.toString())
if (c != null) { }
backgroundColor = Color(c.toString()) }.toString()
}
span("board-schedule-name") {
+schedule.workGroup.name
}
div("board-schedule-bottom") {
span("board-schedule-time") {
attributes["data-time"] = time.toString()
attributes["data-duration"] = schedule.workGroup.length.toString()
val startTime = (time % MINUTES_OF_DAY).let {
if (it < 0) it + MINUTES_OF_DAY else it
}
val sm = (startTime % 60).toString().padStart(2, '0')
val sh = (startTime / 60).toString().padStart(2, '0')
val startTimeString = "$sh:$sm"
val endTime = ((time + schedule.workGroup.length) % MINUTES_OF_DAY).let {
if (it < 0) it + MINUTES_OF_DAY else it
}
val em = (endTime % 60).toString().padStart(2, '0')
val eh = (endTime / 60).toString().padStart(2, '0')
val endTimeString = "$eh:$em"
+"$startTimeString - $endTimeString"
} }
}.toString()
} span("board-schedule-room") {
span("board-schedule-name") { +schedule.room.name
+schedule.workGroup.name }
}
} }
} }
} }
} }
div("board-posts") { div("board-posts") {
div("board-header") {
+"News"
}
for (post in postList) { for (post in postList) {
createPost(post, false, "board-post overview-post") createPost(post, false, "board-card board-post")
} }
} }
div("board-twitter") { div("board-twitter") {
div("board-header") {
+"Tweets"
}
div("board-card") {
unsafe {
raw(
"""
<a
class="twitter-timeline"
href="${Configuration.Twitter.timeline}"
data-chrome="transparent noheader nofooter"
data-theme="${if (theme.dark) "dark" else "light"}"
data-link-color="${theme.primaryColor}"
data-cards="hidden"
data-lang="de"
data-dnt="true"
>Tweets by kiforbiter</a>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
""".trimIndent()
)
}
}
} }
} }
} }

View file

@ -77,7 +77,7 @@ fun Route.overview() {
val postList = PostRepository.all().asReversed() val postList = PostRepository.all().asReversed()
respondMain { respondMain { theme ->
content { content {
div("overview") { div("overview") {
div("overview-main") { div("overview-main") {
@ -94,7 +94,21 @@ fun Route.overview() {
} }
} }
div("overview-twitter") { div("overview-twitter") {
+"The Twitter Wall" unsafe {
raw("""
<a
class="twitter-timeline"
href="${Configuration.Twitter.timeline}"
data-chrome="transparent"
data-theme="${if (theme.dark) "dark" else "light"}"
data-link-color="${theme.primaryColor}"
data-cards="hidden"
data-lang="de"
data-dnt="true"
>Tweets by kiforbiter</a>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
""".trimIndent())
}
} }
} }
} }

View file

@ -2,7 +2,6 @@ package de.kif.backend.view
import de.kif.backend.PortalSession import de.kif.backend.PortalSession
import de.kif.backend.Resources import de.kif.backend.Resources
import de.kif.backend.authenticate
import de.kif.common.model.User import de.kif.common.model.User
import io.ktor.application.ApplicationCall import io.ktor.application.ApplicationCall
import io.ktor.application.call import io.ktor.application.call
@ -34,7 +33,7 @@ class MainTemplate(
link(href = "/static/external/material-icons.css", type = LinkType.textCss, rel = LinkRel.stylesheet) link(href = "/static/external/material-icons.css", type = LinkType.textCss, rel = LinkRel.stylesheet)
link(href = "/static/external/font/Montserrat.css", type = LinkType.textCss, rel = LinkRel.stylesheet) link(href = "/static/external/font/Montserrat.css", type = LinkType.textCss, rel = LinkRel.stylesheet)
link( link(
href = "https://fonts.googleapis.com/css?family=Bungee|Oswald", href = "https://fonts.googleapis.com/css?family=Bungee|Oswald|Raleway",
type = LinkType.textCss, type = LinkType.textCss,
rel = LinkRel.stylesheet rel = LinkRel.stylesheet
) )
@ -50,6 +49,9 @@ class MainTemplate(
Theme.PRINCESS -> { Theme.PRINCESS -> {
link(href = "/static/style/princess.css", type = LinkType.textCss, rel = LinkRel.stylesheet) link(href = "/static/style/princess.css", type = LinkType.textCss, rel = LinkRel.stylesheet)
} }
Theme.BRETT -> {
link(href = "/static/style/board.css", type = LinkType.textCss, rel = LinkRel.stylesheet)
}
} }
script(src = "/static/require.min.js") {} script(src = "/static/require.min.js") {}
@ -79,8 +81,7 @@ class MainTemplate(
div("footer-credit") { div("footer-credit") {
} }
div("footer-theme") { div("footer-theme") {
for (it in Theme.values()) { for ((it, name) in Theme.displayThemes) {
val name = it.name.toLowerCase()
a("?theme=${it.name}", classes = if (theme == it) "selected" else "") { a("?theme=${it.name}", classes = if (theme == it) "selected" else "") {
id = "theme-$name" id = "theme-$name"
+name.capitalize() +name.capitalize()
@ -94,14 +95,19 @@ class MainTemplate(
} }
} }
enum class Theme { enum class Theme(val display: Boolean, val dark: Boolean, val primaryColor: String) {
LIGHT, DARK, PRINCESS; LIGHT(true, false, "#B11D33"),
DARK(true, true, "#ef5350"),
PRINCESS(true, false, "#B11D33"),
BRETT(false, false, "#B11D33");
companion object { companion object {
private val loopup = values().toList().associateBy { it.name } private val lookup = values().toList().associateBy { it.name }
val displayThemes = values().filter { it.display }.map { it to it.name.toLowerCase() }
fun lookup(name: String?): Theme { fun lookup(name: String?): Theme {
return loopup[(name ?: return LIGHT).toUpperCase()] ?: LIGHT return lookup[(name ?: return LIGHT).toUpperCase()] ?: LIGHT
} }
} }
} }
@ -109,7 +115,7 @@ enum class Theme {
suspend fun PipelineContext<Unit, ApplicationCall>.respondMain( suspend fun PipelineContext<Unit, ApplicationCall>.respondMain(
noMenu: Boolean = false, noMenu: Boolean = false,
stretch: Boolean = false, stretch: Boolean = false,
body: MainTemplate.() -> Unit body: MainTemplate.(Theme) -> Unit
) { ) {
val param = call.request.queryParameters["theme"] val param = call.request.queryParameters["theme"]
val url = call.request.uri.substring(1) val url = call.request.uri.substring(1)
@ -124,15 +130,17 @@ suspend fun PipelineContext<Unit, ApplicationCall>.respondMain(
) )
call.respondRedirect(call.request.path()) call.respondRedirect(call.request.path())
} else { } else {
val theme = Theme.lookup(call.request.cookies["theme"])
call.respondHtmlTemplate( call.respondHtmlTemplate(
MainTemplate( MainTemplate(
Theme.lookup(call.request.cookies["theme"]), theme,
url, url,
user, user,
noMenu, noMenu,
stretch stretch
), )
body = body ) {
) body(theme)
}
} }
} }

View file

@ -1,5 +0,0 @@
package twitter4j
fun addTwitterStreamListener(stream: TwitterStream, listener: StatusListener) {
stream.addListener(listener)
}