diff --git a/src/jsMain/resources/style/_color.scss b/src/jsMain/resources/style/_color.scss new file mode 100644 index 0000000..be962f4 --- /dev/null +++ b/src/jsMain/resources/style/_color.scss @@ -0,0 +1,39 @@ +$background-primary-color: #fff; +$background-secondary-color: #fcfcfc; +$text-primary-color: #333; +$text-secondary-color: rgba($text-primary-color, 0.5); +$primary-color: #B11D33; +$primary-text-color: #fff; +$error-color: #F00; +$error-text-color: #fff; +$input-border-color: #888; +$table-border-color: rgba($text-primary-color, 0.1); +$table-header-color: rgba($text-primary-color, 0.06); +$shadow-color: rgba($text-primary-color, 0.8); +$bg-disabled-color: rgba($text-primary-color, .26); +$bg-enabled-color: rgba($primary-color, .5); +$lever-disabled-color: $background-primary-color; +$lever-enabled-color: $primary-color; +$error-background-color: rgba($error-color, 0.5); + +@mixin color-setting { + :root { + --background-primary-color: $background-primary-color; + --background-secondary-color: $background-secondary-color; + --text-primary-color: $text-primary-color; + --text-secondary-color: $text-secondary-color; + --primary-color: $primary-color; + --primary-text-color: $primary-text-color; + --error-color: $error-color; + --error-text-color: $error-text-color; + --input-border-color: $input-border-color; + --table-border-color: $table-border-color; + --table-header-color: $table-header-color; + --shadow-color: $shadow-color; + --bg-disabled-color: $bg-disabled-color; + --bg-enabled-color: $bg-enabled-color; + --lever-disabled-color: $lever-disabled-color; + --lever-enabled-color: $lever-enabled-color; + --error-background-color: $error-background-color; + } +} \ No newline at end of file diff --git a/src/jsMain/resources/style/dark.scss b/src/jsMain/resources/style/dark.scss new file mode 100644 index 0000000..1cde9bd --- /dev/null +++ b/src/jsMain/resources/style/dark.scss @@ -0,0 +1,21 @@ +@import "_color.scss"; + +$background-primary-color: #2d2d2d; +$background-secondary-color: #373737; +$text-primary-color: #fff; +$text-secondary-color: rgba($text-primary-color, 0.5); +$primary-color: #dd213d; +$primary-text-color: #fff; +$error-color: #F00; +$error-text-color: #fff; +$input-border-color: #888; +$table-border-color: rgba($text-primary-color, 0.1); +$table-header-color: rgba($text-primary-color, 0.06); +$shadow-color: rgba($text-primary-color, 0.8); +$bg-disabled-color: rgba($text-primary-color, .26); +$bg-enabled-color: rgba($primary-color, .5); +$lever-disabled-color: $background-primary-color; +$lever-enabled-color: $primary-color; +$error-background-color: rgba($error-color, 0.5); + +@include color-setting; diff --git a/src/jsMain/resources/style/style.scss b/src/jsMain/resources/style/style.scss index 7524785..50e7235 100644 --- a/src/jsMain/resources/style/style.scss +++ b/src/jsMain/resources/style/style.scss @@ -1,3 +1,5 @@ +@import "_color.scss"; + @mixin no-select() { -webkit-touch-callout: none; -webkit-user-select: none; @@ -7,35 +9,14 @@ user-select: none; } -$background-primary-color: #fff; -$background-secondary-color: #fcfcfc; - -$text-primary-color: #333; -$text-secondary-color: rgba($text-primary-color, 0.5); - -$primary-color: #B11D33; -$primary-text-color: #fff; - -$error-color: #D55225; -$error-text-color: #fff; - -$input-border-color: #888; -$table-border-color: rgba($text-primary-color, 0.1); -$table-header-color: rgba($text-primary-color, 0.06); - $border-radius: 0.2rem; $transitionTime: 150ms; -$bg-disabled-color: rgba($text-primary-color, .26); -$bg-enabled-color: rgba($primary-color, .5); -$lever-disabled-color: $background-primary-color; -$lever-enabled-color: $primary-color; - -$error-background-color: #FFCDD2; +@include color-setting; body, html { - color: $text-primary-color; - background: $background-secondary-color; + color: var(--text-primary-color); + background: var(--background-secondary-color); font-family: 'Montserrat', Roboto, Arial, sans-serif; font-weight: 600; @@ -57,14 +38,14 @@ body, html { a { text-decoration: none; outline: none; - color: $primary-color; + color: var(--primary-color); &:hover { text-decoration: none; } &:active { - color: $primary-color; + color: var(--primary-color); } } @@ -98,8 +79,8 @@ a { } .menu { - background-color: $background-secondary-color; - color: $text-primary-color; + background-color: var(--background-secondary-color); + color: var(--text-primary-color); width: 100%; clear: both; height: 6rem; @@ -107,7 +88,7 @@ a { a { padding: 0 1rem; - color: $text-primary-color; + color: var(--text-primary-color); height: 100%; display: inline-block; font-family: "Bungee", sans-serif; @@ -132,14 +113,14 @@ a { } &.active::after { - background: $text-primary-color; + background: var(--text-primary-color); } &:hover { - background-color: $table-border-color; + background-color: var(--table-border-color); &::after { - background: $primary-color; + background: var(--primary-color); } } } @@ -162,7 +143,7 @@ a { cursor: default; padding: 0 1rem; - color: $text-primary-color; + color: var(--text-primary-color); height: 100%; font-size: 2rem; position: relative; @@ -171,7 +152,7 @@ a { .menu-content { display: none; position: absolute; - background-color: $background-secondary-color; + background-color: var(--background-secondary-color); z-index: 5; left: 0; right: 0; @@ -264,14 +245,10 @@ a { } tr { - border-top: solid 1px $table-border-color; - - &:nth-child(odd) { - //background-color: rgba($text-primary-color, 0.01); - } + border-top: solid 1px var(--table-border-color); &:first-child { - background-color: $table-header-color; + background-color: var(--table-header-color); height: 2.5rem; line-height: 2.5rem; } @@ -281,7 +258,7 @@ a { line-height: 2rem; &:hover { - background-color: $table-header-color; + background-color: var(--table-header-color); } } } @@ -295,16 +272,16 @@ a { } &.error { - background-color: $error-background-color; + background-color: var(--error-background-color); } } .table-select-box { position: absolute; z-index: 1; - background: $background-primary-color; + background: var(--background-primary-color); width: 10rem; - border: solid 1px $input-border-color; + border: solid 1px var(--input-border-color); border-radius: $border-radius; padding: 0.5rem 0; @@ -312,26 +289,27 @@ a { padding: 0 0.5rem; &:hover { - background-color: $table-header-color; + background-color: var(--table-header-color); } } } } .form-control { - border: solid 1px $input-border-color; + border: solid 1px var(--input-border-color); outline: none; padding: 0 1rem; line-height: 2.5rem; height: 2.5rem; width: 100%; - background-color: $background-primary-color; + background-color: var(--background-primary-color); border-radius: $border-radius; margin: 1px; transition: border-color $transitionTime; + color: var(--text-primary-color); &:focus { - border-color: $primary-color; + border-color: var(--primary-color); border-width: 2px; } } @@ -344,7 +322,7 @@ textarea.form-control { select:-moz-focusring { color: transparent; - text-shadow: 0 0 0 $text-primary-color; + text-shadow: 0 0 0 var(--text-primary-color); } .form-group { @@ -385,7 +363,7 @@ select:-moz-focusring { left: 0; width: 36px; height: 14px; - background-color: $bg-disabled-color; + background-color: var(--bg-disabled-color); border-radius: 14px; z-index: 1; transition: background-color 0.28s cubic-bezier(.4, 0, .2, 1); @@ -398,7 +376,7 @@ select:-moz-focusring { left: 0; width: 20px; height: 20px; - background-color: $lever-disabled-color; + background-color: var(--lever-disabled-color); border-radius: 14px; box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .14), 0 3px 1px -2px rgba(0, 0, 0, .2), 0 1px 5px 0 rgba(0, 0, 0, .12); z-index: 2; @@ -411,12 +389,12 @@ select:-moz-focusring { input:checked + label { &:before { - background-color: $bg-enabled-color; + background-color: var(--bg-enabled-color); } &:after { left: 16px; - background-color: $lever-enabled-color; + background-color: var(--lever-enabled-color); } } } @@ -426,12 +404,12 @@ select:-moz-focusring { } .form-btn { - border: solid 1px $input-border-color; + border: solid 1px var(--input-border-color); outline: none; padding: 0 1rem; line-height: 2rem; - background-color: $background-primary-color; - color: $primary-color; + background-color: var(--background-primary-color); + color: var(--primary-color); display: inline-block; margin-right: 0.6rem; @@ -446,21 +424,21 @@ select:-moz-focusring { cursor: pointer; &:focus, &:hover { - border-color: $primary-color; - outline-color: $primary-color; + border-color: var(--primary-color); + outline-color: var(--primary-color); } } .btn-primary { - background-color: $primary-color; - color: $primary-text-color; - border-color: $primary-color; + background-color: var(--primary-color); + color: var(--primary-text-color); + border-color: var(--primary-color); } .btn-danger { - background-color: $error-color; - color: $error-text-color; - border-color: $error-color; + background-color: var(--error-color); + color: var(--error-text-color); + border-color: var(--error-color); } button::-moz-focus-inner, input::-moz-focus-inner, select::-moz-focus-inner { @@ -522,9 +500,28 @@ form { float: left; } - i { - font-size: 1.5rem; - padding: 0 0.5rem; + a { + i { + font-size: 1.8rem; + padding: 0 0.5rem; + position: relative; + } + + &:first-child i::after { + content: ''; + position: absolute; + left: 100%; + height: 100%; + width: 4rem; + } + + &:last-child i::after { + content: ''; + position: absolute; + height: 100%; + left: -4rem; + width: 4rem; + } } } @@ -589,8 +586,8 @@ form { white-space: nowrap; text-overflow: ellipsis; - background-color: $primary-color; - color: $primary-text-color; + background-color: var(--primary-color); + color: var(--primary-text-color); padding: 0 0.5rem; margin: 0.5rem; @@ -609,7 +606,7 @@ form { } &.drag { - box-shadow: 0 0.1rem 0.2rem rgba($text-primary-color, 0.8); + box-shadow: 0 0.1rem 0.2rem var(--shadow-color); z-index: 2; .calendar-tools { @@ -625,7 +622,7 @@ form { top: 0; width: 100%; height: 100%; - background-color: $background-primary-color; + background-color: var(--background-primary-color); opacity: 0.6; } @@ -635,7 +632,7 @@ form { .calendar[data-editable = "true"].edit { .calendar-table { width: calc(100% - 16rem); - border-right: solid 1px $table-border-color; + border-right: solid 1px var(--table-border-color); } .calendar-edit-main { @@ -655,8 +652,8 @@ form { display: none; z-index: 10; - border: solid 1px $input-border-color; - box-shadow: 0 0.1rem 0.2rem $primary-text-color; + border: solid 1px var(--input-border-color); + box-shadow: 0 0.1rem 0.2rem var(--primary-text-color); a { padding: 0.2rem; @@ -686,8 +683,8 @@ form { white-space: nowrap; text-overflow: ellipsis; - background-color: $primary-color; - color: $primary-text-color; + background-color: var(--primary-color); + color: var(--primary-text-color); padding: 0 0.5rem; @@ -705,7 +702,7 @@ form { } &.drag { - box-shadow: 0 0.1rem 0.2rem rgba($text-primary-color, 0.8); + box-shadow: 0 0.1rem 0.2rem var(--shadow-color); z-index: 2; .calendar-tools { @@ -721,12 +718,12 @@ form { top: 0; width: 100%; height: 100%; - background-color: $background-primary-color; + background-color: var(--background-primary-color); opacity: 0.6; } &.error { - outline: solid 0.4rem $error-color; + outline: solid 0.4rem var(--error-color); } @include no-select() @@ -754,14 +751,14 @@ form { height: 100%; left: 0; top: 0; - border-left: solid 1px $table-border-color; + border-left: solid 1px var(--table-border-color); position: absolute; } } } .calendar-row { - border-top: solid 1px $table-border-color; + border-top: solid 1px var(--table-border-color); line-height: 3rem; height: 3rem; @@ -774,12 +771,12 @@ form { height: 100%; left: 0; top: 0; - border-left: solid 1px $table-border-color; + border-left: solid 1px var(--table-border-color); position: absolute; } &:hover { - background-color: $table-header-color; + background-color: var(--table-header-color); } .calendar-entry { @@ -796,7 +793,7 @@ form { width: 6rem; left: 0; text-align: center; - border-right: solid 1px $table-border-color; + border-right: solid 1px var(--table-border-color); } .calendar-link { @@ -827,7 +824,7 @@ form { height: 100%; left: 0; top: 0; - border-left: solid 1px $table-border-color; + border-left: solid 1px var(--table-border-color); position: absolute; } } @@ -847,12 +844,12 @@ form { width: 100%; left: 0; top: 0; - border-left: solid 1px $table-border-color; + border-left: solid 1px var(--table-border-color); position: absolute; } &:hover { - background-color: $table-header-color; + background-color: var(--table-header-color); } .calendar-entry { @@ -873,7 +870,7 @@ form { } &:nth-child(4n + 2) .calendar-cell::before { - border-top: solid 1px $table-border-color; + border-top: solid 1px var(--table-border-color); } } @@ -920,8 +917,8 @@ form { width: 1.1rem; height: 0.5rem; transform: rotate(-45deg); - border-left: solid 0.3rem $background-primary-color; - border-bottom: solid 0.3rem $background-primary-color; + border-left: solid 0.3rem var(--background-primary-color); + border-bottom: solid 0.3rem var(--background-primary-color); } } @@ -942,7 +939,7 @@ form { height: 3rem; border-radius: 1.5rem; z-index: 1; - border: solid 0.1rem $text-primary-color; + border: solid 0.1rem var(--text-primary-color); } input:checked ~ label::before { @@ -954,8 +951,8 @@ form { width: 1.1rem; height: 0.5rem; transform: rotate(-45deg); - border-left: solid 0.3rem $text-primary-color; - border-bottom: solid 0.3rem $text-primary-color; + border-left: solid 0.3rem var(--text-primary-color); + border-bottom: solid 0.3rem var(--text-primary-color); } label input { @@ -993,8 +990,8 @@ form { text-align: center; font-weight: bold; - color: $primary-text-color; - background: $primary-color; + color: var(--primary-text-color); + background: var(--primary-color); } } @@ -1018,8 +1015,8 @@ form { display: none; padding: 0.5rem 0; - background: $background-primary-color; - border: solid 1px $input-border-color; + background: var(--background-primary-color); + border: solid 1px var(--input-border-color); border-radius: $border-radius; span { @@ -1028,7 +1025,7 @@ form { display: block; &:hover { - background-color: $table-header-color; + background-color: var(--table-header-color); } } @@ -1068,7 +1065,7 @@ form { top: 0; left: 0; font-size: 1.2rem; - color: $primary-color; + color: var(--primary-color); line-height: 2rem; padding: 0 1rem; @@ -1078,7 +1075,7 @@ form { opacity: 0.5; font-size: 1.2rem; line-height: 2rem; - color: $text-primary-color; + color: var(--text-primary-color); } } @@ -1148,11 +1145,11 @@ form { } td { - border-top: solid 1px $table-border-color; + border-top: solid 1px var(--table-border-color); } th { - background-color: $table-header-color; + background-color: var(--table-header-color); } td, th { @@ -1161,7 +1158,7 @@ form { } .post-footer { - color: $text-secondary-color; + color: var(--text-secondary-color); padding: 0 1rem; font-size: 0.8rem; font-weight: 400; @@ -1195,9 +1192,9 @@ form { .post-edit-image { width: 100%; padding-top: 75%; - border: solid 1px $input-border-color; + border: solid 1px var(--input-border-color); margin: 0; - background-color: $background-primary-color; + background-color: var(--background-primary-color); background-position: center; background-size: cover; } @@ -1213,7 +1210,7 @@ form { height: 1px; left: 0; right: 0; - background: $table-border-color; + background: var(--table-border-color); } } @@ -1258,3 +1255,49 @@ form { flex-direction: row; } } + +.footer { + height: 5rem; +} + +.footer-credit { + float: left; +} + +.footer-theme { + float: right; + line-height: 2rem; + margin-top: 0.5rem; + + a { + display: block; + position: relative; + padding-left: 2.5rem; + + &::after { + content: ''; + width: 1.2rem; + height: 1.2rem; + border-radius: 100%; + position: absolute; + top: 1rem; + left: 1rem; + transform: translate(-50%, -50%); + border: solid 0.2rem transparent; + } + + &.selected::after { + border-color: var(--primary-color) !important; + } + } + + #theme-light::after { + background-color: #fff; + border-color: #fff; + } + + #theme-dark::after { + background-color: #2d2d2d; + border-color: #2d2d2d; + } +} \ No newline at end of file diff --git a/src/jvmMain/kotlin/de/kif/backend/route/Account.kt b/src/jvmMain/kotlin/de/kif/backend/route/Account.kt index 6502b64..c6c5a8d 100644 --- a/src/jvmMain/kotlin/de/kif/backend/route/Account.kt +++ b/src/jvmMain/kotlin/de/kif/backend/route/Account.kt @@ -9,6 +9,7 @@ import de.kif.backend.route.api.error 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.common.RepositoryType import de.kif.common.model.Permission import io.ktor.application.call @@ -38,7 +39,7 @@ fun Route.account() { val tracks = TrackRepository.all() val wikiSections = WikiImporter.loadSections() - call.respondHtmlTemplate(MainTemplate()) { + respondMain { menuTemplate { this.user = user active = MenuTemplate.Tab.ACCOUNT diff --git a/src/jvmMain/kotlin/de/kif/backend/route/Calendar.kt b/src/jvmMain/kotlin/de/kif/backend/route/Calendar.kt index c44e877..77e0fb6 100644 --- a/src/jvmMain/kotlin/de/kif/backend/route/Calendar.kt +++ b/src/jvmMain/kotlin/de/kif/backend/route/Calendar.kt @@ -11,6 +11,7 @@ import de.kif.backend.repository.WorkGroupRepository import de.kif.backend.view.MainTemplate import de.kif.backend.view.MenuTemplate import de.kif.backend.view.TableTemplate +import de.kif.backend.view.respondMain import de.kif.common.CALENDAR_GRID_WIDTH import de.kif.common.Search import de.kif.common.model.Permission @@ -303,7 +304,7 @@ fun Route.calendar() { .withLocale(KlockLocale.german) .format(date) - call.respondHtmlTemplate(MainTemplate()) { + respondMain { menuTemplate { this.user = user active = MenuTemplate.Tab.CALENDAR @@ -315,13 +316,13 @@ fun Route.calendar() { div("header") { div("header-left") { - if (day - 1 in range) { + if (editable || day - 1 > range.start) { a("/calendar/${day - 1}") { i("material-icons") { +"chevron_left" } } } span { +dateString } - if (day + 1 in range) { + if (editable || day + 1 < range.endInclusive) { a("/calendar/${day + 1}") { i("material-icons") { +"chevron_right" } } } } @@ -400,7 +401,7 @@ fun Route.calendar() { val list = WorkGroupRepository.all() val room = RoomRepository.get(roomId) ?: return@get - call.respondHtmlTemplate(MainTemplate()) { + respondMain { menuTemplate { this.user = user active = MenuTemplate.Tab.WORK_GROUP diff --git a/src/jvmMain/kotlin/de/kif/backend/route/Login.kt b/src/jvmMain/kotlin/de/kif/backend/route/Login.kt index 6f7cf92..694cfa6 100644 --- a/src/jvmMain/kotlin/de/kif/backend/route/Login.kt +++ b/src/jvmMain/kotlin/de/kif/backend/route/Login.kt @@ -3,6 +3,7 @@ package de.kif.backend.route import de.kif.backend.PortalSession import de.kif.backend.UserPrinciple import de.kif.backend.view.MainTemplate +import de.kif.backend.view.respondMain import io.ktor.application.call import io.ktor.auth.authenticate import io.ktor.auth.principal @@ -32,7 +33,7 @@ fun Route.login() { get { val needLogin = call.sessions.get() == null if (needLogin) { - call.respondHtmlTemplate(MainTemplate()) { + respondMain { content { div { div { diff --git a/src/jvmMain/kotlin/de/kif/backend/route/Overview.kt b/src/jvmMain/kotlin/de/kif/backend/route/Overview.kt index 6b13b81..d6f8ede 100644 --- a/src/jvmMain/kotlin/de/kif/backend/route/Overview.kt +++ b/src/jvmMain/kotlin/de/kif/backend/route/Overview.kt @@ -8,6 +8,7 @@ import de.kif.backend.repository.PostRepository import de.kif.backend.util.markdownToHtml import de.kif.backend.view.MainTemplate import de.kif.backend.view.MenuTemplate +import de.kif.backend.view.respondMain import de.kif.common.formatDateTime import de.kif.common.model.Permission import de.kif.common.model.Post @@ -76,7 +77,7 @@ fun Route.overview() { val postList = PostRepository.all().asReversed() - call.respondHtmlTemplate(MainTemplate()) { + respondMain { menuTemplate { this.user = user active = MenuTemplate.Tab.BOARD @@ -116,7 +117,7 @@ fun Route.overview() { return@get } - call.respondHtmlTemplate(MainTemplate()) { + respondMain { menuTemplate { this.user = user active = MenuTemplate.Tab.BOARD @@ -133,7 +134,7 @@ fun Route.overview() { authenticateOrRedirect(Permission.POST) { user -> val postId = call.parameters["id"]?.toLongOrNull() ?: return@get val editPost = PostRepository.get(postId) ?: return@get - call.respondHtmlTemplate(MainTemplate()) { + respondMain { menuTemplate { this.user = user active = MenuTemplate.Tab.BOARD @@ -363,7 +364,7 @@ fun Route.overview() { get("/post/new") { authenticateOrRedirect(Permission.POST) { user -> - call.respondHtmlTemplate(MainTemplate()) { + respondMain { menuTemplate { this.user = user active = MenuTemplate.Tab.BOARD diff --git a/src/jvmMain/kotlin/de/kif/backend/route/Room.kt b/src/jvmMain/kotlin/de/kif/backend/route/Room.kt index 84044bc..9f9bc60 100644 --- a/src/jvmMain/kotlin/de/kif/backend/route/Room.kt +++ b/src/jvmMain/kotlin/de/kif/backend/route/Room.kt @@ -5,6 +5,7 @@ import de.kif.backend.repository.RoomRepository import de.kif.backend.view.MainTemplate import de.kif.backend.view.MenuTemplate import de.kif.backend.view.TableTemplate +import de.kif.backend.view.respondMain import de.kif.common.Search import de.kif.common.model.Permission import de.kif.common.model.Room @@ -30,7 +31,8 @@ fun Route.room() { authenticateOrRedirect(Permission.ROOM) { user -> val search = call.parameters["search"] ?: "" val list = RoomRepository.all() - call.respondHtmlTemplate(MainTemplate()) { + + respondMain { menuTemplate { this.user = user active = MenuTemplate.Tab.ROOM @@ -110,7 +112,7 @@ fun Route.room() { authenticateOrRedirect(Permission.ROOM) { user -> val roomId = call.parameters["id"]?.toLongOrNull() ?: return@get val editRoom = RoomRepository.get(roomId) ?: return@get - call.respondHtmlTemplate(MainTemplate()) { + respondMain { menuTemplate { this.user = user active = MenuTemplate.Tab.ROOM @@ -273,7 +275,7 @@ fun Route.room() { get("/room/new") { authenticateOrRedirect(Permission.ROOM) { user -> - call.respondHtmlTemplate(MainTemplate()) { + respondMain { menuTemplate { this.user = user active = MenuTemplate.Tab.ROOM diff --git a/src/jvmMain/kotlin/de/kif/backend/route/Track.kt b/src/jvmMain/kotlin/de/kif/backend/route/Track.kt index e358148..785af28 100644 --- a/src/jvmMain/kotlin/de/kif/backend/route/Track.kt +++ b/src/jvmMain/kotlin/de/kif/backend/route/Track.kt @@ -6,6 +6,7 @@ import de.kif.backend.repository.TrackRepository import de.kif.backend.view.MainTemplate import de.kif.backend.view.MenuTemplate import de.kif.backend.view.TableTemplate +import de.kif.backend.view.respondMain import de.kif.common.Search import de.kif.common.model.Color import de.kif.common.model.Permission @@ -88,7 +89,7 @@ fun Route.track() { authenticateOrRedirect(Permission.WORK_GROUP) { user -> val search = call.parameters["search"] ?: "" val list = TrackRepository.all() - call.respondHtmlTemplate(MainTemplate()) { + respondMain { menuTemplate { this.user = user active = MenuTemplate.Tab.WORK_GROUP @@ -148,7 +149,7 @@ fun Route.track() { authenticateOrRedirect(Permission.WORK_GROUP) { user -> val trackId = call.parameters["id"]?.toLongOrNull() ?: return@get val editTrack = TrackRepository.get(trackId) ?: return@get - call.respondHtmlTemplate(MainTemplate()) { + respondMain { menuTemplate { this.user = user active = MenuTemplate.Tab.WORK_GROUP @@ -217,7 +218,7 @@ fun Route.track() { get("/track/new") { authenticateOrRedirect(Permission.WORK_GROUP) { user -> - call.respondHtmlTemplate(MainTemplate()) { + respondMain { menuTemplate { this.user = user active = MenuTemplate.Tab.WORK_GROUP diff --git a/src/jvmMain/kotlin/de/kif/backend/route/User.kt b/src/jvmMain/kotlin/de/kif/backend/route/User.kt index 746cfe1..658ee88 100644 --- a/src/jvmMain/kotlin/de/kif/backend/route/User.kt +++ b/src/jvmMain/kotlin/de/kif/backend/route/User.kt @@ -7,6 +7,7 @@ import de.kif.backend.repository.UserRepository import de.kif.backend.view.MainTemplate import de.kif.backend.view.MenuTemplate import de.kif.backend.view.TableTemplate +import de.kif.backend.view.respondMain import de.kif.common.Search import de.kif.common.model.Permission import de.kif.common.model.User @@ -31,7 +32,7 @@ fun Route.user() { authenticateOrRedirect(Permission.USER) { user -> val search = call.parameters["search"] ?: "" val list = UserRepository.all() - call.respondHtmlTemplate(MainTemplate()) { + respondMain { menuTemplate { this.user = user active = MenuTemplate.Tab.USER @@ -90,7 +91,7 @@ fun Route.user() { authenticateOrRedirect(Permission.USER) { user -> val userId = call.parameters["id"]?.toLongOrNull() ?: return@get val editUser = UserRepository.get(userId) ?: return@get - call.respondHtmlTemplate(MainTemplate()) { + respondMain { menuTemplate { this.user = user active = MenuTemplate.Tab.USER @@ -183,7 +184,7 @@ fun Route.user() { get("/user/new") { authenticateOrRedirect(Permission.USER) { user -> - call.respondHtmlTemplate(MainTemplate()) { + respondMain { menuTemplate { this.user = user active = MenuTemplate.Tab.USER diff --git a/src/jvmMain/kotlin/de/kif/backend/route/WorkGroup.kt b/src/jvmMain/kotlin/de/kif/backend/route/WorkGroup.kt index acc6d75..00a3a0a 100644 --- a/src/jvmMain/kotlin/de/kif/backend/route/WorkGroup.kt +++ b/src/jvmMain/kotlin/de/kif/backend/route/WorkGroup.kt @@ -6,6 +6,7 @@ import de.kif.backend.repository.WorkGroupRepository import de.kif.backend.view.MainTemplate import de.kif.backend.view.MenuTemplate import de.kif.backend.view.TableTemplate +import de.kif.backend.view.respondMain import de.kif.common.Search import de.kif.common.model.* import io.ktor.application.call @@ -27,7 +28,7 @@ fun Route.workGroup() { authenticateOrRedirect(Permission.WORK_GROUP) { user -> val search = call.parameters["search"] ?: "" val list = WorkGroupRepository.all() - call.respondHtmlTemplate(MainTemplate()) { + respondMain { menuTemplate { this.user = user active = MenuTemplate.Tab.WORK_GROUP @@ -164,7 +165,7 @@ fun Route.workGroup() { WorkGroupRepository.get(it)!! } - call.respondHtmlTemplate(MainTemplate()) { + respondMain { menuTemplate { this.user = user active = MenuTemplate.Tab.WORK_GROUP @@ -527,7 +528,7 @@ fun Route.workGroup() { get("/workgroup/new") { authenticateOrRedirect(Permission.WORK_GROUP) { user -> val tracks = TrackRepository.all() - call.respondHtmlTemplate(MainTemplate()) { + respondMain { menuTemplate { this.user = user active = MenuTemplate.Tab.WORK_GROUP diff --git a/src/jvmMain/kotlin/de/kif/backend/view/MainTemplate.kt b/src/jvmMain/kotlin/de/kif/backend/view/MainTemplate.kt index 7ce0b3c..a80117b 100644 --- a/src/jvmMain/kotlin/de/kif/backend/view/MainTemplate.kt +++ b/src/jvmMain/kotlin/de/kif/backend/view/MainTemplate.kt @@ -1,13 +1,15 @@ package de.kif.backend.view import de.kif.backend.Resources -import io.ktor.html.Placeholder -import io.ktor.html.Template -import io.ktor.html.TemplatePlaceholder -import io.ktor.html.insert +import io.ktor.application.ApplicationCall +import io.ktor.application.call +import io.ktor.html.* +import io.ktor.request.path +import io.ktor.response.respondRedirect +import io.ktor.util.pipeline.PipelineContext import kotlinx.html.* -class MainTemplate : Template { +class MainTemplate(private val theme: Theme) : Template { val content = Placeholder() val menuTemplate = TemplatePlaceholder() @@ -27,6 +29,15 @@ class MainTemplate : Template { ) link(href = "/static/style/style.css", type = LinkType.textCss, rel = LinkRel.stylesheet) + when (theme) { + Theme.LIGHT -> { + // Ignore + } + Theme.DARK -> { + link(href = "/static/style/dark.css", type = LinkType.textCss, rel = LinkRel.stylesheet) + } + } + script(src = "/static/require.min.js") {} script { @@ -43,6 +54,46 @@ class MainTemplate : Template { insert(content) } } + + div("footer") { + div("container") { + div("footer-credit") { + } + div("footer-theme") { + for (it in Theme.values()) { + val name = it.name.toLowerCase() + a("?theme=$name", classes = if (theme == it) "selected" else "") { + id = "theme-$name" + +name.capitalize() + } + } + } + } + } } } } + +enum class Theme { + LIGHT, DARK +} + +private fun String?.toTheme() = this?.toUpperCase()?.let { str -> + Theme.values().find { str == it.name } +} ?: Theme.LIGHT + +suspend fun PipelineContext.respondMain(body: MainTemplate.() -> Unit) { + val param = call.request.queryParameters["theme"] + + if (param != null) { + call.response.cookies.append("theme", param.toTheme().name.toLowerCase()) + call.respondRedirect(call.request.path()) + } else { + call.respondHtmlTemplate( + MainTemplate( + call.request.cookies["theme"].toTheme() + ), + body = body + ) + } +}