diff options
author | Marvin Borner | 2019-05-13 18:18:57 +0200 |
---|---|---|
committer | Marvin Borner | 2019-05-13 18:18:57 +0200 |
commit | b9a392f5f1db5c7de60e929fdcc0ca42885f81ca (patch) | |
tree | 0f9aa014bcabfc3d7205898ada71f15d4490cb0a /src | |
parent | 72073df2c225f96889620e30c963dd807ca01a90 (diff) |
Added user based dark theme support
Co-authored-by: LarsVomMars <lars@kroenner.eu>
Diffstat (limited to 'src')
-rw-r--r-- | src/main/kotlin/App.kt | 11 | ||||
-rw-r--r-- | src/main/kotlin/DatabaseController.kt | 36 | ||||
-rw-r--r-- | src/main/kotlin/FileController.kt | 9 | ||||
-rw-r--r-- | src/main/kotlin/UserHandler.kt | 54 | ||||
-rw-r--r-- | src/main/resources/css/darkLayout.css | 32 | ||||
-rw-r--r-- | src/main/resources/css/index.css | 6 | ||||
-rw-r--r-- | src/main/resources/js/index.js | 6 | ||||
-rw-r--r-- | src/main/resources/views/admin.rocker.html | 5 | ||||
-rw-r--r-- | src/main/resources/views/files.rocker.html | 5 | ||||
-rw-r--r-- | src/main/resources/views/fileview.rocker.html | 5 | ||||
-rw-r--r-- | src/main/resources/views/index.rocker.html | 17 | ||||
-rw-r--r-- | src/main/resources/views/layout.rocker.html | 10 | ||||
-rw-r--r-- | src/main/resources/views/login.rocker.html | 5 | ||||
-rw-r--r-- | src/main/resources/views/register.rocker.html | 5 | ||||
-rw-r--r-- | src/main/resources/views/setup.rocker.html | 5 |
15 files changed, 172 insertions, 39 deletions
diff --git a/src/main/kotlin/App.kt b/src/main/kotlin/App.kt index df845a1..3607702 100644 --- a/src/main/kotlin/App.kt +++ b/src/main/kotlin/App.kt @@ -14,11 +14,11 @@ import java.util.logging.* import kotlin.system.* // TODO: Add abstract and secure file home support for windows/BSD/macOS -val fileHome = if (System.getProperty("os.name") != "Linux") "files" else "/usr/share/kloud/files" +const val debug = true +val fileHome = if (System.getProperty("os.name") != "Linux" || debug) "files" else "/usr/share/kloud/files" val databaseController = DatabaseController() val userHandler = UserHandler() val fileController = FileController() -const val debug = false private val log = Logger.getLogger("App.kt") fun main(args: Array<String>) { @@ -82,7 +82,7 @@ fun main(args: Array<String>) { get("/", { ctx -> ctx.render( "index.rocker.html", - model("username", databaseController.getUsername(userHandler.getVerifiedUserId(ctx))) + model("username", databaseController.getUsername(userHandler.getVerifiedUserId(ctx)), "ctx", ctx) ) }, roles(Roles.GUEST, Roles.USER)) @@ -102,6 +102,11 @@ fun main(args: Array<String>) { get("/user/logout", userHandler::logout, roles(Roles.USER)) /** + * Toggles the users theme + */ + post("/user/theme", userHandler::toggleTheme, roles(Roles.USER)) + + /** * Renders the registration page */ get("/user/register", userHandler::renderRegistration, roles(Roles.GUEST)) diff --git a/src/main/kotlin/DatabaseController.kt b/src/main/kotlin/DatabaseController.kt index 24a8278..bdbdc18 100644 --- a/src/main/kotlin/DatabaseController.kt +++ b/src/main/kotlin/DatabaseController.kt @@ -35,6 +35,7 @@ class DatabaseController { val username = varchar("username", 24).uniqueIndex() val password = varchar("password", 64) val verification = varchar("verification", 64).uniqueIndex() + val darkTheme = bool("darkTheme").default(false) } /** @@ -161,13 +162,14 @@ class DatabaseController { } } - if (error) ctx.render("admin.rocker.html", model("message", "User already exists!")) + if (error) ctx.render("admin.rocker.html", model("message", "User already exists!", "ctx", ctx)) else ctx.render( "admin.rocker.html", model( - "message", "http://${ctx.host()}/user/register?username=$usernameString&token=$tokenString" + "message", "http://${ctx.host()}/user/register?username=$usernameString&token=$tokenString", + "ctx", ctx ) ) - } else ctx.render("admin.rocker.html", model("message", "Please only use alphabetical characters!")) + } else ctx.render("admin.rocker.html", model("message", "Please only use alphabetical characters!", "ctx", ctx)) } /** @@ -221,6 +223,34 @@ class DatabaseController { } /** + * Returns true when user uses dark theme + */ + fun isDarkTheme(userId: Int): Boolean { + return transaction { + try { + UserData.select { UserData.id eq userId }.map { it[UserData.darkTheme] }[0] + } catch (_: Exception) { + false + } + } + } + + /** + * Toggles the dark theme + */ + fun toggleDarkTheme(userId: Int) { + return transaction { + try { + UserData.update({ (UserData.id eq userId) }) { + it[darkTheme] = !isDarkTheme(userId) + } + } catch (_: Exception) { + // + } + } + } + + /** * Returns the corresponding verification id using [usernameString] */ fun getVerificationId(usernameString: String): String { diff --git a/src/main/kotlin/FileController.kt b/src/main/kotlin/FileController.kt index 32c9369..d62b4b4 100644 --- a/src/main/kotlin/FileController.kt +++ b/src/main/kotlin/FileController.kt @@ -36,7 +36,8 @@ class FileController { "files.rocker.html", model( "files", files, "path", (if (firstParam.firstOrNull() == '/') firstParam.drop(1) else firstParam), - "isShared", false + "isShared", false, + "ctx", ctx ) ) } @@ -178,7 +179,8 @@ class FileController { "files.rocker.html", model( "files", files, "path", (if (fileLocation.firstOrNull() == '/') fileLocation.drop(1) else fileLocation), - "isShared", true + "isShared", true, + "ctx", ctx ) ) } @@ -216,7 +218,8 @@ class FileController { Charsets.UTF_8 ).joinToString(separator = "\n"), "filename", File(filePath).name, - "extension", File(filePath).extension + "extension", File(filePath).extension, + "ctx", ctx ) ) } diff --git a/src/main/kotlin/UserHandler.kt b/src/main/kotlin/UserHandler.kt index 33f3f14..e9d0ada 100644 --- a/src/main/kotlin/UserHandler.kt +++ b/src/main/kotlin/UserHandler.kt @@ -14,7 +14,7 @@ class UserHandler { */ fun renderLogin(ctx: Context) { if (userHandler.getVerifiedUserId(ctx) > 0 || !databaseController.isSetup()) ctx.redirect("/") - else ctx.render("login.rocker.html", model("message", "", "counter", 0)) + else ctx.render("login.rocker.html", model("message", "", "counter", 0, "ctx", ctx)) } /** @@ -54,7 +54,8 @@ class UserHandler { model( "message", "Login failed!", - "counter", if (nextThreshold / 60 > 60) 3600 else nextThreshold.toInt() + "counter", if (nextThreshold / 60 > 60) 3600 else nextThreshold.toInt(), + "ctx", ctx ) ) } @@ -65,7 +66,8 @@ class UserHandler { model( "message", "Too many request.", - "counter", if (nextThreshold / 60 > 60) 3600 else nextThreshold.toInt() + "counter", if (nextThreshold / 60 > 60) 3600 else nextThreshold.toInt(), + "ctx", ctx ) ) } @@ -81,10 +83,19 @@ class UserHandler { } /** + * Toggles the users dark theme + */ + fun toggleTheme(ctx: Context) { + databaseController.toggleDarkTheme(userHandler.getVerifiedUserId(ctx)) + val dark = databaseController.isDarkTheme(userHandler.getVerifiedUserId(ctx)) + ctx.json(mapOf("dark" to dark)) + } + + /** * Renders the admin interface */ fun renderAdmin(ctx: Context) { - ctx.render("admin.rocker.html", model("message", "")) + ctx.render("admin.rocker.html", model("message", "", "ctx", ctx)) } /** @@ -92,7 +103,7 @@ class UserHandler { */ fun renderSetup(ctx: Context) { if (databaseController.isSetup()) ctx.redirect("/user/login") - else ctx.render("setup.rocker.html", model("message", "")) + else ctx.render("setup.rocker.html", model("message", "", "ctx", ctx)) } /** @@ -105,21 +116,30 @@ class UserHandler { val verifyPassword = ctx.formParam("verifyPassword").toString() // TODO: Clean up ugly if statements in validation - if (!username.matches("[a-zA-Z0-9]+".toRegex()) || username.length <= 3) { + if (username.matches("[a-zA-Z0-9]+".toRegex()) && username.length > 3) { if (password == verifyPassword) { if (password.length >= 8) if (databaseController.createUser(username, password, "ADMIN")) { databaseController.toggleSetup() ctx.redirect("/user/login") - } else ctx.status(400).render("setup.rocker.html", model("message", "User already exists!")) - else ctx.status(400).render("setup.rocker.html", model("message", "Password is too short!")) - } else ctx.status(400).render("setup.rocker.html", model("message", "Passwords do not match!")) + } else ctx.status(400).render( + "setup.rocker.html", + model("message", "User already exists!", "ctx", ctx) + ) + else ctx.status(400).render( + "setup.rocker.html", + model("message", "Password is too short!", "ctx", ctx) + ) + } else ctx.status(400).render( + "setup.rocker.html", + model("message", "Passwords do not match!", "ctx", ctx) + ) } else ctx.status(400).render( "setup.rocker.html", - model("message", "Username must only use alphabetical characters!") + model("message", "Username must only use alphabetical characters!", "ctx", ctx) ) } catch (err: Exception) { - ctx.status(400).render("setup.rocker.html", model("message", "An error occurred!")) + ctx.status(400).render("setup.rocker.html", model("message", "An error occurred!", "ctx", ctx)) error(err) } } @@ -135,7 +155,10 @@ class UserHandler { else if (token.isNullOrEmpty()) throw ForbiddenResponse("Please provide a valid token!") else { if (databaseController.isUserRegistrationValid(username, token)) - ctx.render("register.rocker.html", model("username", username, "token", token, "message", "")) + ctx.render( + "register.rocker.html", + model("username", username, "token", token, "message", "", "ctx", ctx) + ) else ctx.redirect("/user/login") } } @@ -158,19 +181,20 @@ class UserHandler { ctx.redirect("/user/login") } else ctx.render( "register.rocker.html", - model("username", username, "token", token, "message", "Not authorized!") + model("username", username, "token", token, "message", "Not authorized!", "ctx", ctx) ) else ctx.render( "register.rocker.html", model( "username", username, "token", token, - "message", "Please make sure that your password is at least 8 digits long!" + "message", "Please make sure that your password is at least 8 digits long!", + "ctx", ctx ) ) } else ctx.render( "register.rocker.html", - model("username", username, "token", token, "message", "The passwords don't match!") + model("username", username, "token", token, "message", "The passwords don't match!", "ctx", ctx) ) } catch (err: Exception) { throw BadRequestResponse() diff --git a/src/main/resources/css/darkLayout.css b/src/main/resources/css/darkLayout.css new file mode 100644 index 0000000..71172a5 --- /dev/null +++ b/src/main/resources/css/darkLayout.css @@ -0,0 +1,32 @@ +/** + Main + */ +body { + background-color: #181a1b; +} + +.main { + color: #d0cdc6 +} + +button { + text-decoration-color: initial; + background-color: #3d4043; + border-top-color: #595959; + border-right-color: #595959; + border-bottom-color: #595959; + border-left-color: #595959; + color: #ffffff; +} + +input { + border-color: #575757; + color: #e8e6e3; +} + +/** + Other stuff + */ +tr:hover { + background-color: #121516 !important; +} diff --git a/src/main/resources/css/index.css b/src/main/resources/css/index.css new file mode 100644 index 0000000..5cf3c78 --- /dev/null +++ b/src/main/resources/css/index.css @@ -0,0 +1,6 @@ +.toggle { + position: absolute; + margin: 20px; + right: 0; + top: 0; +} diff --git a/src/main/resources/js/index.js b/src/main/resources/js/index.js new file mode 100644 index 0000000..4939622 --- /dev/null +++ b/src/main/resources/js/index.js @@ -0,0 +1,6 @@ +document.querySelector("#toggle").addEventListener("click", () => { + const request = new XMLHttpRequest(); + request.open("POST", "/user/theme"); + request.onload = () => location.reload(); + request.send(); +}); diff --git a/src/main/resources/views/admin.rocker.html b/src/main/resources/views/admin.rocker.html index 26859eb..7bd25a9 100644 --- a/src/main/resources/views/admin.rocker.html +++ b/src/main/resources/views/admin.rocker.html @@ -1,6 +1,7 @@ -@args (String message) +@import io.javalin.* +@args (String message, Context ctx) -@layout.template("Index", RockerContent.NONE, RockerContent.NONE) -> { +@layout.template("Index", ctx, RockerContent.NONE, RockerContent.NONE) -> { <div class="flex"> <div> <h1>Add new user</h1> diff --git a/src/main/resources/views/files.rocker.html b/src/main/resources/views/files.rocker.html index 43a3488..8e75ac2 100644 --- a/src/main/resources/views/files.rocker.html +++ b/src/main/resources/views/files.rocker.html @@ -1,5 +1,6 @@ @import java.util.ArrayList -@args (ArrayList files, String path, Boolean isShared) +@import io.javalin.* +@args (ArrayList files, String path, Boolean isShared, Context ctx) @css => { <link href="/css/files.css" rel="stylesheet"> @@ -14,7 +15,7 @@ <script src="/js/files.js"></script> } -@layout.template(files.size() + " Files", css, js) -> { +@layout.template(files.size() + " Files", ctx, css, js) -> { <div class="drop" id="drop"> <h2 class="navigation"> <i class="icon ion-md-home"></i> diff --git a/src/main/resources/views/fileview.rocker.html b/src/main/resources/views/fileview.rocker.html index c1fdff8..b3f8341 100644 --- a/src/main/resources/views/fileview.rocker.html +++ b/src/main/resources/views/fileview.rocker.html @@ -1,4 +1,5 @@ -@args (String content, String filename, String extension) +@import io.javalin.* +@args (String content, String filename, String extension, Context ctx) @css => { <link href="/css/fileview.css" rel="stylesheet"> @@ -12,7 +13,7 @@ <script src="/js/fileview.js"></script> } -@layout.template("File " + filename, css, js) -> { +@layout.template("File " + filename, ctx, css, js) -> { <button class="switch" id="raw">Show raw</button> <span class="settings" id="settings"> <label for="code">Linecount</label><input id="code" type="checkbox"> diff --git a/src/main/resources/views/index.rocker.html b/src/main/resources/views/index.rocker.html index cc18d3b..2e1b9dd 100644 --- a/src/main/resources/views/index.rocker.html +++ b/src/main/resources/views/index.rocker.html @@ -1,9 +1,22 @@ @import space.anity.DatabaseController @import space.anity.UserHandler -@args (String username) +@import io.javalin.* +@args (String username, Context ctx) -@layout.template("Index", RockerContent.NONE, RockerContent.NONE) -> { +@css => { +<link href="/css/index.css" rel="stylesheet"> +} + +@js => { +<script src="/js/index.js"></script> +} + +@layout.template("Index", ctx, css, js) -> { <div class="flex"> + @if (username.length() > 0) { + <button class="toggle" id="toggle">Dark theme</button> + } + <h1>Welcome to Kloud<span class="username">@(username == "" ? "" : " " + username)</span>!</h1> <div> diff --git a/src/main/resources/views/layout.rocker.html b/src/main/resources/views/layout.rocker.html index 3e3fb5e..9963aad 100644 --- a/src/main/resources/views/layout.rocker.html +++ b/src/main/resources/views/layout.rocker.html @@ -1,4 +1,7 @@ -@args (String title, RockerContent css, RockerContent js, RockerBody content) +@import space.anity.DatabaseController +@import space.anity.UserHandler +@import io.javalin.* +@args (String title, Context ctx, RockerContent css, RockerContent js, RockerBody content) <!doctype html> <html lang="en"> @@ -10,6 +13,11 @@ <link href="/css/icons.css" rel="stylesheet"> <link href="/css/layout.css" rel="stylesheet"> @css + + @if((new DatabaseController()).isDarkTheme((new UserHandler()).getVerifiedUserId(ctx))) { + <link href="/css/darkLayout.css" rel="stylesheet"> + } + <title>@title</title> </head> <body> diff --git a/src/main/resources/views/login.rocker.html b/src/main/resources/views/login.rocker.html index a8b06be..1e2adc4 100644 --- a/src/main/resources/views/login.rocker.html +++ b/src/main/resources/views/login.rocker.html @@ -1,11 +1,12 @@ -@args (String message, Integer counter) +@import io.javalin.* +@args (String message, Integer counter, Context ctx) @js => { <script>const counter = @counter;</script> <script src="/js/login.js"></script> } -@layout.template("Login", RockerContent.NONE, js) -> { +@layout.template("Login", ctx, RockerContent.NONE, js) -> { <div class="flex"> <h1>Login</h1> diff --git a/src/main/resources/views/register.rocker.html b/src/main/resources/views/register.rocker.html index b86c2e0..8516561 100644 --- a/src/main/resources/views/register.rocker.html +++ b/src/main/resources/views/register.rocker.html @@ -1,6 +1,7 @@ -@args (String username, String token, String message) +@import io.javalin.* +@args (String username, String token, String message, Context ctx) -@layout.template("Register", RockerContent.NONE, RockerContent.NONE) -> { +@layout.template("Register", ctx, RockerContent.NONE, RockerContent.NONE) -> { <div class="flex"> <h1>Register</h1> diff --git a/src/main/resources/views/setup.rocker.html b/src/main/resources/views/setup.rocker.html index 595f84a..3601817 100644 --- a/src/main/resources/views/setup.rocker.html +++ b/src/main/resources/views/setup.rocker.html @@ -1,6 +1,7 @@ -@args (String message) +@import io.javalin.* +@args (String message, Context ctx) -@layout.template("Setup", RockerContent.NONE, RockerContent.NONE) -> { +@layout.template("Setup", ctx, RockerContent.NONE, RockerContent.NONE) -> { <div class="flex"> <h1>Setup</h1> |