Add octave controls to KeyboardComponent

Introduced buttons to dynamically adjust the octave within the range of 0 to 8. Added new CSS classes for layout and styling of octave controls, updated component logic with range validation, and reorganized the title and octave display for improved UI.
This commit is contained in:
2025-06-06 19:32:15 +02:00
parent b48d6f3aca
commit 68a15bab8b

View File

@@ -6,8 +6,14 @@ import kotlinx.html.js.onMouseLeaveFunction
import kotlinx.html.js.onMouseUpFunction import kotlinx.html.js.onMouseUpFunction
import kotlinx.html.style import kotlinx.html.style
import kotlinx.html.svg import kotlinx.html.svg
import nl.astraeus.css.properties.AlignItems
import nl.astraeus.css.properties.Display
import nl.astraeus.css.properties.FlexDirection
import nl.astraeus.css.properties.FontWeight
import nl.astraeus.css.properties.JustifyContent
import nl.astraeus.css.properties.Position import nl.astraeus.css.properties.Position
import nl.astraeus.css.properties.TextAlign import nl.astraeus.css.properties.TextAlign
import nl.astraeus.css.properties.prc
import nl.astraeus.css.properties.px import nl.astraeus.css.properties.px
import nl.astraeus.css.properties.rem import nl.astraeus.css.properties.rem
import nl.astraeus.css.style.cls import nl.astraeus.css.style.cls
@@ -28,13 +34,26 @@ import org.w3c.dom.events.MouseEvent
*/ */
class KeyboardComponent( class KeyboardComponent(
val title: String = "Keyboard", val title: String = "Keyboard",
val octave: Int = 4, initialOctave: Int = 4,
val keyboardWidth: Int = 210, val keyboardWidth: Int = 210,
val keyboardHeight: Int = keyboardWidth / 2, val keyboardHeight: Int = keyboardWidth / 2,
val onNoteDown: (Int) -> Unit = {}, val onNoteDown: (Int) -> Unit = {},
val onNoteUp: (Int) -> Unit = {} val onNoteUp: (Int) -> Unit = {}
) : Komponent() { ) : Komponent() {
// Current octave with range validation
private var _octave: Int = initialOctave
var octave: Int
get() = _octave
set(value) {
_octave = when {
value < 0 -> 0
value > 8 -> 8
else -> value
}
requestUpdate()
}
// Set to track which notes are currently pressed // Set to track which notes are currently pressed
private val pressedNotes = mutableSetOf<Int>() private val pressedNotes = mutableSetOf<Int>()
@@ -87,14 +106,43 @@ class KeyboardComponent(
} }
} }
div(KeyboardTitleCls.name) { div(KeyboardControlsCls.name) {
// Show title of the keyboard // Decrease octave button
+title div(OctaveButtonCls.name) {
} style = "width: ${whiteKeyWidth}px"
+"<"
onMouseDownFunction = { event ->
if (event is MouseEvent) {
octave--
event.preventDefault()
}
}
}
div(KeyboardOctaveCls.name) { // Title and octave display container
// Show current octave the piano is being played at div(KeyboardInfoCls.name) {
+"Octave: $octave" div(KeyboardTitleCls.name) {
// Show title of the keyboard
+title
}
div(KeyboardOctaveCls.name) {
// Show current octave the piano is being played at
+"Octave: $octave"
}
}
// Increase octave button
div(OctaveButtonCls.name) {
style = "width: ${whiteKeyWidth}px"
+">"
onMouseDownFunction = { event ->
if (event is MouseEvent) {
octave++
event.preventDefault()
}
}
}
} }
div(KeyboardKeysCls.name) { div(KeyboardKeysCls.name) {
@@ -207,9 +255,12 @@ class KeyboardComponent(
companion object : CssId("keyboard") { companion object : CssId("keyboard") {
object KeyboardCls : CssName() object KeyboardCls : CssName()
object KeyboardControlsCls : CssName()
object KeyboardInfoCls : CssName()
object KeyboardTitleCls : CssName() object KeyboardTitleCls : CssName()
object KeyboardOctaveCls : CssName() object KeyboardOctaveCls : CssName()
object KeyboardKeysCls : CssName() object KeyboardKeysCls : CssName()
object OctaveButtonCls : CssName()
object WhiteKeyCls : CssName() object WhiteKeyCls : CssName()
object BlackKeyCls : CssName() object BlackKeyCls : CssName()
@@ -219,31 +270,57 @@ class KeyboardComponent(
position(Position.relative) position(Position.relative)
margin(5.px) margin(5.px)
select(cls(KeyboardControlsCls)) {
position(Position.relative)
display(Display.flex)
flexDirection(FlexDirection.row)
justifyContent(JustifyContent.spaceBetween)
alignItems(AlignItems.center)
width(100.prc)
height(50.px)
marginBottom(10.px)
}
select(cls(KeyboardInfoCls)) {
display(Display.flex)
flexDirection(FlexDirection.column)
alignItems(AlignItems.center)
justifyContent(JustifyContent.center)
flex("1")
}
select(cls(KeyboardTitleCls)) { select(cls(KeyboardTitleCls)) {
position(Position.absolute)
width(100.px)
textAlign(TextAlign.center) textAlign(TextAlign.center)
fontSize(1.2.rem) fontSize(1.2.rem)
color(Css.currentStyle.mainFontColor) color(Css.currentStyle.mainFontColor)
top(5.px)
left(0.px)
right(0.px)
} }
select(cls(KeyboardOctaveCls)) { select(cls(KeyboardOctaveCls)) {
position(Position.absolute)
width(100.px)
textAlign(TextAlign.center) textAlign(TextAlign.center)
fontSize(1.0.rem) fontSize(1.0.rem)
color(Css.currentStyle.mainFontColor) color(Css.currentStyle.mainFontColor)
top(30.px) marginTop(5.px)
left(0.px) }
right(0.px)
select(cls(OctaveButtonCls)) {
height(50.px)
plain("background-color", Css.currentStyle.buttonBackgroundColor.toString())
color(Css.currentStyle.mainFontColor)
border("1px solid ${Css.currentStyle.buttonBorderColor}")
textAlign(TextAlign.center)
lineHeight(50.px)
fontSize(1.5.rem)
fontWeight(FontWeight.bold)
cursor("pointer")
plain("-webkit-touch-callout", "none")
plain("-webkit-user-select", "none")
plain("-moz-user-select", "none")
plain("-ms-user-select", "none")
plain("user-select", "none")
} }
select(cls(KeyboardKeysCls)) { select(cls(KeyboardKeysCls)) {
position(Position.absolute) position(Position.relative)
top(60.px)
} }
} }