From 6e53c6d2a50d7ab63cbd9ca5f2d66874349e8012 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikl=C3=B3s=20T=C3=B3th?= <tothmiklostibor@gmail.com> Date: Mon, 21 Feb 2022 12:40:03 +0100 Subject: [PATCH] Styling basically done --- mosogepsch/build.gradle.kts | 1 - mosogepsch/src/jsMain/kotlin/Main.kt | 40 +++-- mosogepsch/src/jsMain/kotlin/api/Api.kt | 18 ++- mosogepsch/src/jsMain/kotlin/api/Types.kt | 25 ++- .../src/jsMain/kotlin/components/Card.kt | 2 - .../src/jsMain/kotlin/components/Content.kt | 10 +- .../src/jsMain/kotlin/components/Floor.kt | 145 ++++++++++++++++++ .../src/jsMain/kotlin/components/Mosogep.kt | 38 ----- mosogepsch/src/jsMain/kotlin/styles/Style.kt | 34 +++- 9 files changed, 240 insertions(+), 73 deletions(-) create mode 100644 mosogepsch/src/jsMain/kotlin/components/Floor.kt delete mode 100644 mosogepsch/src/jsMain/kotlin/components/Mosogep.kt diff --git a/mosogepsch/build.gradle.kts b/mosogepsch/build.gradle.kts index 46e18fe..2a5fd2e 100644 --- a/mosogepsch/build.gradle.kts +++ b/mosogepsch/build.gradle.kts @@ -39,7 +39,6 @@ kotlin { implementation(compose.runtime) implementation("app.softwork:bootstrap-compose:0.0.49") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.2.2") - implementation(npm("@js-joda/core", "1.11.0")) implementation(npm("@js-joda/timezone", "2.3.0")) implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.2.1") } diff --git a/mosogepsch/src/jsMain/kotlin/Main.kt b/mosogepsch/src/jsMain/kotlin/Main.kt index e60a5fd..be10abf 100644 --- a/mosogepsch/src/jsMain/kotlin/Main.kt +++ b/mosogepsch/src/jsMain/kotlin/Main.kt @@ -1,30 +1,27 @@ -import androidx.compose.runtime.CompositionLocalProvider -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.setValue +import androidx.compose.runtime.* import app.softwork.bootstrapcompose.* import app.softwork.bootstrapcompose.Color -import components.CardStyle -import components.content -import components.credits -import components.switch +import components.* import kotlinx.browser.localStorage import kotlinx.browser.window import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* import org.jetbrains.compose.web.renderComposable +import org.w3c.dom.HTMLDivElement import org.w3c.dom.get import org.w3c.dom.set import styles.LocalStyle import styles.Style -//@JsModule("@js-joda/timezone") -//@JsNonModule -//external object JsJodaTimeZoneModule - -//private val jsJodaTz = JsJodaTimeZoneModule +@JsModule("@js-joda/timezone") +@JsNonModule +external object JsJodaTimeZoneModule +private val jsJodaTz: dynamic = JsJodaTimeZoneModule fun main() { + val alma: dynamic = window + alma.alma = jsJodaTz + val dark = localStorage["darkMode"]?.equals("true") ?: window.matchMedia("(prefers-color-scheme: dark)").matches @@ -33,14 +30,22 @@ fun main() { val mosogepStyle = Style(darkTheme) Style(mosogepStyle) Style(CardStyle) + Style(FloorStyle) CompositionLocalProvider(LocalStyle provides mosogepStyle) { Header { Navbar( - attrs = { classes("bg-secondary") }, + attrs = { + style { + backgroundColor(mosogepStyle.colors.appBarColor) + } + }, placement = NavbarPlacement.StickyTop, collapseBehavior = NavbarCollapseBehavior.AtBreakpoint(Breakpoint.Large), colorScheme = Color.Dark, ) { + DomSideEffect { + it.setImportantBg(mosogepStyle.colors.appBarColor) + } Brand { Text("MosógépSCH") } switch( label = "Sötét téma", @@ -56,7 +61,7 @@ fun main() { content() } Footer( - attrs = { classes("footer", "mt-auto") } + attrs = { classes("footer", "mt-auto", mosogepStyle.footer) } ) { Container { credits() } } @@ -64,3 +69,8 @@ fun main() { } } +@NoLiveLiterals +private fun HTMLDivElement.setImportantBg(color: CSSColorValue) { + val alma: dynamic = parentElement + alma.style.setProperty("background-color", color.toString(), "important") +} \ No newline at end of file diff --git a/mosogepsch/src/jsMain/kotlin/api/Api.kt b/mosogepsch/src/jsMain/kotlin/api/Api.kt index 2f4d59c..72ecb6b 100644 --- a/mosogepsch/src/jsMain/kotlin/api/Api.kt +++ b/mosogepsch/src/jsMain/kotlin/api/Api.kt @@ -5,9 +5,14 @@ import kotlinx.serialization.decodeFromString import kotlinx.serialization.json.Json -@OptIn(ExperimentalSerializationApi::class) -fun Api(): Response { - val jsonStr = """ +object Api { + private val json = Json { + ignoreUnknownKeys = true + } + + @OptIn(ExperimentalSerializationApi::class) + fun getOnce(): Response { + val jsonStr = """ { "floors": [ { @@ -184,5 +189,10 @@ fun Api(): Response { ] } """.trimIndent() - return Json.decodeFromString(jsonStr) + val dec = json.decodeFromString<Response>(jsonStr) + val floors = dec.floors.map { floor -> + floor.copy(machines = floor.machines.sortedBy { it.kindOf }) + }.sortedBy { it.id } + return dec.copy(floors = floors) + } } \ No newline at end of file diff --git a/mosogepsch/src/jsMain/kotlin/api/Types.kt b/mosogepsch/src/jsMain/kotlin/api/Types.kt index e1617a2..5fe877e 100644 --- a/mosogepsch/src/jsMain/kotlin/api/Types.kt +++ b/mosogepsch/src/jsMain/kotlin/api/Types.kt @@ -1,7 +1,14 @@ package api import kotlinx.datetime.Instant +import kotlinx.serialization.KSerializer +import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable +import kotlinx.serialization.descriptors.PrimitiveKind +import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder @Serializable data class Response( @@ -18,12 +25,22 @@ data class Floor( data class Machine( val id: Int, val kindOf: MachineKind, - val status: MachineStatus, - val lastQueryTime: Instant, - val unixTimeStamp: Int, + var status: MachineStatus, + + @SerialName("unixTimeStamp") + @Serializable(with = UnixDateSerializer::class) + var lastQueryTime: Instant, ) @Serializable enum class MachineKind { Dryer, Washer } @Serializable -enum class MachineStatus { NotAvailable, Available } \ No newline at end of file +enum class MachineStatus { NotAvailable, Available } + +object UnixDateSerializer : KSerializer<Instant> { + override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Instant", PrimitiveKind.LONG) + + override fun serialize(encoder: Encoder, value: Instant) = encoder.encodeLong(value.epochSeconds) + + override fun deserialize(decoder: Decoder): Instant = Instant.fromEpochSeconds(decoder.decodeLong()) +} \ No newline at end of file diff --git a/mosogepsch/src/jsMain/kotlin/components/Card.kt b/mosogepsch/src/jsMain/kotlin/components/Card.kt index f768d77..0bd53f1 100644 --- a/mosogepsch/src/jsMain/kotlin/components/Card.kt +++ b/mosogepsch/src/jsMain/kotlin/components/Card.kt @@ -1,8 +1,6 @@ package components import androidx.compose.runtime.Composable -import kotlinx.browser.document -import org.jetbrains.compose.web.attributes.AttrsBuilder import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.AttrBuilderContext import org.jetbrains.compose.web.dom.Div diff --git a/mosogepsch/src/jsMain/kotlin/components/Content.kt b/mosogepsch/src/jsMain/kotlin/components/Content.kt index f36d380..cb91f97 100644 --- a/mosogepsch/src/jsMain/kotlin/components/Content.kt +++ b/mosogepsch/src/jsMain/kotlin/components/Content.kt @@ -1,21 +1,25 @@ package components -import androidx.compose.runtime.Composable +import androidx.compose.runtime.* +import api.Api import app.softwork.bootstrapcompose.Container import org.jetbrains.compose.web.css.* @Composable fun content() { + val data by remember { mutableStateOf(Api.getOnce()) } + Container(attrs = { style { display(DisplayStyle.Flex) flexDirection(FlexDirection.Row) flexWrap(FlexWrap.Wrap) justifyContent(JustifyContent.Center) + paddingTop(1.em) } }) { - repeat(50) { - mosogep(it) + data.floors.forEach { + floor(it) } } } \ No newline at end of file diff --git a/mosogepsch/src/jsMain/kotlin/components/Floor.kt b/mosogepsch/src/jsMain/kotlin/components/Floor.kt new file mode 100644 index 0000000..2afb63a --- /dev/null +++ b/mosogepsch/src/jsMain/kotlin/components/Floor.kt @@ -0,0 +1,145 @@ +package components + +import styles.LocalStyle +import androidx.compose.runtime.* +import api.Floor +import api.Machine +import api.MachineKind +import api.MachineStatus +import org.jetbrains.compose.web.css.* +import org.jetbrains.compose.web.dom.* + +object FloorStyle: StyleSheet() { + val container by style { + display(DisplayStyle.Flex) + flexDirection(FlexDirection.Column) + justifyContent(JustifyContent.SpaceAround) + alignItems(AlignItems.Center) + position(Position.Relative) + } + + val card by style { + maxWidth(20.em) + width(20.em) + flexDirection(FlexDirection.Row) + justifyContent(JustifyContent.SpaceAround) + } + + val floorNum by style { + minWidth(2.75.ch) + textAlign("right") + } + + val machine by style { + flexGrow(1) + } + + val absCnt by style { + position(Position.Absolute) + left(0.px) + bottom(4.em) + width(0.px) + height(0.px) + property("z-index", -1) + } + val relCnt by style { + position(Position.Relative) + width(0.px) + height(0.px) + } + val underflowCnt by style { + margin(0.px) + padding(0.px) + marginLeft(1.em) + width(20.em) + property("transition", "max-height 0.75s") + overflow("hidden") + } + val underflowCard by style { + flexDirection(FlexDirection.Column) + margin(0.px) + width(100.percent) + paddingTop(5.em) + } +} + +@Composable +fun floor(floor: Floor) { + val colors = LocalStyle.current.colors + fun MachineStatus.toColor(): CSSColorValue = when (this) { + MachineStatus.Available -> colors.offColor + MachineStatus.NotAvailable -> colors.onColor + } + fun MachineKind.toIcon(): String { return "${this.name[0]}" } + + val zIndex = 200 - floor.id*2 + + Div(attrs = { + classes(FloorStyle.container) + style { + property("z-index", zIndex) + } + }) { + var selectedMachine by remember { mutableStateOf<Machine>(floor.machines[0]) } + var machineSelected by remember { mutableStateOf(false) } + + card(attrs = { + classes(FloorStyle.card) + style { + backgroundColor(colors.cardBg) + } + }) { + H3(attrs = { + classes(FloorStyle.floorNum) + }) { Text("${floor.id}.") } + floor.machines.forEach { machine -> + card(attrs = { + classes(FloorStyle.machine) + style { + backgroundColor(machine.status.toColor()) + } + onClick { + if (selectedMachine == machine) { + machineSelected = !machineSelected + } else { + machineSelected = true + } + selectedMachine = machine + } + }) { H3 { Text(machine.kindOf.toIcon()) } } + } + } + + floor.machines.forEach { + Div(attrs = { + classes(FloorStyle.absCnt) + }) { + Div(attrs = { + classes(FloorStyle.relCnt) + }) { + Div(attrs = { + classes(FloorStyle.underflowCnt) + style { + if (machineSelected && selectedMachine == it) { + maxHeight(20.em) + } else { + maxHeight(0.px) + } + } + }) { + card(attrs = { + classes(FloorStyle.underflowCard) + style { + backgroundColor(it.status.toColor()) + } + }) { + P { Text(it.status.name) } + } + } + } + } + } + + } +} + diff --git a/mosogepsch/src/jsMain/kotlin/components/Mosogep.kt b/mosogepsch/src/jsMain/kotlin/components/Mosogep.kt deleted file mode 100644 index 5d1e8ab..0000000 --- a/mosogepsch/src/jsMain/kotlin/components/Mosogep.kt +++ /dev/null @@ -1,38 +0,0 @@ -package components - -import styles.LocalStyle -import androidx.compose.runtime.Composable -import app.softwork.bootstrapcompose.Card -import org.jetbrains.compose.web.css.* -import org.jetbrains.compose.web.dom.* - -@Composable -fun mosogep(floor: Int) { - card(attrs = { - style { - maxWidth(20.em) - width(20.em) - flexDirection(FlexDirection.Row) - justifyContent(JustifyContent.SpaceAround) - } - }) { - H3(attrs = { - style { - minWidth(2.75.ch) - textAlign("right") - } - }) { Text("$floor.") } - card(attrs = { - style { - backgroundColor(Color("#ff8a65cc")) - flexGrow(1) - } - }) { H3 { Text("M") } } - card(attrs = { - style { - backgroundColor(Color("#aed581cc")) - flexGrow(1) - } - }) { H3 { Text("Sz") } } - } -} \ No newline at end of file diff --git a/mosogepsch/src/jsMain/kotlin/styles/Style.kt b/mosogepsch/src/jsMain/kotlin/styles/Style.kt index 26c6a4a..bf32c50 100644 --- a/mosogepsch/src/jsMain/kotlin/styles/Style.kt +++ b/mosogepsch/src/jsMain/kotlin/styles/Style.kt @@ -1,11 +1,27 @@ +@file:Suppress("NonAsciiCharacters") package styles import androidx.compose.runtime.compositionLocalOf import org.jetbrains.compose.web.css.* + + +private val kszkék = Color("#3051bf") +private val vilagosKszkék = Color("#3faef7") + + +class Colors(val dark: Boolean) { + val appBarColor = kszkék + val cardBg = if (dark) kszkék else vilagosKszkék + val onColor = Color(if (dark) "#bd5b40" else "#DB6748") + val offColor = Color(if (dark) "#57af00" else "#94DB40") +} + class Style(val dark: Boolean = false): StyleSheet() { private val footHeight = 4.em + val colors = Colors(dark) + init { "html, body, #root" style { position(Position.Relative) @@ -16,12 +32,9 @@ class Style(val dark: Boolean = false): StyleSheet() { marginBottom(0.px) } ".footer" style { - position(Position.Absolute) - bottom(0.px) - width(100.percent) - height(footHeight) - lineHeight(footHeight) - backgroundColor(Color("#0000007f")) + } + "*" { + property("transition", "background-color 0.75s") } } @@ -30,6 +43,15 @@ class Style(val dark: Boolean = false): StyleSheet() { height(100.percent) paddingBottom(footHeight * 2) } + val footer by style { + position(Position.Absolute) + bottom(0.px) + width(100.percent) + height(footHeight) + lineHeight(footHeight) + backgroundColor(Color("#0000007f")) + property("z-index", 2000) + } } val LocalStyle = compositionLocalOf { Style() } \ No newline at end of file -- GitLab