From: TheSaminator Date: Thu, 31 Mar 2022 18:27:48 +0000 (-0400) Subject: Add mobile-friendly CSS X-Git-Url: https://gitweb.starshipfights.net/?a=commitdiff_plain;h=c8896390d67de761b844b17543cdc750cb2b08ab;p=starship-fights Add mobile-friendly CSS --- diff --git a/src/jvmMain/kotlin/starshipfights/data/auth/user_sessions.kt b/src/jvmMain/kotlin/starshipfights/data/auth/user_sessions.kt index 2b79c89..aec6b46 100644 --- a/src/jvmMain/kotlin/starshipfights/data/auth/user_sessions.kt +++ b/src/jvmMain/kotlin/starshipfights/data/auth/user_sessions.kt @@ -65,23 +65,3 @@ data class UserSession( index(UserSession::user) }) } - -/* -@Serializable -data class PrivateMessage( - @SerialName("_id") - override val id: Id = Id(), - val sender: Id, - val receiver: Id, - val subject: String, - val message: String, - val sentAt: @Contextual Instant, - val isRead: Boolean -) : DataDocument { - companion object Table : DocumentTable by DocumentTable.create({ - index(PrivateMessage::sender) - index(PrivateMessage::receiver) - index(PrivateMessage::sentAt) - }) -} -*/ diff --git a/src/jvmMain/kotlin/starshipfights/data/auth/user_trophies.kt b/src/jvmMain/kotlin/starshipfights/data/auth/user_trophies.kt index a498bd4..9a845bd 100644 --- a/src/jvmMain/kotlin/starshipfights/data/auth/user_trophies.kt +++ b/src/jvmMain/kotlin/starshipfights/data/auth/user_trophies.kt @@ -6,8 +6,8 @@ import starshipfights.CurrentConfiguration @Serializable sealed class UserTrophy : Comparable { - protected abstract fun ASIDE.render() - fun renderInto(sidebar: ASIDE) = sidebar.render() + protected abstract fun TagConsumer<*>.render() + fun renderInto(consumer: TagConsumer<*>) = consumer.render() // Higher rank = lower on page protected abstract val rank: Int @@ -16,11 +16,11 @@ sealed class UserTrophy : Comparable { } } -fun ASIDE.renderTrophy(trophy: UserTrophy) = trophy.renderInto(this) +fun TagConsumer<*>.renderTrophy(trophy: UserTrophy) = trophy.renderInto(this) @Serializable object SiteOwnerTrophy : UserTrophy() { - override fun ASIDE.render() { + override fun TagConsumer<*>.render() { p { style = "text-align:center;border:2px solid #a82;padding:3px;background-color:#fc3;color:#541;font-variant:small-caps;font-family:'JetBrains Mono',monospace" +"Site Owner" @@ -33,7 +33,7 @@ object SiteOwnerTrophy : UserTrophy() { @Serializable object SiteDeveloperTrophy : UserTrophy() { - override fun ASIDE.render() { + override fun TagConsumer<*>.render() { p { style = "text-align:center;border:2px solid #62a;padding:3px;background-color:#93f;color:#315;font-variant:small-caps;font-family:'JetBrains Mono',monospace" title = "This person helps with coding the game" @@ -47,7 +47,7 @@ object SiteDeveloperTrophy : UserTrophy() { @Serializable data class SiteJanitorTrophy(val isSenior: Boolean) : UserTrophy() { - override fun ASIDE.render() { + override fun TagConsumer<*>.render() { p { style = "text-align:center;border:2px solid #840;padding:3px;background-color:#c60;color:#420;font-variant:small-caps;font-family:'JetBrains Mono',monospace" title = "This person helps with cleaning the poo out of the site" @@ -61,7 +61,7 @@ data class SiteJanitorTrophy(val isSenior: Boolean) : UserTrophy() { @Serializable data class SiteSupporterTrophy(val amountInUsCents: Int) : UserTrophy() { - override fun ASIDE.render() { + override fun TagConsumer<*>.render() { p { style = "text-align:center;border:2px solid #694;padding:3px;background-color:#af7;color:#231;font-variant:small-caps;font-family:'JetBrains Mono',monospace" title = "\"I spent money on an online game and all I got was this lousy trophy!\"" diff --git a/src/jvmMain/kotlin/starshipfights/info/html_utils.kt b/src/jvmMain/kotlin/starshipfights/info/html_utils.kt index 881ff9e..a068e85 100644 --- a/src/jvmMain/kotlin/starshipfights/info/html_utils.kt +++ b/src/jvmMain/kotlin/starshipfights/info/html_utils.kt @@ -1,8 +1,6 @@ package starshipfights.info -import kotlinx.html.A -import kotlinx.html.FORM -import kotlinx.html.hiddenInput +import kotlinx.html.* import starshipfights.auth.CsrfProtector import starshipfights.data.Id import starshipfights.data.auth.UserSession @@ -24,3 +22,16 @@ fun FORM.csrfToken(cookie: Id) = hiddenInput { name = CsrfProtector.csrfInputName value = CsrfProtector.newNonce(cookie, this@csrfToken.action) } + +fun interface SECTIONS { + fun section(classes: String?, body: SECTION.() -> Unit) + fun section(body: SECTION.() -> Unit) = section(null, body) +} + +fun MAIN.sectioned(): SECTIONS = MainSections(this) + +private class MainSections(private val delegate: MAIN) : SECTIONS { + override fun section(classes: String?, body: SECTION.() -> Unit) { + delegate.section(classes, body) + } +} diff --git a/src/jvmMain/kotlin/starshipfights/info/view_bar.kt b/src/jvmMain/kotlin/starshipfights/info/view_bar.kt index 722cb3e..a9fa8eb 100644 --- a/src/jvmMain/kotlin/starshipfights/info/view_bar.kt +++ b/src/jvmMain/kotlin/starshipfights/info/view_bar.kt @@ -5,16 +5,16 @@ import starshipfights.game.ShipType import starshipfights.game.getDefiniteShortName abstract class Sidebar { - protected abstract fun ASIDE.display() - fun displayIn(aside: ASIDE) = aside.display() + protected abstract fun TagConsumer<*>.display() + fun displayIn(aside: ASIDE) = aside.consumer.display() } -class CustomSidebar(private val block: ASIDE.() -> Unit) : Sidebar() { - override fun ASIDE.display() = block() +class CustomSidebar(private val block: TagConsumer<*>.() -> Unit) : Sidebar() { + override fun TagConsumer<*>.display() = block() } data class ShipViewSidebar(val shipType: ShipType) : Sidebar() { - override fun ASIDE.display() { + override fun TagConsumer<*>.display() { p { img(alt = "Flag of ${shipType.faction.getDefiniteShortName()}", src = shipType.faction.flagUrl) } @@ -28,7 +28,7 @@ data class ShipViewSidebar(val shipType: ShipType) : Sidebar() { } data class PageNavSidebar(val contents: List) : Sidebar() { - override fun ASIDE.display() { + override fun TagConsumer<*>.display() { div(classes = "list") { contents.forEach { div(classes = "item") { diff --git a/src/jvmMain/kotlin/starshipfights/info/view_nav.kt b/src/jvmMain/kotlin/starshipfights/info/view_nav.kt index 47d7dbe..f7a89de 100644 --- a/src/jvmMain/kotlin/starshipfights/info/view_nav.kt +++ b/src/jvmMain/kotlin/starshipfights/info/view_nav.kt @@ -24,9 +24,9 @@ data class NavHead(val label: String) : NavItem() { } } -data class NavLink(val to: String, val text: String, val isPost: Boolean = false, val csrfUserCookie: Id? = null) : NavItem() { +data class NavLink(val to: String, val text: String, val classes: String? = null, val isPost: Boolean = false, val csrfUserCookie: Id? = null) : NavItem() { override fun DIV.display() { - a(href = to) { + a(href = to, classes = classes) { if (isPost) method = "post" csrfUserCookie?.let { csrfToken(it) } @@ -51,17 +51,7 @@ suspend fun ApplicationCall.standardNavBar(): List = listOf( listOf( NavLink("/me", user.profileName), NavLink("/me/manage", "User Preferences"), - /*NavLink( - "/me/inbox", "Inbox (${ - PrivateMessage.number( - and( - PrivateMessage::receiver eq user.id, - PrivateMessage::isRead eq false - ) - ) - })" - ),*/ - NavLink("/lobby", "Enter Game Lobby"), + NavLink("/lobby", "Enter Game Lobby", classes = "desktop"), NavLink("/logout", "Log Out", isPost = true, csrfUserCookie = session.id), ) } + listOf( diff --git a/src/jvmMain/kotlin/starshipfights/info/view_tpl.kt b/src/jvmMain/kotlin/starshipfights/info/view_tpl.kt index f45f755..4d34fac 100644 --- a/src/jvmMain/kotlin/starshipfights/info/view_tpl.kt +++ b/src/jvmMain/kotlin/starshipfights/info/view_tpl.kt @@ -2,9 +2,10 @@ package starshipfights.info import kotlinx.html.* -fun page(pageTitle: String? = null, navBar: List? = null, sidebar: Sidebar? = null, content: MAIN.() -> Unit): HTML.() -> Unit = { +fun page(pageTitle: String? = null, navBar: List? = null, sidebar: Sidebar? = null, content: SECTIONS.() -> Unit): HTML.() -> Unit = { head { meta(charset = "utf-8") + meta(name = "viewport", content = "width=device-width, initial-scale=1.0") link(rel = "icon", type = "image/svg+xml", href = "/static/images/icon.svg") link(rel = "preconnect", href = "https://fonts.googleapis.com") @@ -21,7 +22,7 @@ fun page(pageTitle: String? = null, navBar: List? = null, sidebar: Side div { id = "bg" } navBar?.let { - nav { + nav(classes = "desktop") { div(classes = "list") { it.forEach { div(classes = "item") { @@ -33,13 +34,33 @@ fun page(pageTitle: String? = null, navBar: List? = null, sidebar: Side } sidebar?.let { - aside { + aside(classes = "desktop") { it.displayIn(this) } } main { - content() + sidebar?.let { + aside(classes = "mobile") { + it.displayIn(this) + } + } + + with(sectioned()) { + content() + } + + navBar?.let { + nav(classes = "mobile") { + div(classes = "list") { + it.forEach { + div(classes = "item") { + it.displayIn(this) + } + } + } + } + } } script(src = "/static/init.js") {} diff --git a/src/jvmMain/kotlin/starshipfights/info/views_error.kt b/src/jvmMain/kotlin/starshipfights/info/views_error.kt index d548aff..a7eb0a9 100644 --- a/src/jvmMain/kotlin/starshipfights/info/views_error.kt +++ b/src/jvmMain/kotlin/starshipfights/info/views_error.kt @@ -5,7 +5,7 @@ import io.ktor.features.* import kotlinx.html.* import starshipfights.CurrentConfiguration -private fun MAIN.devModeCallId(callId: String?) { +private fun SECTIONS.devModeCallId(callId: String?) { callId?.let { id -> section { style = if (CurrentConfiguration.isDevEnv) "" else "display:none" diff --git a/src/jvmMain/resources/static/style.css b/src/jvmMain/resources/static/style.css index 5650586..2293a28 100644 --- a/src/jvmMain/resources/static/style.css +++ b/src/jvmMain/resources/static/style.css @@ -1,10 +1,15 @@ html { margin: 0; - padding: 20px 5vw; + padding: 0; color: #222; + background-color: #aaa; font-family: 'Noto Sans', sans-serif; font-size: 100%; + + --h1-size: 1.6em; + --h2-size: 1.4em; + --h3-size: 1.2em; } ::selection { @@ -13,20 +18,7 @@ html { } div#bg { - width: 100%; - height: 100%; - position: fixed; - top: 0; - left: 0; - - background-image: url("/static/images/background.svg"); - background-attachment: fixed; - background-position: center; - background-size: cover; - - filter: blur(4px); - - z-index: 0; + display: none; } h1, h2, h3 { @@ -39,60 +31,128 @@ h1, h2 { } h1 { - border: 3px solid #888; - box-shadow: inset 0 0 0 4px #444; - padding: 5px; + border: 0.1875rem solid #888; + box-shadow: inset 0 0 0 0.25rem #444; + padding: 0.3125rem; background-color: #aaa; font-variant: small-caps; - font-size: 2.6em; + font-size: var(--h1-size); font-weight: 800; } h2 { - border-bottom: 2px solid #666; - font-size: 2.2em; + border-bottom: 0.125rem solid #666; + font-size: var(--h2-size); font-weight: 600; } h3 { text-decoration: underline; text-decoration-color: #888; - font-size: 1.8em; + font-size: var(--h3-size); font-weight: 400; } -main { - padding: 5vh 0; +.desktop { + display: none; } /*noinspection CssOverwrittenProperties*/ -main > section, nav, aside { +main > section, main > nav.mobile, main > aside.mobile { border-image-source: url("/static/images/panel.svg"); border-image-slice: 40% fill; - border-image-width: 2em; - border-width: 2em; + border-image-width: 1em; + border-width: 1em; + + padding: 1.5em 1.5em; box-sizing: border-box; - padding: 2.5em 3em; + width: 90vw; + margin: 5vw 5vw; position: relative; z-index: 1; } -main > section { - width: 40%; - margin: 5vh auto; -} +@media only screen and (min-width: 8in) { + html { + padding: 1.25rem 5vw; -main > section:first-child { - margin: 0 auto 5vh; -} + --h1-size: 2.6em; + --h2-size: 2.2em; + --h3-size: 1.8em; + } + + div#bg { + display: unset; + + width: 100%; + height: 100%; + position: fixed; + top: 0; + left: 0; + + background-image: url("/static/images/background.svg"); + background-attachment: fixed; + background-position: center; + background-size: cover; + + filter: blur(0.25rem); + + z-index: 0; + } -nav { - width: 20%; - float: left; - margin: 5vh 5vw; + main { + padding: 5vh 0; + } + + /*noinspection CssOverwrittenProperties*/ + main > section, nav.desktop, aside.desktop { + border-image-source: url("/static/images/panel.svg"); + border-image-slice: 40% fill; + border-image-width: 2em; + border-width: 2em; + + box-sizing: border-box; + padding: 2.5em 3em; + + position: relative; + z-index: 1; + } + + main > section { + width: 40%; + margin: 5vh auto; + } + + main > section:first-of-type { + margin: 0 auto 5vh; + } + + .mobile { + display: none; + } + + .desktop { + display: unset; + } + + nav.desktop { + width: 20%; + float: left; + margin: 5vh 5vw; + } + + aside.desktop { + width: 20%; + float: right; + margin: 5vh 5vw; + } + + aside.desktop img { + width: 100%; + } } div.list { @@ -138,7 +198,7 @@ div.list > div.item > a { vertical-align: middle; text-align: center; - border-radius: 5px; + border-radius: 0.3em; color: #369; text-decoration: none; } @@ -170,20 +230,10 @@ a[href^="http://"]::after, a[href^="https://"]::after { height: 1em; } -aside { - width: 20%; - float: right; - margin: 5vh 5vw; -} - -aside img { - width: 100%; -} - table { table-layout: fixed; border-collapse: collapse; - border: 2pt solid #036; + border: 0.125rem solid #036; background-color: #ccc; width: 100%; @@ -200,7 +250,7 @@ table + table tr:first-child th { } td { - border: 2pt solid #036; + border: 0.125rem solid #036; background-color: #eee; font-size: 0.7em; padding: 0.15em 0; @@ -210,7 +260,7 @@ td { } th { - border: 2pt solid #036; + border: 0.125rem solid #036; background-color: #036; padding: 0.15em 0; @@ -231,7 +281,7 @@ textarea { box-sizing: border-box; background-color: #aaa; border: none; - border-bottom: 2px solid #222; + border-bottom: 0.1em solid #222; color: #024; font-size: 1.5em; @@ -264,7 +314,7 @@ textarea:invalid { input[type=submit] { background-color: #06c; border: none; - border-radius: 8pt; + border-radius: 0.3em; color: #bdf; cursor: pointer; display: block; @@ -285,7 +335,7 @@ input[type=submit]:active { input[type=submit].evil { background-color: #c66; border: none; - border-radius: 8pt; + border-radius: 0.3em; color: #fcc; cursor: pointer; display: block;