feat: M3-M7 全模块落地 + 集成接线
- M3 认证/权限/审计/限流 + 全部 REST 接口 - M4 管理面板(MIUIx + 成绩录入/积分榜下钻/大屏控制) - M5a 大屏页面(六页 + 明细覆盖层 + 缩放适配) - M6 WebSocket 实时同步中心 - M7 xlsx 导出 + 赛事包 zip + 备份 - 规则包 YAML 导入导出(差异预览) - 字体 vendor 子集化(4 套 x2 字重) - 集成:realtime/export/rules 接入 main+httpapi;backup 子命令 - 修复:中间件包装 ResponseWriter 丢失 Hijacker,导致 WS 握手 501
This commit is contained in:
1 parent
d0e3b93e76
commit
bc8b1ee6c0
145 files changed
+25159
-321
No files matched your search
Vendored
+90
@@ -0,0 +1,90 @@
|
||||
# vendor/fonts —— 本地字体(离线部署,禁止 CDN)
|
||||
|
||||
现场部署无外网,所有中文字体必须随仓库分发、从本目录本地加载。本目录只放**子集化后的 woff2**,
|
||||
原始大字体(每套 8–12 MB)不入库。
|
||||
|
||||
## 字体清单
|
||||
|
||||
| id | 显示名 | font-family | 字重 | 单套合计 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `noto-sans` | Noto Sans SC | `Noto Sans SC` | 400 / 700 | 2.72 MB |
|
||||
| `noto-serif` | Noto Serif SC | `Noto Serif SC` | 400 / 700 | 3.71 MB |
|
||||
| `misans` | MiSans | `MiSans` | 400 / 700 | 1.76 MB |
|
||||
| `source-han-sans` | 思源黑体 Source Han Sans CN | `Source Han Sans CN` | 400 / 700 | 2.72 MB |
|
||||
|
||||
合计 8 个 woff2、10.91 MB。逐文件体积与 sha256 见 [`manifest.json`](./manifest.json),
|
||||
每个文件均 ≤ 4 MB / 套的目标(最大为 Noto Serif SC 的 3.71 MB)。
|
||||
|
||||
## 来源与授权
|
||||
|
||||
| 字体 | 来源 | 授权 |
|
||||
| --- | --- | --- |
|
||||
| Noto Sans SC | Google Noto(`~/Fonts/noto-sans/sc`) | SIL Open Font License 1.1 |
|
||||
| Noto Serif SC | Google Noto(`~/Fonts/noto-serif/sc/SubsetOTF/SC`) | SIL Open Font License 1.1 |
|
||||
| MiSans | 小米(`~/Fonts/MiSans/ttf`) | MiSans 字体知识产权许可协议 |
|
||||
| 思源黑体 Source Han Sans CN | Adobe(`~/Fonts/思源黑体`) | SIL Open Font License 1.1 |
|
||||
|
||||
> **授权说明**:本项目为**内部赛事**使用,不对外公开发布,字体授权不构成障碍
|
||||
> (见 `devdocs/06-大屏端设计.md` 9.1、`devdocs/07-管理面板设计.md` 9)。
|
||||
> 若将来对外分发,需逐字体复核许可:Noto / 思源黑体为 OFL,可自由分发;
|
||||
> **MiSans 为厂商许可,公开分发前必须另行确认**。OFL 字体保留其原始版权声明,
|
||||
> 本目录未附 LICENSE 副本,需要时从 `~/Fonts/<字体目录>/LICENSE` 取回。
|
||||
|
||||
## 子集化命令
|
||||
|
||||
依赖 `fonttools` + `brotli`(生成 woff2 必需):
|
||||
|
||||
```bash
|
||||
pip install fonttools brotli
|
||||
# 系统 Python 受 PEP 668 保护时,用带系统包的虚拟环境:
|
||||
python3 -m venv --system-site-packages ~/.tmp/fontenv
|
||||
~/.tmp/fontenv/bin/pip install brotli
|
||||
PYTHON=~/.tmp/fontenv/bin/python vendor/fonts/tools/subset-fonts.sh
|
||||
```
|
||||
|
||||
脚本会:生成字符集 → 逐字体跑 `fontTools.subset` → 重新生成 `manifest.json`。
|
||||
|
||||
**子集字符集**:ASCII 可打印字符 + GB2312 全部合法码位(一级 3755 + 二级 3008 汉字,
|
||||
含全角标点、希腊/俄文、全角数字)+ 常用中文标点与数字符号,共 **7553 字符**。
|
||||
|
||||
**子集化参数**:
|
||||
|
||||
```bash
|
||||
python -m fontTools.subset <源字体> \
|
||||
--flavor=woff2 \
|
||||
--layout-features='kern,liga,clig,calt,ccmp,locl,mark,mkmk' \
|
||||
--name-IDs='*' --name-languages='*' \
|
||||
--recommended-glyphs --drop-tables+=DSIG \
|
||||
--text="$(字符集)" --output-file=<id>-<weight>.woff2
|
||||
```
|
||||
|
||||
去掉 CJK 竖排(`vert`/`vrt2`)等用不到的 OpenType 特性以压体积;保留 `kern`/`liga` 等排版特性。
|
||||
|
||||
## 如何使用
|
||||
|
||||
`web/src/shared/styles/fonts.css` 为每套字体写好 `@font-face`(`font-display: swap`)
|
||||
与 `--font-<id>` 变量。在全局样式入口加一行即可生效:
|
||||
|
||||
```css
|
||||
@import './fonts.css';
|
||||
```
|
||||
|
||||
CSS 里的 `url()` 是相对 `web/src/shared/styles/` 的 `../../../../vendor/fonts/...`。
|
||||
Vite 构建时会把这些 woff2 作为资源打进产物(输出到 `server/internal/webui/assets/`),
|
||||
运行时不再依赖仓库外的路径。
|
||||
|
||||
## 如何新增字体
|
||||
|
||||
1. 把源字体(`.otf`/`.ttf`)放到 `~/Fonts/<目录>/`(不要直接复制进仓库)。
|
||||
2. 在 `tools/fonts.conf` 追加一行:`id|显示名|font-family|分类|授权|来源说明|Regular 源文件|Bold 源文件`。
|
||||
3. 重跑 `PYTHON=... vendor/fonts/tools/subset-fonts.sh`,它会生成 `<id>-regular.woff2`、
|
||||
`<id>-bold.woff2` 并更新 `manifest.json`。
|
||||
4. 在 `web/src/shared/styles/fonts.css` 补对应 `@font-face` 和 `--font-<id>` 变量。
|
||||
5. 检查单套合计 ≤ 4 MB;超了就精简字符集或换更轻的字重。
|
||||
|
||||
## 已知限制
|
||||
|
||||
- MiSans 缺 `・`(U+30FB,日文片假名中点,GB2312 内含),其余 7552 个字符齐全;
|
||||
中文场景无影响。其余三套字符集全覆盖。
|
||||
- 只做 Regular + Bold 两档;如需 Medium/Light,按上节流程加字重(需扩展 `fonts.conf` 的字段格式)。
|
||||
- 字体文件已子集化,**不要**用原始 `~/Fonts` 大字体覆盖本目录文件。
|
||||
Vendored
+139
@@ -0,0 +1,139 @@
|
||||
{
|
||||
"version": 1,
|
||||
"generatedAt": "2026-09-09",
|
||||
"generator": "vendor/fonts/tools/subset-fonts.sh",
|
||||
"subset": {
|
||||
"charset": "ASCII + GB2312 一级/二级汉字 + 中文标点 + 数字符号",
|
||||
"charCount": 7553,
|
||||
"format": "woff2",
|
||||
"layoutFeatures": "kern,liga,clig,calt,ccmp,locl,mark,mkmk"
|
||||
},
|
||||
"totalBytes": 11434920,
|
||||
"totalSize": "10.91 MB",
|
||||
"fonts": [
|
||||
{
|
||||
"id": "noto-sans",
|
||||
"displayName": "Noto Sans SC",
|
||||
"fontFamily": "Noto Sans SC",
|
||||
"cssVar": "--font-noto-sans",
|
||||
"category": "sans-serif",
|
||||
"license": "OFL-1.1",
|
||||
"source": "Google Noto Sans SC (noto-sans/sc)",
|
||||
"totalBytes": 2849388,
|
||||
"totalSize": "2.72 MB",
|
||||
"weights": [
|
||||
{
|
||||
"weight": 400,
|
||||
"style": "normal",
|
||||
"file": "noto-sans-regular.woff2",
|
||||
"path": "vendor/fonts/noto-sans-regular.woff2",
|
||||
"bytes": 1399176,
|
||||
"size": "1.33 MB",
|
||||
"sha256": "a126c29405324acddf2cf3d47ba76762f1fa39cd7b1c0be6dc98f4fd26cfafb8"
|
||||
},
|
||||
{
|
||||
"weight": 700,
|
||||
"style": "normal",
|
||||
"file": "noto-sans-bold.woff2",
|
||||
"path": "vendor/fonts/noto-sans-bold.woff2",
|
||||
"bytes": 1450212,
|
||||
"size": "1.38 MB",
|
||||
"sha256": "206e958255a9e961243fbbd44c52ba05fb166e452de315fa3967e3c78bb8d499"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "noto-serif",
|
||||
"displayName": "Noto Serif SC",
|
||||
"fontFamily": "Noto Serif SC",
|
||||
"cssVar": "--font-noto-serif",
|
||||
"category": "serif",
|
||||
"license": "OFL-1.1",
|
||||
"source": "Google Noto Serif SC (noto-serif/sc/SubsetOTF/SC)",
|
||||
"totalBytes": 3887184,
|
||||
"totalSize": "3.71 MB",
|
||||
"weights": [
|
||||
{
|
||||
"weight": 400,
|
||||
"style": "normal",
|
||||
"file": "noto-serif-regular.woff2",
|
||||
"path": "vendor/fonts/noto-serif-regular.woff2",
|
||||
"bytes": 1892872,
|
||||
"size": "1.81 MB",
|
||||
"sha256": "666a88ddc3f50f8ae999991d9ebd5eeb58ad267f6f9b38b75a580599e0fe72c2"
|
||||
},
|
||||
{
|
||||
"weight": 700,
|
||||
"style": "normal",
|
||||
"file": "noto-serif-bold.woff2",
|
||||
"path": "vendor/fonts/noto-serif-bold.woff2",
|
||||
"bytes": 1994312,
|
||||
"size": "1.90 MB",
|
||||
"sha256": "7a8fc67787af8d4a8ff88b63f672b888ff29746ad08af0c4b4b31273d15ffce3"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "misans",
|
||||
"displayName": "MiSans",
|
||||
"fontFamily": "MiSans",
|
||||
"cssVar": "--font-misans",
|
||||
"category": "sans-serif",
|
||||
"license": "MiSans Font License",
|
||||
"source": "小米 MiSans (MiSans/ttf)",
|
||||
"totalBytes": 1841888,
|
||||
"totalSize": "1.76 MB",
|
||||
"weights": [
|
||||
{
|
||||
"weight": 400,
|
||||
"style": "normal",
|
||||
"file": "misans-regular.woff2",
|
||||
"path": "vendor/fonts/misans-regular.woff2",
|
||||
"bytes": 910956,
|
||||
"size": "890 KB",
|
||||
"sha256": "ca7c73c33dde913833012f16334e59d8f6a3cdea856e537a52ff27b95ab01493"
|
||||
},
|
||||
{
|
||||
"weight": 700,
|
||||
"style": "normal",
|
||||
"file": "misans-bold.woff2",
|
||||
"path": "vendor/fonts/misans-bold.woff2",
|
||||
"bytes": 930932,
|
||||
"size": "909 KB",
|
||||
"sha256": "18119cd03ed6931c339d8f7cfc4bcf2c7258ee6a9e2191b43d75dcc26ef64f41"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "source-han-sans",
|
||||
"displayName": "思源黑体 Source Han Sans CN",
|
||||
"fontFamily": "Source Han Sans CN",
|
||||
"cssVar": "--font-source-han-sans",
|
||||
"category": "sans-serif",
|
||||
"license": "OFL-1.1",
|
||||
"source": "Adobe Source Han Sans CN (思源黑体)",
|
||||
"totalBytes": 2856460,
|
||||
"totalSize": "2.72 MB",
|
||||
"weights": [
|
||||
{
|
||||
"weight": 400,
|
||||
"style": "normal",
|
||||
"file": "source-han-sans-regular.woff2",
|
||||
"path": "vendor/fonts/source-han-sans-regular.woff2",
|
||||
"bytes": 1399540,
|
||||
"size": "1.33 MB",
|
||||
"sha256": "f85482af4eb07d66df271e475f00484f764326c1cb4fb9b65c90589bc4588875"
|
||||
},
|
||||
{
|
||||
"weight": 700,
|
||||
"style": "normal",
|
||||
"file": "source-han-sans-bold.woff2",
|
||||
"path": "vendor/fonts/source-han-sans-bold.woff2",
|
||||
"bytes": 1456920,
|
||||
"size": "1.39 MB",
|
||||
"sha256": "3e2e3f54161b8a96c59001d40855835539ef97f6c80c58cdb93fcc4f2baae4dd"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
+12
@@ -0,0 +1,12 @@
|
||||
# 字体清单(subset-fonts.sh 与 gen-manifest.py 的唯一数据源)
|
||||
#
|
||||
# 字段(| 分隔):
|
||||
# id | 显示名 | font-family | 分类 | 授权 | 来源说明 | Regular 源文件 | Bold 源文件
|
||||
#
|
||||
# 源文件相对 $FONT_SRC(默认 ~/Fonts)。
|
||||
# 新增字体:在下面加一行,然后重跑
|
||||
# PYTHON=<带 fonttools+brotli 的 python> vendor/fonts/tools/subset-fonts.sh
|
||||
noto-sans|Noto Sans SC|Noto Sans SC|sans-serif|OFL-1.1|Google Noto Sans SC (noto-sans/sc)|noto-sans/sc/NotoSansSC-Regular.otf|noto-sans/sc/NotoSansSC-Bold.otf
|
||||
noto-serif|Noto Serif SC|Noto Serif SC|serif|OFL-1.1|Google Noto Serif SC (noto-serif/sc/SubsetOTF/SC)|noto-serif/sc/SubsetOTF/SC/NotoSerifSC-Regular.otf|noto-serif/sc/SubsetOTF/SC/NotoSerifSC-Bold.otf
|
||||
misans|MiSans|MiSans|sans-serif|MiSans Font License|小米 MiSans (MiSans/ttf)|MiSans/ttf/MiSans-Regular.ttf|MiSans/ttf/MiSans-Bold.ttf
|
||||
source-han-sans|思源黑体 Source Han Sans CN|Source Han Sans CN|sans-serif|OFL-1.1|Adobe Source Han Sans CN (思源黑体)|思源黑体/SourceHanSansCN-Regular.otf|思源黑体/SourceHanSansCN-Bold.otf
|
||||
Vendored
+132
@@ -0,0 +1,132 @@
|
||||
#!/usr/bin/env python3
|
||||
"""生成 vendor/fonts/manifest.json。
|
||||
|
||||
数据源:vendor/fonts/tools/fonts.conf(字体元数据)+ vendor/fonts/*.woff2(实际产物)。
|
||||
每次跑完 subset-fonts.sh 会自动调用;也可单独运行:
|
||||
python3 vendor/fonts/tools/gen-manifest.py
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
from datetime import date
|
||||
from pathlib import Path
|
||||
|
||||
HERE = Path(__file__).resolve().parent
|
||||
OUT_DIR = HERE.parent
|
||||
ROOT = OUT_DIR.parent.parent # 仓库根,用于生成 vendor/fonts/... 形式的相对路径
|
||||
CONF = HERE / "fonts.conf"
|
||||
|
||||
WEIGHTS = (("regular", 400), ("bold", 700))
|
||||
SUBSET_DESC = "ASCII + GB2312 一级/二级汉字 + 中文标点 + 数字符号"
|
||||
|
||||
|
||||
def charset_count() -> int:
|
||||
"""复用 subset-fonts.sh 的字符集生成逻辑,保证清单与产物一致。"""
|
||||
code = (
|
||||
"chars=set()\n"
|
||||
"for c in range(0x20,0x7F): chars.add(chr(c))\n"
|
||||
"for hi in range(0xA1,0xFF):\n"
|
||||
" for lo in range(0xA1,0xFF):\n"
|
||||
" try: chars.add(bytes((hi,lo)).decode('gb2312'))\n"
|
||||
" except UnicodeDecodeError: pass\n"
|
||||
"chars.update(' ·—…‘’“”※→←↑↓√×÷±≈≠≤≥∞°℃℉¥€£©®™№§¶†‡•‰′″〇')\n"
|
||||
"chars.update('「」『』【】〔〕〖〗《》〈〉')\n"
|
||||
"chars.update('0123456789')\n"
|
||||
"chars.update('!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~')\n"
|
||||
"print(len(chars))\n"
|
||||
)
|
||||
return int(subprocess.run([sys.executable, "-c", code], capture_output=True, text=True, check=True).stdout)
|
||||
|
||||
|
||||
def human(n: int) -> str:
|
||||
return f"{n / 1024 / 1024:.2f} MB" if n >= 1024 * 1024 else f"{n / 1024:.0f} KB"
|
||||
|
||||
|
||||
def read_conf() -> list[dict[str, str]]:
|
||||
rows = []
|
||||
for line in CONF.read_text(encoding="utf-8").splitlines():
|
||||
line = line.strip()
|
||||
if not line or line.startswith("#"):
|
||||
continue
|
||||
fid, name, family, category, license_, source, reg, bold = (p.strip() for p in line.split("|"))
|
||||
rows.append(
|
||||
{
|
||||
"id": fid,
|
||||
"displayName": name,
|
||||
"fontFamily": family,
|
||||
"category": category,
|
||||
"license": license_,
|
||||
"source": source,
|
||||
"regular": reg,
|
||||
"bold": bold,
|
||||
}
|
||||
)
|
||||
return rows
|
||||
|
||||
|
||||
def main() -> int:
|
||||
fonts = []
|
||||
grand_total = 0
|
||||
for row in read_conf():
|
||||
weights = []
|
||||
font_total = 0
|
||||
for weight_name, weight_class in WEIGHTS:
|
||||
path = OUT_DIR / f"{row['id']}-{weight_name}.woff2"
|
||||
if not path.is_file():
|
||||
print(f"缺少产物: {path},请先运行 subset-fonts.sh", file=sys.stderr)
|
||||
return 1
|
||||
data = path.read_bytes()
|
||||
size = len(data)
|
||||
font_total += size
|
||||
weights.append(
|
||||
{
|
||||
"weight": weight_class,
|
||||
"style": "normal",
|
||||
"file": path.name,
|
||||
"path": str(path.relative_to(ROOT)),
|
||||
"bytes": size,
|
||||
"size": human(size),
|
||||
"sha256": hashlib.sha256(data).hexdigest(),
|
||||
}
|
||||
)
|
||||
grand_total += font_total
|
||||
fonts.append(
|
||||
{
|
||||
"id": row["id"],
|
||||
"displayName": row["displayName"],
|
||||
"fontFamily": row["fontFamily"],
|
||||
"cssVar": f"--font-{row['id']}",
|
||||
"category": row["category"],
|
||||
"license": row["license"],
|
||||
"source": row["source"],
|
||||
"totalBytes": font_total,
|
||||
"totalSize": human(font_total),
|
||||
"weights": weights,
|
||||
}
|
||||
)
|
||||
|
||||
manifest = {
|
||||
"version": 1,
|
||||
"generatedAt": date.today().isoformat(),
|
||||
"generator": "vendor/fonts/tools/subset-fonts.sh",
|
||||
"subset": {
|
||||
"charset": SUBSET_DESC,
|
||||
"charCount": charset_count(),
|
||||
"format": "woff2",
|
||||
"layoutFeatures": "kern,liga,clig,calt,ccmp,locl,mark,mkmk",
|
||||
},
|
||||
"totalBytes": grand_total,
|
||||
"totalSize": human(grand_total),
|
||||
"fonts": fonts,
|
||||
}
|
||||
out = OUT_DIR / "manifest.json"
|
||||
out.write_text(json.dumps(manifest, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
|
||||
print(f"manifest.json: {len(fonts)} 套字体,{len(fonts) * 2} 个文件,合计 {human(grand_total)}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
#!/usr/bin/env python3
|
||||
"""把子集字体内部的 name 表 / OS2 字重统一成 CSS 期望的规范值。
|
||||
|
||||
为什么需要:思源黑体的老版本 OTF 把每个字重写成独立族名
|
||||
(`Source Han Sans CN Regular` / `Source Han Sans CN Bold`),
|
||||
MiSans 的 usWeightClass 是 330/630 这类非标准值。
|
||||
@font-face 的 `font-family` 描述符虽然能屏蔽内部族名,但保持一致更省心,
|
||||
也避免字体被单独安装/引用时族名对不上。
|
||||
|
||||
用法(由 subset-fonts.sh 调用):
|
||||
python3 vendor/fonts/tools/normalize-names.py
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from fontTools.ttLib import TTFont
|
||||
|
||||
HERE = Path(__file__).resolve().parent
|
||||
OUT_DIR = HERE.parent
|
||||
CONF = HERE / "fonts.conf"
|
||||
|
||||
WEIGHTS = (("regular", "Regular", 400), ("bold", "Bold", 700))
|
||||
STALE_NAME_IDS = (1, 2, 3, 4, 6, 16, 17, 21, 22)
|
||||
PLATFORMS = ((3, 1, 0x409), (1, 0, 0)) # Windows / Mac,英文
|
||||
|
||||
|
||||
def set_name(name, name_id: int, value: str) -> None:
|
||||
for platform_id, plat_enc_id, lang_id in PLATFORMS:
|
||||
name.setName(value, name_id, platform_id, plat_enc_id, lang_id)
|
||||
|
||||
|
||||
def normalize(path: Path, family: str, style: str, weight: int) -> None:
|
||||
font = TTFont(path)
|
||||
name = font["name"]
|
||||
for record in list(name.names):
|
||||
if record.nameID in STALE_NAME_IDS:
|
||||
name.removeNames(record.nameID, record.platformID, record.platEncID, record.langID)
|
||||
|
||||
full_name = family if style == "Regular" else f"{family} {style}"
|
||||
set_name(name, 1, family) # family
|
||||
set_name(name, 2, style) # subfamily
|
||||
set_name(name, 3, f"{full_name}:subset") # unique id
|
||||
set_name(name, 4, full_name) # full name
|
||||
set_name(name, 6, full_name.replace(" ", "")) # postscript name
|
||||
set_name(name, 16, family) # typographic family
|
||||
set_name(name, 17, style) # typographic subfamily
|
||||
|
||||
os2 = font["OS/2"]
|
||||
os2.usWeightClass = weight
|
||||
if weight >= 700:
|
||||
os2.fsSelection = (os2.fsSelection & ~0x40) | 0x20 # BOLD
|
||||
font["head"].macStyle |= 0x01
|
||||
else:
|
||||
os2.fsSelection = (os2.fsSelection & ~0x20) | 0x40 # REGULAR
|
||||
font["head"].macStyle &= ~0x01
|
||||
|
||||
font.flavor = "woff2"
|
||||
font.save(path)
|
||||
font.close()
|
||||
|
||||
|
||||
def main() -> int:
|
||||
for line in CONF.read_text(encoding="utf-8").splitlines():
|
||||
line = line.strip()
|
||||
if not line or line.startswith("#"):
|
||||
continue
|
||||
fid, _, family = [p.strip() for p in line.split("|")][:3]
|
||||
for weight_name, style, weight_class in WEIGHTS:
|
||||
path = OUT_DIR / f"{fid}-{weight_name}.woff2"
|
||||
if not path.is_file():
|
||||
print(f"缺少产物: {path}", file=sys.stderr)
|
||||
return 1
|
||||
normalize(path, family, style, weight_class)
|
||||
print(f" {path.name:32s} -> {family} / {style} ({weight_class})")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
#!/usr/bin/env bash
|
||||
# 字体子集化脚本 —— 把 ~/Fonts 下的中文字体裁剪成 woff2 并写入 vendor/fonts/
|
||||
#
|
||||
# 用途:离线部署,字体必须随仓库分发,禁止 CDN。
|
||||
# 产物:vendor/fonts/<id>-<weight>.woff2 + vendor/fonts/manifest.json
|
||||
#
|
||||
# 依赖:python3 + fonttools + brotli
|
||||
# pip install fonttools brotli
|
||||
# # 系统 Python 受 PEP 668 保护时用虚拟环境:
|
||||
# # python3 -m venv --system-site-packages ~/.tmp/fontenv
|
||||
# # ~/.tmp/fontenv/bin/pip install brotli
|
||||
# # PYTHON=~/.tmp/fontenv/bin/python vendor/fonts/tools/subset-fonts.sh
|
||||
#
|
||||
# 用法:
|
||||
# vendor/fonts/tools/subset-fonts.sh
|
||||
# FONT_SRC=~/Fonts PYTHON=python3 vendor/fonts/tools/subset-fonts.sh
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
OUT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
FONT_SRC="${FONT_SRC:-$HOME/Fonts}"
|
||||
PYTHON="${PYTHON:-python3}"
|
||||
FONTS_CONF="$SCRIPT_DIR/fonts.conf"
|
||||
|
||||
# 子集字符集:ASCII + GB2312 一级/二级汉字 + 中文标点 + 数字/全角符号
|
||||
CHARSET="$("$PYTHON" - <<'PY'
|
||||
import sys
|
||||
|
||||
chars = set()
|
||||
# 1) ASCII 可打印字符
|
||||
for c in range(0x20, 0x7F):
|
||||
chars.add(chr(c))
|
||||
# 2) GB2312 全部合法双字节码位(一级 3755 + 二级 3008 汉字,及全角标点/希腊/俄文等)
|
||||
for hi in range(0xA1, 0xFF):
|
||||
for lo in range(0xA1, 0xFF):
|
||||
try:
|
||||
chars.add(bytes((hi, lo)).decode("gb2312"))
|
||||
except UnicodeDecodeError:
|
||||
pass
|
||||
# 3) 常用中文标点 / 数字符号补充
|
||||
chars.update(
|
||||
" ·—…‘’“”※→←↑↓√×÷±≈≠≤≥∞°℃℉¥€£©®™№§¶†‡•‰′″〇"
|
||||
"「」『』【】〔〕〖〗《》〈〉"
|
||||
"0123456789"
|
||||
"!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~"
|
||||
)
|
||||
sys.stdout.write("".join(sorted(chars)))
|
||||
PY
|
||||
)"
|
||||
CHAR_COUNT="$(printf '%s' "$CHARSET" | "$PYTHON" -c 'import sys; print(len(sys.stdin.read()))')"
|
||||
|
||||
# 子集化参数:
|
||||
# --flavor=woff2 输出 woff2(需 brotli)
|
||||
# --layout-features 保留字距/连字等,丢弃 CJK 竖排等无用特性以压体积
|
||||
# --name-IDs='*' 保留完整 name 表(含本地化族名)
|
||||
# --recommended-glyphs 保留 .notdef/.null 等推荐字形
|
||||
# --drop-tables+=DSIG 丢弃无用的数字签名表
|
||||
SUBSET_OPTS=(
|
||||
--flavor=woff2
|
||||
--layout-features='kern,liga,clig,calt,ccmp,locl,mark,mkmk'
|
||||
--name-IDs='*'
|
||||
--name-languages='*'
|
||||
--recommended-glyphs
|
||||
--drop-tables+=DSIG
|
||||
)
|
||||
|
||||
mkdir -p "$OUT_DIR"
|
||||
echo "charset: ${CHAR_COUNT} 个字符(ASCII + GB2312 一级/二级 + 中文标点 + 数字符号)"
|
||||
|
||||
while IFS='|' read -r id name family category license source_note reg_src bold_src; do
|
||||
case "$id" in ''|'#'*) continue ;; esac
|
||||
for pair in "regular:400:$reg_src" "bold:700:$bold_src"; do
|
||||
IFS=':' read -r weight_name weight_class src_rel <<<"$pair"
|
||||
src="$FONT_SRC/$src_rel"
|
||||
out="$OUT_DIR/$id-$weight_name.woff2"
|
||||
[ -f "$src" ] || { echo "缺少源字体: $src" >&2; exit 1; }
|
||||
printf ' %-26s %s -> %s\n' "$id-$weight_name" "$(basename "$src")" "$(basename "$out")"
|
||||
"$PYTHON" -m fontTools.subset "$src" "${SUBSET_OPTS[@]}" \
|
||||
--text="$CHARSET" --output-file="$out"
|
||||
done
|
||||
done < "$FONTS_CONF"
|
||||
|
||||
"$PYTHON" "$SCRIPT_DIR/normalize-names.py"
|
||||
"$PYTHON" "$SCRIPT_DIR/gen-manifest.py"
|
||||
|
||||
echo "完成。产物目录:$OUT_DIR"
|
||||
ls -la "$OUT_DIR"/*.woff2
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
/* ═══════════════════════════════════════════
|
||||
MIUIX CONSOLE — Accordion / Collapse Component
|
||||
═══════════════════════════════════════════ */
|
||||
|
||||
.mx-accordion{
|
||||
display:flex;flex-direction:column;
|
||||
border:1px solid var(--mx-divider);
|
||||
border-radius:var(--mx-r);
|
||||
overflow:hidden;
|
||||
}
|
||||
|
||||
/* Item */
|
||||
.mx-accordion-item{
|
||||
border-bottom:1px solid var(--mx-divider);
|
||||
}
|
||||
.mx-accordion-item:last-child{border-bottom:none}
|
||||
|
||||
/* Header / Trigger */
|
||||
.mx-accordion-header{
|
||||
display:flex;align-items:center;gap:10px;
|
||||
padding:14px 16px;
|
||||
cursor:pointer;
|
||||
font-size:14px;font-weight:600;
|
||||
color:var(--mx-text);
|
||||
transition:all var(--mx-d1) var(--mx-ease);
|
||||
-webkit-tap-highlight-color:transparent;
|
||||
}
|
||||
.mx-accordion-header:hover{background:var(--mx-s-hover)}
|
||||
.mx-accordion-header:active{background:var(--mx-s-active)}
|
||||
|
||||
/* Icon slot */
|
||||
.mx-accordion-header svg{flex-shrink:0;color:var(--mx-t2)}
|
||||
.mx-accordion-header .mx-accordion-title{flex:1}
|
||||
|
||||
/* Arrow */
|
||||
.mx-accordion-arrow{
|
||||
color:var(--mx-t3);flex-shrink:0;
|
||||
transition:transform var(--mx-d2) var(--mx-ease);
|
||||
}
|
||||
.mx-accordion-item.open .mx-accordion-arrow{transform:rotate(180deg)}
|
||||
|
||||
/* Content */
|
||||
.mx-accordion-content{
|
||||
max-height:0;overflow:hidden;
|
||||
transition:max-height var(--mx-d3) var(--mx-ease);
|
||||
}
|
||||
.mx-accordion-item.open .mx-accordion-content{
|
||||
max-height:500px;
|
||||
}
|
||||
.mx-accordion-body{
|
||||
padding:0 16px 16px;
|
||||
font-size:13px;line-height:1.6;
|
||||
color:var(--mx-text-on-surface);
|
||||
}
|
||||
|
||||
/* Card variant — separate cards */
|
||||
.mx-accordion-card{border:none;gap:8px;background:none}
|
||||
.mx-accordion-card .mx-accordion-item{
|
||||
background:var(--mx-s2);
|
||||
border:1px solid var(--mx-divider);
|
||||
border-radius:var(--mx-r);
|
||||
overflow:hidden;
|
||||
}
|
||||
.mx-accordion-card .mx-accordion-item:last-child{border-bottom:1px solid var(--mx-divider)}
|
||||
|
||||
/* Flush variant — no borders */
|
||||
.mx-accordion-flush{border:none;border-radius:0}
|
||||
.mx-accordion-flush .mx-accordion-item{border:none}
|
||||
.mx-accordion-flush .mx-accordion-header{padding:12px 0}
|
||||
|
||||
/* Disabled */
|
||||
.mx-accordion-header.disabled{
|
||||
opacity:0.4;cursor:not-allowed;pointer-events:none;
|
||||
}
|
||||
|
||||
/* Mobile */
|
||||
@media(max-width:767px){
|
||||
.mx-accordion-header{padding:14px 14px;min-height:48px}
|
||||
.mx-accordion-body{font-size:14px}
|
||||
.mx-accordion-card .mx-accordion-item{border-radius:var(--mx-r-sm)}
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
/* ═══════════════════════════════════════════
|
||||
MIUIX CONSOLE — Activity List Component
|
||||
═══════════════════════════════════════════ */
|
||||
|
||||
.mx-activity-item{
|
||||
display:flex;align-items:flex-start;gap:12px;
|
||||
padding:13px 0;
|
||||
border-bottom:1px solid var(--mx-divider);
|
||||
transition:all var(--mx-d1);
|
||||
}
|
||||
.mx-activity-item:last-child{border-bottom:none}
|
||||
.mx-activity-item:active{
|
||||
background:var(--mx-s-active);
|
||||
margin:0 -16px;padding:13px 16px;border-radius:var(--mx-r-sm);
|
||||
}
|
||||
|
||||
.mx-activity-dot{
|
||||
width:8px;height:8px;border-radius:50%;
|
||||
margin-top:6px;flex-shrink:0;
|
||||
transition:transform var(--mx-d2) var(--mx-spring);
|
||||
}
|
||||
.mx-activity-item:hover .mx-activity-dot{transform:scale(1.5)}
|
||||
|
||||
.mx-activity-text{font-size:13px;line-height:1.5}
|
||||
.mx-activity-text b{font-weight:600;color:var(--mx-text)}
|
||||
.mx-activity-time{font-size:11px;color:var(--mx-t3);margin-top:3px}
|
||||
|
||||
/* ═══════════════════════════════════════════
|
||||
MIUIX CONSOLE — Chart Bar Component
|
||||
═══════════════════════════════════════════ */
|
||||
|
||||
.mx-chart{display:flex;align-items:flex-end;gap:5px;height:160px}
|
||||
.mx-chart-bar-col{
|
||||
flex:1;display:flex;flex-direction:column;
|
||||
align-items:center;gap:6px;min-width:0;
|
||||
}
|
||||
.mx-chart-bar{
|
||||
width:100%;border-radius:7px 7px 3px 3px;
|
||||
background:var(--mx-primary);
|
||||
transform-origin:bottom;
|
||||
transition:filter var(--mx-d1),transform var(--mx-d1);
|
||||
}
|
||||
.mx-chart-bar.alt{background:var(--mx-s4)}
|
||||
.mx-chart-bar:active{filter:brightness(1.2);transform:scaleY(1.04)}
|
||||
|
||||
.mx-chart-label{
|
||||
font-size:10px;color:var(--mx-t3);
|
||||
font-variant-numeric:tabular-nums;
|
||||
}
|
||||
|
||||
/* Responsive chart height */
|
||||
@media(min-width:768px){.mx-chart{height:180px}}
|
||||
@media(min-width:1024px){.mx-chart{height:200px}}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
/* ═══════════════════════════════════════════
|
||||
MIUIX CONSOLE — Avatar Component
|
||||
═══════════════════════════════════════════ */
|
||||
|
||||
/* Base avatar (extend existing .mx-avatar) */
|
||||
.mx-avatar-img{
|
||||
width:32px;height:32px;border-radius:50%;
|
||||
object-fit:cover;flex-shrink:0;
|
||||
border:2px solid var(--mx-s2);
|
||||
}
|
||||
|
||||
/* Sizes */
|
||||
.mx-avatar-xs{width:24px;height:24px;font-size:10px}
|
||||
.mx-avatar-sm{width:28px;height:28px;font-size:11px}
|
||||
.mx-avatar-md{width:36px;height:36px;font-size:14px}
|
||||
.mx-avatar-lg{width:44px;height:44px;font-size:16px}
|
||||
.mx-avatar-xl{width:56px;height:56px;font-size:20px}
|
||||
|
||||
/* Avatar Group */
|
||||
.mx-avatar-group{
|
||||
display:flex;
|
||||
}
|
||||
.mx-avatar-group .mx-avatar,
|
||||
.mx-avatar-group .mx-avatar-img{
|
||||
margin-left:-8px;
|
||||
border:2px solid var(--mx-s2);
|
||||
transition:transform var(--mx-d2) var(--mx-spring);
|
||||
}
|
||||
.mx-avatar-group .mx-avatar:first-child,
|
||||
.mx-avatar-group .mx-avatar-img:first-child{margin-left:0}
|
||||
.mx-avatar-group .mx-avatar:hover,
|
||||
.mx-avatar-group .mx-avatar-img:hover{
|
||||
transform:translateY(-2px);
|
||||
z-index:1;
|
||||
}
|
||||
|
||||
/* Overflow counter */
|
||||
.mx-avatar-overflow{
|
||||
width:32px;height:32px;
|
||||
border-radius:50%;
|
||||
background:var(--mx-s3);
|
||||
border:2px solid var(--mx-s2);
|
||||
display:flex;align-items:center;justify-content:center;
|
||||
font-size:11px;font-weight:700;
|
||||
color:var(--mx-t2);
|
||||
margin-left:-8px;
|
||||
}
|
||||
|
||||
/* Status dot */
|
||||
.mx-avatar-status{
|
||||
position:relative;
|
||||
}
|
||||
.mx-avatar-status::after{
|
||||
content:'';position:absolute;
|
||||
bottom:0;right:0;
|
||||
width:10px;height:10px;
|
||||
border-radius:50%;
|
||||
border:2px solid var(--mx-s2);
|
||||
}
|
||||
.mx-avatar-status.online::after{background:var(--mx-green)}
|
||||
.mx-avatar-status.busy::after{background:var(--mx-red)}
|
||||
.mx-avatar-status.away::after{background:var(--mx-amber)}
|
||||
.mx-avatar-status.offline::after{background:var(--mx-t3)}
|
||||
|
||||
/* Mobile */
|
||||
@media(max-width:767px){
|
||||
.mx-avatar-group .mx-avatar,
|
||||
.mx-avatar-group .mx-avatar-img{margin-left:-10px}
|
||||
.mx-avatar-overflow{width:28px;height:28px;font-size:10px}
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/* ═══════════════════════════════════════════
|
||||
MIUIX CONSOLE — Badge & Tag Component
|
||||
Miuix capsule shape badges
|
||||
═══════════════════════════════════════════ */
|
||||
|
||||
.mx-badge{
|
||||
display:inline-flex;align-items:center;gap:5px;
|
||||
padding:3px 10px;
|
||||
border-radius:var(--mx-r-pill);
|
||||
font-size:12px;font-weight:600;
|
||||
transition:filter var(--mx-d1);
|
||||
}
|
||||
.mx-badge:hover{filter:brightness(1.15)}
|
||||
|
||||
.mx-badge::before{
|
||||
content:'';width:6px;height:6px;
|
||||
border-radius:50%;flex-shrink:0;
|
||||
}
|
||||
|
||||
/* Variants */
|
||||
.mx-badge-success{background:rgba(52,211,153,0.1);color:var(--mx-green)}
|
||||
.mx-badge-success::before{background:var(--mx-green);animation:mx-pulse 2s infinite}
|
||||
|
||||
.mx-badge-warning{background:rgba(251,191,36,0.1);color:var(--mx-amber)}
|
||||
.mx-badge-warning::before{background:var(--mx-amber)}
|
||||
|
||||
.mx-badge-error{background:rgba(248,113,113,0.1);color:var(--mx-red)}
|
||||
.mx-badge-error::before{background:var(--mx-red);animation:mx-pulse 1.5s infinite}
|
||||
|
||||
.mx-badge-info{background:rgba(96,165,250,0.1);color:var(--mx-blue)}
|
||||
.mx-badge-info::before{background:var(--mx-blue)}
|
||||
|
||||
.mx-badge-neutral{background:rgba(139,149,165,0.1);color:var(--mx-t2)}
|
||||
.mx-badge-neutral::before{background:var(--mx-t2)}
|
||||
|
||||
/* Dot-only badge */
|
||||
.mx-dot{
|
||||
width:8px;height:8px;
|
||||
border-radius:50%;
|
||||
flex-shrink:0;
|
||||
}
|
||||
|
||||
/* Count badge */
|
||||
.mx-count{
|
||||
display:inline-flex;align-items:center;justify-content:center;
|
||||
min-width:18px;height:18px;padding:0 5px;
|
||||
border-radius:var(--mx-r-pill);
|
||||
font-size:10px;font-weight:700;
|
||||
background:var(--mx-primary);color:#fff;
|
||||
}
|
||||
|
||||
@keyframes mx-pulse{
|
||||
0%,100%{opacity:1;transform:scale(1)}
|
||||
50%{opacity:0.5;transform:scale(1.3)}
|
||||
}
|
||||
|
||||
/* Mobile */
|
||||
@media(max-width:767px){
|
||||
.mx-badge{padding:4px 12px;font-size:13px}
|
||||
.mx-count{min-width:20px;height:20px;font-size:11px}
|
||||
}
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
/* ═══════════════════════════════════════════
|
||||
MIUIX CONSOLE — Button Component
|
||||
═══════════════════════════════════════════ */
|
||||
|
||||
.mx-btn{
|
||||
display:inline-flex;align-items:center;justify-content:center;gap:6px;
|
||||
height:36px;padding:0 18px;
|
||||
border-radius:var(--mx-r-sm);
|
||||
font-size:13px;font-weight:600;
|
||||
cursor:pointer;
|
||||
transition:all var(--mx-d1) var(--mx-ease);
|
||||
-webkit-tap-highlight-color:transparent;
|
||||
position:relative;overflow:hidden;
|
||||
white-space:nowrap;
|
||||
}
|
||||
.mx-btn:active{transform:scale(0.95);box-shadow:inset 0 2px 4px rgba(0,0,0,0.2)}
|
||||
|
||||
/* Primary */
|
||||
.mx-btn-primary{
|
||||
background:var(--mx-primary);color:#fff;
|
||||
box-shadow:0 2px 8px rgba(76,139,245,0.2);
|
||||
}
|
||||
.mx-btn-primary:hover{
|
||||
background:var(--mx-primary-hover);
|
||||
box-shadow:0 4px 14px rgba(76,139,245,0.3);
|
||||
transform:translateY(-1px);
|
||||
}
|
||||
.mx-btn-primary:active{transform:scale(0.95) translateY(0)}
|
||||
|
||||
/* Secondary */
|
||||
.mx-btn-secondary{
|
||||
background:var(--mx-s3);color:var(--mx-text);
|
||||
border:1px solid var(--mx-border);
|
||||
}
|
||||
.mx-btn-secondary:hover{
|
||||
background:var(--mx-s4);
|
||||
border-color:var(--mx-t3);
|
||||
}
|
||||
|
||||
/* Ghost */
|
||||
.mx-btn-ghost{
|
||||
background:transparent;color:var(--mx-t2);
|
||||
}
|
||||
.mx-btn-ghost:hover{
|
||||
background:var(--mx-s-hover);color:var(--mx-text);
|
||||
}
|
||||
|
||||
/* Danger */
|
||||
.mx-btn-danger{
|
||||
background:var(--mx-red);color:#fff;
|
||||
}
|
||||
.mx-btn-danger:hover{
|
||||
filter:brightness(1.1);
|
||||
box-shadow:0 4px 14px rgba(248,113,113,0.25);
|
||||
}
|
||||
|
||||
/* Pill — Miuix style capsule button */
|
||||
.mx-btn-pill{
|
||||
border-radius:var(--mx-r-pill);
|
||||
height:32px;padding:0 14px;
|
||||
font-size:12px;
|
||||
}
|
||||
|
||||
/* Icon button */
|
||||
.mx-btn-icon{
|
||||
width:36px;height:36px;padding:0;
|
||||
border-radius:var(--mx-r-sm);
|
||||
}
|
||||
|
||||
/* Sizes */
|
||||
.mx-btn-sm{height:30px;padding:0 12px;font-size:12px;border-radius:var(--mx-r-xs)}
|
||||
.mx-btn-lg{height:42px;padding:0 22px;font-size:14px}
|
||||
|
||||
/* Disabled */
|
||||
.mx-btn[disabled]{
|
||||
opacity:0.4;cursor:not-allowed;pointer-events:none;
|
||||
}
|
||||
|
||||
/* Mobile: 加大触控区 */
|
||||
/* ═══ DARK MODE — button pressed inner shadow ═══ */
|
||||
[data-theme="dark"] .mx-btn:active{box-shadow:inset 0 2px 4px rgba(0,0,0,0.3)}
|
||||
|
||||
@media(max-width:767px){
|
||||
.mx-btn{height:40px;padding:0 20px;font-size:14px}
|
||||
.mx-btn-sm{height:36px;padding:0 14px;font-size:13px}
|
||||
.mx-btn-lg{height:46px;padding:0 24px;font-size:15px}
|
||||
.mx-btn-icon{width:40px;height:40px}
|
||||
.mx-btn-pill{height:34px;padding:0 16px;font-size:13px}
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
/* ═══════════════════════════════════════════
|
||||
MIUIX CONSOLE — Card Component
|
||||
对应 Miuix Card.kt
|
||||
CornerRadius = 16.dp, surfaceContainer 背景
|
||||
═══════════════════════════════════════════ */
|
||||
|
||||
.mx-card{
|
||||
background:var(--mx-s2);
|
||||
border-radius:var(--mx-r);
|
||||
overflow:hidden;
|
||||
box-shadow:var(--mx-sh1);
|
||||
transition:box-shadow var(--mx-d3) var(--mx-ease);
|
||||
}
|
||||
.mx-card:hover{
|
||||
box-shadow:var(--mx-sh2);
|
||||
transition-duration:var(--mx-d2);
|
||||
}
|
||||
|
||||
.mx-card-head{
|
||||
display:flex;align-items:center;justify-content:space-between;
|
||||
padding:12px 16px;
|
||||
border-bottom:1px solid var(--mx-divider);
|
||||
}
|
||||
.mx-card-title{font-size:15px;font-weight:700}
|
||||
|
||||
.mx-card-body{padding:16px}
|
||||
.mx-card-body > * + * { margin-top: 12px; }
|
||||
.mx-card-body > .mx-table-wrap { margin-top: 0; }
|
||||
.mx-card-body > .mx-chart { margin-top: 0; }
|
||||
|
||||
/* 可点击卡片 — Miuix BasicCard with press feedback */
|
||||
.mx-card-clickable{
|
||||
cursor:pointer;
|
||||
transition:box-shadow var(--mx-d3) var(--mx-ease),
|
||||
transform var(--mx-d3) var(--mx-ease);
|
||||
}
|
||||
.mx-card-clickable:hover{
|
||||
transition-duration:var(--mx-d2);
|
||||
}
|
||||
.mx-card-clickable:active{transform:scale(0.98)}
|
||||
|
||||
/* Mobile: 卡片内边距调整 */
|
||||
@media(max-width:767px){
|
||||
.mx-card-body{padding:14px}
|
||||
.mx-card-head{padding:12px 14px}
|
||||
}
|
||||
|
||||
/* Miuix: 顶部 accent 线 */
|
||||
.mx-card-accent{
|
||||
position:relative;overflow:hidden;
|
||||
}
|
||||
.mx-card-accent::before{
|
||||
content:'';position:absolute;top:0;left:0;right:0;height:2px;
|
||||
background:var(--mx-card-accent,var(--mx-primary));
|
||||
opacity:0;transition:opacity var(--mx-d2);
|
||||
}
|
||||
.mx-card-accent:hover::before{opacity:1}
|
||||
|
||||
/* Miuix: 右上角柔光晕 */
|
||||
.mx-card-accent::after{
|
||||
content:'';position:absolute;top:-40%;right:-20%;
|
||||
width:100px;height:100px;
|
||||
background:var(--mx-card-accent,var(--mx-primary));
|
||||
border-radius:50%;opacity:0.04;
|
||||
transition:opacity var(--mx-d2);
|
||||
}
|
||||
.mx-card-accent:hover::after{opacity:0.08}
|
||||
+139
@@ -0,0 +1,139 @@
|
||||
/* ═══════════════════════════════════════════
|
||||
MIUIX CONSOLE — Checkbox & Radio Component
|
||||
═══════════════════════════════════════════ */
|
||||
|
||||
/* ── Checkbox ── */
|
||||
.mx-checkbox{
|
||||
display:inline-flex;align-items:center;gap:8px;
|
||||
cursor:pointer;
|
||||
-webkit-tap-highlight-color:transparent;
|
||||
}
|
||||
.mx-checkbox input{display:none}
|
||||
|
||||
.mx-checkbox-box{
|
||||
width:18px;height:18px;
|
||||
border:2px solid var(--mx-border);
|
||||
border-radius:5px;
|
||||
display:flex;align-items:center;justify-content:center;
|
||||
flex-shrink:0;
|
||||
transition:all var(--mx-d2) var(--mx-spring);
|
||||
background:transparent;
|
||||
}
|
||||
.mx-checkbox-box svg{
|
||||
width:12px;height:12px;
|
||||
color:#fff;opacity:0;
|
||||
transform:scale(0);
|
||||
transition:all var(--mx-d2) var(--mx-spring);
|
||||
}
|
||||
|
||||
/* Checked */
|
||||
.mx-checkbox input:checked + .mx-checkbox-box{
|
||||
background:var(--mx-primary);
|
||||
border-color:var(--mx-primary);
|
||||
}
|
||||
.mx-checkbox input:checked + .mx-checkbox-box svg{
|
||||
opacity:1;transform:scale(1);
|
||||
}
|
||||
|
||||
/* Indeterminate */
|
||||
.mx-checkbox input:indeterminate + .mx-checkbox-box{
|
||||
background:var(--mx-primary);
|
||||
border-color:var(--mx-primary);
|
||||
}
|
||||
.mx-checkbox input:indeterminate + .mx-checkbox-box svg{
|
||||
opacity:1;transform:scale(1);
|
||||
}
|
||||
|
||||
/* Hover */
|
||||
.mx-checkbox:hover .mx-checkbox-box{border-color:var(--mx-primary)}
|
||||
|
||||
/* Disabled */
|
||||
.mx-checkbox input:disabled + .mx-checkbox-box{
|
||||
opacity:0.4;cursor:not-allowed;
|
||||
}
|
||||
.mx-checkbox input:disabled ~ .mx-checkbox-label{
|
||||
opacity:0.4;cursor:not-allowed;
|
||||
}
|
||||
|
||||
/* Focus */
|
||||
.mx-checkbox input:focus-visible + .mx-checkbox-box{
|
||||
box-shadow:0 0 0 3px var(--mx-primary-glow);
|
||||
}
|
||||
|
||||
/* Label */
|
||||
.mx-checkbox-label{
|
||||
font-size:14px;color:var(--mx-text);
|
||||
transition:color var(--mx-d1);
|
||||
user-select:none;
|
||||
}
|
||||
|
||||
/* ── Radio ── */
|
||||
.mx-radio{
|
||||
display:inline-flex;align-items:center;gap:8px;
|
||||
cursor:pointer;
|
||||
-webkit-tap-highlight-color:transparent;
|
||||
}
|
||||
.mx-radio input{display:none}
|
||||
|
||||
.mx-radio-dot{
|
||||
width:18px;height:18px;
|
||||
border:2px solid var(--mx-border);
|
||||
border-radius:50%;
|
||||
display:flex;align-items:center;justify-content:center;
|
||||
flex-shrink:0;
|
||||
transition:all var(--mx-d2) var(--mx-spring);
|
||||
}
|
||||
.mx-radio-dot::after{
|
||||
content:'';width:8px;height:8px;
|
||||
border-radius:50%;background:#fff;
|
||||
transform:scale(0);
|
||||
transition:transform var(--mx-d2) var(--mx-spring);
|
||||
}
|
||||
|
||||
/* Checked */
|
||||
.mx-radio input:checked + .mx-radio-dot{
|
||||
background:var(--mx-primary);
|
||||
border-color:var(--mx-primary);
|
||||
}
|
||||
.mx-radio input:checked + .mx-radio-dot::after{
|
||||
transform:scale(1);
|
||||
}
|
||||
|
||||
/* Hover */
|
||||
.mx-radio:hover .mx-radio-dot{border-color:var(--mx-primary)}
|
||||
|
||||
/* Disabled */
|
||||
.mx-radio input:disabled + .mx-radio-dot{
|
||||
opacity:0.4;cursor:not-allowed;
|
||||
}
|
||||
.mx-radio input:disabled ~ .mx-radio-label{
|
||||
opacity:0.4;cursor:not-allowed;
|
||||
}
|
||||
|
||||
/* Focus */
|
||||
.mx-radio input:focus-visible + .mx-radio-dot{
|
||||
box-shadow:0 0 0 3px var(--mx-primary-glow);
|
||||
}
|
||||
|
||||
/* Label */
|
||||
.mx-radio-label{
|
||||
font-size:14px;color:var(--mx-text);
|
||||
transition:color var(--mx-d1);
|
||||
user-select:none;
|
||||
}
|
||||
|
||||
/* ── Checkbox Group / Radio Group layout ── */
|
||||
.mx-checkbox-group,.mx-radio-group{
|
||||
display:flex;flex-direction:column;gap:10px;
|
||||
}
|
||||
.mx-checkbox-group.horizontal,.mx-radio-group.horizontal{
|
||||
flex-direction:row;flex-wrap:wrap;gap:16px;
|
||||
}
|
||||
|
||||
/* Mobile: 加大触控区 */
|
||||
@media(max-width:767px){
|
||||
.mx-checkbox,.mx-radio{min-height:44px;padding:4px 0}
|
||||
.mx-checkbox-box,.mx-radio-dot{width:22px;height:22px}
|
||||
.mx-checkbox-box svg{width:14px;height:14px}
|
||||
.mx-radio-dot::after{width:10px;height:10px}
|
||||
}
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
/* ═══════════════════════════════════════════
|
||||
MIUIX CONSOLE — Drawer / Side Panel Component
|
||||
═══════════════════════════════════════════ */
|
||||
|
||||
/* Overlay */
|
||||
.mx-drawer-overlay{
|
||||
position:fixed;inset:0;z-index:900;
|
||||
background:var(--mx-window-dim);
|
||||
opacity:0;visibility:hidden;
|
||||
transition:opacity var(--mx-d2) var(--mx-ease),
|
||||
visibility var(--mx-d2);
|
||||
}
|
||||
.mx-drawer-overlay.open{opacity:1;visibility:visible}
|
||||
|
||||
/* Drawer */
|
||||
.mx-drawer{
|
||||
position:fixed;top:0;z-index:950;
|
||||
width:320px;height:100dvh;
|
||||
background:var(--mx-s1);
|
||||
box-shadow:var(--mx-sh3);
|
||||
display:flex;flex-direction:column;
|
||||
transition:transform var(--mx-d3) var(--mx-spring);
|
||||
}
|
||||
|
||||
/* Position: right (default) */
|
||||
.mx-drawer-right{
|
||||
right:0;
|
||||
transform:translateX(100%);
|
||||
}
|
||||
.mx-drawer-right.open{transform:translateX(0)}
|
||||
|
||||
/* Position: left */
|
||||
.mx-drawer-left{
|
||||
left:0;
|
||||
transform:translateX(-100%);
|
||||
}
|
||||
.mx-drawer-left.open{transform:translateX(0)}
|
||||
|
||||
/* Size variants */
|
||||
.mx-drawer-sm{width:280px}
|
||||
.mx-drawer-lg{width:420px}
|
||||
@media(min-width:1024px){
|
||||
.mx-drawer-xl{width:560px}
|
||||
}
|
||||
|
||||
/* Header */
|
||||
.mx-drawer-head{
|
||||
display:flex;align-items:center;justify-content:space-between;
|
||||
padding:16px 20px;
|
||||
border-bottom:1px solid var(--mx-divider);
|
||||
flex-shrink:0;
|
||||
}
|
||||
.mx-drawer-title{font-size:15px;font-weight:700}
|
||||
.mx-drawer-close{
|
||||
width:28px;height:28px;
|
||||
display:flex;align-items:center;justify-content:center;
|
||||
border-radius:var(--mx-r-xs);
|
||||
cursor:pointer;color:var(--mx-t3);
|
||||
transition:all var(--mx-d1);
|
||||
}
|
||||
.mx-drawer-close:hover{background:var(--mx-s-hover);color:var(--mx-text)}
|
||||
|
||||
/* Body */
|
||||
.mx-drawer-body{
|
||||
flex:1;overflow-y:auto;padding:20px;
|
||||
font-size:14px;line-height:1.6;
|
||||
}
|
||||
|
||||
/* Footer */
|
||||
.mx-drawer-foot{
|
||||
display:flex;align-items:center;justify-content:flex-end;gap:8px;
|
||||
padding:12px 20px;
|
||||
border-top:1px solid var(--mx-divider);
|
||||
flex-shrink:0;
|
||||
}
|
||||
|
||||
/* Full width on mobile */
|
||||
@media(max-width:767px){
|
||||
.mx-drawer{width:100%}
|
||||
.mx-drawer-sm,.mx-drawer-lg,.mx-drawer-xl{width:100%}
|
||||
}
|
||||
|
||||
/* Tablet */
|
||||
@media(min-width:768px) and (max-width:1023px){
|
||||
.mx-drawer{width:360px}
|
||||
.mx-drawer-sm{width:300px}
|
||||
.mx-drawer-lg{width:420px}
|
||||
}
|
||||
|
||||
/* ═══ DARK MODE INNER GLOW — unified with Card/Stat ═══ */
|
||||
[data-theme="dark"] .mx-drawer{
|
||||
box-shadow:var(--mx-sh3),inset 0 1px 0 rgba(255,255,255,0.04);
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/* ═══════════════════════════════════════════
|
||||
MIUIX CONSOLE — Empty State Component
|
||||
═══════════════════════════════════════════ */
|
||||
|
||||
.mx-empty{
|
||||
display:flex;flex-direction:column;
|
||||
align-items:center;justify-content:center;
|
||||
padding:48px 24px;text-align:center;
|
||||
}
|
||||
|
||||
.mx-empty-icon{
|
||||
width:64px;height:64px;
|
||||
border-radius:var(--mx-r);
|
||||
background:var(--mx-s3);
|
||||
display:flex;align-items:center;justify-content:center;
|
||||
margin-bottom:16px;
|
||||
color:var(--mx-t3);
|
||||
}
|
||||
.mx-empty-icon svg{width:28px;height:28px}
|
||||
|
||||
.mx-empty-title{
|
||||
font-size:15px;font-weight:700;
|
||||
color:var(--mx-text);margin-bottom:6px;
|
||||
}
|
||||
.mx-empty-desc{
|
||||
font-size:13px;color:var(--mx-t3);
|
||||
line-height:1.5;max-width:320px;margin-bottom:20px;
|
||||
}
|
||||
|
||||
/* Inline variant — smaller */
|
||||
.mx-empty-inline{
|
||||
padding:24px 16px;
|
||||
}
|
||||
.mx-empty-inline .mx-empty-icon{
|
||||
width:48px;height:48px;
|
||||
}
|
||||
.mx-empty-inline .mx-empty-icon svg{width:22px;height:22px}
|
||||
|
||||
/* Mobile */
|
||||
@media(max-width:767px){
|
||||
.mx-empty{padding:32px 16px}
|
||||
.mx-empty-icon{width:52px;height:52px}
|
||||
.mx-empty-icon svg{width:24px;height:24px}
|
||||
.mx-empty-title{font-size:14px}
|
||||
.mx-empty-desc{font-size:12px}
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
/* ═══════════════════════════════════════════
|
||||
MIUIX CONSOLE — Input Component
|
||||
═══════════════════════════════════════════ */
|
||||
|
||||
.mx-input-wrap{
|
||||
display:flex;align-items:center;gap:10px;
|
||||
background:var(--mx-s3);
|
||||
border:1px solid var(--mx-border);
|
||||
border-radius:var(--mx-r-sm);
|
||||
padding:0 16px;height:40px;
|
||||
transition:all var(--mx-d2) var(--mx-ease);
|
||||
}
|
||||
.mx-input-wrap:focus-within{
|
||||
border-color:var(--mx-primary);
|
||||
box-shadow:0 0 0 3px var(--mx-primary-glow);
|
||||
background:var(--mx-s2);
|
||||
}
|
||||
.mx-input-wrap .mx-input-icon{
|
||||
color:var(--mx-t3);flex-shrink:0;
|
||||
display:flex;align-items:center;
|
||||
}
|
||||
.mx-input{
|
||||
width:100%;height:100%;
|
||||
background:none;
|
||||
color:var(--mx-text);font-size:14px;
|
||||
font-family:var(--mx-font);
|
||||
}
|
||||
.mx-input::placeholder{color:var(--mx-t3)}
|
||||
|
||||
/* Textarea */
|
||||
.mx-textarea-wrap{
|
||||
padding:12px 14px;height:auto;min-height:80px;
|
||||
align-items:flex-start;
|
||||
}
|
||||
.mx-textarea{
|
||||
width:100%;resize:vertical;min-height:60px;
|
||||
background:none;border:none;outline:none;
|
||||
color:var(--mx-text);font-size:14px;
|
||||
font-family:var(--mx-font);line-height:1.6;
|
||||
}
|
||||
.mx-textarea::placeholder{color:var(--mx-t3)}
|
||||
|
||||
/* Sizes */
|
||||
.mx-input-sm{height:34px;padding:0 12px;font-size:13px;border-radius:var(--mx-r-xs)}
|
||||
.mx-input-lg{height:46px;padding:0 16px;font-size:15px}
|
||||
|
||||
/* Error */
|
||||
.mx-input-error{border-color:var(--mx-red)}
|
||||
.mx-input-error:focus-within{box-shadow:0 0 0 3px rgba(248,113,113,0.15)}
|
||||
|
||||
/* Disabled */
|
||||
.mx-input-wrap.mx-disabled{
|
||||
opacity:0.4;cursor:not-allowed;
|
||||
}
|
||||
.mx-input-wrap.mx-disabled input{pointer-events:none}
|
||||
|
||||
/* Label */
|
||||
.mx-label{
|
||||
display:block;font-size:12px;font-weight:600;
|
||||
color:var(--mx-t2);margin-bottom:6px;
|
||||
text-transform:uppercase;letter-spacing:0.04em;
|
||||
}
|
||||
|
||||
/* Helper text */
|
||||
.mx-helper{font-size:12px;color:var(--mx-t3);margin-top:4px}
|
||||
.mx-helper-error{color:var(--mx-red)}
|
||||
|
||||
/* Mobile: 防止 iOS 自动缩放 + 加大触控区 */
|
||||
@media(max-width:767px){
|
||||
.mx-input-wrap{height:44px;padding:0 16px}
|
||||
.mx-input{font-size:16px}
|
||||
.mx-input-sm{height:38px;font-size:15px}
|
||||
.mx-input-lg{height:50px;font-size:16px}
|
||||
.mx-textarea-wrap{min-height:88px}
|
||||
.mx-textarea{font-size:16px;min-height:72px}
|
||||
.mx-label{font-size:13px;margin-bottom:8px}
|
||||
}
|
||||
+327
@@ -0,0 +1,327 @@
|
||||
/* ═══════════════════════════════════════════
|
||||
MIUIX CONSOLE — Layout System
|
||||
全设备适配:手机 / 平板 / 桌面 / 大屏
|
||||
═══════════════════════════════════════════ */
|
||||
|
||||
/* ── App Shell ── */
|
||||
.mx-app{display:flex;flex-direction:column;height:100dvh}
|
||||
|
||||
/* ── Scrollable Body ── */
|
||||
.mx-body{
|
||||
flex:1;overflow-y:auto;overflow-x:hidden;
|
||||
-webkit-overflow-scrolling:touch;
|
||||
}
|
||||
|
||||
/* ── 自动为手机端主内容区添加底部内边距,防止 fixed 底栏遮挡 ── */
|
||||
@media(max-width:1023px){
|
||||
.mx-app > .mx-body,
|
||||
.mx-app > .mx-desktop-main.mx-body{
|
||||
padding-bottom:calc(72px + var(--mx-safe-b));
|
||||
}
|
||||
}
|
||||
@media(min-width:1024px){
|
||||
.mx-app > .mx-body,
|
||||
.mx-app > .mx-desktop-main.mx-body{
|
||||
padding-bottom:0;
|
||||
}
|
||||
}
|
||||
|
||||
/* ── Padding utilities ── */
|
||||
.mx-pad{padding:12px}
|
||||
.mx-pad-b{padding-bottom:calc(72px + var(--mx-safe-b))}
|
||||
@media(min-width:768px){.mx-pad{padding:20px}.mx-pad-b{padding-bottom:20px}}
|
||||
@media(min-width:1024px){.mx-pad{padding:28px}}
|
||||
|
||||
/* ── Page Header ── */
|
||||
.mx-page-head{margin-bottom:16px}
|
||||
@media(min-width:768px){.mx-page-head{margin-bottom:20px}}
|
||||
.mx-page-title{
|
||||
font-size:20px;font-weight:800;letter-spacing:-0.02em;
|
||||
background:linear-gradient(135deg,var(--mx-text),var(--mx-t2));
|
||||
-webkit-background-clip:text;-webkit-text-fill-color:transparent;
|
||||
}
|
||||
@media(min-width:768px){.mx-page-title{font-size:24px}}
|
||||
.mx-page-sub{
|
||||
font-size:12px;color:var(--mx-t3);margin-top:4px;
|
||||
display:flex;align-items:center;gap:6px;
|
||||
}
|
||||
|
||||
/* ── Section ── */
|
||||
.mx-section{margin-bottom:12px}
|
||||
@media(min-width:768px){.mx-section{margin-bottom:16px}}
|
||||
|
||||
/* ══════════════════════════════════════════
|
||||
MOBILE (< 768px) — 触控优先
|
||||
══════════════════════════════════════════ */
|
||||
@media(max-width:767px){
|
||||
/* 触控友好的最小高度 */
|
||||
.mx-btn{height:40px;padding:0 20px;font-size:14px}
|
||||
.mx-btn-sm{height:36px;padding:0 14px;font-size:13px}
|
||||
.mx-btn-lg{height:46px;padding:0 24px;font-size:15px}
|
||||
.mx-btn-icon{width:40px;height:40px}
|
||||
|
||||
/* 输入框加大 */
|
||||
.mx-input-wrap{height:44px;padding:0 16px}
|
||||
.mx-input{font-size:16px} /* 防止 iOS 自动缩放 */
|
||||
.mx-input-sm{height:38px;font-size:15px}
|
||||
.mx-input-lg{height:50px;font-size:16px}
|
||||
|
||||
/* Select 加大 */
|
||||
.mx-select-trigger{height:44px;font-size:16px}
|
||||
|
||||
/* Switch 加大 */
|
||||
.mx-switch-track{width:48px;height:28px}
|
||||
.mx-switch-thumb{width:22px;height:22px;top:3px;left:3px}
|
||||
.mx-switch input:checked + .mx-switch-track .mx-switch-thumb{transform:translateX(20px)}
|
||||
|
||||
/* Checkbox/Radio 加大触控区 */
|
||||
.mx-checkbox-box,.mx-radio-dot{width:20px;height:20px}
|
||||
.mx-checkbox-box svg{width:14px;height:14px}
|
||||
.mx-radio-dot::after{width:9px;height:9px}
|
||||
|
||||
/* Slider 触控加大 */
|
||||
.mx-slider input[type="range"]::-webkit-slider-thumb{width:22px;height:22px}
|
||||
.mx-slider input[type="range"]::-moz-range-thumb{width:22px;height:22px}
|
||||
|
||||
/* Navigation 触控加大 */
|
||||
.mx-nav-item{padding:11px 10px}
|
||||
.mx-btm-item{padding:8px 16px}
|
||||
.mx-btm-item span{font-size:11px}
|
||||
|
||||
/* TopBar */
|
||||
.mx-topbar{height:48px;padding:0 12px}
|
||||
|
||||
/* BottomNav */
|
||||
.mx-bottom-nav{height:auto}
|
||||
|
||||
/* Modal 全屏化 */
|
||||
.mx-modal-overlay{padding:0;align-items:flex-end}
|
||||
.mx-modal{
|
||||
max-width:100%;max-height:90dvh;
|
||||
border-radius:var(--mx-r) var(--mx-r) 0 0;
|
||||
transform:translateY(100%);
|
||||
opacity:1;
|
||||
}
|
||||
.mx-modal-overlay.open .mx-modal{transform:translateY(0)}
|
||||
.mx-modal-sm,.mx-modal-lg,.mx-modal-xl{max-width:100%}
|
||||
|
||||
/* Drawer 全宽 */
|
||||
.mx-drawer{width:100%}
|
||||
.mx-drawer-sm,.mx-drawer-lg,.mx-drawer-xl{width:100%}
|
||||
|
||||
/* Grid 单列降级 */
|
||||
.mx-grid-2,.mx-grid-3{grid-template-columns:1fr}
|
||||
.mx-grid-sidebar{grid-template-columns:1fr}
|
||||
|
||||
/* Stat 单列(窄屏手机) */
|
||||
.mx-stat-grid{grid-template-columns:1fr 1fr}
|
||||
|
||||
/* Table 卡片式响应 */
|
||||
.mx-table{border:0}
|
||||
.mx-table thead{display:none}
|
||||
.mx-table tbody tr{
|
||||
display:block;margin-bottom:12px;
|
||||
border:1px solid var(--mx-divider);
|
||||
border-radius:var(--mx-r-sm);
|
||||
padding:12px;
|
||||
background:var(--mx-s2);
|
||||
}
|
||||
.mx-table tbody td{
|
||||
display:flex;justify-content:space-between;align-items:center;
|
||||
padding:6px 0;border-bottom:1px solid var(--mx-divider);
|
||||
white-space:normal;
|
||||
}
|
||||
.mx-table tbody td:last-child{border-bottom:none}
|
||||
.mx-table tbody td::before{
|
||||
content:attr(data-label);
|
||||
font-size:11px;font-weight:700;color:var(--mx-t3);
|
||||
text-transform:uppercase;letter-spacing:0.04em;
|
||||
flex-shrink:0;margin-right:12px;
|
||||
}
|
||||
.mx-table tbody tr:hover td{padding-left:0}
|
||||
|
||||
/* Tabs 横向滚动 */
|
||||
.mx-tabs{overflow-x:auto;-webkit-overflow-scrolling:touch}
|
||||
.mx-tab{padding:10px 14px}
|
||||
|
||||
/* Pagination 精简 */
|
||||
.mx-page-prev span,.mx-page-next span{display:none}
|
||||
.mx-page-info{display:none}
|
||||
.mx-pagination{gap:2px}
|
||||
.mx-page-btn{width:32px;height:32px;font-size:12px}
|
||||
|
||||
/* Popover 全宽 */
|
||||
.mx-popover{
|
||||
position:fixed;left:8px!important;right:8px!important;
|
||||
bottom:8px!important;top:auto!important;
|
||||
width:auto!important;max-width:none;
|
||||
transform:translateY(100%)!important;
|
||||
transform-origin:bottom center;
|
||||
border-radius:var(--mx-r);
|
||||
}
|
||||
.mx-popover.open{transform:translateY(0)!important}
|
||||
|
||||
/* Select dropdown 全宽 */
|
||||
.mx-select-dropdown{
|
||||
position:fixed;left:8px!important;right:8px!important;
|
||||
bottom:8px!important;top:auto!important;
|
||||
max-height:50dvh;
|
||||
transform:translateY(100%)!important;
|
||||
transform-origin:bottom center;
|
||||
border-radius:var(--mx-r);
|
||||
}
|
||||
.mx-select-dropdown.open{transform:translateY(0)!important}
|
||||
|
||||
/* Datepicker dropdown 全宽 */
|
||||
.mx-datepicker-dropdown{
|
||||
position:fixed;left:8px!important;right:8px!important;
|
||||
bottom:8px!important;top:auto!important;
|
||||
transform:translateY(100%)!important;
|
||||
transform-origin:bottom center;
|
||||
border-radius:var(--mx-r);
|
||||
}
|
||||
.mx-datepicker-dropdown.open{transform:translateY(0)!important}
|
||||
|
||||
/* Accordion */
|
||||
.mx-accordion-header{padding:12px 14px}
|
||||
|
||||
/* Upload */
|
||||
.mx-upload{padding:24px 16px}
|
||||
|
||||
/* Avatar group */
|
||||
.mx-avatar-group .mx-avatar,
|
||||
.mx-avatar-group .mx-avatar-img{margin-left:-10px}
|
||||
}
|
||||
|
||||
/* ══════════════════════════════════════════
|
||||
TABLET (768px — 1023px)
|
||||
══════════════════════════════════════════ */
|
||||
@media(min-width:768px) and (max-width:1023px){
|
||||
.mx-grid-3{grid-template-columns:1fr 1fr}
|
||||
.mx-grid-sidebar{grid-template-columns:1fr}
|
||||
.mx-stat-grid{grid-template-columns:repeat(4,1fr)}
|
||||
|
||||
/* Modal 稍宽 */
|
||||
.mx-modal{max-width:480px}
|
||||
|
||||
/* Drawer */
|
||||
.mx-drawer{width:360px}
|
||||
.mx-drawer-sm{width:300px}
|
||||
.mx-drawer-lg{width:420px}
|
||||
|
||||
/* Tabs 横向滚动 */
|
||||
.mx-tabs{overflow-x:auto;-webkit-overflow-scrolling:touch}
|
||||
}
|
||||
|
||||
/* ══════════════════════════════════════════
|
||||
DESKTOP (≥ 1024px)
|
||||
══════════════════════════════════════════ */
|
||||
@media(min-width:1024px){
|
||||
.mx-app{flex-direction:row}
|
||||
.mx-app>.mx-topbar{display:none}
|
||||
.mx-app>.mx-bottom-nav{display:none!important}
|
||||
|
||||
.mx-desktop-shell{
|
||||
display:flex;flex-direction:column;width:100%;
|
||||
}
|
||||
.mx-desktop-topbar{
|
||||
display:flex;align-items:center;justify-content:space-between;
|
||||
height:52px;padding:0 24px;
|
||||
border-bottom:1px solid var(--mx-divider);
|
||||
backdrop-filter:blur(24px) saturate(1.8);
|
||||
-webkit-backdrop-filter:blur(24px) saturate(1.8);
|
||||
flex-shrink:0;
|
||||
}
|
||||
[data-theme="dark"] .mx-desktop-topbar{background:rgba(0,0,0,0.6)}
|
||||
[data-theme="light"] .mx-desktop-topbar{background:rgba(247,247,247,0.65)}
|
||||
|
||||
.mx-desktop-main{
|
||||
flex:1;padding:28px;overflow-y:auto;background:var(--mx-bg);
|
||||
}
|
||||
|
||||
.mx-sidebar{display:block}
|
||||
.mx-bottom-nav{display:none!important}
|
||||
|
||||
/* Grid 正常 */
|
||||
.mx-grid-2{grid-template-columns:1fr 1fr}
|
||||
.mx-grid-3{grid-template-columns:1fr 1fr 1fr}
|
||||
.mx-grid-sidebar{display:grid;grid-template-columns:1fr 320px;gap:16px}
|
||||
.mx-stat-grid{grid-template-columns:repeat(4,1fr)}
|
||||
}
|
||||
|
||||
/* Hide desktop elements on mobile */
|
||||
@media(max-width:1023px){
|
||||
.mx-sidebar{display:none}
|
||||
.mx-desktop-shell{display:none}
|
||||
}
|
||||
|
||||
/* ── Wide (≥1440px) ── */
|
||||
@media(min-width:1440px){
|
||||
.mx-sidebar{width:260px}
|
||||
.mx-desktop-main{padding:28px 32px}
|
||||
}
|
||||
|
||||
/* ══════════════════════════════════════════
|
||||
TOUCH DETECTION — 精确触控增强
|
||||
══════════════════════════════════════════ */
|
||||
@media(hover:none) and (pointer:coarse){
|
||||
/* 触控设备额外加大可交互区域 */
|
||||
.mx-tab{min-height:44px}
|
||||
.mx-nav-item{min-height:44px}
|
||||
.mx-accordion-header{min-height:48px}
|
||||
.mx-popover-item{min-height:44px}
|
||||
.mx-select-option{min-height:44px}
|
||||
.mx-page-btn{min-height:36px}
|
||||
.mx-tag{min-height:32px}
|
||||
|
||||
/* 禁用 hover 效果(触控无 hover) */
|
||||
.mx-card:hover{box-shadow:var(--mx-sh1)}
|
||||
.mx-stat:hover::before{opacity:0}
|
||||
.mx-stat:hover::after{opacity:0.04}
|
||||
.mx-stat:hover .mx-stat-icon{transform:none}
|
||||
.mx-table tbody tr:hover{background:transparent}
|
||||
.mx-table tbody tr:hover td{padding-left:14px}
|
||||
.mx-table th:hover::after{transform:scaleX(0)}
|
||||
|
||||
/* 用 :active 替代 */
|
||||
.mx-card:active{box-shadow:var(--mx-sh2)}
|
||||
.mx-stat:active{box-shadow:var(--mx-sh2)}
|
||||
.mx-table tbody tr:active{background:var(--mx-s-hover)}
|
||||
|
||||
/* Tooltip 改为长按触发 */
|
||||
.mx-tooltip::after{
|
||||
transition:none;
|
||||
opacity:0;visibility:hidden;
|
||||
}
|
||||
.mx-tooltip:active::after{
|
||||
opacity:1;visibility:visible;
|
||||
}
|
||||
}
|
||||
|
||||
/* ══════════════════════════════════════════
|
||||
LANDSCAPE PHONE — 横屏手机
|
||||
══════════════════════════════════════════ */
|
||||
@media(max-height:500px) and (orientation:landscape){
|
||||
.mx-topbar{height:40px}
|
||||
.mx-bottom-nav{display:none!important}
|
||||
.mx-modal{max-height:95dvh;border-radius:var(--mx-r)}
|
||||
.mx-modal-overlay{align-items:center;padding:8px}
|
||||
.mx-drawer{height:100dvh}
|
||||
}
|
||||
|
||||
/* ══════════════════════════════════════════
|
||||
FLEX utilities
|
||||
══════════════════════════════════════════ */
|
||||
.mx-flex{display:flex}
|
||||
.mx-flex-center{display:flex;align-items:center;justify-content:center}
|
||||
.mx-flex-between{display:flex;align-items:center;justify-content:space-between}
|
||||
.mx-gap-4{gap:4px}.mx-gap-8{gap:8px}.mx-gap-12{gap:12px}.mx-gap-16{gap:16px}
|
||||
|
||||
/* ══════════════════════════════════════════
|
||||
SAFE AREA — 全面屏设备
|
||||
══════════════════════════════════════════ */
|
||||
@supports(padding:max(0px)){
|
||||
.mx-pad{padding:max(12px, env(safe-area-inset-left)) max(12px, env(safe-area-inset-right))}
|
||||
@media(min-width:768px){.mx-pad{padding:max(20px, env(safe-area-inset-left)) max(20px, env(safe-area-inset-right))}}
|
||||
.mx-bottom-nav{padding-bottom:max(4px, env(safe-area-inset-bottom))}
|
||||
}
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
/* ═══════════════════════════════════════════
|
||||
MIUIX CONSOLE — Modal / Dialog Component
|
||||
对应 Miuix Dialog — 多层 Surface + 弹簧入场
|
||||
═══════════════════════════════════════════ */
|
||||
|
||||
/* Overlay */
|
||||
.mx-modal-overlay{
|
||||
position:fixed;inset:0;z-index:1000;
|
||||
display:flex;align-items:center;justify-content:center;
|
||||
background:var(--mx-window-dim);
|
||||
opacity:0;visibility:hidden;
|
||||
transition:opacity var(--mx-d2) var(--mx-ease),
|
||||
visibility var(--mx-d2);
|
||||
padding:16px;
|
||||
}
|
||||
.mx-modal-overlay.open{
|
||||
opacity:1;visibility:visible;
|
||||
}
|
||||
|
||||
/* Dialog */
|
||||
.mx-modal{
|
||||
background:var(--mx-s2);
|
||||
border-radius:var(--mx-r);
|
||||
box-shadow:var(--mx-sh3);
|
||||
width:100%;max-width:420px;
|
||||
max-height:calc(100dvh - 48px);
|
||||
overflow:hidden;
|
||||
display:flex;flex-direction:column;
|
||||
transform:scale(0.92) translateY(16px);
|
||||
opacity:0;
|
||||
transition:transform var(--mx-d3) var(--mx-spring),
|
||||
opacity var(--mx-d2) var(--mx-ease);
|
||||
}
|
||||
.mx-modal-overlay.open .mx-modal{
|
||||
transform:scale(1) translateY(0);
|
||||
opacity:1;
|
||||
}
|
||||
|
||||
/* Size variants */
|
||||
.mx-modal-sm{max-width:340px}
|
||||
.mx-modal-lg{max-width:560px}
|
||||
.mx-modal-xl{max-width:720px}
|
||||
.mx-modal-full{max-width:calc(100dvw - 32px);max-height:calc(100dvh - 32px)}
|
||||
|
||||
/* Header */
|
||||
.mx-modal-head{
|
||||
display:flex;align-items:center;justify-content:space-between;
|
||||
padding:16px 20px;
|
||||
border-bottom:1px solid var(--mx-divider);
|
||||
flex-shrink:0;
|
||||
}
|
||||
.mx-modal-title{
|
||||
font-size:15px;font-weight:700;
|
||||
}
|
||||
.mx-modal-close{
|
||||
width:28px;height:28px;
|
||||
display:flex;align-items:center;justify-content:center;
|
||||
border-radius:var(--mx-r-xs);
|
||||
cursor:pointer;color:var(--mx-t3);
|
||||
transition:all var(--mx-d1) var(--mx-ease);
|
||||
}
|
||||
.mx-modal-close:hover{background:var(--mx-s-hover);color:var(--mx-text)}
|
||||
.mx-modal-close:active{transform:scale(0.9)}
|
||||
|
||||
/* Body */
|
||||
.mx-modal-body{
|
||||
padding:20px;
|
||||
overflow-y:auto;flex:1;
|
||||
font-size:14px;line-height:1.6;color:var(--mx-text-on-surface);
|
||||
}
|
||||
|
||||
/* Footer */
|
||||
.mx-modal-foot{
|
||||
display:flex;align-items:center;justify-content:flex-end;gap:8px;
|
||||
padding:12px 20px;
|
||||
border-top:1px solid var(--mx-divider);
|
||||
flex-shrink:0;
|
||||
}
|
||||
|
||||
/* Confirmation variant — icon + centered text */
|
||||
.mx-modal-confirm-icon{
|
||||
width:48px;height:48px;
|
||||
border-radius:50%;
|
||||
display:flex;align-items:center;justify-content:center;
|
||||
margin:0 auto 16px;
|
||||
}
|
||||
.mx-modal-confirm-icon.info{background:rgba(96,165,250,0.12);color:var(--mx-blue)}
|
||||
.mx-modal-confirm-icon.success{background:rgba(52,211,153,0.12);color:var(--mx-green)}
|
||||
.mx-modal-confirm-icon.warning{background:rgba(251,191,36,0.12);color:var(--mx-amber)}
|
||||
.mx-modal-confirm-icon.danger{background:rgba(248,113,113,0.12);color:var(--mx-red)}
|
||||
.mx-modal-confirm-text{
|
||||
text-align:center;font-size:14px;color:var(--mx-text-on-surface);
|
||||
line-height:1.6;margin-bottom:4px;
|
||||
}
|
||||
.mx-modal-confirm-title{
|
||||
text-align:center;font-size:16px;font-weight:700;
|
||||
margin-bottom:8px;
|
||||
}
|
||||
.mx-modal-confirm-foot{justify-content:center}
|
||||
|
||||
/* Mobile: 按钮全宽堆叠 */
|
||||
@media(max-width:767px){
|
||||
.mx-modal-foot{flex-direction:column-reverse}
|
||||
.mx-modal-foot .mx-btn{width:100%}
|
||||
}
|
||||
|
||||
/* Tablet: 居中弹窗 */
|
||||
@media(min-width:768px) and (max-width:1023px){
|
||||
.mx-modal-overlay{align-items:center;padding:16px}
|
||||
.mx-modal{max-width:480px;transform:scale(0.92) translateY(16px)}
|
||||
.mx-modal-overlay.open .mx-modal{transform:scale(1) translateY(0)}
|
||||
}
|
||||
|
||||
/* ═══ DARK MODE INNER GLOW — unified with Card/Stat ═══ */
|
||||
[data-theme="dark"] .mx-modal{
|
||||
box-shadow:var(--mx-sh3),inset 0 1px 0 rgba(255,255,255,0.04);
|
||||
}
|
||||
+212
@@ -0,0 +1,212 @@
|
||||
/* ═══════════════════════════════════════════
|
||||
MIUIX CONSOLE — Navigation Components
|
||||
TopBar + Sidebar + BottomNav
|
||||
═══════════════════════════════════════════ */
|
||||
|
||||
/* ── TopBar — Miuix frosted glass ── */
|
||||
.mx-topbar{
|
||||
position:sticky;top:0;z-index:100;
|
||||
display:flex;align-items:center;justify-content:space-between;
|
||||
height:52px;padding:0 16px;
|
||||
padding-top:var(--mx-safe-t);
|
||||
border-bottom:1px solid var(--mx-divider);
|
||||
backdrop-filter:blur(24px) saturate(1.8);
|
||||
-webkit-backdrop-filter:blur(24px) saturate(1.8);
|
||||
flex-shrink:0;
|
||||
}
|
||||
[data-theme="dark"] .mx-topbar{background:rgba(0,0,0,0.6)}
|
||||
[data-theme="light"] .mx-topbar{background:rgba(247,247,247,0.65)}
|
||||
|
||||
.mx-topbar-left{display:flex;align-items:center;gap:10px}
|
||||
.mx-topbar-right{display:flex;align-items:center;gap:4px}
|
||||
|
||||
/* Logo */
|
||||
.mx-logo{
|
||||
display:flex;align-items:center;gap:10px;
|
||||
}
|
||||
.mx-logo-icon{
|
||||
width:32px;height:32px;
|
||||
background:linear-gradient(135deg,var(--mx-primary),var(--mx-accent));
|
||||
border-radius:10px;
|
||||
display:flex;align-items:center;justify-content:center;
|
||||
transition:transform var(--mx-d2) var(--mx-ease);
|
||||
box-shadow:0 2px 8px rgba(76,139,245,0.2);
|
||||
flex-shrink:0;
|
||||
}
|
||||
.mx-logo-icon:active{transform:scale(0.92)}
|
||||
.mx-logo-icon svg{color:#fff}
|
||||
.mx-logo-text{font-size:16px;font-weight:700}
|
||||
|
||||
/* ── Sidebar ── */
|
||||
.mx-sidebar{
|
||||
width:240px;flex-shrink:0;
|
||||
background:var(--mx-s1);
|
||||
border-right:1px solid var(--mx-divider);
|
||||
padding:12px;
|
||||
overflow-y:auto;scrollbar-width:none;
|
||||
}
|
||||
.mx-sidebar::-webkit-scrollbar{display:none}
|
||||
|
||||
.mx-sidebar-section{
|
||||
font-size:11px;font-weight:700;color:var(--mx-t3);
|
||||
text-transform:uppercase;letter-spacing:0.06em;
|
||||
padding:0 10px;margin:16px 0 4px;
|
||||
}
|
||||
.mx-sidebar-section:first-child{margin-top:4px}
|
||||
|
||||
.mx-nav-item{
|
||||
display:flex;align-items:center;gap:10px;
|
||||
padding:8px 10px;border-radius:var(--mx-r-sm);
|
||||
cursor:pointer;color:var(--mx-t2);
|
||||
font-size:13px;font-weight:500;
|
||||
transition:all var(--mx-d1) var(--mx-ease);
|
||||
position:relative;
|
||||
-webkit-tap-highlight-color:transparent;
|
||||
}
|
||||
.mx-nav-item::before{
|
||||
content:'';position:absolute;left:0;top:50%;
|
||||
width:3px;height:0;
|
||||
background:var(--mx-primary);
|
||||
border-radius:0 3px 3px 0;
|
||||
transform:translateY(-50%);
|
||||
transition:height var(--mx-d2) var(--mx-spring);
|
||||
}
|
||||
.mx-nav-item:hover{background:var(--mx-s-hover);color:var(--mx-text)}
|
||||
.mx-nav-item.active{background:var(--mx-primary-glow);color:var(--mx-primary)}
|
||||
.mx-nav-item.active::before{height:18px}
|
||||
.mx-nav-item:active{transform:scale(0.97)}
|
||||
.mx-nav-item svg{flex-shrink:0}
|
||||
.mx-nav-label{flex:1}
|
||||
|
||||
.mx-sidebar-bottom{
|
||||
margin-top:auto;padding-top:12px;
|
||||
border-top:1px solid var(--mx-divider);
|
||||
}
|
||||
|
||||
/* ── BottomNav — mobile only ── */
|
||||
.mx-bottom-nav{
|
||||
position:fixed;bottom:0;left:0;right:0;z-index:200;
|
||||
border-top:1px solid var(--mx-divider);
|
||||
backdrop-filter:blur(24px) saturate(1.8);
|
||||
-webkit-backdrop-filter:blur(24px) saturate(1.8);
|
||||
padding:4px 0;
|
||||
padding-bottom:calc(4px + var(--mx-safe-b));
|
||||
}
|
||||
[data-theme="dark"] .mx-bottom-nav{background:rgba(0,0,0,0.6)}
|
||||
[data-theme="light"] .mx-bottom-nav{background:rgba(247,247,247,0.65)}
|
||||
|
||||
.mx-bottom-nav-items{
|
||||
display:flex;justify-content:space-around;
|
||||
}
|
||||
|
||||
.mx-btm-item{
|
||||
display:flex;flex-direction:column;align-items:center;gap:2px;
|
||||
padding:6px 16px;border-radius:var(--mx-r-sm);
|
||||
cursor:pointer;color:var(--mx-t3);
|
||||
transition:all var(--mx-d2) var(--mx-spring);
|
||||
-webkit-tap-highlight-color:transparent;
|
||||
position:relative;
|
||||
}
|
||||
.mx-btm-item.active{color:var(--mx-primary)}
|
||||
.mx-btm-item.active::before{
|
||||
content:'';position:absolute;top:2px;left:50%;
|
||||
width:5px;height:5px;
|
||||
background:var(--mx-primary);
|
||||
border-radius:50%;transform:translateX(-50%);
|
||||
animation:mx-dot-in var(--mx-d2) var(--mx-spring);
|
||||
}
|
||||
.mx-btm-item span{font-size:10px;font-weight:600}
|
||||
.mx-btm-item:active{transform:scale(0.88)}
|
||||
|
||||
@keyframes mx-dot-in{
|
||||
from{transform:translateX(-50%) scale(0);opacity:0}
|
||||
to{transform:translateX(-50%) scale(1);opacity:1}
|
||||
}
|
||||
|
||||
/* ── Breadcrumb ── */
|
||||
.mx-breadcrumb{
|
||||
display:flex;align-items:center;gap:8px;
|
||||
font-size:13px;color:var(--mx-t3);
|
||||
}
|
||||
.mx-breadcrumb span{transition:color var(--mx-d1)}
|
||||
.mx-breadcrumb span:last-child{color:var(--mx-t2);font-weight:500}
|
||||
.mx-breadcrumb .mx-breadcrumb-sep{color:var(--mx-t3);font-size:11px}
|
||||
|
||||
/* ── Pill Group — density/theme toggle ── */
|
||||
.mx-pill-group{
|
||||
display:inline-flex;
|
||||
background:var(--mx-s3);
|
||||
border-radius:var(--mx-r-pill);
|
||||
padding:3px;gap:2px;
|
||||
}
|
||||
.mx-pill-group button{
|
||||
padding:5px 14px;border-radius:var(--mx-r-pill);
|
||||
font-size:12px;font-weight:600;cursor:pointer;
|
||||
color:var(--mx-t3);
|
||||
transition:all var(--mx-d2) var(--mx-ease);
|
||||
}
|
||||
.mx-pill-group button.active{
|
||||
background:var(--mx-primary);color:#fff;
|
||||
box-shadow:0 2px 8px rgba(76,139,245,0.25);
|
||||
}
|
||||
.mx-pill-group button:hover:not(.active){color:var(--mx-text)}
|
||||
|
||||
/* ── Avatar ── */
|
||||
.mx-avatar{
|
||||
width:32px;height:32px;border-radius:50%;
|
||||
background:linear-gradient(135deg,var(--mx-primary),var(--mx-accent));
|
||||
display:flex;align-items:center;justify-content:center;
|
||||
font-size:13px;font-weight:700;color:#fff;
|
||||
cursor:pointer;flex-shrink:0;
|
||||
transition:all var(--mx-d2) var(--mx-ease);
|
||||
box-shadow:0 0 0 0 var(--mx-primary-glow);
|
||||
}
|
||||
.mx-avatar:hover{box-shadow:0 0 0 4px var(--mx-primary-glow)}
|
||||
.mx-avatar:active{transform:scale(0.9)}
|
||||
|
||||
/* ── Notification Dot ── */
|
||||
.mx-notify{
|
||||
position:relative;
|
||||
}
|
||||
.mx-notify .mx-notify-dot{
|
||||
position:absolute;top:7px;right:7px;
|
||||
width:7px;height:7px;
|
||||
background:var(--mx-red);
|
||||
border-radius:50%;
|
||||
border:2px solid var(--mx-s1);
|
||||
animation:mx-pulse 2s infinite;
|
||||
}
|
||||
|
||||
/* ═══ MOBILE ADAPTATIONS ═══ */
|
||||
@media(max-width:767px){
|
||||
/* TopBar 更紧凑 */
|
||||
.mx-topbar{height:48px;padding:0 12px}
|
||||
.mx-logo-icon{width:28px;height:28px;border-radius:8px}
|
||||
.mx-logo-text{font-size:14px}
|
||||
.mx-avatar{width:28px;height:28px;font-size:12px}
|
||||
|
||||
/* BottomNav 加大触控区 */
|
||||
.mx-btm-item{padding:8px 16px;min-width:56px}
|
||||
.mx-btm-item span{font-size:11px}
|
||||
.mx-btm-item svg{width:24px;height:24px}
|
||||
|
||||
/* Sidebar section */
|
||||
.mx-sidebar-section{font-size:10px}
|
||||
.mx-nav-item{padding:11px 10px;min-height:44px}
|
||||
|
||||
/* Breadcrumb 滚动 */
|
||||
.mx-breadcrumb{overflow-x:auto;white-space:nowrap;-webkit-overflow-scrolling:touch}
|
||||
|
||||
/* Pill group */
|
||||
.mx-pill-group button{padding:6px 12px;font-size:11px}
|
||||
|
||||
/* Notification dot */
|
||||
.mx-notify .mx-notify-dot{top:5px;right:5px;width:6px;height:6px}
|
||||
}
|
||||
|
||||
/* ═══ TABLET ADAPTATIONS ═══ */
|
||||
@media(min-width:768px) and (max-width:1023px){
|
||||
.mx-topbar{height:50px}
|
||||
.mx-bottom-nav{padding:6px 0}
|
||||
.mx-btm-item span{font-size:10px}
|
||||
}
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
/* ═══════════════════════════════════════════
|
||||
MIUIX CONSOLE — Pagination Component
|
||||
═══════════════════════════════════════════ */
|
||||
|
||||
.mx-pagination{
|
||||
display:flex;align-items:center;gap:4px;
|
||||
font-size:13px;
|
||||
}
|
||||
|
||||
/* Page button */
|
||||
.mx-page-btn{
|
||||
width:34px;height:34px;
|
||||
display:flex;align-items:center;justify-content:center;
|
||||
border-radius:var(--mx-r-xs);
|
||||
cursor:pointer;color:var(--mx-t2);
|
||||
font-weight:500;
|
||||
transition:all var(--mx-d1) var(--mx-ease);
|
||||
-webkit-tap-highlight-color:transparent;
|
||||
}
|
||||
.mx-page-btn:hover{background:var(--mx-s-hover);color:var(--mx-text)}
|
||||
.mx-page-btn:active{transform:scale(0.92)}
|
||||
|
||||
/* Active */
|
||||
.mx-page-btn.active{
|
||||
background:var(--mx-primary);color:#fff;
|
||||
box-shadow:0 2px 8px rgba(76,139,245,0.25);
|
||||
}
|
||||
|
||||
/* Disabled */
|
||||
.mx-page-btn.disabled{
|
||||
opacity:0.3;pointer-events:none;
|
||||
}
|
||||
|
||||
/* Ellipsis */
|
||||
.mx-page-ellipsis{
|
||||
width:34px;height:34px;
|
||||
display:flex;align-items:center;justify-content:center;
|
||||
color:var(--mx-t3);font-size:12px;
|
||||
letter-spacing:2px;
|
||||
}
|
||||
|
||||
/* Prev / Next with text */
|
||||
.mx-page-prev,.mx-page-next{
|
||||
display:flex;align-items:center;gap:4px;
|
||||
padding:0 10px;height:34px;
|
||||
border-radius:var(--mx-r-xs);
|
||||
cursor:pointer;color:var(--mx-t2);
|
||||
font-size:13px;font-weight:500;
|
||||
transition:all var(--mx-d1) var(--mx-ease);
|
||||
}
|
||||
.mx-page-prev:hover,.mx-page-next:hover{
|
||||
background:var(--mx-s-hover);color:var(--mx-text);
|
||||
}
|
||||
.mx-page-prev:active,.mx-page-next:active{transform:scale(0.95)}
|
||||
.mx-page-prev.disabled,.mx-page-next.disabled{
|
||||
opacity:0.3;pointer-events:none;
|
||||
}
|
||||
|
||||
/* Size info */
|
||||
.mx-page-info{
|
||||
font-size:12px;color:var(--mx-t3);
|
||||
margin:0 8px;
|
||||
}
|
||||
|
||||
/* Simple variant — just prev/next + info */
|
||||
.mx-pagination-simple .mx-page-btn{display:none}
|
||||
.mx-pagination-simple .mx-page-ellipsis{display:none}
|
||||
|
||||
/* Mobile: 精简显示 */
|
||||
@media(max-width:767px){
|
||||
.mx-page-prev span,.mx-page-next span{display:none}
|
||||
.mx-page-info{display:none}
|
||||
.mx-pagination{gap:2px}
|
||||
.mx-page-btn{width:32px;height:32px;font-size:12px}
|
||||
.mx-page-prev,.mx-page-next{padding:0 6px;height:32px}
|
||||
/* 只显示前 5 页 */
|
||||
.mx-page-btn:nth-child(n+8){display:none}
|
||||
}
|
||||
|
||||
/* Tablet */
|
||||
@media(min-width:768px) and (max-width:1023px){
|
||||
.mx-page-btn{width:36px;height:36px}
|
||||
}
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
/* ═══════════════════════════════════════════
|
||||
MIUIX CONSOLE — Popover Component
|
||||
═══════════════════════════════════════════ */
|
||||
|
||||
.mx-popover-wrap{position:relative;display:inline-flex}
|
||||
|
||||
.mx-popover{
|
||||
position:absolute;z-index:600;
|
||||
min-width:180px;
|
||||
background:var(--mx-s4);
|
||||
border:1px solid var(--mx-divider);
|
||||
border-radius:var(--mx-r-sm);
|
||||
box-shadow:var(--mx-sh3);
|
||||
padding:6px;
|
||||
opacity:0;visibility:hidden;
|
||||
transform:scale(0.95) translateY(-4px);
|
||||
transform-origin:top center;
|
||||
transition:all var(--mx-d2) var(--mx-spring);
|
||||
pointer-events:none;
|
||||
}
|
||||
.mx-popover.open{
|
||||
opacity:1;visibility:visible;
|
||||
transform:scale(1) translateY(0);
|
||||
pointer-events:auto;
|
||||
}
|
||||
|
||||
/* Position: bottom */
|
||||
.mx-popover-bottom{
|
||||
top:calc(100% + 6px);left:50%;
|
||||
transform:translateX(-50%) scale(0.95) translateY(-4px);
|
||||
transform-origin:top center;
|
||||
}
|
||||
.mx-popover-bottom.open{
|
||||
transform:translateX(-50%) scale(1) translateY(0);
|
||||
}
|
||||
|
||||
/* Position: left */
|
||||
.mx-popover-left{
|
||||
right:calc(100% + 6px);top:50%;
|
||||
transform:translateY(-50%) scale(0.95) translateX(4px);
|
||||
transform-origin:center right;
|
||||
}
|
||||
.mx-popover-left.open{
|
||||
transform:translateY(-50%) scale(1) translateX(0);
|
||||
}
|
||||
|
||||
/* Position: right */
|
||||
.mx-popover-right{
|
||||
left:calc(100% + 6px);top:50%;
|
||||
transform:translateY(-50%) scale(0.95) translateX(-4px);
|
||||
transform-origin:center left;
|
||||
}
|
||||
.mx-popover-right.open{
|
||||
transform:translateY(-50%) scale(1) translateX(0);
|
||||
}
|
||||
|
||||
/* Item */
|
||||
.mx-popover-item{
|
||||
display:flex;align-items:center;gap:8px;
|
||||
padding:8px 10px;border-radius:var(--mx-r-xs);
|
||||
font-size:13px;font-weight:500;
|
||||
cursor:pointer;color:var(--mx-text);
|
||||
transition:all var(--mx-d1) var(--mx-ease);
|
||||
}
|
||||
.mx-popover-item:hover{background:var(--mx-s-hover)}
|
||||
.mx-popover-item:active{background:var(--mx-s-active);transform:scale(0.98)}
|
||||
.mx-popover-item svg{flex-shrink:0;color:var(--mx-t2)}
|
||||
|
||||
/* Divider */
|
||||
.mx-popover-divider{
|
||||
height:1px;background:var(--mx-divider);
|
||||
margin:4px 0;
|
||||
}
|
||||
|
||||
/* Danger item */
|
||||
.mx-popover-item.danger{color:var(--mx-red)}
|
||||
.mx-popover-item.danger svg{color:var(--mx-red)}
|
||||
|
||||
/* Mobile: 底部弹出 + 加大触控 */
|
||||
@media(max-width:767px){
|
||||
.mx-popover-item{padding:12px 14px;min-height:44px;font-size:14px}
|
||||
}
|
||||
|
||||
/* ═══ DARK MODE INNER GLOW — unified with Card/Stat ═══ */
|
||||
[data-theme="dark"] .mx-popover{
|
||||
box-shadow:var(--mx-sh3),inset 0 1px 0 rgba(255,255,255,0.04);
|
||||
}
|
||||
+135
@@ -0,0 +1,135 @@
|
||||
/* ═══════════════════════════════════════════
|
||||
MIUIX CONSOLE — Progress Component
|
||||
进度条 + 加载指示器
|
||||
═══════════════════════════════════════════ */
|
||||
|
||||
/* ── Linear Progress ── */
|
||||
.mx-progress{
|
||||
height:4px;background:var(--mx-s3);
|
||||
border-radius:var(--mx-r-pill);
|
||||
overflow:hidden;
|
||||
position:relative;
|
||||
}
|
||||
.mx-progress-bar{
|
||||
height:100%;
|
||||
background:var(--mx-primary);
|
||||
border-radius:var(--mx-r-pill);
|
||||
transition:width var(--mx-d3) var(--mx-ease);
|
||||
position:relative;
|
||||
}
|
||||
|
||||
/* Striped */
|
||||
.mx-progress-striped .mx-progress-bar{
|
||||
background-image:linear-gradient(
|
||||
45deg,
|
||||
rgba(255,255,255,0.15) 25%,
|
||||
transparent 25%,
|
||||
transparent 50%,
|
||||
rgba(255,255,255,0.15) 50%,
|
||||
rgba(255,255,255,0.15) 75%,
|
||||
transparent 75%
|
||||
);
|
||||
background-size:16px 16px;
|
||||
}
|
||||
|
||||
/* Animated striped */
|
||||
.mx-progress-animated .mx-progress-bar{
|
||||
animation:mx-progress-stripes 0.8s linear infinite;
|
||||
}
|
||||
@keyframes mx-progress-stripes{
|
||||
from{background-position:16px 0}
|
||||
to{background-position:0 0}
|
||||
}
|
||||
|
||||
/* Indeterminate */
|
||||
.mx-progress-indeterminate{
|
||||
overflow:hidden;
|
||||
}
|
||||
.mx-progress-indeterminate .mx-progress-bar{
|
||||
width:30%;
|
||||
animation:mx-progress-slide 1.5s var(--mx-ease) infinite;
|
||||
}
|
||||
@keyframes mx-progress-slide{
|
||||
0%{transform:translateX(-100%)}
|
||||
100%{transform:translateX(400%)}
|
||||
}
|
||||
|
||||
/* Color variants */
|
||||
.mx-progress-success .mx-progress-bar{background:var(--mx-green)}
|
||||
.mx-progress-warning .mx-progress-bar{background:var(--mx-amber)}
|
||||
.mx-progress-error .mx-progress-bar{background:var(--mx-red)}
|
||||
|
||||
/* Size */
|
||||
.mx-progress-sm{height:2px}
|
||||
.mx-progress-lg{height:8px}
|
||||
|
||||
/* With label */
|
||||
.mx-progress-label{
|
||||
display:flex;align-items:center;justify-content:space-between;
|
||||
margin-bottom:6px;
|
||||
font-size:12px;font-weight:600;color:var(--mx-t2);
|
||||
}
|
||||
.mx-progress-label .mx-progress-value{
|
||||
color:var(--mx-primary);font-variant-numeric:tabular-nums;
|
||||
}
|
||||
|
||||
/* ── Circular Progress (Spinner) ── */
|
||||
.mx-spinner{
|
||||
width:24px;height:24px;
|
||||
border:2.5px solid var(--mx-s3);
|
||||
border-top-color:var(--mx-primary);
|
||||
border-radius:50%;
|
||||
animation:mx-spin 0.7s linear infinite;
|
||||
}
|
||||
@keyframes mx-spin{to{transform:rotate(360deg)}}
|
||||
|
||||
.mx-spinner-sm{width:18px;height:18px;border-width:2px}
|
||||
.mx-spinner-lg{width:36px;height:36px;border-width:3px}
|
||||
|
||||
/* Dots spinner */
|
||||
.mx-spinner-dots{
|
||||
display:flex;gap:4px;
|
||||
}
|
||||
.mx-spinner-dots span{
|
||||
width:6px;height:6px;
|
||||
border-radius:50%;
|
||||
background:var(--mx-primary);
|
||||
animation:mx-dot-bounce 1.2s ease-in-out infinite;
|
||||
}
|
||||
.mx-spinner-dots span:nth-child(2){animation-delay:0.15s}
|
||||
.mx-spinner-dots span:nth-child(3){animation-delay:0.3s}
|
||||
@keyframes mx-dot-bounce{
|
||||
0%,80%,100%{transform:scale(0.6);opacity:0.4}
|
||||
40%{transform:scale(1);opacity:1}
|
||||
}
|
||||
|
||||
/* ── Progress Ring (circular) ── */
|
||||
.mx-progress-ring{
|
||||
display:inline-flex;align-items:center;justify-content:center;
|
||||
position:relative;
|
||||
}
|
||||
.mx-progress-ring svg{
|
||||
transform:rotate(-90deg);
|
||||
}
|
||||
.mx-progress-ring-track{
|
||||
fill:none;stroke:var(--mx-s3);stroke-width:4;
|
||||
}
|
||||
.mx-progress-ring-bar{
|
||||
fill:none;stroke:var(--mx-primary);stroke-width:4;
|
||||
stroke-linecap:round;
|
||||
transition:stroke-dashoffset var(--mx-d3) var(--mx-ease);
|
||||
}
|
||||
.mx-progress-ring-text{
|
||||
position:absolute;
|
||||
font-size:12px;font-weight:700;
|
||||
color:var(--mx-text);
|
||||
font-variant-numeric:tabular-nums;
|
||||
}
|
||||
|
||||
/* Mobile */
|
||||
@media(max-width:767px){
|
||||
.mx-progress{height:6px}
|
||||
.mx-progress-lg{height:10px}
|
||||
.mx-spinner{width:28px;height:28px}
|
||||
.mx-spinner-lg{width:40px;height:40px}
|
||||
}
|
||||
+130
@@ -0,0 +1,130 @@
|
||||
/* ═══════════════════════════════════════════
|
||||
MIUIX CONSOLE — Select / Dropdown Component
|
||||
═══════════════════════════════════════════ */
|
||||
|
||||
/* Trigger */
|
||||
.mx-select{
|
||||
position:relative;display:inline-flex;
|
||||
}
|
||||
.mx-select-trigger{
|
||||
display:flex;align-items:center;gap:8px;
|
||||
height:40px;padding:0 16px;
|
||||
background:var(--mx-s3);
|
||||
border:1px solid var(--mx-border);
|
||||
border-radius:var(--mx-r-sm);
|
||||
font-size:14px;color:var(--mx-text);
|
||||
cursor:pointer;
|
||||
transition:all var(--mx-d2) var(--mx-ease);
|
||||
min-width:160px;
|
||||
}
|
||||
.mx-select-trigger:hover{border-color:var(--mx-t3)}
|
||||
.mx-select-trigger.open{
|
||||
border-color:var(--mx-primary);
|
||||
box-shadow:0 0 0 3px var(--mx-primary-glow);
|
||||
}
|
||||
.mx-select-trigger .mx-select-placeholder{color:var(--mx-t3);flex:1}
|
||||
.mx-select-trigger .mx-select-value{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
||||
.mx-select-trigger .mx-select-arrow{
|
||||
color:var(--mx-t3);flex-shrink:0;
|
||||
transition:transform var(--mx-d2) var(--mx-ease);
|
||||
}
|
||||
.mx-select-trigger.open .mx-select-arrow{transform:rotate(180deg)}
|
||||
|
||||
/* Sizes */
|
||||
.mx-select-sm .mx-select-trigger{height:34px;padding:0 12px;font-size:13px;border-radius:var(--mx-r-xs)}
|
||||
.mx-select-lg .mx-select-trigger{height:46px;padding:0 16px;font-size:15px}
|
||||
|
||||
/* Dropdown */
|
||||
.mx-select-dropdown{
|
||||
position:absolute;top:calc(100% + 4px);left:0;z-index:700;
|
||||
min-width:100%;max-height:280px;
|
||||
background:var(--mx-s4);
|
||||
border:1px solid var(--mx-divider);
|
||||
border-radius:var(--mx-r-sm);
|
||||
box-shadow:var(--mx-sh3);
|
||||
padding:4px;
|
||||
overflow-y:auto;
|
||||
opacity:0;visibility:hidden;
|
||||
transform:scale(0.96) translateY(-4px);
|
||||
transform-origin:top center;
|
||||
transition:all var(--mx-d2) var(--mx-spring);
|
||||
}
|
||||
.mx-select-dropdown.open{
|
||||
opacity:1;visibility:visible;
|
||||
transform:scale(1) translateY(0);
|
||||
}
|
||||
|
||||
/* Search input inside dropdown */
|
||||
.mx-select-search{
|
||||
display:flex;align-items:center;gap:8px;
|
||||
padding:8px 10px;margin-bottom:2px;
|
||||
border-bottom:1px solid var(--mx-divider);
|
||||
}
|
||||
.mx-select-search input{
|
||||
flex:1;background:none;border:none;outline:none;
|
||||
font-size:13px;color:var(--mx-text);
|
||||
}
|
||||
.mx-select-search input::placeholder{color:var(--mx-t3)}
|
||||
.mx-select-search svg{color:var(--mx-t3);flex-shrink:0}
|
||||
|
||||
/* Option */
|
||||
.mx-select-option{
|
||||
display:flex;align-items:center;gap:8px;
|
||||
padding:8px 10px;border-radius:var(--mx-r-xs);
|
||||
font-size:13px;cursor:pointer;
|
||||
color:var(--mx-text);
|
||||
transition:all var(--mx-d1) var(--mx-ease);
|
||||
}
|
||||
.mx-select-option:hover{background:var(--mx-s-hover)}
|
||||
.mx-select-option:active{background:var(--mx-s-active)}
|
||||
.mx-select-option.selected{
|
||||
background:var(--mx-primary-glow);color:var(--mx-primary);
|
||||
font-weight:600;
|
||||
}
|
||||
.mx-select-option .mx-select-check{
|
||||
margin-left:auto;color:var(--mx-primary);
|
||||
opacity:0;transition:opacity var(--mx-d1);
|
||||
}
|
||||
.mx-select-option.selected .mx-select-check{opacity:1}
|
||||
|
||||
/* Group label */
|
||||
.mx-select-group-label{
|
||||
font-size:11px;font-weight:700;color:var(--mx-t3);
|
||||
text-transform:uppercase;letter-spacing:0.06em;
|
||||
padding:8px 10px 4px;
|
||||
}
|
||||
|
||||
/* Disabled */
|
||||
.mx-select.disabled{opacity:0.4;pointer-events:none}
|
||||
|
||||
/* Mobile: trigger 加大 */
|
||||
@media(max-width:767px){
|
||||
.mx-select-trigger{height:44px;font-size:16px}
|
||||
.mx-select-sm .mx-select-trigger{height:40px;font-size:15px}
|
||||
.mx-select-lg .mx-select-trigger{height:50px;font-size:16px}
|
||||
.mx-select-option{min-height:44px;padding:10px}
|
||||
}
|
||||
|
||||
/* Multi-select tags */
|
||||
.mx-select-tags{
|
||||
display:flex;flex-wrap:wrap;gap:4px;flex:1;
|
||||
}
|
||||
.mx-select-tag{
|
||||
display:inline-flex;align-items:center;gap:4px;
|
||||
padding:2px 8px;border-radius:var(--mx-r-pill);
|
||||
background:var(--mx-primary-glow);
|
||||
color:var(--mx-primary);
|
||||
font-size:12px;font-weight:600;
|
||||
}
|
||||
.mx-select-tag-remove{
|
||||
width:14px;height:14px;
|
||||
display:flex;align-items:center;justify-content:center;
|
||||
border-radius:50%;cursor:pointer;
|
||||
transition:background var(--mx-d1);
|
||||
}
|
||||
.mx-select-tag-remove:hover{background:rgba(52,130,255,0.2)}
|
||||
|
||||
/* ═══ DARK MODE INNER GLOW — unified with Card/Stat ═══ */
|
||||
[data-theme="dark"] .mx-select-dropdown{
|
||||
box-shadow:var(--mx-sh3),inset 0 1px 0 rgba(255,255,255,0.04);
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
/* ═══════════════════════════════════════════
|
||||
MIUIX CONSOLE — Stat Card Component
|
||||
═══════════════════════════════════════════ */
|
||||
|
||||
.mx-stat{
|
||||
background:var(--mx-s2);
|
||||
border-radius:var(--mx-r);
|
||||
padding:16px;
|
||||
position:relative;overflow:hidden;
|
||||
cursor:pointer;
|
||||
box-shadow:var(--mx-sh1);
|
||||
transition:all var(--mx-d3) var(--mx-ease);
|
||||
}
|
||||
.mx-stat:hover{transition-duration:var(--mx-d2)}
|
||||
.mx-stat:active{transform:scale(0.97)}
|
||||
|
||||
/* 顶部 accent 线 */
|
||||
.mx-stat::before{
|
||||
content:'';position:absolute;top:0;left:0;right:0;height:2px;
|
||||
background:var(--mx-stat-accent,var(--mx-primary));
|
||||
opacity:0;transition:opacity var(--mx-d2);
|
||||
}
|
||||
.mx-stat:hover::before{opacity:1}
|
||||
|
||||
/* 右上角柔光晕 */
|
||||
.mx-stat::after{
|
||||
content:'';position:absolute;top:-40%;right:-20%;
|
||||
width:100px;height:100px;
|
||||
background:var(--mx-stat-accent,var(--mx-primary));
|
||||
border-radius:50%;opacity:0.04;
|
||||
transition:opacity var(--mx-d2);
|
||||
}
|
||||
.mx-stat:hover::after{opacity:0.08}
|
||||
|
||||
.mx-stat-label{
|
||||
font-size:11px;font-weight:600;color:var(--mx-t3);
|
||||
text-transform:uppercase;letter-spacing:0.06em;
|
||||
margin-bottom:10px;display:flex;align-items:center;gap:8px;
|
||||
}
|
||||
|
||||
.mx-stat-icon{
|
||||
width:26px;height:26px;border-radius:var(--mx-r-xs);
|
||||
display:flex;align-items:center;justify-content:center;
|
||||
transition:transform var(--mx-d2) var(--mx-ease);
|
||||
}
|
||||
.mx-stat:hover .mx-stat-icon{transform:scale(1.12) rotate(-3deg)}
|
||||
|
||||
.mx-stat-value{
|
||||
font-size:28px;font-weight:800;
|
||||
letter-spacing:-0.03em;
|
||||
font-variant-numeric:tabular-nums;
|
||||
line-height:1;margin-bottom:8px;
|
||||
}
|
||||
|
||||
.mx-stat-delta{
|
||||
display:inline-flex;align-items:center;gap:4px;
|
||||
font-size:11px;font-weight:600;
|
||||
padding:2px 8px;border-radius:var(--mx-r-pill);
|
||||
}
|
||||
.mx-stat-delta.up{background:rgba(52,211,153,0.1);color:var(--mx-green)}
|
||||
.mx-stat-delta.down{background:rgba(248,113,113,0.1);color:var(--mx-red)}
|
||||
|
||||
/* Grid layout */
|
||||
.mx-stat-grid{
|
||||
display:grid;grid-template-columns:repeat(2,1fr);gap:12px;
|
||||
}
|
||||
@media(min-width:768px){
|
||||
.mx-stat-grid{grid-template-columns:repeat(4,1fr)}
|
||||
}
|
||||
|
||||
/* Mobile */
|
||||
@media(max-width:767px){
|
||||
.mx-stat{padding:14px}
|
||||
.mx-stat-value{font-size:22px}
|
||||
.mx-stat-icon{width:24px;height:24px}
|
||||
.mx-stat-icon svg{width:12px;height:12px}
|
||||
.mx-stat-label{font-size:10px}
|
||||
.mx-stat-delta{font-size:10px;padding:2px 6px}
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
/* ═══════════════════════════════════════════
|
||||
MIUIX CONSOLE — Switch Component
|
||||
对应 Miuix Switch.kt — miuixCapsuleShape
|
||||
═══════════════════════════════════════════ */
|
||||
|
||||
.mx-switch{
|
||||
display:inline-flex;align-items:center;gap:10px;
|
||||
cursor:pointer;
|
||||
-webkit-tap-highlight-color:transparent;
|
||||
}
|
||||
.mx-switch input{display:none}
|
||||
|
||||
.mx-switch-track{
|
||||
width:44px;height:26px;
|
||||
background:var(--mx-s4);
|
||||
border-radius:var(--mx-r-pill);
|
||||
position:relative;
|
||||
transition:background var(--mx-d2) var(--mx-ease);
|
||||
flex-shrink:0;
|
||||
}
|
||||
.mx-switch-thumb{
|
||||
position:absolute;top:3px;left:3px;
|
||||
width:20px;height:20px;
|
||||
background:#fff;
|
||||
border-radius:50%;
|
||||
box-shadow:0 1px 4px rgba(0,0,0,0.25);
|
||||
transition:transform var(--mx-d2) var(--mx-spring);
|
||||
}
|
||||
|
||||
@keyframes mx-switch-bounce{
|
||||
0%{transform:translateX(0)}
|
||||
50%{transform:translateX(22px)}
|
||||
100%{transform:translateX(20px)}
|
||||
}
|
||||
|
||||
/* Checked */
|
||||
.mx-switch input:checked + .mx-switch-track{
|
||||
background:var(--mx-primary);
|
||||
}
|
||||
.mx-switch input:checked + .mx-switch-track .mx-switch-thumb{
|
||||
animation:mx-switch-bounce 0.3s cubic-bezier(0.34,1.56,0.64,1) forwards;
|
||||
}
|
||||
|
||||
/* Disabled */
|
||||
.mx-switch input:disabled + .mx-switch-track{
|
||||
opacity:0.4;cursor:not-allowed;
|
||||
}
|
||||
|
||||
/* Label */
|
||||
.mx-switch-label{
|
||||
font-size:14px;color:var(--mx-text);
|
||||
transition:color var(--mx-d1);
|
||||
}
|
||||
|
||||
/* Mobile: 加大触控区 */
|
||||
@media(max-width:767px){
|
||||
.mx-switch{min-height:44px;padding:4px 0}
|
||||
.mx-switch-track{width:48px;height:28px}
|
||||
.mx-switch-thumb{width:22px;height:22px;top:3px;left:3px}
|
||||
@keyframes mx-switch-bounce-mobile{
|
||||
0%{transform:translateX(0)}
|
||||
50%{transform:translateX(22px)}
|
||||
100%{transform:translateX(20px)}
|
||||
}
|
||||
.mx-switch input:checked + .mx-switch-track .mx-switch-thumb{animation:mx-switch-bounce-mobile 0.3s cubic-bezier(0.34,1.56,0.64,1) forwards}
|
||||
.mx-switch-label{font-size:15px}
|
||||
}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
/* ═══════════════════════════════════════════
|
||||
MIUIX CONSOLE — Table Component
|
||||
═══════════════════════════════════════════ */
|
||||
|
||||
.mx-table-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch}
|
||||
.mx-table{width:100%;border-collapse:collapse}
|
||||
|
||||
.mx-table th{
|
||||
padding:12px 16px;
|
||||
font-size:11px;font-weight:700;
|
||||
color:var(--mx-t3);text-align:left;
|
||||
text-transform:uppercase;letter-spacing:0.06em;
|
||||
border-bottom:1px solid var(--mx-divider);
|
||||
white-space:nowrap;cursor:pointer;
|
||||
position:relative;transition:color var(--mx-d1);
|
||||
-webkit-user-select:none;user-select:none;
|
||||
}
|
||||
.mx-table th:hover{color:var(--mx-t2)}
|
||||
/* Miuix: 表头 hover 底部亮线 */
|
||||
.mx-table th::after{
|
||||
content:'';position:absolute;bottom:0;left:14px;right:14px;
|
||||
height:2px;background:var(--mx-primary);border-radius:1px;
|
||||
transform:scaleX(0);transition:transform var(--mx-d2) var(--mx-ease);
|
||||
}
|
||||
.mx-table th:hover::after{transform:scaleX(1)}
|
||||
|
||||
.mx-table td{
|
||||
padding:12px 16px;
|
||||
font-size:13px;
|
||||
border-bottom:1px solid var(--mx-divider);
|
||||
white-space:nowrap;
|
||||
transition:padding var(--mx-d1);
|
||||
}
|
||||
|
||||
.mx-table tbody tr{
|
||||
transition:background var(--mx-d3);
|
||||
}
|
||||
.mx-table tbody tr:hover{
|
||||
background:var(--mx-s-hover);
|
||||
transition-duration:var(--mx-d2);
|
||||
}
|
||||
.mx-table tbody tr:active{background:var(--mx-s-active)}
|
||||
/* Miuix: hover 时左 padding 微推 */
|
||||
.mx-table tbody tr:hover td{padding-left:18px}
|
||||
|
||||
/* Mono cell */
|
||||
.mx-table .mono{
|
||||
font-family:var(--mx-mono);font-size:12px;color:var(--mx-t2);
|
||||
}
|
||||
|
||||
/* Compact mode */
|
||||
.mx-table-compact th{padding:8px 12px}
|
||||
.mx-table-compact td{padding:10px 12px}
|
||||
.mx-table-compact tbody tr:hover td{padding-left:14px}
|
||||
|
||||
/* Mobile: 表格卡片化(需 data-label 属性配合) */
|
||||
@media(max-width:767px){
|
||||
.mx-table-wrap{overflow-x:visible}
|
||||
.mx-table{border:0}
|
||||
.mx-table thead{display:none}
|
||||
.mx-table tbody tr{
|
||||
display:block;margin-bottom:12px;
|
||||
border:1px solid var(--mx-divider);
|
||||
border-radius:var(--mx-r-sm);
|
||||
padding:12px;
|
||||
background:var(--mx-s2);
|
||||
}
|
||||
.mx-table tbody td{
|
||||
display:flex;justify-content:space-between;align-items:center;
|
||||
padding:6px 0;border-bottom:1px solid var(--mx-divider);
|
||||
white-space:normal;
|
||||
}
|
||||
.mx-table tbody td:last-child{border-bottom:none}
|
||||
.mx-table tbody td::before{
|
||||
content:attr(data-label);
|
||||
font-size:11px;font-weight:700;color:var(--mx-t3);
|
||||
text-transform:uppercase;letter-spacing:0.04em;
|
||||
flex-shrink:0;margin-right:12px;
|
||||
}
|
||||
.mx-table tbody tr:hover td{padding-left:0}
|
||||
.mx-table tbody tr:active{background:var(--mx-s-hover)}
|
||||
|
||||
.mx-table-compact tbody tr{padding:10px}
|
||||
.mx-table-compact td{padding:5px 0}
|
||||
}
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
/* ═══════════════════════════════════════════
|
||||
MIUIX CONSOLE — Tabs Component
|
||||
═══════════════════════════════════════════ */
|
||||
|
||||
/* Tab bar */
|
||||
.mx-tabs{
|
||||
display:flex;align-items:center;
|
||||
border-bottom:1px solid var(--mx-divider);
|
||||
overflow-x:auto;scrollbar-width:none;
|
||||
-webkit-overflow-scrolling:touch;
|
||||
}
|
||||
.mx-tabs::-webkit-scrollbar{display:none}
|
||||
|
||||
/* Tab item */
|
||||
.mx-tab{
|
||||
display:flex;align-items:center;gap:6px;
|
||||
padding:10px 16px;
|
||||
font-size:13px;font-weight:500;
|
||||
color:var(--mx-t3);
|
||||
cursor:pointer;white-space:nowrap;
|
||||
position:relative;
|
||||
transition:all var(--mx-d1) var(--mx-ease);
|
||||
-webkit-tap-highlight-color:transparent;
|
||||
}
|
||||
.mx-tab:hover{color:var(--mx-text)}
|
||||
|
||||
/* Active indicator — bottom line */
|
||||
.mx-tab::after{
|
||||
content:'';position:absolute;bottom:0;left:8px;right:8px;
|
||||
height:2px;border-radius:1px;
|
||||
background:var(--mx-primary);
|
||||
transform:scaleX(0);
|
||||
transition:transform var(--mx-d2) var(--mx-spring);
|
||||
}
|
||||
.mx-tab.active{color:var(--mx-primary);font-weight:600}
|
||||
.mx-tab.active::after{transform:scaleX(1)}
|
||||
|
||||
/* Badge in tab */
|
||||
.mx-tab .mx-count{margin-left:4px}
|
||||
|
||||
/* Disabled */
|
||||
.mx-tab.disabled{opacity:0.4;pointer-events:none}
|
||||
|
||||
/* Pill variant */
|
||||
.mx-tabs-pill{
|
||||
border-bottom:none;
|
||||
background:var(--mx-s3);
|
||||
border-radius:var(--mx-r-pill);
|
||||
padding:3px;gap:2px;
|
||||
}
|
||||
.mx-tabs-pill .mx-tab{
|
||||
border-radius:var(--mx-r-pill);
|
||||
padding:6px 14px;
|
||||
}
|
||||
.mx-tabs-pill .mx-tab::after{display:none}
|
||||
.mx-tabs-pill .mx-tab.active{
|
||||
background:var(--mx-primary);color:#fff;
|
||||
box-shadow:0 2px 8px rgba(76,139,245,0.25);
|
||||
}
|
||||
|
||||
/* Card variant */
|
||||
.mx-tabs-card{
|
||||
border-bottom:none;gap:4px;
|
||||
}
|
||||
.mx-tabs-card .mx-tab{
|
||||
border-radius:var(--mx-r-sm);
|
||||
padding:8px 14px;
|
||||
}
|
||||
.mx-tabs-card .mx-tab::after{display:none}
|
||||
.mx-tabs-card .mx-tab.active{
|
||||
background:var(--mx-primary-glow);color:var(--mx-primary);
|
||||
}
|
||||
|
||||
/* Tab content */
|
||||
.mx-tab-panel{display:none;padding:16px 0}
|
||||
.mx-tab-panel.active{display:block}
|
||||
|
||||
/* Alignment */
|
||||
.mx-tabs-center{justify-content:center}
|
||||
.mx-tabs-end{justify-content:flex-end}
|
||||
|
||||
/* Mobile: 触控友好 + 可滚动 */
|
||||
@media(max-width:767px){
|
||||
.mx-tab{padding:12px 14px;min-height:44px;font-size:14px}
|
||||
.mx-tabs-pill .mx-tab{padding:8px 16px}
|
||||
.mx-tabs-card .mx-tab{padding:10px 14px}
|
||||
/* 隐藏超出的 badge */
|
||||
.mx-tab .mx-count{display:none}
|
||||
}
|
||||
|
||||
/* Tablet: 可滚动 */
|
||||
@media(min-width:768px) and (max-width:1023px){
|
||||
.mx-tabs{overflow-x:auto;-webkit-overflow-scrolling:touch}
|
||||
}
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
/* ═══════════════════════════════════════════
|
||||
MIUIX CONSOLE — Tag / Chip Component
|
||||
═══════════════════════════════════════════ */
|
||||
|
||||
.mx-tag{
|
||||
display:inline-flex;align-items:center;gap:4px;
|
||||
padding:4px 10px;
|
||||
border-radius:var(--mx-r-pill);
|
||||
font-size:12px;font-weight:600;
|
||||
background:var(--mx-s3);color:var(--mx-text);
|
||||
transition:all var(--mx-d1) var(--mx-ease);
|
||||
cursor:default;
|
||||
-webkit-tap-highlight-color:transparent;
|
||||
}
|
||||
|
||||
/* Clickable */
|
||||
.mx-tag-clickable{cursor:pointer}
|
||||
.mx-tag-clickable:hover{background:var(--mx-s4)}
|
||||
.mx-tag-clickable:active{transform:scale(0.95)}
|
||||
|
||||
/* Color variants */
|
||||
.mx-tag-primary{background:var(--mx-primary-glow);color:var(--mx-primary)}
|
||||
.mx-tag-success{background:rgba(52,211,153,0.1);color:var(--mx-green)}
|
||||
.mx-tag-warning{background:rgba(251,191,36,0.1);color:var(--mx-amber)}
|
||||
.mx-tag-error{background:rgba(248,113,113,0.1);color:var(--mx-red)}
|
||||
.mx-tag-info{background:rgba(96,165,250,0.1);color:var(--mx-blue)}
|
||||
|
||||
/* Outline variant */
|
||||
.mx-tag-outline{
|
||||
background:transparent;
|
||||
border:1px solid var(--mx-border);
|
||||
}
|
||||
.mx-tag-outline.mx-tag-primary{border-color:var(--mx-primary);color:var(--mx-primary)}
|
||||
.mx-tag-outline.mx-tag-success{border-color:var(--mx-green);color:var(--mx-green)}
|
||||
.mx-tag-outline.mx-tag-warning{border-color:var(--mx-amber);color:var(--mx-amber)}
|
||||
.mx-tag-outline.mx-tag-error{border-color:var(--mx-red);color:var(--mx-red)}
|
||||
|
||||
/* With dot */
|
||||
.mx-tag-dot::before{
|
||||
content:'';width:6px;height:6px;
|
||||
border-radius:50%;flex-shrink:0;
|
||||
}
|
||||
.mx-tag-primary.mx-tag-dot::before{background:var(--mx-primary)}
|
||||
.mx-tag-success.mx-tag-dot::before{background:var(--mx-green)}
|
||||
.mx-tag-warning.mx-tag-dot::before{background:var(--mx-amber)}
|
||||
.mx-tag-error.mx-tag-dot::before{background:var(--mx-red)}
|
||||
.mx-tag-info.mx-tag-dot::before{background:var(--mx-blue)}
|
||||
|
||||
/* Close button */
|
||||
.mx-tag-close{
|
||||
width:14px;height:14px;
|
||||
display:flex;align-items:center;justify-content:center;
|
||||
border-radius:50%;cursor:pointer;
|
||||
transition:background var(--mx-d1);
|
||||
}
|
||||
.mx-tag-close:hover{background:rgba(0,0,0,0.1)}
|
||||
[data-theme="dark"] .mx-tag-close:hover{background:rgba(255,255,255,0.1)}
|
||||
|
||||
/* Sizes */
|
||||
.mx-tag-sm{padding:2px 8px;font-size:11px}
|
||||
.mx-tag-lg{padding:6px 14px;font-size:13px}
|
||||
|
||||
/* Tag group */
|
||||
.mx-tag-group{
|
||||
display:flex;flex-wrap:wrap;gap:6px;
|
||||
}
|
||||
|
||||
/* Input tag — for editable tag list */
|
||||
.mx-tag-input{
|
||||
display:flex;flex-wrap:wrap;gap:6px;
|
||||
padding:6px 10px;
|
||||
background:var(--mx-s3);
|
||||
border:1px solid var(--mx-border);
|
||||
border-radius:var(--mx-r-sm);
|
||||
min-height:40px;align-items:center;
|
||||
transition:all var(--mx-d2) var(--mx-ease);
|
||||
cursor:text;
|
||||
}
|
||||
|
||||
/* Mobile */
|
||||
@media(max-width:767px){
|
||||
.mx-tag{min-height:32px;padding:4px 12px}
|
||||
.mx-tag-lg{min-height:38px}
|
||||
.mx-tag-close{width:18px;height:18px}
|
||||
}
|
||||
.mx-tag-input:focus-within{
|
||||
border-color:var(--mx-primary);
|
||||
box-shadow:0 0 0 3px var(--mx-primary-glow);
|
||||
}
|
||||
.mx-tag-input input{
|
||||
flex:1;min-width:60px;border:none;outline:none;
|
||||
background:none;font-size:13px;color:var(--mx-text);
|
||||
}
|
||||
.mx-tag-input input::placeholder{color:var(--mx-t3)}
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
/* ═══════════════════════════════════════════
|
||||
MIUIX CONSOLE — Toast / Snackbar Component
|
||||
Miuix 轻量反馈 — 底部弹出 + 自动消失
|
||||
═══════════════════════════════════════════ */
|
||||
|
||||
/* Container */
|
||||
.mx-toast-container{
|
||||
position:fixed;bottom:16px;left:50%;
|
||||
transform:translateX(-50%);
|
||||
z-index:2000;
|
||||
display:flex;flex-direction:column-reverse;align-items:center;gap:8px;
|
||||
pointer-events:none;
|
||||
padding-bottom:var(--mx-safe-b);
|
||||
}
|
||||
|
||||
/* Toast */
|
||||
.mx-toast{
|
||||
display:flex;align-items:center;gap:10px;
|
||||
padding:10px 16px;
|
||||
background:var(--mx-s4);
|
||||
border-radius:var(--mx-r-sm);
|
||||
box-shadow:var(--mx-sh3);
|
||||
font-size:13px;font-weight:500;
|
||||
color:var(--mx-text);
|
||||
pointer-events:auto;
|
||||
max-width:calc(100vw - 32px);
|
||||
transform:translateY(12px) scale(0.95);
|
||||
opacity:0;
|
||||
transition:transform var(--mx-d3) var(--mx-spring),
|
||||
opacity var(--mx-d2) var(--mx-ease);
|
||||
}
|
||||
.mx-toast.show{
|
||||
transform:translateY(0) scale(1);
|
||||
opacity:1;
|
||||
}
|
||||
.mx-toast.hide{
|
||||
transform:translateY(-8px) scale(0.95);
|
||||
opacity:0;
|
||||
}
|
||||
|
||||
/* Icon */
|
||||
.mx-toast-icon{
|
||||
width:20px;height:20px;flex-shrink:0;
|
||||
display:flex;align-items:center;justify-content:center;
|
||||
}
|
||||
.mx-toast-icon svg{width:18px;height:18px}
|
||||
|
||||
/* Variants */
|
||||
.mx-toast-success .mx-toast-icon{color:var(--mx-green)}
|
||||
.mx-toast-warning .mx-toast-icon{color:var(--mx-amber)}
|
||||
.mx-toast-error .mx-toast-icon{color:var(--mx-red)}
|
||||
.mx-toast-info .mx-toast-icon{color:var(--mx-blue)}
|
||||
|
||||
/* Action button */
|
||||
.mx-toast-action{
|
||||
padding:4px 10px;border-radius:var(--mx-r-xs);
|
||||
font-size:12px;font-weight:600;
|
||||
cursor:pointer;
|
||||
transition:all var(--mx-d1) var(--mx-ease);
|
||||
flex-shrink:0;
|
||||
}
|
||||
.mx-toast-action{color:var(--mx-primary)}
|
||||
.mx-toast-action:hover{background:var(--mx-primary-glow)}
|
||||
|
||||
/* Close button */
|
||||
.mx-toast-close{
|
||||
width:20px;height:20px;
|
||||
display:flex;align-items:center;justify-content:center;
|
||||
border-radius:var(--mx-r-xs);
|
||||
cursor:pointer;color:var(--mx-t3);
|
||||
transition:all var(--mx-d1);
|
||||
flex-shrink:0;
|
||||
}
|
||||
.mx-toast-close:hover{color:var(--mx-text)}
|
||||
|
||||
/* Progress bar (auto dismiss) */
|
||||
.mx-toast-progress{
|
||||
position:absolute;bottom:0;left:0;
|
||||
height:2px;border-radius:0 0 var(--mx-r-sm) var(--mx-r-sm);
|
||||
background:var(--mx-primary);
|
||||
opacity:0.4;
|
||||
transition:width linear;
|
||||
}
|
||||
|
||||
/* Mobile — full width + 底部安全区 */
|
||||
@media(max-width:767px){
|
||||
.mx-toast-container{
|
||||
left:8px;right:8px;
|
||||
transform:none;
|
||||
align-items:stretch;
|
||||
}
|
||||
.mx-toast{border-radius:var(--mx-r)}
|
||||
}
|
||||
|
||||
/* Tablet */
|
||||
@media(min-width:768px) and (max-width:1023px){
|
||||
.mx-toast-container{bottom:20px}
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
/* ═══════════════════════════════════════════
|
||||
MIUIX CONSOLE — Tooltip Component
|
||||
═══════════════════════════════════════════ */
|
||||
|
||||
.mx-tooltip{
|
||||
position:relative;
|
||||
}
|
||||
.mx-tooltip::after{
|
||||
content:attr(data-tooltip);
|
||||
position:absolute;
|
||||
bottom:calc(100% + 8px);left:50%;
|
||||
transform:translateX(-50%) translateY(4px);
|
||||
padding:5px 10px;
|
||||
background:var(--mx-s4);
|
||||
color:var(--mx-text);
|
||||
font-size:12px;font-weight:500;
|
||||
white-space:nowrap;
|
||||
border-radius:var(--mx-r-xs);
|
||||
box-shadow:var(--mx-sh2);
|
||||
opacity:0;visibility:hidden;
|
||||
pointer-events:none;
|
||||
transition:all var(--mx-d2) var(--mx-spring);
|
||||
z-index:500;
|
||||
}
|
||||
.mx-tooltip:hover::after{
|
||||
opacity:1;visibility:visible;
|
||||
transform:translateX(-50%) translateY(0);
|
||||
}
|
||||
|
||||
/* Position variants */
|
||||
.mx-tooltip-bottom::after{
|
||||
bottom:auto;top:calc(100% + 8px);
|
||||
transform:translateX(-50%) translateY(-4px);
|
||||
}
|
||||
.mx-tooltip-bottom:hover::after{
|
||||
transform:translateX(-50%) translateY(0);
|
||||
}
|
||||
|
||||
.mx-tooltip-left::after{
|
||||
bottom:auto;left:auto;
|
||||
right:calc(100% + 8px);top:50%;
|
||||
transform:translateY(-50%) translateX(4px);
|
||||
}
|
||||
.mx-tooltip-left:hover::after{
|
||||
transform:translateY(-50%) translateX(0);
|
||||
}
|
||||
|
||||
.mx-tooltip-right::after{
|
||||
bottom:auto;left:calc(100% + 8px);top:50%;
|
||||
transform:translateY(-50%) translateX(-4px);
|
||||
}
|
||||
.mx-tooltip-right:hover::after{
|
||||
transform:translateY(-50%) translateX(0);
|
||||
}
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
/* ═══════════════════════════════════════════
|
||||
MIUIX CONSOLE — Animations
|
||||
═══════════════════════════════════════════ */
|
||||
|
||||
/* ── Entry animations ── */
|
||||
@keyframes mx-slide-up{
|
||||
from{opacity:0;transform:translateY(16px)}
|
||||
to{opacity:1;transform:translateY(0)}
|
||||
}
|
||||
@keyframes mx-card-in{
|
||||
from{opacity:0;transform:scale(0.96) translateY(10px)}
|
||||
to{opacity:1;transform:scale(1) translateY(0)}
|
||||
}
|
||||
@keyframes mx-fade-item{
|
||||
from{opacity:0;transform:translateX(-8px)}
|
||||
to{opacity:1;transform:translateX(0)}
|
||||
}
|
||||
@keyframes mx-fade-row{
|
||||
from{opacity:0;transform:translateY(4px)}
|
||||
to{opacity:1;transform:translateY(0)}
|
||||
}
|
||||
@keyframes mx-bar-grow{
|
||||
from{transform:scaleY(0);opacity:0}
|
||||
to{transform:scaleY(1);opacity:1}
|
||||
}
|
||||
@keyframes mx-pulse{
|
||||
0%,100%{opacity:1;transform:scale(1)}
|
||||
50%{opacity:0.5;transform:scale(1.3)}
|
||||
}
|
||||
@keyframes mx-dot-in{
|
||||
from{transform:translateX(-50%) scale(0);opacity:0}
|
||||
to{transform:translateX(-50%) scale(1);opacity:1}
|
||||
}
|
||||
@keyframes mx-ripple{
|
||||
to{transform:scale(4);opacity:0}
|
||||
}
|
||||
@keyframes mx-shimmer{
|
||||
from{background-position:200% 0}
|
||||
to{background-position:-200% 0}
|
||||
}
|
||||
|
||||
/* ── Animation classes ── */
|
||||
.mx-anim-slide-up{animation:mx-slide-up var(--mx-d3) var(--mx-ease)}
|
||||
.mx-anim-card-in{animation:mx-card-in var(--mx-d3) var(--mx-ease) both}
|
||||
.mx-anim-fade-item{animation:mx-fade-item var(--mx-d3) var(--mx-ease) both}
|
||||
.mx-anim-fade-row{animation:mx-fade-row var(--mx-d3) var(--mx-ease) both}
|
||||
.mx-anim-bar-grow{
|
||||
transform-origin:bottom;
|
||||
animation:mx-bar-grow var(--mx-d4) var(--mx-ease) both;
|
||||
}
|
||||
|
||||
/* ── Stagger delays ── */
|
||||
.mx-delay-0{animation-delay:0ms}
|
||||
.mx-delay-1{animation-delay:50ms}
|
||||
.mx-delay-2{animation-delay:100ms}
|
||||
.mx-delay-3{animation-delay:150ms}
|
||||
.mx-delay-4{animation-delay:200ms}
|
||||
.mx-delay-5{animation-delay:250ms}
|
||||
.mx-delay-6{animation-delay:300ms}
|
||||
.mx-delay-7{animation-delay:350ms}
|
||||
.mx-delay-8{animation-delay:400ms}
|
||||
|
||||
/* ── Skeleton loading — dual-layer overlay ── */
|
||||
.mx-skeleton{
|
||||
background:
|
||||
linear-gradient(90deg, transparent 25%, rgba(255,255,255,0.06) 50%, transparent 75%),
|
||||
var(--mx-s3);
|
||||
background-size:200% 100%, 100% 100%;
|
||||
animation:mx-shimmer 1.5s ease-in-out infinite;
|
||||
border-radius:var(--mx-r-sm);
|
||||
}
|
||||
Vendored
+50
@@ -0,0 +1,50 @@
|
||||
/* ═══════════════════════════════════════════
|
||||
MIUIX CONSOLE — Base Reset & Globals
|
||||
═══════════════════════════════════════════ */
|
||||
*,*::before,*::after{margin:0;padding:0;box-sizing:border-box}
|
||||
html{font-size:14px;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}
|
||||
body{
|
||||
font-family:var(--mx-font);
|
||||
background:var(--mx-bg);
|
||||
color:var(--mx-text);
|
||||
overflow-x:hidden;
|
||||
min-height:100dvh;
|
||||
}
|
||||
button,input,textarea,select{font-family:inherit;border:none;outline:none;background:none}
|
||||
ul,ol{list-style:none}
|
||||
a{text-decoration:none;color:inherit}
|
||||
img{display:block;max-width:100%}
|
||||
|
||||
/* Smooth scroll */
|
||||
html{scroll-behavior:smooth}
|
||||
|
||||
/* Selection */
|
||||
::selection{background:var(--mx-primary-glow);color:var(--mx-text)}
|
||||
|
||||
/* Scrollbar — Miuix thin style, auto-hide */
|
||||
::-webkit-scrollbar{width:4px;height:4px}
|
||||
::-webkit-scrollbar-track{background:transparent}
|
||||
::-webkit-scrollbar-thumb{background:var(--mx-s4);border-radius:2px;opacity:0;transition:opacity 0.3s}
|
||||
::-webkit-scrollbar-thumb:hover{background:var(--mx-t3)}
|
||||
body:hover ::-webkit-scrollbar-thumb{opacity:1}
|
||||
|
||||
/* Firefox scrollbar auto-hide */
|
||||
*{scrollbar-color:transparent transparent}
|
||||
body:hover *{scrollbar-color:var(--mx-s4) transparent}
|
||||
|
||||
/* Prevent selection on interactive */
|
||||
.no-select{-webkit-user-select:none;user-select:none}
|
||||
|
||||
/* ═══ DARK MODE INNER GLOW — Miuix signature depth ═══ */
|
||||
[data-theme="dark"] .mx-card,
|
||||
[data-theme="dark"] .mx-stat{
|
||||
box-shadow:var(--mx-sh1),inset 0 1px 0 rgba(255,255,255,0.04);
|
||||
}
|
||||
|
||||
/* ═══ prefers-reduced-motion — kill all animation ═══ */
|
||||
@media(prefers-reduced-motion:reduce){
|
||||
*,*::before,*::after{
|
||||
animation-duration:0.01ms !important;
|
||||
transition-duration:0.01ms !important;
|
||||
}
|
||||
}
|
||||
Vendored
+230
@@ -0,0 +1,230 @@
|
||||
/* ═══════════════════════════════════════════
|
||||
MIUIX CONSOLE — Liquid Glass Effect v2
|
||||
液体玻璃效果系统(完整版)
|
||||
通过 [data-glass="liquid"] 属性启用
|
||||
═══════════════════════════════════════════ */
|
||||
|
||||
/* ── Glass Variables ── */
|
||||
:root {
|
||||
--mx-glass-blur: 12px;
|
||||
--mx-glass-saturation: 180%;
|
||||
--mx-glass-displacement: 25;
|
||||
--mx-glass-aberration: 2;
|
||||
--mx-glass-elasticity: 0.15;
|
||||
--mx-glass-corner-radius: 16px;
|
||||
--mx-glass-activation-zone: 200;
|
||||
--mx-glass-bg-light: rgba(255, 255, 255, 0.25);
|
||||
--mx-glass-bg-dark: rgba(0, 0, 0, 0.35);
|
||||
--mx-glass-border-light: rgba(255, 255, 255, 0.2);
|
||||
--mx-glass-border-dark: rgba(255, 255, 255, 0.08);
|
||||
--mx-glass-mouse-x: 0;
|
||||
--mx-glass-mouse-y: 0;
|
||||
}
|
||||
|
||||
/* ═══════════════════════════════════════════
|
||||
DARK MODE (default)
|
||||
═══════════════════════════════════════════ */
|
||||
|
||||
/* ── TopBar ── */
|
||||
[data-glass="liquid"] .mx-topbar {
|
||||
background: rgba(22, 22, 22, 0.45);
|
||||
backdrop-filter: blur(var(--mx-glass-blur)) saturate(var(--mx-glass-saturation));
|
||||
-webkit-backdrop-filter: blur(var(--mx-glass-blur)) saturate(var(--mx-glass-saturation));
|
||||
border-bottom: 1px solid var(--mx-glass-border-dark);
|
||||
filter: url(#mx-glass-filter);
|
||||
}
|
||||
|
||||
/* ── Sidebar ── */
|
||||
[data-glass="liquid"] .mx-sidebar {
|
||||
background: rgba(22, 22, 22, 0.45);
|
||||
backdrop-filter: blur(var(--mx-glass-blur)) saturate(var(--mx-glass-saturation));
|
||||
-webkit-backdrop-filter: blur(var(--mx-glass-blur)) saturate(var(--mx-glass-saturation));
|
||||
border-right: 1px solid var(--mx-glass-border-dark);
|
||||
filter: url(#mx-glass-filter);
|
||||
}
|
||||
|
||||
/* ── Bottom Nav ── */
|
||||
[data-glass="liquid"] .mx-bottom-nav {
|
||||
background: rgba(22, 22, 22, 0.45);
|
||||
backdrop-filter: blur(var(--mx-glass-blur)) saturate(var(--mx-glass-saturation));
|
||||
-webkit-backdrop-filter: blur(var(--mx-glass-blur)) saturate(var(--mx-glass-saturation));
|
||||
border-top: 1px solid var(--mx-glass-border-dark);
|
||||
filter: url(#mx-glass-filter);
|
||||
}
|
||||
|
||||
/* ── Modal ── */
|
||||
[data-glass="liquid"] .mx-modal {
|
||||
background: rgba(30, 30, 30, 0.5);
|
||||
backdrop-filter: blur(var(--mx-glass-blur)) saturate(var(--mx-glass-saturation));
|
||||
-webkit-backdrop-filter: blur(var(--mx-glass-blur)) saturate(var(--mx-glass-saturation));
|
||||
border: 1px solid var(--mx-glass-border-dark);
|
||||
filter: url(#mx-glass-filter);
|
||||
}
|
||||
|
||||
/* ── Drawer ── */
|
||||
[data-glass="liquid"] .mx-drawer {
|
||||
background: rgba(22, 22, 22, 0.5);
|
||||
backdrop-filter: blur(var(--mx-glass-blur)) saturate(var(--mx-glass-saturation));
|
||||
-webkit-backdrop-filter: blur(var(--mx-glass-blur)) saturate(var(--mx-glass-saturation));
|
||||
border-left: 1px solid var(--mx-glass-border-dark);
|
||||
filter: url(#mx-glass-filter);
|
||||
}
|
||||
|
||||
/* ── Popover ── */
|
||||
[data-glass="liquid"] .mx-popover {
|
||||
background: rgba(30, 30, 30, 0.5);
|
||||
backdrop-filter: blur(var(--mx-glass-blur)) saturate(var(--mx-glass-saturation));
|
||||
-webkit-backdrop-filter: blur(var(--mx-glass-blur)) saturate(var(--mx-glass-saturation));
|
||||
border: 1px solid var(--mx-glass-border-dark);
|
||||
filter: url(#mx-glass-filter);
|
||||
}
|
||||
|
||||
/* ── Select Dropdown ── */
|
||||
[data-glass="liquid"] .mx-select-dropdown {
|
||||
background: rgba(30, 30, 30, 0.5);
|
||||
backdrop-filter: blur(var(--mx-glass-blur)) saturate(var(--mx-glass-saturation));
|
||||
-webkit-backdrop-filter: blur(var(--mx-glass-blur)) saturate(var(--mx-glass-saturation));
|
||||
border: 1px solid var(--mx-glass-border-dark);
|
||||
filter: url(#mx-glass-filter);
|
||||
}
|
||||
|
||||
/* ── Card (opt-in via .mx-card-glass) ── */
|
||||
[data-glass="liquid"] .mx-card-glass {
|
||||
background: rgba(30, 30, 30, 0.4);
|
||||
backdrop-filter: blur(var(--mx-glass-blur)) saturate(var(--mx-glass-saturation));
|
||||
-webkit-backdrop-filter: blur(var(--mx-glass-blur)) saturate(var(--mx-glass-saturation));
|
||||
border: 1px solid var(--mx-glass-border-dark);
|
||||
filter: url(#mx-glass-filter);
|
||||
}
|
||||
|
||||
/* ═══════════════════════════════════════════
|
||||
LIGHT MODE
|
||||
═══════════════════════════════════════════ */
|
||||
|
||||
[data-theme="light"][data-glass="liquid"] .mx-topbar {
|
||||
background: rgba(255, 255, 255, 0.45);
|
||||
border-bottom: 1px solid var(--mx-glass-border-light);
|
||||
}
|
||||
|
||||
[data-theme="light"][data-glass="liquid"] .mx-sidebar {
|
||||
background: rgba(255, 255, 255, 0.45);
|
||||
border-right: 1px solid var(--mx-glass-border-light);
|
||||
}
|
||||
|
||||
[data-theme="light"][data-glass="liquid"] .mx-bottom-nav {
|
||||
background: rgba(255, 255, 255, 0.45);
|
||||
border-top: 1px solid var(--mx-glass-border-light);
|
||||
}
|
||||
|
||||
[data-theme="light"][data-glass="liquid"] .mx-modal {
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
border: 1px solid var(--mx-glass-border-light);
|
||||
}
|
||||
|
||||
[data-theme="light"][data-glass="liquid"] .mx-drawer {
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
border-left: 1px solid var(--mx-glass-border-light);
|
||||
}
|
||||
|
||||
[data-theme="light"][data-glass="liquid"] .mx-popover {
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
border: 1px solid var(--mx-glass-border-light);
|
||||
}
|
||||
|
||||
[data-theme="light"][data-glass="liquid"] .mx-select-dropdown {
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
border: 1px solid var(--mx-glass-border-light);
|
||||
}
|
||||
|
||||
[data-theme="light"][data-glass="liquid"] .mx-card-glass {
|
||||
background: rgba(255, 255, 255, 0.4);
|
||||
border: 1px solid var(--mx-glass-border-light);
|
||||
}
|
||||
|
||||
/* ═══════════════════════════════════════════
|
||||
OVER-LIGHT 模式
|
||||
亮色背景上使用的深色玻璃
|
||||
═══════════════════════════════════════════ */
|
||||
|
||||
[data-glass="liquid"][data-glass-over-light="true"] .mx-topbar,
|
||||
[data-glass="liquid"][data-glass-over-light="true"] .mx-sidebar,
|
||||
[data-glass="liquid"][data-glass-over-light="true"] .mx-bottom-nav,
|
||||
[data-glass="liquid"][data-glass-over-light="true"] .mx-modal,
|
||||
[data-glass="liquid"][data-glass-over-light="true"] .mx-drawer,
|
||||
[data-glass="liquid"][data-glass-over-light="true"] .mx-popover,
|
||||
[data-glass="liquid"][data-glass-over-light="true"] .mx-select-dropdown,
|
||||
[data-glass="liquid"][data-glass-over-light="true"] .mx-card-glass {
|
||||
background: rgba(0, 0, 0, 0.45);
|
||||
border-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
/* ═══════════════════════════════════════════
|
||||
GLASS 可追踪元素
|
||||
鼠标跟踪 + 弹性变换 + 双层边框
|
||||
═══════════════════════════════════════════ */
|
||||
|
||||
.mx-glass-trackable {
|
||||
position: relative;
|
||||
transition: transform 0.2s ease-out;
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
.mx-glass-trackable .mx-glass-border-layer {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
pointer-events: none;
|
||||
border-radius: inherit;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
/* Hover 高光层 */
|
||||
.mx-glass-trackable::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
border-radius: inherit;
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s ease-out;
|
||||
background-image: radial-gradient(circle at 50% 0%, rgba(255,255,255,0.5) 0%, rgba(255,255,255,0) 50%);
|
||||
mix-blend-mode: overlay;
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
.mx-glass-trackable:hover::after {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.mx-glass-trackable:active::after {
|
||||
opacity: 0.8;
|
||||
background-image: radial-gradient(circle at 50% 0%, rgba(255,255,255,1) 0%, rgba(255,255,255,0) 80%);
|
||||
}
|
||||
|
||||
/* ═══════════════════════════════════════════
|
||||
FALLBACK — browsers without SVG filter support
|
||||
═══════════════════════════════════════════ */
|
||||
@supports not (filter: url(#mx-glass-filter)) {
|
||||
[data-glass="liquid"] .mx-topbar,
|
||||
[data-glass="liquid"] .mx-sidebar,
|
||||
[data-glass="liquid"] .mx-bottom-nav,
|
||||
[data-glass="liquid"] .mx-modal,
|
||||
[data-glass="liquid"] .mx-drawer,
|
||||
[data-glass="liquid"] .mx-popover,
|
||||
[data-glass="liquid"] .mx-select-dropdown,
|
||||
[data-glass="liquid"] .mx-card-glass {
|
||||
filter: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* ═══════════════════════════════════════════
|
||||
REDUCED MOTION
|
||||
═══════════════════════════════════════════ */
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.mx-glass-trackable {
|
||||
transition: none !important;
|
||||
transform: none !important;
|
||||
}
|
||||
.mx-glass-trackable::after {
|
||||
transition: none !important;
|
||||
}
|
||||
}
|
||||
Vendored
+198
@@ -0,0 +1,198 @@
|
||||
/* ═══════════════════════════════════════════
|
||||
MIUIX CONSOLE — Design Tokens
|
||||
直接从 Miuix Colors.kt lightColorScheme() / darkColorScheme() 移植
|
||||
═══════════════════════════════════════════ */
|
||||
|
||||
:root {
|
||||
/* ── Primary — from Miuix lightColorScheme primary = Color(0xFF3482FF) ── */
|
||||
--mx-primary: #3482FF;
|
||||
--mx-primary-hover: #5D9BFF;
|
||||
--mx-primary-active: #277AF7;
|
||||
--mx-primary-on: #FFFFFF;
|
||||
--mx-primary-glow: rgba(52,130,255,0.12);
|
||||
--mx-primary-container: #5D9BFF;
|
||||
--mx-primary-container-on: #FFFFFF;
|
||||
--mx-primary-variant: #3482FF;
|
||||
--mx-primary-variant-on: #AECDFF;
|
||||
--mx-tertiary-container: #EAF2FF;
|
||||
--mx-tertiary-container-on: #3482FF;
|
||||
|
||||
/* ── Error — from Miuix error = Color(0xFFE94634) ── */
|
||||
--mx-error: #E94634;
|
||||
--mx-error-on: #FFFFFF;
|
||||
--mx-error-container: #FDF6F4;
|
||||
--mx-error-container-on: #410002;
|
||||
|
||||
/* ── Semantic ── */
|
||||
--mx-green: #34D399;
|
||||
--mx-amber: #FBBF24;
|
||||
--mx-blue: #60A5FA;
|
||||
|
||||
/* ── Surface — from Miuix lightColorScheme() 源码 ── */
|
||||
--mx-bg: #FFFFFF; /* background = White */
|
||||
--mx-surface: #F7F7F7; /* surface = 0xFFF7F7F7 */
|
||||
--mx-surface-variant: #FFFFFF; /* surfaceVariant = White */
|
||||
--mx-s1: #F7F7F7; /* surface */
|
||||
--mx-s2: #FFFFFF; /* surfaceContainer = White */
|
||||
--mx-s3: #E8E8E8; /* surfaceContainerHigh = 0xFFE8E8E8 */
|
||||
--mx-s4: #E8E8E8; /* surfaceContainerHighest = 0xFFE8E8E8 */
|
||||
--mx-s-hover: rgba(0,0,0,0.04);
|
||||
--mx-s-active: rgba(0,0,0,0.07);
|
||||
|
||||
/* ── Text — from Miuix 源码 ── */
|
||||
--mx-text: #000000; /* onSurface = Black */
|
||||
--mx-text-on-surface: rgba(0,0,0,0.8); /* onSurfaceSecondary = 0xCC000000 */
|
||||
--mx-text-variant: rgba(0,0,0,0.6); /* onSurfaceVariantSummary = 0x99000000 */
|
||||
--mx-text-actions: rgba(0,0,0,0.4); /* onSurfaceVariantActions = 0x66000000 */
|
||||
--mx-t2: rgba(0,0,0,0.6);
|
||||
--mx-t3: rgba(0,0,0,0.4);
|
||||
--mx-text-bg-variant: #8C93B0; /* onBackgroundVariant */
|
||||
--mx-text-container-variant: #959595; /* onSurfaceContainerVariant */
|
||||
--mx-text-container-high: #A2A2A2; /* onSurfaceContainerHigh */
|
||||
--mx-text-disabled: #B2B2B2; /* disabledOnSurface */
|
||||
|
||||
/* ── Secondary — from Miuix 源码 ── */
|
||||
--mx-secondary: #E6E6E6; /* secondary */
|
||||
--mx-secondary-variant: #F0F0F0; /* secondaryVariant */
|
||||
--mx-secondary-container: #F0F0F0;
|
||||
--mx-secondary-container-on: #A9A9A9;
|
||||
|
||||
/* ── Border / Divider — from Miuix 源码 ── */
|
||||
--mx-border: #D9D9D9; /* outline = 0xFFD9D9D9 */
|
||||
--mx-divider: #E0E0E0; /* dividerLine = 0xFFE0E0E0 */
|
||||
|
||||
/* ── Disabled — from Miuix 源码 ── */
|
||||
--mx-disabled-primary: #C2D9FF;
|
||||
--mx-disabled-primary-on: #F3F8FF;
|
||||
--mx-disabled-secondary: #F0F0F0;
|
||||
--mx-disabled-secondary-on: #FCFCFC;
|
||||
|
||||
/* ── Window ── */
|
||||
--mx-window-dim: rgba(0,0,0,0.3); /* windowDimming */
|
||||
|
||||
/* ── Slider — from Miuix 源码 ── */
|
||||
--mx-slider-bg: rgba(0,0,0,0.06); /* 0x0F000000 */
|
||||
--mx-slider-key: rgba(163,179,205,0.3);
|
||||
--mx-slider-key-fg: #6EB5FF;
|
||||
|
||||
/* ── Radius (Miuix Smooth Corner — 16dp default) ── */
|
||||
--mx-r: 16px;
|
||||
--mx-r-sm: 12px;
|
||||
--mx-r-xs: 8px;
|
||||
--mx-r-pill: 9999px;
|
||||
|
||||
/* ── Shadow (Miuix multi-layer soft shadow) ── */
|
||||
--mx-sh1: 0 1px 4px rgba(0,0,0,0.08);
|
||||
--mx-sh2: 0 4px 16px rgba(0,0,0,0.06);
|
||||
--mx-sh3: 0 8px 32px rgba(0,0,0,0.08);
|
||||
--mx-glow: 0 0 0 1px rgba(52,130,255,0.06), 0 2px 12px rgba(52,130,255,0.04);
|
||||
|
||||
/* ── Motion (Miuix spring + ease) ── */
|
||||
--mx-ease: cubic-bezier(0.16, 1, 0.3, 1);
|
||||
--mx-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||
--mx-d1: 100ms;
|
||||
--mx-d2: 200ms;
|
||||
--mx-d3: 320ms;
|
||||
--mx-d4: 500ms;
|
||||
|
||||
/* ── Typography ── */
|
||||
--mx-font: "MiSans", "Mi Sans", -apple-system, "PingFang SC", "Noto Sans SC", sans-serif;
|
||||
--mx-mono: "JetBrains Mono", "SF Mono", monospace;
|
||||
|
||||
/* Typography scale */
|
||||
--mx-text-xs: 11px;
|
||||
--mx-text-sm: 12px;
|
||||
--mx-text-base: 13px;
|
||||
--mx-text-md: 14px;
|
||||
--mx-text-lg: 15px;
|
||||
--mx-text-xl: 16px;
|
||||
--mx-text-2xl: 20px;
|
||||
--mx-text-3xl: 24px;
|
||||
|
||||
/* ── Safe area ── */
|
||||
--mx-safe-t: env(safe-area-inset-top, 0px);
|
||||
--mx-safe-b: env(safe-area-inset-bottom, 0px);
|
||||
}
|
||||
|
||||
/* ═══════════════════════════════════════════
|
||||
DARK MODE — from Miuix darkColorScheme() 源码
|
||||
═══════════════════════════════════════════ */
|
||||
[data-theme="dark"] {
|
||||
/* Primary — darkColorScheme primary = Color(0xFF277AF7) */
|
||||
--mx-primary: #277AF7;
|
||||
--mx-primary-hover: #338FE4;
|
||||
--mx-primary-active: #0073DD;
|
||||
--mx-primary-on: #FFFFFF;
|
||||
--mx-primary-glow: rgba(39,122,247,0.15);
|
||||
--mx-primary-container: #338FE4;
|
||||
--mx-primary-container-on: #FFFFFF;
|
||||
--mx-primary-variant: #0073DD;
|
||||
--mx-primary-variant-on: #99C7F1;
|
||||
--mx-tertiary-container: #2B3B54;
|
||||
--mx-tertiary-container-on: #4788FF;
|
||||
|
||||
/* Error — darkColorScheme error = Color(0xFFF12522) */
|
||||
--mx-error: #F12522;
|
||||
--mx-error-on: #FFFFFF;
|
||||
--mx-error-container: #2E0603;
|
||||
--mx-error-container-on: #FFDAD6;
|
||||
|
||||
/* Surface — 5-level gradient with 3-5% brightness steps */
|
||||
--mx-bg: #161616; /* 页面背景 — 最底层 */
|
||||
--mx-surface: #0C0C0C; /* surface = s1 */
|
||||
--mx-surface-variant: #1C1C1C; /* surfaceVariant = s2 */
|
||||
--mx-s1: #0C0C0C; /* 导航栏、侧边栏 — 比 bg 深 */
|
||||
--mx-s2: #1C1C1C; /* 卡片 — 比 bg 浅 */
|
||||
--mx-s3: #242424; /* 输入框、浮层 — 比 s2 浅 */
|
||||
--mx-s4: #2C2C2C; /* 下拉菜单 — 最亮 */
|
||||
--mx-s-hover: rgba(255,255,255,0.04);
|
||||
--mx-s-active: rgba(255,255,255,0.07);
|
||||
|
||||
/* Text — from Miuix darkColorScheme() 源码 */
|
||||
--mx-text: #F2F2F2; /* onSurface = 0xFFF2F2F2 */
|
||||
--mx-text-on-surface: rgba(255,255,255,0.8); /* 0xCCFFFFFF */
|
||||
--mx-text-variant: rgba(255,255,255,0.5); /* 0x80FFFFFF */
|
||||
--mx-text-actions: rgba(255,255,255,0.4); /* 0x66FFFFFF */
|
||||
--mx-t2: rgba(255,255,255,0.6);
|
||||
--mx-t3: rgba(255,255,255,0.4);
|
||||
--mx-text-bg-variant: #787E96;
|
||||
--mx-text-container-variant: #737373;
|
||||
--mx-text-container-high: #666666;
|
||||
--mx-text-disabled: #666666;
|
||||
|
||||
/* Secondary — from Miuix darkColorScheme() 源码 */
|
||||
--mx-secondary: #505050;
|
||||
--mx-secondary-variant: #434343;
|
||||
--mx-secondary-container: #434343;
|
||||
--mx-secondary-container-on: #7C7C7C;
|
||||
|
||||
/* Border / Divider — 提升对比度 */
|
||||
--mx-border: #484848; /* outline = 提升到可见 */
|
||||
--mx-divider: #404040; /* dividerLine = 提升到可见 */
|
||||
|
||||
/* Disabled */
|
||||
--mx-disabled-primary: #253E64;
|
||||
--mx-disabled-primary-on: #677993;
|
||||
--mx-disabled-secondary: #3F3F3F;
|
||||
--mx-disabled-secondary-on: #797979;
|
||||
|
||||
/* Window */
|
||||
--mx-window-dim: rgba(0,0,0,0.6);
|
||||
|
||||
/* Slider */
|
||||
--mx-slider-bg: rgba(255,255,255,0.15);
|
||||
--mx-slider-key: rgba(122,138,166,0.3);
|
||||
--mx-slider-key-fg: #5DAAFF;
|
||||
|
||||
/* Shadow — dark mode 阴影更重 */
|
||||
--mx-sh1: 0 1px 4px rgba(0,0,0,0.5);
|
||||
--mx-sh2: 0 4px 16px rgba(0,0,0,0.4);
|
||||
--mx-sh3: 0 8px 32px rgba(0,0,0,0.45);
|
||||
--mx-glow: 0 0 0 1px rgba(39,122,247,0.08), 0 2px 12px rgba(39,122,247,0.06);
|
||||
}
|
||||
|
||||
/* ═══ COMPACT DENSITY ═══ */
|
||||
[data-density="compact"] {
|
||||
--mx-r: 14px;
|
||||
--mx-r-sm: 10px;
|
||||
}
|
||||
Reference in new issue
Block a user