fix(ui): 按原版 DOM 重构滑杆与开关结构

This commit is contained in:
TermiNexus committed 2026-10-26 19:56:42 +08:00
1 parent 8ab4e62838
commit dd233e6fb9
3 files changed
+206 -98

No files matched your search

+35 -1
View File
@@ -91,4 +91,38 @@
| 滑杆进度渐变 | `hUi.tap` | `module_82347.js:200507` |
| `SettingsComponentStyle-slider` | `kNi.z1jp_1` | `module_82347.js:89620` |
`ksc-130` 是 `SettingsComponentStyle-slider` 的 Emotion 生成类名;当前实现用 `data-ui="SettingsComponentStyle-slider"` 标记,等价于给滑杆挂上该样式。
`ksc-130` 是 `SettingsComponentStyle-slider` 的 Emotion 生成类名;当前实现直接使用 `InputRangeComponentStyle-*` / `SettingsComponentStyle-slider` 语义类名,并用 `ksc-56` / `ksc-57` 标记标签与滑杆。
## 7. 真实 DOM 结构
滑杆:
```html
<div class="InputRangeComponentStyle-blockSoundVolume SettingsComponentStyle-slider">
<p>主音量<span class="ksc-56">(80%)</span></p>
<div class="InputRangeComponentStyle-soundVolume">
<input type="range" min="0" max="100" step="1"
class="ksc-57 InputRangeComponentStyle-range" value="80">
</div>
</div>
```
开关:
```html
<div class="ksc-46">
<div class="CheckBoxComponentStyle-oneSetting">
<div class="CheckBoxStyle-checkbox">
<label>
<input type="checkbox" class="ksc-47" checked>
<span class="ksc-62 -displayFlex"></span>
</label>
</div>
<div class="ksc-63 -flexStartAlignCenter">
<label>显示帧数和延迟</label>
</div>
</div>
</div>
```
当前实现已按这个结构输出;带描述的开关行增加 `has-description` 修饰类,让描述与标签对齐。
@@ -24,6 +24,7 @@ import react.dom.html.ReactHTML.h3
import react.dom.html.ReactHTML.i
import react.dom.html.ReactHTML.img
import react.dom.html.ReactHTML.input
import react.dom.html.ReactHTML.label
import react.dom.html.ReactHTML.option
import react.dom.html.ReactHTML.p
import react.dom.html.ReactHTML.select
@@ -2356,37 +2357,6 @@ private val SettingsChevron: csstype.PropertiesBuilder.() -> Unit = {
Style("flex", "0 0 0.813em")
}
private val SettingsSliderWrap: csstype.PropertiesBuilder.() -> Unit = {
Style("display", "flex")
Style("flex-direction", "column")
Style("justify-content", "space-between")
Style("align-items", "flex-start")
Style("width", "31.25em")
Style("height", "3.188em")
Style("min-height", "3.188em")
Style("margin-bottom", "1.75em")
}
private val SettingsSliderLabel: csstype.PropertiesBuilder.() -> Unit = {
Style("display", "flex")
Style("justify-content", "space-between")
Style("align-items", "center")
Style("width", "100%")
Style("color", "white")
Style("font-size", "0.9375em")
Style("margin-top", "0")
}
private val SettingsRange: csstype.PropertiesBuilder.() -> Unit = {
Style("cursor", "pointer")
Style("-webkit-appearance", "none")
Style("appearance", "none")
Style("width", "100%")
Style("height", "0.563em")
Style("outline", "none")
Style("border-radius", "0")
}
private fun SettingsSliderGradient(Value: Int): String {
val Percent = Value.coerceIn(0, 100)
return "linear-gradient(to right, #ffbc09 0%, #ffbc09 $Percent%, rgba(255, 255, 255, 0.1) $Percent%, rgba(255, 255, 255, 0.1) 100%)"
@@ -2430,46 +2400,6 @@ private val SettingsActionButton: csstype.PropertiesBuilder.() -> Unit = {
Style("padding", "0 1em")
}
private val SettingsCheckboxRow: csstype.PropertiesBuilder.() -> Unit = {
Style("display", "flex")
Style("align-items", "center")
Style("justify-content", "flex-start")
Style("width", "100%")
Style("height", "2.25em")
Style("margin-bottom", "1.25em")
Style("gap", "0.75em")
}
private fun SettingsCheckbox(On: Boolean): csstype.PropertiesBuilder.() -> Unit = {
Style("position", "relative")
Style("display", "flex")
Style("align-items", "center")
Style("justify-content", "center")
Style("width", "2.75em")
Style("height", "1.5em")
Style("flex", "0 0 2.75em")
Style("box-sizing", "border-box")
Style("background-color", if (On) "rgba(118, 255, 51, 0.25)" else "rgba(191, 213, 255, 0.25)")
Style("border", "0.063em solid rgba(255, 255, 255, 0.2)")
Style("border-radius", "6.25rem")
Style("cursor", "pointer")
Style("padding", "0")
Style("transition", "background-color 0.2s")
}
private fun SettingsToggleKnob(On: Boolean): csstype.PropertiesBuilder.() -> Unit = {
Style("position", "absolute")
Style("top", "50%")
Style("left", if (On) "calc(100% - 1.3em)" else "0.2em")
Style("width", "1.1em")
Style("height", "1.1em")
Style("border-radius", "50%")
Style("background-color", "white")
Style("transform", "translateY(-50%)")
Style("transition", "left 0.2s")
Style("pointer-events", "none")
}
private val SettingsKeysGrid: csstype.PropertiesBuilder.() -> Unit = {
Style("display", "grid")
Style("grid-template-columns", "1fr 1fr")
@@ -2570,41 +2500,57 @@ private val SettingsScreen = FC<Props> {
is SettingEntry.Toggle -> {
val On = Toggles[Entry.Id] ?: Entry.Default
div {
css(SettingsCheckboxRow)
Ui("CheckBoxComponentStyle-oneSetting")
button {
css(SettingsCheckbox(On))
onClick = { Toggles = Toggles + (Entry.Id to !On) }
div { css(SettingsToggleKnob(On)) }
}
asDynamic()["className"] = "ksc-46"
div {
css { Style("flex", "1"); Style("min-width", "0") }
div { css(SettingsLabel); +Entry.Label }
if (Entry.Desc.isNotEmpty()) div { css(SettingsDesc); +Entry.Desc }
asDynamic()["className"] = "CheckBoxComponentStyle-oneSetting" + if (Entry.Desc.isNotEmpty()) " has-description" else ""
div {
asDynamic()["className"] = "CheckBoxStyle-checkbox"
label {
input {
asDynamic()["className"] = "ksc-47"
asDynamic()["type"] = "checkbox"
asDynamic()["checked"] = On
onChange = { Toggles = Toggles + (Entry.Id to !On) }
}
span {
asDynamic()["className"] = "ksc-62 -displayFlex"
asDynamic()["data-on"] = On.toString()
}
}
}
div {
asDynamic()["className"] = "ksc-63 -flexStartAlignCenter" + if (Entry.Desc.isNotEmpty()) " has-description" else ""
label { +Entry.Label }
if (Entry.Desc.isNotEmpty()) div { css(SettingsDesc); +Entry.Desc }
}
}
}
}
is SettingEntry.Slider -> {
val Value = Sliders[Entry.Id] ?: Entry.Default
div {
css(SettingsSliderWrap)
Ui("InputRangeComponentStyle-blockSoundVolume")
asDynamic()["className"] = "InputRangeComponentStyle-blockSoundVolume SettingsComponentStyle-slider"
p {
+Entry.Label
span {
asDynamic()["className"] = "ksc-56"
+"($Value%)"
}
}
div {
css(SettingsSliderLabel)
span { +Entry.Label }
span { +"$Value%" }
}
input {
css {
Apply(SettingsRange)
Style("background", SettingsSliderGradient(Value))
asDynamic()["className"] = "InputRangeComponentStyle-soundVolume"
input {
asDynamic()["className"] = "ksc-57 InputRangeComponentStyle-range"
asDynamic()["type"] = "range"
asDynamic()["min"] = "0"
asDynamic()["max"] = "100"
asDynamic()["step"] = "1"
asDynamic()["value"] = "$Value"
val StyleObj = js("({})")
StyleObj["background"] = SettingsSliderGradient(Value)
asDynamic()["style"] = StyleObj
onChange = { E -> Sliders = Sliders + (Entry.Id to (E.target.value.toString().toIntOrNull() ?: Value)) }
}
Ui("SettingsComponentStyle-slider")
asDynamic()["type"] = "range"
asDynamic()["min"] = "0"
asDynamic()["max"] = "100"
asDynamic()["value"] = "$Value"
onChange = { E -> Sliders = Sliders + (Entry.Id to (E.target.value.toString().toIntOrNull() ?: Value)) }
}
}
}
@@ -984,4 +984,132 @@ body { margin: 0; overflow: hidden; background: #001926; color: #fff; }
border: 0;
border-radius: 0.25em;
background: #ffbc09;
}
/* 原版设置页语义类 */
.-displayFlex { display: flex; }
.-flexStartAlignCenter { display: flex; align-items: center; justify-content: flex-start; }
.InputRangeComponentStyle-blockSoundVolume {
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: flex-start;
width: 31.25em;
height: 3.188em;
min-height: 3.188em;
margin-bottom: 1.75em;
}
.SettingsComponentStyle-slider { width: 31.25em; }
.InputRangeComponentStyle-blockSoundVolume p {
margin: 0;
color: #fff;
font-family: BaseFontRegular, "Segoe UI", sans-serif;
font-size: 0.9375em;
line-height: normal;
}
.InputRangeComponentStyle-blockSoundVolume p span { margin-left: 0.2em; }
.InputRangeComponentStyle-soundVolume {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
width: 100%;
height: 1.25em;
}
.InputRangeComponentStyle-range {
-webkit-appearance: none;
appearance: none;
width: 100%;
height: 0.563em;
outline: none;
cursor: pointer;
border-radius: 0;
}
.InputRangeComponentStyle-range::-webkit-slider-runnable-track {
width: 100%;
height: 0.375em;
background: transparent;
}
.InputRangeComponentStyle-range::-webkit-slider-thumb {
-webkit-appearance: none;
width: 1.875em;
height: 1em;
border-radius: 0.25em;
background: #ffbc09;
margin-top: -0.3em;
}
.InputRangeComponentStyle-range::-moz-range-track { background: transparent; }
.InputRangeComponentStyle-range::-moz-range-progress { background: #ffbc09; }
.InputRangeComponentStyle-range::-moz-range-thumb {
width: 1.875em;
height: 1em;
border: 0;
border-radius: 0.25em;
background: #ffbc09;
}
.CheckBoxComponentStyle-oneSetting {
display: flex;
align-items: center;
justify-content: flex-start;
width: 100%;
height: 2.25em;
margin-bottom: 1.25em;
}
.CheckBoxComponentStyle-oneSetting.has-description {
height: auto;
min-height: 2.25em;
align-items: flex-start;
}
.CheckBoxStyle-checkbox { display: flex; z-index: 1; }
.CheckBoxStyle-checkbox label {
display: flex;
align-items: center;
cursor: pointer;
}
.CheckBoxStyle-checkbox input {
position: absolute;
width: 0;
height: 0;
opacity: 0;
pointer-events: none;
}
.ksc-62 {
position: relative;
display: flex;
width: 2.75em;
height: 1.5em;
border: 0.063em solid rgba(255, 255, 255, 0.2);
border-radius: 6.25rem;
background: rgba(191, 213, 255, 0.25);
transition: background-color 0.2s;
}
.ksc-62[data-on="true"] { background: rgba(118, 255, 51, 0.25); }
.ksc-62::after {
content: "";
position: absolute;
top: 50%;
left: 0.2em;
width: 1.1em;
height: 1.1em;
border-radius: 50%;
background: #fff;
transform: translateY(-50%);
transition: left 0.2s;
}
.ksc-62[data-on="true"]::after { left: calc(100% - 1.3em); }
.ksc-63 { display: flex; align-items: center; justify-content: flex-start; }
.ksc-63.has-description {
flex-direction: column;
align-items: flex-start;
justify-content: flex-start;
gap: 0.15em;
padding-top: 0.2em;
}
.ksc-63 label {
color: rgba(255, 255, 255, 0.9);
font-family: BaseFontRegular, "Segoe UI", sans-serif;
font-size: 1em;
line-height: normal;
}