fix(ui): 按原包样式校准设置页布局与控件
This commit is contained in:
1 parent
233a8b5c05
commit
04b59558d1
4 files changed
+529
-121
No files matched your search
@@ -0,0 +1,58 @@
|
||||
# Settings Style Table(设置页校准)
|
||||
|
||||
> 来源:`3dtank.com/play/static/js/unpacked/module_82347.js` 的 `SettingsComponentStyle` / `SettingsMenuComponentStyle` / `SettingsButtonsComponentStyle` / `GameSettingsStyle` / `DropDownStyle` / `CheckBoxComponentStyle` / `InputRangeComponentStyle`。
|
||||
> 方法:在无头页面中加载原包模块,patch `module_37036` 的 `ld` 捕获样式类,实例化样式类后逐个执行 `duv_1[0]` 样式函数,并用 recording style object 记录 `rpf` / `gp8` 调用。
|
||||
|
||||
## 1. 页面骨架
|
||||
|
||||
| 原版字段 | CSS |
|
||||
|---|---|
|
||||
| `blockContentOptions` | `display:flex; flex-wrap:wrap; justify-content:flex-start; align-items:flex-start; width:72.25em; height:calc(100% - 8.5em); padding-top:4.5em; position:relative` |
|
||||
| `scroll` | `display:flex; flex-direction:column; width:46.875em; overflow-x:hidden; overflow-y:scroll; scrollbar-width:thin` |
|
||||
| `settingsBlockOptions` | `display:flex; flex-direction:column; width:46.875em; height:100%; padding:1.875em; padding-bottom:0; background:rgba(255,255,255,0.1); position:relative` |
|
||||
| `containerBlock` | `width:50.625em; height:100%; padding-left:2.625em` |
|
||||
| `borderLineOption` | `width:49.125em; height:0.063em; margin-left:-1.875em; margin-bottom:1.875em; background:rgba(255,255,255,0.1)` |
|
||||
| `commonBlock` | `display:flex; flex-direction:column; justify-content:flex-start; align-items:center; width:100%; height:auto` |
|
||||
| `rowBlock` | `display:flex; flex-direction:row; justify-content:space-between; align-items:center; width:100%; height:auto` |
|
||||
| `textHeadlineOptions` | `font:500 1.125em/normal BaseFontBold; text-transform:uppercase` |
|
||||
| `dropDownTitle` | `font:400 1em/normal BaseFontRegular; margin:0 0 1em` |
|
||||
| `dropDown` | `width:30.625em; margin-bottom:1.75em` |
|
||||
| `slider` | `width:31.25em` |
|
||||
|
||||
## 2. 左侧菜单
|
||||
|
||||
| 原版字段 | CSS |
|
||||
|---|---|
|
||||
| `slideMenuOptions` | `display:flex; flex-direction:column; justify-content:center; width:18em; height:2.5em; background:linear-gradient(to right,#2E3235,rgba(46,50,53,0)); color:rgb(255,188,9); z-index:1; transition:all .1s ease-in-out; position:relative` |
|
||||
| `yellowLineMenuOptions` | `width:0.313em; height:2.5em; background:rgb(255,188,9); position:absolute; z-index:3` |
|
||||
| `menuItemOptions` | `display:flex; align-items:center; justify-content:flex-start; width:18em; height:5em; position:relative; z-index:4; cursor:pointer` |
|
||||
| `menuItemOptions span` | `font:500 1.125em/normal BaseFontBold; text-transform:uppercase; margin-left:1.875em; margin-top:0.1em; color:rgba(255,255,255,0.6)` |
|
||||
| `activeItemOptions span` | `color:white; transition:.5s` |
|
||||
|
||||
## 3. 底部按钮
|
||||
|
||||
| 原版字段 | CSS |
|
||||
|---|---|
|
||||
| `containerGroupButton` | `display:flex; align-items:center; justify-content:flex-end; width:100%; height:3.125em; padding-bottom:1.875em; align-self:flex-end; background:transparent` |
|
||||
| `buttonsWidthBackReset` | `width:15.625em` |
|
||||
| `buttonSaveLeave` | `width:18.125em` |
|
||||
|
||||
## 4. 控件
|
||||
|
||||
| 原版类/字段 | CSS |
|
||||
|---|---|
|
||||
| `DropDownStyle` 容器 | `width:100%; position:relative` |
|
||||
| `DropDownStyle` 按钮 | `display:flex; align-items:center; justify-content:space-between; min-width:4.375em; width:100%; height:3.125em; border:0.063em solid rgba(255,255,255,0.2); background:rgba(255,255,255,0.1); padding:0 0.875em; box-sizing:border-box` |
|
||||
| `CheckBoxComponentStyle` | `display:flex; align-items:center; justify-content:flex-start; width:100%; height:2.25em; margin-bottom:1.25em` |
|
||||
| `InputRangeComponentStyle` | `display:flex; flex-direction:column; justify-content:space-between; align-items:flex-start; height:3.188em; min-height:3.188em; margin-bottom:1.75em` |
|
||||
| `InputRangeComponentStyle` label | `color:white; font-size:0.9375em; margin-top:0` |
|
||||
| `InputRangeComponentStyle` input | `-webkit-appearance:none; width:100%; height:0.563em; background:transparent; cursor:pointer` |
|
||||
| `GameSettingsStyle.containerFormOptions` | `display:flex; flex-direction:column; margin-left:0.9em; margin-bottom:1em` |
|
||||
| `GameSettingsStyle.notificationText` | `color:rgba(255,255,255,0.5); text-align:left` |
|
||||
|
||||
## 5. 当前仍为近似
|
||||
|
||||
- 复选框内部图形:原版由组件内部 SVG/伪元素绘制,当前用 1.25em 黄色方块 + 勾。
|
||||
- 设置行的组合方式:已按 `rowBlock` / `dropDownTitle` / `slider` 的尺寸重建,但原版每个设置项的具体子组件层级仍需继续展开。
|
||||
- 下拉选项弹层:当前用原生 `select`,原版是自定义列表;尺寸/边框/背景已对齐。
|
||||
- 菜单滑动条的动态位置:当前按 `index * 5em + 1.25em` 计算,原版由组件状态计算 `margin-top`。
|
||||
@@ -15,7 +15,7 @@
|
||||
| 幸运礼盒 | 同上 | 4 种礼盒美术、钥匙图标/数量、可能奖励稀有度、右侧详情/开启确认 |
|
||||
| 战斗选择 | 同上 | 模式筛选(DM/TDM/CTF/CP/AS/JGR/SGE/RUGBY 图标)+ 战场列表 + 右侧详情/加入/创建入口 |
|
||||
| 任务 | 同上 | 分类侧栏(主要/每日/每周/星级挑战/合约)+ 任务卡(进度、奖励图标、领取/去完成)+ 星级挑战横幅 + 离线示例 |
|
||||
| 设置 | 同上 | 8 个分类侧栏;开关/滑杆/下拉/按键表;账户、安全、支持分组;全部重置 |
|
||||
| 设置 | 同上 | 8 个分类侧栏;开关/滑杆/下拉/按键表;账户、安全、支持分组;全部重置。**已按原包 `SettingsComponentStyle` 展开值校准**(72.25em 内容区、18em 菜单、46.875em 面板、1.875em 内边距、黄色滑动条/左侧线),详见 `3DTank/docs/SettingsStyleTable.md` |
|
||||
| 聊天 | 同上 | 频道侧栏(公共/战斗/军团/私聊)+ 消息行(头像/作者/时间)+ 发送;军团频道读 `ClanChatState` |
|
||||
| 新闻 | 同上 | 左列表 + 右详情;真实图片/日期/正文;无数据时显示带标记的离线示例 |
|
||||
| 军团 | 同上 | 未加入:军团美术、创建/搜索、许可证;已加入:军团头图、信息/成员/请求/邀请页签与成员表 |
|
||||
@@ -54,4 +54,5 @@
|
||||
- `LobbyView` 的旧 HTML 字符串子页面已删除,只保留车库 HTML 容器;非车库页面全部走 `ScreenMount`。
|
||||
- 已用无头浏览器核对非战斗页面:首页、车库(总览/底盘/迷彩)、商店、礼盒、战斗选择、任务、设置(游戏/画面/音效)、聊天、新闻、军团、好友。
|
||||
- 任务/新闻/好友在离线无数据时显示带「离线示例」标记的演示内容;连接服务器后自动使用真实状态。
|
||||
- 下一步:继续展开战斗 HUD / 结算的精确尺寸与弹窗实例,再处理车库真实迷彩预览与 3D 模型。
|
||||
- **设置页已按原包 style 类展开值重建**;其余非战斗页面仍使用通用 `UiTheme` 样式,尚未逐页校准,不能视为最终 1:1。
|
||||
- 下一步:以设置页为基准,逐页提取原版 style 类并替换,再处理战斗 HUD / 结算的精确尺寸与弹窗实例。
|
||||
@@ -146,6 +146,7 @@ private val BreadcrumbsFullscreenText: csstype.PropertiesBuilder.() -> Unit = {
|
||||
private fun ChildrenBuilder.ScreenShell(
|
||||
Title: String,
|
||||
Subtitle: String = "",
|
||||
FullBleed: Boolean = false,
|
||||
Body: ChildrenBuilder.() -> Unit,
|
||||
) {
|
||||
div {
|
||||
@@ -207,7 +208,7 @@ private fun ChildrenBuilder.ScreenShell(
|
||||
}
|
||||
}
|
||||
div {
|
||||
css(ScreenBody)
|
||||
if (FullBleed) css(ScreenBodyFull) else css(ScreenBody)
|
||||
Body()
|
||||
}
|
||||
}
|
||||
@@ -2126,6 +2127,309 @@ private fun SettingsEntries(Tab: Int, UserName: String): List<SettingEntry> = wh
|
||||
)
|
||||
}
|
||||
|
||||
private val SettingsPage: csstype.PropertiesBuilder.() -> Unit = {
|
||||
Style("display", "flex")
|
||||
Style("justify-content", "center")
|
||||
Style("width", "100%")
|
||||
Style("height", "100%")
|
||||
Style("overflow", "hidden")
|
||||
}
|
||||
|
||||
private val SettingsBlock: csstype.PropertiesBuilder.() -> Unit = {
|
||||
Style("display", "flex")
|
||||
Style("flex-wrap", "wrap")
|
||||
Style("justify-content", "flex-start")
|
||||
Style("align-items", "flex-start")
|
||||
Style("width", "72.25em")
|
||||
Style("height", "calc(100% - 8.5em)")
|
||||
Style("margin-left", "0")
|
||||
Style("padding-top", "4.5em")
|
||||
Style("position", "relative")
|
||||
Style("box-sizing", "border-box")
|
||||
}
|
||||
|
||||
private val SettingsMenu: csstype.PropertiesBuilder.() -> Unit = {
|
||||
Style("position", "relative")
|
||||
Style("width", "18em")
|
||||
Style("flex", "0 0 18em")
|
||||
Style("height", "100%")
|
||||
}
|
||||
|
||||
private val SettingsMenuHighlight: csstype.PropertiesBuilder.() -> Unit = {
|
||||
Style("position", "absolute")
|
||||
Style("left", "0")
|
||||
Style("width", "18em")
|
||||
Style("height", "2.5em")
|
||||
Style("background", "linear-gradient(to right, #2E3235, rgba(46, 50, 53, 0))")
|
||||
Style("color", "rgb(255, 188, 9)")
|
||||
Style("z-index", "1")
|
||||
Style("transition", "all 0.1s ease-in-out")
|
||||
Style("pointer-events", "none")
|
||||
}
|
||||
|
||||
private val SettingsMenuLine: csstype.PropertiesBuilder.() -> Unit = {
|
||||
Style("position", "absolute")
|
||||
Style("left", "0")
|
||||
Style("width", "0.313em")
|
||||
Style("height", "2.5em")
|
||||
Style("background-color", "rgb(255, 188, 9)")
|
||||
Style("z-index", "3")
|
||||
Style("transition", "all 0.1s ease-in-out")
|
||||
Style("pointer-events", "none")
|
||||
}
|
||||
|
||||
private val SettingsMenuItem: csstype.PropertiesBuilder.() -> Unit = {
|
||||
Style("display", "flex")
|
||||
Style("align-items", "center")
|
||||
Style("justify-content", "flex-start")
|
||||
Style("width", "18em")
|
||||
Style("height", "5em")
|
||||
Style("position", "relative")
|
||||
Style("margin", "0")
|
||||
Style("padding", "0")
|
||||
Style("border", "0")
|
||||
Style("background", "transparent")
|
||||
Style("z-index", "4")
|
||||
Style("cursor", "pointer")
|
||||
Style("text-align", "left")
|
||||
}
|
||||
|
||||
private fun SettingsMenuLabel(Active: Boolean): csstype.PropertiesBuilder.() -> Unit = {
|
||||
Style("font-family", "BaseFontBold, FallbackFontBold")
|
||||
Style("font-style", "normal")
|
||||
Style("font-weight", "500")
|
||||
Style("font-size", "1.125em")
|
||||
Style("line-height", "normal")
|
||||
Style("text-transform", "uppercase")
|
||||
Style("margin-left", "1.875em")
|
||||
Style("margin-top", "0.1em")
|
||||
Style("color", if (Active) "white" else "rgba(255, 255, 255, 0.6)")
|
||||
Style("transition", "0.5s")
|
||||
}
|
||||
|
||||
private val SettingsContainer: csstype.PropertiesBuilder.() -> Unit = {
|
||||
Style("display", "flex")
|
||||
Style("align-items", "flex-start")
|
||||
Style("width", "50.625em")
|
||||
Style("height", "100%")
|
||||
Style("padding-left", "2.625em")
|
||||
Style("box-sizing", "border-box")
|
||||
}
|
||||
|
||||
private val SettingsPanel: csstype.PropertiesBuilder.() -> Unit = {
|
||||
Style("display", "flex")
|
||||
Style("flex-direction", "column")
|
||||
Style("align-items", "stretch")
|
||||
Style("justify-content", "flex-start")
|
||||
Style("width", "46.875em")
|
||||
Style("height", "100%")
|
||||
Style("margin", "0")
|
||||
Style("padding", "1.875em")
|
||||
Style("padding-bottom", "0")
|
||||
Style("position", "relative")
|
||||
Style("background-color", "rgba(255, 255, 255, 0.1)")
|
||||
Style("box-sizing", "border-box")
|
||||
Style("overflow-x", "hidden")
|
||||
Style("overflow-y", "auto")
|
||||
Style("scrollbar-color", "#BCBCBC rgba(255,255,255,0.2)")
|
||||
Style("scrollbar-width", "thin")
|
||||
}
|
||||
|
||||
private val SettingsDivider: csstype.PropertiesBuilder.() -> Unit = {
|
||||
Style("flex", "0 0 auto")
|
||||
Style("background-color", "rgba(255, 255, 255, 0.1)")
|
||||
Style("width", "49.125em")
|
||||
Style("height", "0.063em")
|
||||
Style("margin-bottom", "1.875em")
|
||||
Style("margin-left", "-1.875em")
|
||||
}
|
||||
|
||||
private val SettingsHeadline: csstype.PropertiesBuilder.() -> Unit = {
|
||||
Style("font-family", "BaseFontBold, FallbackFontBold")
|
||||
Style("font-style", "normal")
|
||||
Style("font-weight", "500")
|
||||
Style("font-size", "1.125em")
|
||||
Style("line-height", "normal")
|
||||
Style("text-transform", "uppercase")
|
||||
Style("margin", "0 0 1.875em")
|
||||
Style("color", "white")
|
||||
}
|
||||
|
||||
private val SettingsRow: csstype.PropertiesBuilder.() -> Unit = {
|
||||
Style("display", "flex")
|
||||
Style("flex-direction", "row")
|
||||
Style("justify-content", "space-between")
|
||||
Style("align-items", "center")
|
||||
Style("width", "100%")
|
||||
Style("height", "auto")
|
||||
Style("min-height", "3.125em")
|
||||
Style("margin-bottom", "1.25em")
|
||||
Style("gap", "1em")
|
||||
}
|
||||
|
||||
private val SettingsLabel: csstype.PropertiesBuilder.() -> Unit = {
|
||||
Style("font-family", "BaseFontRegular, FallbackFontRegular")
|
||||
Style("font-style", "normal")
|
||||
Style("font-weight", "normal")
|
||||
Style("font-size", "1em")
|
||||
Style("line-height", "normal")
|
||||
Style("color", "rgba(255, 255, 255, 0.9)")
|
||||
}
|
||||
|
||||
private val SettingsDesc: csstype.PropertiesBuilder.() -> Unit = {
|
||||
Style("font-family", "BaseFontRegular, FallbackFontRegular")
|
||||
Style("font-size", "0.85em")
|
||||
Style("line-height", "1.35")
|
||||
Style("color", "rgba(255, 255, 255, 0.5)")
|
||||
Style("margin-top", "0.2em")
|
||||
}
|
||||
|
||||
private val SettingsDropdown: csstype.PropertiesBuilder.() -> Unit = {
|
||||
Style("width", "30.625em")
|
||||
Style("margin-bottom", "1.75em")
|
||||
Style("position", "relative")
|
||||
}
|
||||
|
||||
private val SettingsDropTitle: csstype.PropertiesBuilder.() -> Unit = {
|
||||
Style("font-family", "BaseFontRegular, FallbackFontRegular")
|
||||
Style("font-style", "normal")
|
||||
Style("font-weight", "normal")
|
||||
Style("font-size", "1em")
|
||||
Style("line-height", "normal")
|
||||
Style("margin", "0 0 1em")
|
||||
Style("color", "rgba(255, 255, 255, 0.9)")
|
||||
}
|
||||
|
||||
private val SettingsSelect: csstype.PropertiesBuilder.() -> Unit = {
|
||||
Style("display", "flex")
|
||||
Style("align-items", "center")
|
||||
Style("justify-content", "space-between")
|
||||
Style("min-width", "4.375em")
|
||||
Style("width", "100%")
|
||||
Style("height", "3.125em")
|
||||
Style("border", "0.063em solid rgba(255, 255, 255, 0.2)")
|
||||
Style("box-sizing", "border-box")
|
||||
Style("background-color", "rgba(255, 255, 255, 0.1)")
|
||||
Style("padding-left", "0.875em")
|
||||
Style("padding-right", "0.875em")
|
||||
Style("color", "white")
|
||||
Style("font-family", "BaseFontRegular, FallbackFontRegular")
|
||||
Style("font-size", "1em")
|
||||
Style("outline", "none")
|
||||
Style("cursor", "pointer")
|
||||
}
|
||||
|
||||
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("background-color", "rgba(255, 255, 255, 0.2)")
|
||||
Style("outline", "none")
|
||||
Style("accent-color", "rgb(255, 188, 9)")
|
||||
}
|
||||
|
||||
private val SettingsButtons: csstype.PropertiesBuilder.() -> Unit = {
|
||||
Style("display", "flex")
|
||||
Style("align-items", "center")
|
||||
Style("justify-content", "flex-end")
|
||||
Style("width", "100%")
|
||||
Style("height", "3.125em")
|
||||
Style("background-color", "transparent")
|
||||
Style("align-self", "flex-end")
|
||||
Style("padding-bottom", "1.875em")
|
||||
Style("gap", "0.5em")
|
||||
Style("margin-top", "auto")
|
||||
}
|
||||
|
||||
private val SettingsButton: csstype.PropertiesBuilder.() -> Unit = {
|
||||
Style("width", "15.625em")
|
||||
Style("height", "3.125em")
|
||||
Style("background-color", "rgba(255, 255, 255, 0.1)")
|
||||
Style("border", "0")
|
||||
Style("color", "white")
|
||||
Style("font-family", "BaseFontBold, FallbackFontBold")
|
||||
Style("font-weight", "500")
|
||||
Style("font-size", "1.125em")
|
||||
Style("text-transform", "uppercase")
|
||||
Style("cursor", "pointer")
|
||||
}
|
||||
|
||||
private val SettingsButtonWide: csstype.PropertiesBuilder.() -> Unit = {
|
||||
Apply(SettingsButton)
|
||||
Style("width", "18.125em")
|
||||
}
|
||||
|
||||
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("display", "flex")
|
||||
Style("align-items", "center")
|
||||
Style("justify-content", "center")
|
||||
Style("width", "1.25em")
|
||||
Style("height", "1.25em")
|
||||
Style("flex", "0 0 1.25em")
|
||||
Style("border", "0.063em solid ${if (On) "rgb(255, 188, 9)" else "rgba(255, 255, 255, 0.4)"}")
|
||||
Style("background-color", if (On) "rgb(255, 188, 9)" else "rgba(255, 255, 255, 0.1)")
|
||||
Style("cursor", "pointer")
|
||||
Style("padding", "0")
|
||||
}
|
||||
|
||||
private val SettingsCheckMark: csstype.PropertiesBuilder.() -> Unit = {
|
||||
Style("width", "0.65em")
|
||||
Style("height", "0.4em")
|
||||
Style("border-left", "0.15em solid #1b1f22")
|
||||
Style("border-bottom", "0.15em solid #1b1f22")
|
||||
Style("transform", "rotate(-45deg)")
|
||||
Style("margin-top", "-0.1em")
|
||||
}
|
||||
|
||||
private val SettingsKeysGrid: csstype.PropertiesBuilder.() -> Unit = {
|
||||
Style("display", "grid")
|
||||
Style("grid-template-columns", "1fr 1fr")
|
||||
Style("gap", "0.1em 1.2em")
|
||||
Style("width", "100%")
|
||||
Style("margin-bottom", "1.25em")
|
||||
}
|
||||
|
||||
private val SettingsKeyRow: csstype.PropertiesBuilder.() -> Unit = {
|
||||
Style("display", "flex")
|
||||
Style("align-items", "center")
|
||||
Style("justify-content", "space-between")
|
||||
Style("padding", "0.35em 0")
|
||||
Style("border-bottom", "0.063em solid rgba(255, 255, 255, 0.1)")
|
||||
}
|
||||
|
||||
private val SettingsScreen = FC<Props> {
|
||||
var Tab by useState(0)
|
||||
var Toggles by useState<Map<String, Boolean>>(emptyMap())
|
||||
@@ -2141,136 +2445,173 @@ private val SettingsScreen = FC<Props> {
|
||||
ToastContext.Show("已重置当前设置(离线模式)")
|
||||
}
|
||||
|
||||
ScreenShell("设置", SettingsTabs.getOrElse(Tab) { "" }) {
|
||||
ScreenShell("设置", SettingsTabs.getOrElse(Tab) { "" }, FullBleed = true) {
|
||||
div {
|
||||
css(Columns)
|
||||
css(SettingsPage)
|
||||
div {
|
||||
css(SideNav)
|
||||
for ((Index, Name) in SettingsTabs.withIndex()) {
|
||||
NavItem(Name, null, Tab == Index) { Tab = Index }
|
||||
}
|
||||
}
|
||||
div {
|
||||
css(ContentPane)
|
||||
css(SettingsBlock)
|
||||
div {
|
||||
css(PageToolbar)
|
||||
css(SettingsMenu)
|
||||
div {
|
||||
css { Style("flex", "1"); Style("min-width", "0") }
|
||||
div { css(PaneTitle); +SettingsTabs.getOrElse(Tab) { "设置" } }
|
||||
div { css(PaneDesc); +"修改后的设置会在下一次进入战斗时生效。" }
|
||||
css {
|
||||
Apply(SettingsMenuHighlight)
|
||||
Style("top", "calc(${Tab * 5}em + 1.25em)")
|
||||
}
|
||||
}
|
||||
button {
|
||||
css(SecondaryButton)
|
||||
onClick = { ResetAll() }
|
||||
+"全部重置"
|
||||
div {
|
||||
css {
|
||||
Apply(SettingsMenuLine)
|
||||
Style("top", "calc(${Tab * 5}em + 1.25em)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
div {
|
||||
css(Panel)
|
||||
for (Entry in Entries) {
|
||||
when (Entry) {
|
||||
is SettingEntry.Header -> {
|
||||
div {
|
||||
css {
|
||||
Style("padding", "0.55em 1em")
|
||||
Style("background", "rgba(0, 12, 20, 0.45)")
|
||||
Style("border-bottom", "1px solid ${Ui.DividerSoft}")
|
||||
Style("color", Ui.Cyan)
|
||||
Style("font", "500 0.82em/1.3 ${Ui.FontMedium}")
|
||||
Style("text-transform", "uppercase")
|
||||
Style("letter-spacing", "0.05em")
|
||||
}
|
||||
+Entry.Text
|
||||
}
|
||||
}
|
||||
is SettingEntry.Toggle -> {
|
||||
val On = Toggles[Entry.Id] ?: Entry.Default
|
||||
SettingRow(Entry.Label, Entry.Desc) {
|
||||
Toggle(On) { Toggles = Toggles + (Entry.Id to it) }
|
||||
}
|
||||
}
|
||||
is SettingEntry.Slider -> {
|
||||
val Value = Sliders[Entry.Id] ?: Entry.Default
|
||||
SliderRow(Entry.Label, Entry.Desc, Value) {
|
||||
Sliders = Sliders + (Entry.Id to it)
|
||||
}
|
||||
}
|
||||
is SettingEntry.Choice -> {
|
||||
val Index = Choices[Entry.Id] ?: Entry.Default
|
||||
SelectRow(Entry.Label, Entry.Desc, Entry.Options, Index) {
|
||||
Choices = Choices + (Entry.Id to it)
|
||||
}
|
||||
}
|
||||
is SettingEntry.Action -> {
|
||||
SettingRow(Entry.Label, Entry.Desc) {
|
||||
button {
|
||||
css(SecondaryButton)
|
||||
onClick = { ToastContext.Show(Entry.Toast) }
|
||||
+Entry.Button
|
||||
}
|
||||
}
|
||||
}
|
||||
is SettingEntry.Info -> {
|
||||
SettingRow(Entry.Label, Entry.Desc) {
|
||||
span { css(MutedText); +Entry.Value }
|
||||
}
|
||||
}
|
||||
is SettingEntry.Keys -> {
|
||||
div {
|
||||
css {
|
||||
Style("display", "grid")
|
||||
Style("grid-template-columns", "1fr 1fr")
|
||||
Style("gap", "0.1em 1.2em")
|
||||
Style("padding", "0.6em 1em 0.9em")
|
||||
}
|
||||
for ((Action, Key) in Entry.Rows) {
|
||||
div {
|
||||
css {
|
||||
Style("display", "flex")
|
||||
Style("align-items", "center")
|
||||
Style("justify-content", "space-between")
|
||||
Style("padding", "0.35em 0")
|
||||
Style("border-bottom", "1px solid ${Ui.DividerSoft}")
|
||||
}
|
||||
span { css(MutedText); +Action }
|
||||
span {
|
||||
css {
|
||||
Style("min-width", "2.2em")
|
||||
Style("padding", "0.2em 0.45em")
|
||||
Style("border", "1px solid ${Ui.Divider}")
|
||||
Style("border-radius", "0.25em")
|
||||
Style("background", "rgba(0, 12, 20, 0.7)")
|
||||
Style("text-align", "center")
|
||||
Style("font", "500 0.8em/1.3 ${Ui.FontMedium}")
|
||||
}
|
||||
+Key
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for ((Index, Name) in SettingsTabs.withIndex()) {
|
||||
button {
|
||||
css(SettingsMenuItem)
|
||||
onClick = { Tab = Index }
|
||||
span {
|
||||
css(SettingsMenuLabel(Index == Tab))
|
||||
+Name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
div {
|
||||
css {
|
||||
Style("display", "flex")
|
||||
Style("align-items", "center")
|
||||
Style("justify-content", "space-between")
|
||||
Style("gap", "0.6em")
|
||||
Style("margin-top", "0.2em")
|
||||
}
|
||||
button {
|
||||
css(SecondaryButton)
|
||||
onClick = { ScreenContext.OnBack() }
|
||||
+"返回 [Z]"
|
||||
}
|
||||
button {
|
||||
css(SecondaryButton)
|
||||
onClick = { ResetAll() }
|
||||
+"全部重置"
|
||||
css(SettingsContainer)
|
||||
div {
|
||||
css(SettingsPanel)
|
||||
var HasHeader = false
|
||||
for (Entry in Entries) {
|
||||
when (Entry) {
|
||||
is SettingEntry.Header -> {
|
||||
if (HasHeader) div { css(SettingsDivider) }
|
||||
HasHeader = true
|
||||
div {
|
||||
css(SettingsHeadline)
|
||||
+Entry.Text
|
||||
}
|
||||
}
|
||||
is SettingEntry.Toggle -> {
|
||||
val On = Toggles[Entry.Id] ?: Entry.Default
|
||||
div {
|
||||
css(SettingsCheckboxRow)
|
||||
button {
|
||||
css(SettingsCheckbox(On))
|
||||
onClick = { Toggles = Toggles + (Entry.Id to !On) }
|
||||
if (On) div { css(SettingsCheckMark) }
|
||||
}
|
||||
div {
|
||||
css { Style("flex", "1"); Style("min-width", "0") }
|
||||
div { css(SettingsLabel); +Entry.Label }
|
||||
if (Entry.Desc.isNotEmpty()) div { css(SettingsDesc); +Entry.Desc }
|
||||
}
|
||||
}
|
||||
}
|
||||
is SettingEntry.Slider -> {
|
||||
val Value = Sliders[Entry.Id] ?: Entry.Default
|
||||
div {
|
||||
css(SettingsSliderWrap)
|
||||
div {
|
||||
css(SettingsSliderLabel)
|
||||
span { +Entry.Label }
|
||||
span { +"$Value%" }
|
||||
}
|
||||
input {
|
||||
css(SettingsRange)
|
||||
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)) }
|
||||
}
|
||||
}
|
||||
}
|
||||
is SettingEntry.Choice -> {
|
||||
val Index = Choices[Entry.Id] ?: Entry.Default
|
||||
div {
|
||||
css(SettingsDropdown)
|
||||
div { css(SettingsDropTitle); +Entry.Label }
|
||||
select {
|
||||
css(SettingsSelect)
|
||||
value = Entry.Options.getOrElse(Index) { Entry.Options.firstOrNull() ?: "" }
|
||||
onChange = { E ->
|
||||
val Found = Entry.Options.indexOf(E.target.value)
|
||||
if (Found >= 0) Choices = Choices + (Entry.Id to Found)
|
||||
}
|
||||
for (Option in Entry.Options) option { value = Option; +Option }
|
||||
}
|
||||
if (Entry.Desc.isNotEmpty()) div { css(SettingsDesc); +Entry.Desc }
|
||||
}
|
||||
}
|
||||
is SettingEntry.Action -> {
|
||||
div {
|
||||
css(SettingsRow)
|
||||
div {
|
||||
css { Style("flex", "1"); Style("min-width", "0") }
|
||||
div { css(SettingsLabel); +Entry.Label }
|
||||
if (Entry.Desc.isNotEmpty()) div { css(SettingsDesc); +Entry.Desc }
|
||||
}
|
||||
button {
|
||||
css(SettingsButton)
|
||||
onClick = { ToastContext.Show(Entry.Toast) }
|
||||
+Entry.Button
|
||||
}
|
||||
}
|
||||
}
|
||||
is SettingEntry.Info -> {
|
||||
div {
|
||||
css(SettingsRow)
|
||||
div {
|
||||
css { Style("flex", "1"); Style("min-width", "0") }
|
||||
div { css(SettingsLabel); +Entry.Label }
|
||||
if (Entry.Desc.isNotEmpty()) div { css(SettingsDesc); +Entry.Desc }
|
||||
}
|
||||
span {
|
||||
css {
|
||||
Style("color", "rgba(255, 255, 255, 0.6)")
|
||||
Style("font-size", "1em")
|
||||
}
|
||||
+Entry.Value
|
||||
}
|
||||
}
|
||||
}
|
||||
is SettingEntry.Keys -> {
|
||||
div {
|
||||
css(SettingsKeysGrid)
|
||||
for ((Action, Key) in Entry.Rows) {
|
||||
div {
|
||||
css(SettingsKeyRow)
|
||||
span { css(SettingsLabel); +Action }
|
||||
span {
|
||||
css {
|
||||
Style("min-width", "2.2em")
|
||||
Style("padding", "0.2em 0.45em")
|
||||
Style("border", "0.063em solid rgba(255, 255, 255, 0.2)")
|
||||
Style("background-color", "rgba(255, 255, 255, 0.1)")
|
||||
Style("text-align", "center")
|
||||
Style("font", "500 0.8em/1.3 ${Ui.FontMedium}")
|
||||
}
|
||||
+Key
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
div {
|
||||
css(SettingsButtons)
|
||||
button {
|
||||
css(SettingsButton)
|
||||
onClick = { ScreenContext.OnBack() }
|
||||
+"返回 [Z]"
|
||||
}
|
||||
button {
|
||||
css(SettingsButtonWide)
|
||||
onClick = { ResetAll() }
|
||||
+"全部重置"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,6 +87,14 @@ internal val ScreenBody: PropertiesBuilder.() -> Unit = {
|
||||
Style("box-sizing", "border-box")
|
||||
}
|
||||
|
||||
internal val ScreenBodyFull: PropertiesBuilder.() -> Unit = {
|
||||
Style("flex", "1")
|
||||
Style("min-height", "0")
|
||||
Style("overflow", "hidden")
|
||||
Style("padding", "0")
|
||||
Style("box-sizing", "border-box")
|
||||
}
|
||||
|
||||
internal val BackButton: PropertiesBuilder.() -> Unit = {
|
||||
Style("display", "flex")
|
||||
Style("align-items", "center")
|
||||
|
||||
Reference in new issue
Block a user