292 lines
10 KiB
Markdown
292 lines
10 KiB
Markdown
# Shop Style Table
|
||
|
||
> 来源:`3DTank/src/module_82347.js`(与 `3dtank.com/play/static/js/unpacked/module_82347.js` 同构)。
|
||
> 提取方法:`3DTank/tools/headless_probe.js` 加载 `module_37036` + `module_82347`,实例化样式类,执行 `dk(...)` 的 style 函数。
|
||
> Kotlin 侧:`TankiOffline/app/src/jsMain/kotlin/App/Browser/Ui/LobbyScreens.kt` 的 `ShopScreen` 及其上方 `Shop*` 样式。
|
||
|
||
## 1. 样式类
|
||
|
||
| 类 | 语义名 | 定义 | 访问器 |
|
||
|---|---|---|---|
|
||
| `$Fi` | `NewShopCommonComponentStyle` | `93477` | `e1hz` container / `b1sk` commonBlockMenuShop / `b1k7` commonContainer / `c1sj` gradient / `l1sk` containerAnnouncement |
|
||
| `zHi` | `ShopSelectedSectionComponentStyle` | `94195` | `y1qq` commonCard / `a1sp` gradientCategory / `y1so` limitedOffersCommon / `x1so` mobileCardContainer / `c1sp` scrollContainerShop / `u1ju` commonBlock / `u1sj` activeCategory / `v1sj` notifier / `k1nd` timer;参数化 `t1sj(icon, active)` |
|
||
| `MVi` | `ShopCategoryComponentStyle` | `95731` | `e1hz` container / `ri5` header / `gax` description / `t1su` bonusContainer / `v1su` bonus / `w1su` marginItemsContainer;参数化 `u1su(rec, bonus)` |
|
||
| `YVi` | `ShopCategoryOfferSectionStyle` | `95908` | `x1su` promoCodesItemsContainer / `p1st` widthSearchInput / `b1m1` containerItem / `y1su` containerCoin / `z1su` containerLimitOffers / `a1sv` containerKitOffers |
|
||
| `RKi` | `ShopFooterComponentStyle` | `96243` | `u1hz` mainContainer / `n1sw` buttonAndTextContainer / `o1sw` exclamation / `k1sw` reportButton |
|
||
| `uXi` | `ShopItemComponentStyle` | `96891` | `k1sy` 基础卡片 / `h1sy` footerContent / `h1pt` headerContainer / `j1sy` headerScroll / `y1sx` headerContent / `i1sy` containerName / `n1sy` previewContainer / `e1mb` discount / `s1ma` discountContainer 等 |
|
||
| `PZt` | `ShopBuyButtonComponentStyle` | `31920` | `u11p` root / `vck` price |
|
||
|
||
## 2. 关键 CSS
|
||
|
||
### 2.1 左侧分类菜单
|
||
|
||
`commonBlockMenuShop`(`b1sk`):
|
||
|
||
```css
|
||
display:flex; flex-direction:column; align-items:center; justify-content:flex-start;
|
||
cursor:default; background-color:rgba(3,8,13,.25); backdrop-filter:blur(.781em);
|
||
border-radius:1rem; border-right:1.25em solid transparent;
|
||
height:max-content; margin-left:2em; margin-top:2em;
|
||
max-height:calc(100% - 9.8em); z-index:2;
|
||
padding:1.25em; padding-right:0; width:25em;
|
||
```
|
||
|
||
分类项 `t1sj(icon, active)`:
|
||
|
||
```css
|
||
display:flex; align-items:center; justify-content:flex-start;
|
||
width:23.75em; height:3.5em; min-height:3.5em; max-height:3.5em;
|
||
margin:0; position:relative; overflow:hidden; cursor:pointer;
|
||
/* active */
|
||
background-color:rgba(255,204,0,.25); border-radius:.5rem; color:rgb(255,204,0);
|
||
```
|
||
|
||
图标(`div`):
|
||
|
||
```css
|
||
width:1.5em; height:1.5em; margin-right:1.25em;
|
||
background-color:white; /* active: rgb(255,204,0) + margin-left:1.25em */
|
||
mask-image:url(icon); mask-position:center; mask-repeat:no-repeat; mask-size:contain;
|
||
```
|
||
|
||
标签(`h4`):
|
||
|
||
```css
|
||
font:500 1em/1 BaseFontMedium; text-transform:uppercase;
|
||
color:white; /* active: rgb(255,204,0) */
|
||
margin:.2em 0 0;
|
||
```
|
||
|
||
### 2.2 主容器
|
||
|
||
`commonContainer`(`b1k7`):
|
||
|
||
```css
|
||
background:radial-gradient(50% 100% at 50% 100%, #203040 0%, #03080D 100%);
|
||
display:flex; align-items:stretch; justify-content:space-between;
|
||
height:100%; width:100%; max-height:calc(100% - 6em);
|
||
```
|
||
|
||
原版 `pFi.tap` 的三个子节点:左菜单、分类内容、右侧选中区。
|
||
|
||
### 2.3 分类内容
|
||
|
||
`ShopCategoryComponentStyle-container`(`e1hz`)是 `display:contents`;标题/描述/物品网格直接进入 `commonContainer`。
|
||
|
||
标题(`ri5`):
|
||
|
||
```css
|
||
font:500 1.875em/1.4em BaseFontBold; margin:1em 0 0; text-transform:uppercase;
|
||
```
|
||
|
||
描述(`gax`):
|
||
|
||
```css
|
||
opacity:.6; line-height:1.25em; font-size:.938em;
|
||
```
|
||
|
||
物品容器 `u1su(rec, bonus)`:
|
||
|
||
```css
|
||
display:flex; flex-wrap:wrap; align-items:flex-start; justify-content:flex-start;
|
||
width:37em; height:100%; gap:1em; margin-left:.25em; margin-top:.25em; /* bonus: .6em */
|
||
```
|
||
|
||
`containerItem`(`b1m1`):
|
||
|
||
```css
|
||
display:grid; grid-template-columns:50% 50%; grid-template-rows:31.35%;
|
||
gap:1em; width:37.25em; margin:2em .9em 1em .25em; padding:0 0 0 .25em;
|
||
justify-content:flex-start; align-content:flex-start; z-index:3;
|
||
```
|
||
|
||
### 2.4 物品卡片
|
||
|
||
`k1sy`:
|
||
|
||
```css
|
||
display:flex; flex-direction:column; align-items:center; justify-content:center;
|
||
position:relative; user-select:none; box-sizing:border-box; cursor:pointer;
|
||
border-radius:1rem; background-color:rgba(255,255,255,.15);
|
||
width:17.5em; height:inherit;
|
||
box-shadow:0 0 0 1px rgba(255,255,255,.3);
|
||
```
|
||
|
||
标题容器 `h1pt`:
|
||
|
||
```css
|
||
width:calc(100% - 1.5em); position:absolute; left:.75em; top:.75em;
|
||
display:flex; align-items:center; justify-content:flex-start; z-index:1;
|
||
```
|
||
|
||
标题文字 `y1sx`:
|
||
|
||
```css
|
||
font:500 1em/1 BaseFontMedium; text-transform:uppercase; color:white; margin-top:.2em;
|
||
```
|
||
|
||
价格文字 `h1sy`:
|
||
|
||
```css
|
||
font:500 1.125em/1.125 BaseFontMedium; text-transform:uppercase; margin-top:.125em;
|
||
```
|
||
|
||
预览 `n1sy`:
|
||
|
||
```css
|
||
display:flex; align-items:center; justify-content:center;
|
||
height:auto; width:auto; max-width:80%; z-index:3;
|
||
```
|
||
|
||
折扣 `e1mb`:
|
||
|
||
```css
|
||
position:absolute; right:.625em; bottom:1em;
|
||
line-height:1.333em; font-size:.938em; font-weight:bold;
|
||
```
|
||
|
||
### 2.5 底部栏
|
||
|
||
`ShopFooterComponentStyle-mainContainer`(`u1hz`):
|
||
|
||
```css
|
||
display:flex; align-items:center; justify-content:flex-start;
|
||
width:100%; height:3.125em; position:absolute; bottom:0;
|
||
border-top:.063em solid rgba(255,255,255,.1);
|
||
backdrop-filter:blur(2.688em); z-index:3;
|
||
```
|
||
|
||
`buttonAndTextContainer`(`n1sw`):
|
||
|
||
```css
|
||
width:auto; height:2.2em; margin-left:1.8em;
|
||
display:flex; align-items:center; justify-content:flex-start;
|
||
```
|
||
|
||
`exclamation`(`o1sw`):
|
||
|
||
```css
|
||
margin-left:.7em; opacity:.5;
|
||
font:400 .875em/1 BaseFontRegular;
|
||
```
|
||
|
||
### 2.6 分类卡(`ShopSelectedSectionComponentStyle-commonBlock`)
|
||
|
||
原版 `$Gi` 的 DOM:
|
||
|
||
```text
|
||
div (commonCard / limitedOffersCommon)
|
||
├─ div.cardImg (z1so) 背景图 100%×100%,background-size:cover,圆角 .625em
|
||
└─ span (b1sp) 标题,absolute,top:1em(limited: bottom:1em)
|
||
```
|
||
|
||
`commonCard`:
|
||
|
||
```css
|
||
display:flex; align-items:center; justify-content:center;
|
||
width:22.5em; height:calc(100% / 2 - 1.2em);
|
||
padding:.4em; border-radius:.625em; overflow:hidden;
|
||
position:relative; cursor:pointer;
|
||
```
|
||
|
||
`z1so`:
|
||
|
||
```css
|
||
background-color:rgba(191,213,255,.15);
|
||
background-size:cover; background-position:center; background-repeat:no-repeat;
|
||
border-radius:.625em; width:100%; height:100%; z-index:1;
|
||
```
|
||
|
||
`b1sp`:
|
||
|
||
```css
|
||
font:500 1.125em/1 BaseFontMedium; text-transform:uppercase;
|
||
position:absolute; top:1em; z-index:3;
|
||
```
|
||
|
||
离线实现:没有 `dsw_1` 分类美术 URL,保留官方 `z1so` 的背景色/尺寸/圆角,图像区域用 `stub.shop.card.art` 虚线占位;标题仍按 `b1sp` 定位。
|
||
|
||
#### 两种列布局
|
||
|
||
原版 `MGi.tap` 先渲染 `specialCategories`,再渲染 `generalCategories`:
|
||
|
||
| 类型 | 列样式 | 卡片样式 | 高度 |
|
||
|---|---|---|---|
|
||
| 普通分类(一排两行) | `w1hz`:`flex column; justify-content:space-between` | `commonCard` | `calc(100% / 2 - 1.2em)` |
|
||
| 特殊/限时(一排一行) | `f1if`:`flex column; justify-content:flex-start` | `limitedOffersCommon` | `calc(100% - .5em)` |
|
||
|
||
两种列都是 `width:22.5em; flex:0 0 22.5em; height:calc(100% - .5em); margin-right:1em`。
|
||
|
||
离线数据没有原版 `esw_1` 特殊分类标记;当前用 `KIT(套件)` 作为特殊分类演示全高卡(代码内有 `STUB` 注释)。
|
||
|
||
#### Hover 细节
|
||
|
||
| 目标 | 原版 | CSS |
|
||
|---|---|---|
|
||
| 分类卡图像 | `VGi` / `KGi` | `transform:scale(1.05,1.05); transition:all .2s ease-in-out` |
|
||
| 分类菜单项(未激活) | `pHi` / `wHi` | `box-shadow:0 0 0 2px rgb(255,255,255); border-radius:.5em; margin-left:1.25em; transition:all .1s ease-in-out` |
|
||
| 分类菜单项(激活) | `aHi` / `cHi` | `box-shadow:none` |
|
||
| 物品卡 | `TYi` | `box-shadow:0 0 0 2px rgb(255,255,255)` |
|
||
|
||
这些都已用无头探针确认生成的 CSS,例如:
|
||
|
||
```css
|
||
.css-1vz2w25:hover { transform: scale(1.05, 1.05); transition: 0.2s ease-in-out; }
|
||
.css-1owq6vw:hover { box-shadow: rgb(255, 255, 255) 0em 0em 0em 2px; }
|
||
.css-1vberae:hover { box-shadow: none; }
|
||
```
|
||
|
||
## 3. 资源
|
||
|
||
| 用途 | 资源 |
|
||
|---|---|
|
||
| 红宝石 | `ruby.ce62efbc.svg` |
|
||
| 水晶 | `crystalSmall.242e6c15.svg` |
|
||
| 金币 | `coin.3a16e831.svg` |
|
||
| 红宝石加号 | `addRuby.ff47c8be.svg` |
|
||
| 水晶加号 | `addCrystal.af9a397c.svg` |
|
||
| 金币加号 | `addCoin.cc7a25d3.svg` |
|
||
|
||
## 4. 当前实现状态
|
||
|
||
已还原:
|
||
|
||
- 先进入 `ShopSelectedSectionComponentStyle-commonBlock`:横向滚动的 22.5em 分类卡(每列 2 张,`commonCard` / `scrollContainerShop`)
|
||
- 点击分类卡后进入 `NewShopCommonComponentStyle-commonContainer`
|
||
- 左侧竖向分类菜单(25em 面板 + 23.75em × 3.5em 分类项 + 图标/激活态)
|
||
- 主容器径向渐变
|
||
- 右侧 37.25em 物品区:分类标题/描述 + 2 列物品网格
|
||
- 物品卡片(17.5em 宽,1rem 圆角,15% 白底,1px 内描边)
|
||
- 物品名称/价格/货币图标
|
||
- 底部 3.125em 栏 + `报告问题` 按钮 + 提示
|
||
|
||
未展开 / 近似:
|
||
|
||
- 分类卡背景:原版 `z1so` 使用 `dsw_1` 分类美术(服务器下发 URL),离线资源里没有;当前保留官方 `z1so` 背景色/尺寸/圆角,图像区域用 `stub.shop.card.art` 虚线占位(`STUB` 标记)
|
||
- `containerItem` 的 `grid-template-rows:31.35%` 动态行高(当前固定 `11.5em`)
|
||
- `ShopFooterComponentStyle-reportButton` 的共享 Button 完整外观(当前金色按钮近似)
|
||
- 金币 / 限时 / 礼包特殊分类(`containerCoin` / `containerLimitOffers` / `containerKitOffers`)
|
||
- 折扣/加成/促销码/能源条(当前数据模型没有这些字段)
|
||
- 分类菜单的 `(any-hover:hover)` 悬停样式(当前未加)
|
||
- 物品目录按 `Name` 去重显示(离线目录同一炮塔有多个等级条目;原版按服务器商品条目显示)
|
||
|
||
## 5. 验收
|
||
|
||
```powershell
|
||
node 3DTank/tools/headless_probe.js `
|
||
--url "http://localhost:8080/?autoconnect=1" `
|
||
--out "build/probe/shop" `
|
||
--width 1296 --height 1006 --wait 14000 `
|
||
--eval-file "C:\Users\TermiNexus\AppData\Local\Temp\opencode\goto_shop.js"
|
||
```
|
||
|
||
实测:
|
||
|
||
```text
|
||
分类卡页:22.5em 宽,每列 2 张,横向滚动
|
||
shop.menu x=36 y=104 w=328 h=452
|
||
shop.category x=805 y=104 w=483 h=...
|
||
shop.item 226.8 × 149.0(17.5em × 11.5em)
|
||
shop.footer y=966 h=40
|
||
```
|