diff --git a/3DTank/docs/SettingsStyleTable.md b/3DTank/docs/SettingsStyleTable.md index bcdc3c1..8f3167b 100644 --- a/3DTank/docs/SettingsStyleTable.md +++ b/3DTank/docs/SettingsStyleTable.md @@ -68,6 +68,6 @@ ## 5. 当前仍为近似 - 设置行的组合方式:已按 `rowBlock` / `dropDownTitle` / `slider` / `CheckBoxComponentStyle` 的尺寸重建,但原版每个设置项的具体子组件层级仍需继续展开。 -- 下拉选项弹层:已按 `DropDownStyle` + `ContextMenuStyle` 还原菜单/选项高度、背景、hover、选中色;定位仍用 `top:100%`,原版用 `position` 计算屏幕内位置。 +- 下拉选项弹层:已按 `DropDownStyle` + `ContextMenuStyle` 还原菜单/选项高度、背景、hover、选中色;使用 `position:fixed` + 控件 `getBoundingClientRect()`,宽度等于选择框、紧贴下沿,避免被设置面板滚动容器裁剪。 - 菜单滑动条:当前按 `index * 5em + 1.25em` 计算,原版由组件状态计算 `margin-top`。 - 部分设置项的分组/顺序仍以官方 key 和现有状态为准,后续可继续按原组件 render 树核对。 diff --git a/TankiOffline/app/src/jsMain/kotlin/App/Browser/Ui/LobbyScreens.kt b/TankiOffline/app/src/jsMain/kotlin/App/Browser/Ui/LobbyScreens.kt index b4f0bd0..3574c38 100644 --- a/TankiOffline/app/src/jsMain/kotlin/App/Browser/Ui/LobbyScreens.kt +++ b/TankiOffline/app/src/jsMain/kotlin/App/Browser/Ui/LobbyScreens.kt @@ -2292,10 +2292,7 @@ private val SettingsSelect: csstype.PropertiesBuilder.() -> Unit = { } private val SettingsDropdownList: csstype.PropertiesBuilder.() -> Unit = { - Style("position", "absolute") - Style("left", "0") - Style("top", "100%") - Style("min-width", "18.25em") + Style("position", "fixed") Style("max-height", "15.75em") Style("overflow", "auto") Style("z-index", "999") @@ -2306,6 +2303,13 @@ private val SettingsDropdownList: csstype.PropertiesBuilder.() -> Unit = { Style("flex-direction", "column") Style("align-items", "stretch") Style("justify-content", "flex-start") + Style("box-sizing", "border-box") +} + +private val SettingsDropdownOverlay: csstype.PropertiesBuilder.() -> Unit = { + Style("position", "fixed") + Style("inset", "0") + Style("z-index", "998") } private val SettingsDropdownOption: csstype.PropertiesBuilder.() -> Unit = { @@ -2507,6 +2511,9 @@ private val SettingsScreen = FC { var Sliders by useState>(emptyMap()) var Choices by useState>(emptyMap()) var OpenChoice by useState(null) + var DropdownLeft by useState(0.0) + var DropdownTop by useState(0.0) + var DropdownWidth by useState(0.0) val UserName = StateOrNull()?.User?.Uid ?: "" val Tabs = SettingsTabLabels() val Entries = SettingsEntries(Tab, UserName) @@ -2625,13 +2632,28 @@ private val SettingsScreen = FC { div { css(SettingsDropTitle); +Entry.Label } div { css(SettingsSelect) - onClick = { OpenChoice = if (OpenChoice == Entry.Id) null else Entry.Id } + onClick = { E -> + val Rect = E.currentTarget.asDynamic().getBoundingClientRect() + DropdownLeft = (Rect.left as? Number)?.toDouble() ?: 0.0 + DropdownTop = (Rect.bottom as? Number)?.toDouble() ?: 0.0 + DropdownWidth = (Rect.width as? Number)?.toDouble() ?: 0.0 + OpenChoice = if (OpenChoice == Entry.Id) null else Entry.Id + } span { +Entry.Options.getOrElse(Index) { Entry.Options.firstOrNull() ?: "" } } div { css(SettingsChevron) } } if (OpenChoice == Entry.Id) { div { - css(SettingsDropdownList) + css(SettingsDropdownOverlay) + onClick = { OpenChoice = null } + } + div { + css { + Apply(SettingsDropdownList) + Style("left", "${DropdownLeft}px") + Style("top", "${DropdownTop}px") + Style("width", "${DropdownWidth}px") + } for ((OptionIndex, Option) in Entry.Options.withIndex()) { button { val OptionBase = SettingsDropdownOption