Skip to content
Snippets Groups Projects
Commit 6e53c6d2 authored by Tóth Miklós Tibor's avatar Tóth Miklós Tibor :shrug:
Browse files

Styling basically done

parent ea947f4f
No related branches found
No related tags found
No related merge requests found
......@@ -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")
}
......
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
......@@ -5,8 +5,13 @@ import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
object Api {
private val json = Json {
ignoreUnknownKeys = true
}
@OptIn(ExperimentalSerializationApi::class)
fun Api(): Response {
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
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 }
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
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
......
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
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) }
}
}
}
}
}
}
}
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
@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
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment