diff --git a/luci-theme-design/.gitignore b/luci-theme-design/.gitignore
deleted file mode 100644
index e69de29bb..000000000
diff --git a/luci-theme-design/CHANGELOG.md b/luci-theme-design/CHANGELOG.md
deleted file mode 100644
index a5265683d..000000000
--- a/luci-theme-design/CHANGELOG.md
+++ /dev/null
@@ -1,49 +0,0 @@
-# 更新日志
-
-## [7.0] - 2025-12-05
-
-### 新增
-- ✨ 支持 OpenWrt 23.x 版本
-- ✨ 支持 OpenWrt 24.x 版本
-- ✨ 新增版本兼容层 (`compat.js`)
-
-### 改进
-- 🔧 优化 LuCI API 调用,兼容新旧版本
-- 🔧 jQuery 依赖改为可选,无 jQuery 环境下自动降级
-- 🔧 改进 ubus 调用方式,支持不同版本
-- 🔧 优化菜单渲染逻辑,增加空值检查
-- 🔧 改进资源加载,添加版本化 URL
-
-### 修复
-- 🐛 修复新版本 LuCI 中 `dispatchpath` 未定义问题
-- 🐛 修复新版本中 `requestpath` 访问错误
-- 🐛 修复无 jQuery 环境下动画失效问题
-- 🐛 修复某些元素可能不存在导致的错误
-
-### 技术改进
-- 📦 更新 Makefile 版本号到 7.0
-- 📦 改进错误处理和边界检查
-- 📦 优化代码结构,提高可维护性
-
-## [6.0] - 2023-02-24
-
-### 之前的更新
-- 修复安装 package 提示信息背景泛白
-- 优化菜单缩放
-- 优化显示网口 down 状态显示图标
-- 优化 logo 显示
-- 新增各设备状态图标显示
-- 更换 logo 显示为字体 "OpenWrt",支持以主机名显示 logo
-- 修复部分插件显示 bug
-- 修复 vssr 状态 bar
-- 修复诸多 bug
-- 修复兼容部分插件样式
-- 修复 aliyundrive-webdav 样式
-- 修复 vssr 在 iOS/iPadOS WebApp 模式下显示异常
-- 修复 openclash 插件在 iOS/iPadOS WebApp 模式下 env(safe-area-inset-bottom) = 0
-- 优化菜单 hover action 状态分辨
-- 支持 luci-app-wizard 向导菜单
-- Update header box-shadow style
-- Update uci-change overflow
-- Fix nlbw component
-- Added QSDK/QWRT wizard and iStore menu icon fonts
diff --git a/luci-theme-design/COMPATIBILITY.md b/luci-theme-design/COMPATIBILITY.md
deleted file mode 100644
index ee143ad52..000000000
--- a/luci-theme-design/COMPATIBILITY.md
+++ /dev/null
@@ -1,67 +0,0 @@
-# 版本兼容性说明
-
-## 支持的 OpenWrt 版本
-
-本主题已针对以下 OpenWrt 版本进行优化和测试:
-
-- ✅ **OpenWrt 21.x** - 完全支持
-- ✅ **OpenWrt 23.x** - 完全支持
-- ✅ **OpenWrt 24.x** - 完全支持
-
-## 主要兼容性改进
-
-### 1. LuCI API 兼容
-- 兼容新旧版本的 `L.env.dispatchpath` 和 `L.env.requestpath`
-- 支持不同版本的 ubus 调用方式
-- 自动检测并适配 LuCI 版本
-
-### 2. JavaScript 依赖
-- jQuery 可选:在没有 jQuery 的环境下使用原生 JavaScript
-- 动画效果降级:无 jQuery 时使用 CSS 过渡
-- 兼容层自动检测运行环境
-
-### 3. 资源加载
-- 版本化资源 URL,避免缓存问题
-- 兼容不同版本的资源路径结构
-
-## 已知问题
-
-### OpenWrt 23/24 特定问题
-1. 某些第三方插件可能需要单独适配
-2. 如果遇到菜单显示问题,请清除浏览器缓存
-
-## 测试建议
-
-编译安装后,请测试以下功能:
-- [ ] 登录界面显示正常
-- [ ] 主菜单展开/收起
-- [ ] 移动端响应式布局
-- [ ] 深色模式切换
-- [ ] 各插件页面样式
-
-## 反馈问题
-
-如果在特定版本遇到问题,请提供:
-1. OpenWrt 版本号
-2. LuCI 版本号
-3. 浏览器类型和版本
-4. 具体问题截图
-
-## 技术细节
-
-### 兼容层实现
-主题包含 `compat.js` 兼容层,自动检测 LuCI 版本并提供统一接口。
-
-### 版本检测
-```javascript
-// 检测是否为新版本 LuCI (23+)
-if (L.env.luci_version) {
- var majorVersion = parseInt(L.env.luci_version.split('.')[0]);
- var isNewVersion = majorVersion >= 23;
-}
-```
-
-### jQuery 降级
-当 jQuery 不可用时,自动使用原生 DOM API:
-- `$(el).slideUp()` → `el.style.display = 'none'`
-- `$(el).css()` → `el.style.property = value`
diff --git a/luci-theme-design/LICENSE b/luci-theme-design/LICENSE
deleted file mode 100644
index 261eeb9e9..000000000
--- a/luci-theme-design/LICENSE
+++ /dev/null
@@ -1,201 +0,0 @@
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/luci-theme-design/Makefile b/luci-theme-design/Makefile
index d516301bf..bab427d2f 100644
--- a/luci-theme-design/Makefile
+++ b/luci-theme-design/Makefile
@@ -7,8 +7,9 @@ include $(TOPDIR)/rules.mk
LUCI_TITLE:=Design Theme
LUCI_DEPENDS:=
-PKG_VERSION:=7.0
-PKG_RELEASE:=2
+PKG_LICENSE:=Apache-2.0
+PKG_VERSION:=7.1
+PKG_RELEASE:=3
LUCI_MINIFY_CSS:=
CONFIG_LUCI_CSSTIDY:=
diff --git a/luci-theme-design/README.md b/luci-theme-design/README.md
deleted file mode 100644
index 269c000ad..000000000
--- a/luci-theme-design/README.md
+++ /dev/null
@@ -1,140 +0,0 @@
-
-
-# luci-theme-design
-
-**luci-theme-design**基于[luci-theme-neobird](https://github.com/thinktip/luci-theme-neobird)二次开发
-
-## 版本支持
-
-- ✅ OpenWrt 21.x
-- ✅ OpenWrt 23.x
-- ✅ OpenWrt 24.x
-- 适用于官方 [OpenWrt](https://github.com/openwrt/openwrt)
-
-- 修复安装package提示信息背景泛白
-- 优化菜单缩放
-- 优化显示网口down状态显示图标
-- 优化logo显示
-- 新增各设备状态图标显示
-- 更换logo显示为字体"OpenWrt",支持以主机名显示logo
-- 修复部分插件显示bug
-- 修复vssr状态bar
-- 修复诸多bug
-- 修复兼容部分插件样式
-- 修复aliyundrive-webdav样式
-- 修复vssr在iOS/iPadOS WebApp模式下显示异常
-- 修复openclash插件在iOS/iPadOS WebApp 模式下env(safe-area-inset-bottom) = 0
-- 优化菜单hover action状态分辨
-- 支持luci-app-wizard向导菜单
-- Update header box-shadow style
-- Update uci-change overflow
-- Fix nlbw component
-- Added QSDK/QWRT wizard and iStore menu icon fonts
-- 新增 OpenWrt 23/24 版本兼容支持
-- 优化 LuCI 新旧版本兼容层
-- 修复新版本 API 调用问题
-
-## 主要特点
-
-- 针对移动端优化,特别适合手机端做为webapp使用
-- 修改和优化了很多插件显示,完善的icon图标,尽量视觉统一
-- 简洁的登录界面,底部导航栏,类App的沉浸式体验;
-- 适配深色模式,适配系统自动切换;
-
-## 体验Webapp方法
-
-- 在移动端(iOS/iPadOS)浏览器打开管理界面,添加到主屏幕即可。
-- 想要实现完全的沉浸式(无浏览器导航、无地址栏等)体验,需要使用SSL证书,请自行申请域名、证书、安装并启用。
-- 如果不使用SSL证书,基于安全原因,iOS/iPadOS 在打开新的页面后,将会显示浏览器顶部菜单栏。
-
-## PS
-
-- 资源接口icon未完善,如果有能力画图的欢迎pr,但请确保跟现有icon颜色风格一致
-- 有bug欢迎提issue
-- 主题个人配色可能会不符合大众胃口,欢迎提配色建议
-
-## 自行编译
-
-### OpenWrt 21/23/24 通用方法
-
-```bash
-# 进入 OpenWrt 源码目录
-cd openwrt
-
-# 克隆主题到 package 目录
-git clone https://github.com/gngpp/luci-theme-design.git package/luci-theme-design
-
-# 配置编译选项
-make menuconfig
-# 选择: LuCI -> 3. Themes -> luci-theme-design
-
-# 编译
-make package/luci-theme-design/compile V=s
-```
-
-### 安装后测试
-
-```bash
-# 上传测试脚本到路由器
-scp test-compatibility.sh root@192.168.1.1:/tmp/
-
-# SSH 登录路由器
-ssh root@192.168.1.1
-
-# 运行兼容性测试
-sh /tmp/test-compatibility.sh
-```
-
-### 手动激活主题
-
-如果主题未自动激活,可以手动设置:
-
-```bash
-uci set luci.main.mediaurlbase='/luci-static/design'
-uci commit luci
-/etc/init.d/uhttpd restart
-```
-
-## 版本兼容性
-
-详细的兼容性信息请查看 [COMPATIBILITY.md](COMPATIBILITY.md)
-
-- OpenWrt 21.x - 完全支持 ✅
-- OpenWrt 23.x - 完全支持 ✅
-- OpenWrt 24.x - 完全支持 ✅
-
-## 故障排除
-
-### 主题显示异常
-1. 清除浏览器缓存(Ctrl+F5 强制刷新)
-2. 检查主题文件是否完整安装
-3. 运行兼容性测试脚本
-
-### 菜单无法展开
-1. 检查浏览器控制台是否有 JavaScript 错误
-2. 确认 LuCI 版本兼容性
-3. 尝试禁用浏览器扩展
-
-### 移动端显示问题
-1. 确保使用 HTTPS(WebApp 模式需要)
-2. 清除浏览器缓存
-3. 重新添加到主屏幕
-
-## 预览(ps: 下面PC端普通字体为苹果浏览器字体,只有移动端是正常显示的)
-
- iOS
-
-
-
-
- iPadOS
-
-
-
-
-
-
-
-
-
-
diff --git a/luci-theme-design/htdocs/luci-static/design/css/compat-openwrt23.css b/luci-theme-design/htdocs/luci-static/design/css/compat-openwrt23.css
deleted file mode 100644
index e1e5a26df..000000000
--- a/luci-theme-design/htdocs/luci-static/design/css/compat-openwrt23.css
+++ /dev/null
@@ -1,431 +0,0 @@
-/**
- * OpenWrt 23/24 兼容性样式补ä¸?
- *
- * 这个文件包含针对 OpenWrt 23.x å’?24.x 的样式修å¤?
- * 新版 LuCI 使用了一些新çš?CSS 类名和结æž?
- */
-
-/* ============================================
- 1. 新版 LuCI 视图容器兼容
- ============================================ */
-
-/* 新版 LuCI 使用 #view 作为主要内容容器 */
-#view {
- padding: 0;
-}
-
-#view > * {
- margin-bottom: 1rem;
-}
-
-/* 兼容新版 LuCI çš?.cbi-map 结构 */
-.cbi-map {
- margin-top: 10px;
-}
-
-/* ============================================
- 2. 新版表单元素样式
- ============================================ */
-
-/* 新版 LuCI çš?input 样式兼容 */
-.cbi-input-text,
-.cbi-input-password,
-.cbi-input-select {
- color: var(--inputtext_color);
- padding: 5px 10px;
- font-size: 0.92rem;
- border: var(--input_border);
- background-color: var(--inputbg_color);
- border-radius: 8px;
- height: 2.8rem;
- line-height: 2.8rem;
- max-width: 550px;
-}
-
-/* 新版 checkbox å’?radio 样式 */
-.cbi-input-checkbox,
-.cbi-input-radio {
- width: 1.2rem;
- height: 1.2rem;
- margin-right: 0.5rem;
- vertical-align: middle;
- accent-color: var(--active_color);
-}
-
-/* ============================================
- 3. 新版按钮样式兼容
- ============================================ */
-
-/* 新版 LuCI 按钮类名 */
-.btn.cbi-button,
-button.cbi-button {
- -webkit-appearance: none;
- appearance: none;
- text-transform: uppercase;
- color: #fff;
- background-color: #337ab7;
- transition: all 0.2s ease-in-out;
- display: inline-block;
- border: none;
- cursor: pointer;
- text-align: center;
- white-space: nowrap;
- min-width: 80px;
- padding: 0 8px;
- height: 35px;
- line-height: 35px;
- border-radius: 8px;
-}
-
-/* 新版 primary/positive 按钮 */
-.cbi-button-positive,
-.cbi-button-action {
- color: var(--bttext_color) !important;
- background-color: var(--active_color) !important;
-}
-
-.cbi-button-positive:hover,
-.cbi-button-action:hover {
- background-color: #4a8a80 !important;
-}
-
-/* 新版 negative 按钮 */
-.cbi-button-negative {
- color: #fff !important;
- background-color: #d9534f !important;
-}
-
-.cbi-button-negative:hover {
- background-color: #c9302c !important;
-}
-
-/* 新版 neutral 按钮 */
-.cbi-button-neutral {
- color: #fff !important;
- background-color: #617486 !important;
-}
-
-/* ============================================
- 4. 新版表格样式兼容
- ============================================ */
-
-/* 新版 LuCI 表格结构 */
-.table.cbi-section-table {
- width: 100%;
- border-collapse: collapse;
-}
-
-.table.cbi-section-table .tr {
- display: table-row;
-}
-
-.table.cbi-section-table .th,
-.table.cbi-section-table .td {
- display: table-cell;
- padding: 12px;
- vertical-align: middle;
-}
-
-/* 新版表格标题è¡?*/
-.tr.cbi-section-table-titles {
- background-color: var(--inputbg_color);
- font-weight: bold;
-}
-
-/* ============================================
- 5. 新版下拉菜单兼容
- ============================================ */
-
-/* 新版 cbi-dropdown 样式 */
-.cbi-dropdown {
- position: relative;
- display: inline-flex;
- min-height: 2.8rem;
- border: var(--input_border);
- background-color: var(--inputbg_color);
- border-radius: 8px;
-}
-
-.cbi-dropdown > ul {
- display: flex;
- overflow-x: hidden;
- overflow-y: auto;
- width: 100%;
- margin: 0 !important;
- padding: 0;
- list-style: none;
-}
-
-.cbi-dropdown > ul > li {
- display: flex;
- align-items: center;
- padding: 0.5em;
-}
-
-.cbi-dropdown[open] > ul.dropdown {
- position: absolute;
- z-index: 1100;
- top: 100%;
- left: 0;
- right: 0;
- background: var(--sectionbg_color);
- border: var(--input_border);
- border-radius: 0 0 8px 8px;
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
-}
-
-.cbi-dropdown[open] > ul.dropdown > li {
- padding: 0.5em 1em;
- cursor: pointer;
-}
-
-.cbi-dropdown[open] > ul.dropdown > li:hover {
- background-color: var(--active_color);
- color: #fff;
-}
-
-/* ============================================
- 6. 新版标签页样式兼å®?
- ============================================ */
-
-/* 新版 LuCI 标签é¡?*/
-.cbi-tabmenu {
- display: flex;
- flex-wrap: wrap;
- border-bottom: var(--tabmenu_bottom);
- margin-bottom: 1rem;
-}
-
-.cbi-tabmenu > li {
- display: inline-block;
- margin-right: 0.5rem;
-}
-
-.cbi-tabmenu > li > a {
- display: block;
- padding: 0.5rem 1rem;
- text-decoration: none;
- color: var(--text_color);
- border-bottom: 2px solid transparent;
- transition: all 0.2s;
-}
-
-.cbi-tabmenu > li.cbi-tab > a,
-.cbi-tabmenu > li > a:hover {
- color: var(--active_color);
- border-bottom-color: var(--active_color);
-}
-
-/* ============================================
- 7. 新版模态框样式兼容
- ============================================ */
-
-/* 新版 modal 样式 */
-.modal {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- width: 90%;
- max-width: 600px;
- min-height: 32px;
- margin: 5em auto;
- padding: 1em;
- border-radius: 8px;
- background: var(--model_background);
- box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
-}
-
-.modal > * {
- flex-basis: 100%;
- margin-bottom: 0.5em;
-}
-
-.modal > h4 {
- color: var(--text_color);
- margin-bottom: 1em;
-}
-
-.modal > .btn,
-.modal > .cbi-button {
- flex-basis: auto;
- margin: 0.25em;
-}
-
-/* ============================================
- 8. 新版进度条样式兼å®?
- ============================================ */
-
-/* 新版进度æ�?*/
-.cbi-progressbar {
- position: relative;
- min-width: 11rem;
- height: 1.5rem;
- background-color: var(--progressbar_color);
- border-radius: 5px;
- overflow: hidden;
-}
-
-.cbi-progressbar > div {
- height: 100%;
- background: var(--progressbar);
- transition: width 0.25s ease-in;
-}
-
-.cbi-progressbar::after {
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- content: attr(title);
- text-align: center;
- line-height: 1.5rem;
- font-size: 0.75rem;
- color: var(--progressbartxt_color);
-}
-
-/* ============================================
- 9. 新版状态指示器兼容
- ============================================ */
-
-/* 新版状态徽ç«?*/
-.ifacebadge {
- display: inline-flex;
- align-items: center;
- gap: 0.2rem;
- padding: 0.3rem 0.6rem;
- background-color: var(--active_color);
- color: #fff;
- border-radius: 8px;
- font-size: 0.85rem;
-}
-
-.ifacebadge > img,
-.ifacebadge > em {
- width: 16px;
- height: 16px;
-}
-
-/* 区域徽章 */
-.zonebadge {
- display: inline-block;
- padding: 0.2rem 0.5rem;
- border-radius: 4px;
-}
-
-/* ============================================
- 10. 新版响应式布局兼容
- ============================================ */
-
-@media screen and (max-width: 992px) {
- /* 新版移动端菜å�?*/
- .main-left {
- transform: translateX(-100%);
- transition: transform 0.3s ease;
- }
-
- .main-left.active,
- .main-left[style*="width: 17rem"],
- .main-left:not([style*="width: 0"]) {
- transform: translateX(0);
- }
-}
-
-/* ============================================
- 11. 新版 LuCI 特定页面修复
- ============================================ */
-
-/* 系统概览页面 */
-[data-page="admin-status-overview"] .cbi-section {
- margin-bottom: 1rem;
-}
-
-/* 网络接口页面 */
-[data-page="admin-network-network"] .ifacebox {
- margin: 0.5rem;
- border-radius: 8px;
- overflow: hidden;
-}
-
-/* 无线页面 */
-[data-page="admin-network-wireless"] .cbi-section-table {
- overflow-x: auto;
-}
-
-/* 软件包页é�?*/
-[data-page="admin-system-opkg"] .controls {
- display: flex;
- flex-wrap: wrap;
- gap: 0.5rem;
- margin-bottom: 1rem;
-}
-
-[data-page="admin-system-opkg"] .controls input[type="text"] {
- flex: 1;
- min-width: 200px;
-}
-
-/* ============================================
- 12. 深色模式增强
- ============================================ */
-
-@media (prefers-color-scheme: dark) {
- /* 新版深色模式下的代码å�?*/
- code, pre {
- background-color: #2d2d2d;
- color: #f8f8f2;
- }
-
- /* 新版深色模式下的表格 */
- .table.cbi-section-table .tr:nth-child(even) {
- background-color: rgba(255, 255, 255, 0.05);
- }
-
- /* 新版深色模式下的输入æ¡?*/
- .cbi-input-text:focus,
- .cbi-input-password:focus,
- .cbi-input-select:focus {
- border-color: var(--active_color);
- box-shadow: 0 0 6px var(--active_color);
- }
-}
-
-/* ============================================
- 13. 打印样式
- ============================================ */
-
-@media print {
- .main-left,
- .navbar,
- header,
- .showSide,
- .darkMask {
- display: none !important;
- }
-
- .main-right {
- width: 100% !important;
- margin: 0 !important;
- }
-}
-
-/* ============================================
- 14. 无障碍访问增å¼?
- ============================================ */
-
-/* 焦点可见æ€?*/
-:focus-visible {
- outline: 2px solid var(--active_color);
- outline-offset: 2px;
-}
-
-/* 减少动画 (用户偏好) */
-@media (prefers-reduced-motion: reduce) {
- *,
- *::before,
- *::after {
- animation-duration: 0.01ms !important;
- animation-iteration-count: 1 !important;
- transition-duration: 0.01ms !important;
- }
-}
diff --git a/luci-theme-design/htdocs/luci-static/design/css/style.css b/luci-theme-design/htdocs/luci-static/design/css/style.css
index ccc32fb09..c9edb9318 100644
--- a/luci-theme-design/htdocs/luci-static/design/css/style.css
+++ b/luci-theme-design/htdocs/luci-static/design/css/style.css
@@ -115,6 +115,11 @@
src: url('../fonts/Cocon-Regular-Font.otf') format('opentype');
}
+@font-face {
+ font-family: 'genjyuugothic-medium';
+ src: url('../fonts/GenJyuuGothic-Medium.otf') format('opentype');
+}
+
div{
font-family: 'HYk2gj';
}
@@ -289,22 +294,19 @@ input:focus {
-moz-box-shadow:0 0 6px #948FE1;
}
-select,
-.cbi-dropdown {
+select {
width: inherit;
cursor: default;
}
select:not([multiple="multiple"]):focus,
-input:not(.cbi-button):focus,
-.cbi-dropdown:focus {
+input:not(.cbi-button):focus {
border-color: #948FE1;
box-shadow:0 0 6px #948FE1;
-webkit-box-shadow:0 0 6px #948FE1;
-moz-box-shadow:0 0 6px #948FE1;
}
-.cbi-dropdown,
select[multiple="multiple"] {
height: auto;
}
@@ -401,7 +403,10 @@ small {
width: 100%;
height: 100%;
z-index: 1000;
- display: block;
+ display: none;
+ visibility: hidden;
+ opacity: 0;
+ pointer-events: none;
background-color: var(--bgwhite);
top: 0;
}
@@ -502,7 +507,7 @@ header > .fill > .container > #logo > img {
header > .fill > .container > .brand {
font-size: 25px;
- font-family: "cocon_regular_font";
+ font-family: 'genjyuugothic-medium', -apple-system, 'Microsoft Yahei', sans-serif, Helvetica, Arial, sans-serif;
/*font-weight:bold;*/
line-height:60px;
/*color: white;*/
@@ -515,15 +520,15 @@ header > .fill > .container > .brand {
height:60px;
text-align:center;
float:left;
- font-weight:900;
- letter-spacing:1px;
+ font-weight:700;
+ letter-spacing:.04em;
margin-left: 10px;
}
header > .fill > .container > a[class="brand"]:after {
content:"";
font-size:14px;
- font-family:Tahoma;
+ font-family: inherit;
position: absolute;
top:-10px;
font-weight:normal !important;
@@ -547,22 +552,92 @@ header > .fill > .container > .brand-hostname {
header > .fill > .container > .status {
position: absolute;
- top: 25%;
+ top: 50%;
right: 1em;
+ display: flex;
+ align-items: center;
+ gap: 0.2rem;
float: right;
font-size: 1.5rem;
font-family: 'design';
- line-height: unset !important;
+ line-height: 1 !important;
+ transform: translateY(-50%);
}
header > .fill > .container > .status > * {
position: relative;
- top: .2rem;
- float: left;
- margin-left: .3rem;
+ top: auto;
+ float: none;
+ margin-left: 0.3rem;
cursor: pointer;
}
+#indicators > [data-indicator] {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ min-width: 1.6rem;
+ min-height: 1.6rem;
+ padding: 0;
+ border-radius: 999px;
+ background: transparent;
+ box-shadow: none;
+ text-transform: none;
+ text-shadow: none;
+}
+
+#indicators > [data-indicator="poll-status"],
+#indicators > [data-indicator="uci-changes"] {
+ font-size: 0;
+}
+
+#indicators > [data-indicator="poll-status"]::before,
+#indicators > [data-indicator="uci-changes"]::before {
+ font-family: "design" !important;
+ font-style: normal;
+ font-weight: normal;
+ line-height: 1;
+ text-transform: none;
+ -webkit-font-smoothing: antialiased;
+}
+
+#indicators > [data-indicator="poll-status"]::before {
+ content: "\e6b9";
+ font-size: 1.5rem;
+}
+
+#indicators > [data-indicator="poll-status"][data-style="inactive"]::before {
+ color: var(--progressbar_color);
+}
+
+#indicators > [data-indicator="poll-status"]:not([data-style="inactive"])::before {
+ color: var(--active_color);
+}
+
+#indicators > [data-indicator="uci-changes"]::before {
+ content: "\e739";
+ font-size: 1.45rem;
+ color: var(--active_color);
+}
+
+#indicators > [data-indicator="uci-changes"][data-count]:not([data-count=""])::after {
+ content: attr(data-count);
+ position: absolute;
+ top: -0.18rem;
+ right: -0.08rem;
+ min-width: 0.95rem;
+ height: 0.95rem;
+ padding: 0 0.14rem;
+ border-radius: 999px;
+ background: var(--active_color);
+ color: var(--bgwhite);
+ font-family: Tahoma, sans-serif;
+ font-size: 0.62rem;
+ font-weight: normal;
+ line-height: 0.95rem;
+ text-align: center;
+}
+
/* .modemenu-buttons {
display: flex;
flex-wrap: wrap;
@@ -781,6 +856,21 @@ span[data-indicator="uci-changes"] {
content: "\72";
}
+.main > .main-left > .nav > .slide > a[data-title="Modem"]:before,
+.main > .main-left > .nav > li > a[data-title="Modem"]:before,
+.main > .main-left > .nav > .slide > a[data-title="Mobile"]:before,
+.main > .main-left > .nav > li > a[data-title="Mobile"]:before,
+.main > .main-left > .nav > .slide > a[data-title="Mobile_Service"]:before,
+.main > .main-left > .nav > li > a[data-title="Mobile_Service"]:before,
+.main > .main-left > .nav > .slide > a[data-title="Cellular"]:before,
+.main > .main-left > .nav > li > a[data-title="Cellular"]:before,
+.main > .main-left > .nav > .slide > a[data-title="WWAN"]:before,
+.main > .main-left > .nav > li > a[data-title="WWAN"]:before,
+.main > .main-left > .nav > .slide > a[data-title="ModemManager"]:before,
+.main > .main-left > .nav > li > a[data-title="ModemManager"]:before {
+ content: "\e67e";
+}
+
.main > .main-left > .nav > .slide > a[data-title="Bandwidth Monitor"]:before {
content: "\e764";
}
@@ -797,23 +887,26 @@ span[data-indicator="uci-changes"] {
content: "\e7dd";
}
-.main > .main-left > .nav > li > a[data-title="Inital Setup"]:before {
- content: "\e67e";
-}
-
-.main > .main-left > .nav > li > a[href="/cgi-bin/luci//admin/wizard"]:before {
- content: "\e67e";
+.main > .main-left > .nav > li > a[data-title="Inital Setup"]:before,
+.main > .main-left > .nav > li > a[data-title="Setup_Wizard"]:before,
+.main > .main-left > .nav > li > a[href="/cgi-bin/luci//admin/wizard"]:before,
+.main > .main-left > .nav > li > a[href="/cgi-bin/luci/admin/wizard"]:before {
+ content: "\e719";
+ width: 1.2rem;
+ text-align: center;
}
.main > .main-left > .nav > li > a[data-title="iStore"]:before {
content: "\e676";
}
-.main > .main-left > .nav > li > a[data-title="Logout"] {
+.main > .main-left > .nav > li > a[data-title="Logout"],
+.main > .main-left > .nav > li > a[data-title="Log_out"] {
padding: 0.675rem 0 0.675rem 2.5rem;
}
-.main > .main-left > .nav > li > a[data-title="Logout"]:before {
+.main > .main-left > .nav > li > a[data-title="Logout"]:before,
+.main > .main-left > .nav > li > a[data-title="Log_out"]:before {
content: "\e641";
}
@@ -898,7 +991,11 @@ body[class*="node-"] > .main > .main-left > .nav > .slide > .menu.active::before
/* ripple effect */
.main > .main-left > .nav > .slide > .menu,
-.main > .main-left > .nav > li:last-child a
+.main > .main-left > .nav > li:last-child a,
+.main > .main-left > .nav > li > a[data-title="Inital Setup"],
+.main > .main-left > .nav > li > a[data-title="Setup_Wizard"],
+.main > .main-left > .nav > li > a[href="/cgi-bin/luci//admin/wizard"],
+.main > .main-left > .nav > li > a[href="/cgi-bin/luci/admin/wizard"]
{
display: block;
padding: 0.675rem 0 0.675rem 2.5rem;
@@ -1059,15 +1156,25 @@ fieldset > fieldset,
box-shadow: none;
}
+/* Avoid clipping LuCI dropdown popups inside nested form sections. */
+fieldset,
+fieldset.cbi-section {
+ overflow-y: visible;
+}
+
.cbi-section > h3:first-child,
.panel-title {
width: 100%;
display: block;
padding: 10px;
- font-weight: bold;
+ font-weight: 700;
font-size: 1rem;
}
+[data-tab-title] > h3:first-child {
+ font-weight: 700;
+}
+
.cbi-section > h4:first-child,
.cbi-section > p:first-child,
[data-tab-title] > h3:first-child,
@@ -1144,7 +1251,6 @@ table > tr:last-child {
margin-bottom: 0;
}
-.cbi-section-table-row > .cbi-value-field .cbi-dropdown,
.cbi-section-table-row > .cbi-value-field .cbi-input-select,
.cbi-section-table-row > .cbi-value-field .cbi-input-text,
.cbi-section-table-row > .cbi-value-field .cbi-input-password {
@@ -1281,6 +1387,7 @@ form.inline + form.inline,
.cbi-button-edit {
color: #fff !important;
background-color: var(--active_color);
+ border-color: var(--active_color);
}
[data-page="admin-status-iptables"] .right {
@@ -1358,6 +1465,7 @@ form.inline + form.inline,
height: 2.5rem;
line-height: 2.5rem;
font-size: 0.92rem;
+ font-weight: 700;
margin: 0 10px;
}
@@ -1410,6 +1518,7 @@ form.inline + form.inline,
overflow: hidden;
height: 0;
opacity: 0;
+ pointer-events: none;
margin: 0;
padding: 0rem 1rem !important;
}
@@ -1418,6 +1527,7 @@ form.inline + form.inline,
overflow: auto;
height: auto;
opacity: 1;
+ pointer-events: auto;
transition: opacity .25s ease-in;
margin: inherit !important;
display: block;
@@ -1491,7 +1601,6 @@ form.inline + form.inline,
font-weight: normal;
}
-.cbi-value-field .cbi-dropdown,
.cbi-value-field .cbi-input-select,
.cbi-value input[type="text"],
.cbi-value input[type="password"] {
@@ -1651,90 +1760,106 @@ form.inline + form.inline,
min-width: 13rem;
}
-.cbi-dynlist,
-.cbi-dropdown {
+.cbi-dynlist {
position: relative;
display: inline-flex;
padding: 0;
}
-.cbi-dropdown[placeholder*="select"] {
- max-width: 25rem;
- height: auto;
- margin-top: -3px;
+.cbi-dropdown {
+ position: relative;
+ display: inline-flex;
+ align-items: stretch;
+ width: 100%;
+ max-width: 550px;
+ min-height: 2.8rem;
+ color: var(--inputtext_color);
+ background: var(--inputbg_color);
+ border: var(--input_border);
+ border-radius: 8px;
+ transition: color 150ms ease, border-color 150ms ease, box-shadow 150ms ease, background-color 150ms ease;
}
.cbi-dropdown > ul {
display: flex;
- overflow-x: hidden;
- overflow-y: auto;
+ flex: 1 1 auto;
+ overflow: hidden;
width: 100%;
margin: 0 !important;
padding: 0;
list-style: none;
- outline: 0;
+}
+
+.cbi-dropdown.btn,
+.cbi-dropdown.cbi-button {
+ width: auto;
+ max-width: none;
+ min-width: 105px;
+ min-height: 35px;
+ height: 35px;
+ line-height: 35px;
+ color: #fff;
+ background: transparent;
+ border: none;
+ box-shadow: none;
+}
+
+.cbi-dropdown.btn > ul:not(.dropdown),
+.cbi-dropdown.cbi-button > ul:not(.dropdown) {
+ width: auto;
+ padding-left: 0.5em;
+}
+
+.cbi-dropdown.btn.spinning > ul:not(.dropdown),
+.cbi-dropdown.cbi-button.spinning > ul:not(.dropdown) {
+ padding-left: 0;
}
.cbi-dropdown > ul.preview {
display: none;
}
-.cbi-dropdown > .open {
- flex-basis: 15px;
-}
-
.cbi-dropdown > .open,
.cbi-dropdown > .more {
- font-size: 1rem;
- font-weight: 900;
- line-height: 2;
- display: flex;
- flex-direction: column;
- flex-grow: 0;
- flex-shrink: 0;
+ display: inline-flex;
+ align-items: center;
justify-content: center;
- padding: 0 .25em;
- cursor: default;
- text-align: center;
- outline: 0;
+ flex: 0 0 auto;
+ min-width: 2.25rem;
+ padding: 0 0.6rem;
+ color: var(--inputtext_color);
+ border-left: 1px solid rgba(0, 0, 0, 0.08);
}
-.cbi-dropdown.btn {
- min-height: 1.8rem;
- padding-top: 0px;
- padding-bottom: 0px;
- padding-right: 0px;
+.cbi-dropdown.btn > .open,
+.cbi-dropdown.btn > .more,
+.cbi-dropdown.cbi-button > .open,
+.cbi-dropdown.cbi-button > .more {
+ color: inherit;
+ border-left: 1px solid rgba(255, 255, 255, 0.28);
}
-.cbi-dropdown.btn > .open {
- font-size: 0.8rem;
- padding: 0px;
- margin: 0 5px;
-}
-
-.cbi-dropdown.btn > div {
- margin: 0px;
+.cbi-dropdown > .open {
+ font-size: 0.85rem;
}
.cbi-dropdown > .more,
.cbi-dropdown > ul > li[placeholder] {
- font-weight: bold;
+ color: rgba(118, 131, 143, 0.85);
display: none;
- color: #777;
- text-shadow: 1px 1px 0 #fff;
}
.cbi-dropdown > ul > li {
display: none;
- overflow: hidden;
align-items: center;
- align-self: center;
- flex-grow: 1;
- flex-shrink: 1;
- min-height: 20px;
- padding: .25em;
+ flex: 1 1 auto;
+ min-height: 2.8rem;
+ padding: 0 0.75rem;
+ overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
+ color: var(--inputtext_color);
+ background: transparent;
}
.cbi-dropdown > ul > li .hide-open {
@@ -1745,52 +1870,6 @@ form.inline + form.inline,
display: none;
}
-.cbi-dropdown > ul > li[display]:not([display="0"]) {
- border-left: thin solid #ccc;
-}
-
-.cbi-dropdown > ul > li[data-value*="1"] {
- padding-left: 15px !important;
-}
-
-.cbi-dropdown[empty] > ul {
- max-width: 1px;
-}
-
-.cbi-dropdown > ul > li > form {
- display: none;
- margin: 0;
- padding: 0;
- pointer-events: none;
-}
-
-.cbi-dropdown > ul > li img {
- margin-right: .25em;
- vertical-align: middle;
-}
-
-.cbi-dropdown > ul > li > form > input[type="checkbox"] {
- height: auto;
- margin: 0;
-}
-
-.cbi-dropdown > ul > li input[type="text"] {
- height: 20px;
-}
-
-.cbi-dropdown[open] > ul.dropdown {
- position: absolute;
- z-index: 1100;
- display: block;
- width: auto;
- max-height: 200px !important;
- /* border: thin solid #918e8c; */
- background: var(--active_color);
- /* box-shadow: 0 0 4px #918e8c; */
- /* color: var(--main-menu-color); */
- text-align: center;
-}
-
.cbi-dropdown > ul > li[display],
.cbi-dropdown[open] > ul.preview,
.cbi-dropdown[open] > ul.dropdown > li,
@@ -1800,7 +1879,6 @@ form.inline + form.inline,
.cbi-dropdown[multiple][empty] > .more {
display: flex;
align-items: center;
- flex-grow: 1;
}
.cbi-dropdown[empty] > ul > li,
@@ -1809,6 +1887,94 @@ form.inline + form.inline,
display: block;
}
+.cbi-dropdown > ul > li > form {
+ display: none;
+ margin: 0;
+ padding: 0;
+ pointer-events: none;
+}
+
+.cbi-dropdown > ul > li img {
+ margin-right: 0.35rem;
+ vertical-align: middle;
+}
+
+.cbi-dropdown > ul > li input[type="text"] {
+ height: 2.2rem;
+ margin: 0;
+ padding: 0;
+ border: none;
+ background: transparent;
+ box-shadow: none;
+}
+
+.cbi-dropdown[open],
+.cbi-dropdown:focus-within {
+ border-color: #948FE1;
+ box-shadow: 0 0 6px rgba(148, 143, 225, 0.35);
+}
+
+.cbi-dropdown.btn[open],
+.cbi-dropdown.btn:focus-within,
+.cbi-dropdown.cbi-button[open],
+.cbi-dropdown.cbi-button:focus-within {
+ box-shadow: 0 1px 1px rgba(0, 0, 0, .05);
+}
+
+/* Keep LuCI dropdowns functional by only fixing layering/clipping. */
+.cbi-dropdown[open] {
+ position: relative;
+}
+
+.cbi-dropdown[open] > ul.dropdown {
+ position: absolute;
+ top: auto;
+ bottom: auto;
+ left: 0;
+ z-index: 1200;
+ display: block;
+ min-width: 100%;
+ padding: 0.25rem 0;
+ max-height: 200px;
+ overflow-x: hidden;
+ overflow-y: auto;
+ background: var(--sectionbg_color);
+ border: var(--input_border);
+ border-radius: 10px;
+ box-shadow: 0 16px 32px rgba(0, 0, 0, 0.12);
+}
+
+.cbi-dropdown.btn[open] > ul.dropdown,
+.cbi-dropdown.cbi-button[open] > ul.dropdown {
+ color: var(--text_color);
+ background: var(--sectionbg_color);
+ border: var(--input_border);
+}
+
+.cbi-dropdown.btn[open] > ul.dropdown > li[selected],
+.cbi-dropdown.cbi-button[open] > ul.dropdown > li[selected] {
+ color: #2f6f9f;
+ background: #d9eefb;
+}
+
+.cbi-dropdown.btn[open] > ul.dropdown > li.focus:not([selected]),
+.cbi-dropdown.btn[open] > ul.dropdown > li:hover:not([selected]),
+.cbi-dropdown.cbi-button[open] > ul.dropdown > li.focus:not([selected]),
+.cbi-dropdown.cbi-button[open] > ul.dropdown > li:hover:not([selected]) {
+ color: #2f6f9f;
+ background: #eef7ff;
+}
+
+.cbi-dropdown[open] > ul.dropdown > li {
+ position: relative;
+ z-index: 1;
+ display: flex;
+ width: 100%;
+ background: var(--sectionbg_color);
+ min-height: 2.5rem;
+ padding: 0 0.85rem;
+}
+
.cbi-dropdown[open] > ul.dropdown > li .hide-open {
display: none;
}
@@ -1817,26 +1983,23 @@ form.inline + form.inline,
display: initial;
}
-/* .cbi-dropdown[open] > ul.dropdown > li {
- border-bottom: thin solid #ccc;
-} */
+.cbi-dropdown[open] > ul.dropdown > li[unselectable] {
+ opacity: 0.7;
+}
.cbi-dropdown[open] > ul.dropdown > li[selected] {
+ color: #fff;
background: var(--active_color);
}
-.cbi-dropdown[open] > ul.dropdown > li.focus {
- background: linear-gradient(90deg, #a3c2e8 0%, #84aad9 100%);
+.cbi-dropdown[open] > ul.dropdown > li.focus:not([selected]),
+.cbi-dropdown[open] > ul.dropdown > li:hover:not([selected]) {
+ background: rgba(94, 166, 155, 0.16);
}
-.cbi-dropdown[open] > ul.dropdown > li:last-child {
- margin-bottom: 0;
- border-bottom: 0;
- background: #627486;
-}
-
-.cbi-dropdown[open] > ul.dropdown > li[unselectable] {
- opacity: .7;
+.cbi-dropdown.btn[open] > ul.dropdown > li,
+.cbi-dropdown.cbi-button[open] > ul.dropdown > li {
+ color: var(--text_color);
}
.cbi-dropdown[open] > ul.dropdown > li > input.create-item-input:first-child:last-child {
@@ -1845,15 +2008,37 @@ form.inline + form.inline,
.cbi-dropdown[disabled] {
pointer-events: none;
- opacity: .6;
+ opacity: 0.6;
}
-.cbi-dropdown .zonebadge {
- width: 100%;
+.td.cbi-value-field.cbi-dropdown-open,
+td.cbi-value-field.cbi-dropdown-open,
+.cbi-section-table-row > .cbi-value-field.cbi-dropdown-open {
+ position: relative;
+ overflow: visible !important;
+ z-index: 100;
}
-.cbi-dropdown[open] .zonebadge {
- width: auto;
+/* Keep opened dropdowns inside modal flow so menus don't get clipped or spill
+ * outside the dialog frame. */
+body.modal-overlay-active #modal_overlay .modal.cbi-modal .cbi-value-field.cbi-dropdown-open {
+ position: relative;
+ overflow: visible !important;
+ margin-bottom: min(18rem, 50vh);
+ z-index: 120;
+}
+
+body.modal-overlay-active #modal_overlay .modal.cbi-modal [data-tab-active="true"],
+body.modal-overlay-active #modal_overlay .modal.cbi-modal .cbi-section-node,
+body.modal-overlay-active #modal_overlay .modal.cbi-modal .cbi-section-node-tabbed {
+ overflow: visible !important;
+}
+
+.cbi-section,
+.cbi-section-create,
+.cbi-section-table,
+.cbi-section-table-row {
+ overflow: visible;
}
/* progressbar */
@@ -1880,7 +2065,7 @@ form.inline + form.inline,
.cbi-progressbar::after {
/* font-weight: bold; */
/* font-family: monospace; */
- font-size: 0.75rem !important;
+ font-size: 1.0rem !important;
font-size-adjust: .38 !important;
line-height: 1.5rem !important;
position: absolute !important;
@@ -1952,17 +2137,37 @@ form.inline + form.inline,
color: var(--model_text_color);
}
-.modal ul {
+.modal > ul,
+.modal > ol {
margin-left: 2.2em;
word-break: break-word;
color: var(--model_text_color);
}
-.modal li {
+.modal > ul > li,
+.modal > ol > li {
list-style-type: square;
color: var(--model_text_color);
}
+/* Keep LuCI widget lists in modals under JS control instead of generic modal list styling. */
+.modal .cbi-tabmenu,
+.modal .cbi-dropdown > ul,
+.modal .cbi-dropdown > ul.preview,
+.modal .cbi-dropdown[open] > ul.dropdown {
+ margin-left: 0 !important;
+ padding-left: 0 !important;
+ list-style: none !important;
+ color: inherit;
+}
+
+.modal .cbi-tabmenu > li,
+.modal .cbi-dropdown > ul > li,
+.modal .cbi-dropdown[open] > ul.dropdown > li {
+ list-style: none !important;
+ color: inherit;
+}
+
.modal p {
padding-left: .25rem;
word-break: break-word;
@@ -1988,6 +2193,16 @@ form.inline + form.inline,
max-height: none;
}
+[data-page="admin-network-wireless"] #modal_overlay > .modal.cbi-modal {
+ width: calc(100vw - 2.5rem);
+ max-width: 860px;
+ max-height: calc(100vh - 6.5rem);
+ margin: 2rem auto;
+ padding: .85rem 1rem;
+ align-items: flex-start;
+ overflow-y: auto;
+}
+
body.modal-overlay-active {
overflow: hidden;
height: 100vh;
@@ -2032,6 +2247,82 @@ body.modal-overlay-active #modal_overlay {
margin: 0;
}
+/* Keep LuCI split action buttons readable and vertically centered. */
+.cbi-dropdown.btn > ul > li[display],
+.cbi-dropdown.cbi-button > ul > li[display] {
+ display: flex;
+ align-items: center;
+ min-height: 35px;
+ height: 35px;
+ padding-top: 0;
+ padding-bottom: 0;
+ line-height: 35px;
+ color: #fff;
+}
+
+.cbi-dropdown.btn > .open,
+.cbi-dropdown.cbi-button > .open {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ min-width: 2.25rem;
+ min-height: 35px;
+ height: 35px;
+ line-height: 35px;
+ color: transparent;
+ opacity: 1;
+ font-size: 0;
+ position: relative;
+}
+
+.cbi-dropdown.btn > .open::before,
+.cbi-dropdown.cbi-button > .open::before {
+ content: "▾";
+ display: block;
+ font-size: 1rem;
+ font-weight: 700;
+ line-height: 1;
+ color: #fff;
+ text-indent: 0;
+}
+
+.cbi-dropdown.btn > .more,
+.cbi-dropdown.cbi-button > .more {
+ display: none;
+}
+
+.right .cbi-dropdown.btn,
+.right .cbi-dropdown.cbi-button,
+.right .cbi-dropdown.btn > ul > li[display],
+.right .cbi-dropdown.cbi-button > ul > li[display],
+.right .cbi-dropdown.btn > .open,
+.right .cbi-dropdown.cbi-button > .open {
+ line-height: 35px;
+ vertical-align: middle;
+}
+
+/* Override generic .btn/.cbi-button rules so split dropdown buttons keep the
+ arrow inside the same row instead of wrapping below the main label. */
+.cbi-dropdown.btn,
+.cbi-dropdown.cbi-button,
+.btn.cbi-button.cbi-dropdown,
+div.cbi-dropdown.btn,
+div.cbi-dropdown.cbi-button {
+ display: inline-flex !important;
+ align-items: stretch;
+ flex-wrap: nowrap;
+ padding: 0 !important;
+ white-space: nowrap;
+ vertical-align: middle;
+}
+
+.cbi-dropdown.btn > ul,
+.cbi-dropdown.cbi-button > ul {
+ width: auto;
+ flex: 0 1 auto;
+ overflow: hidden;
+}
+
.right,
.right::before {
text-align: right !important;
@@ -2059,10 +2350,53 @@ body.modal-overlay-active #modal_overlay {
.cbi-page-actions {
text-align: center;
}
+
.cbi-page-actions > form[method="post"] {
display: inline-block;
}
+[data-page="admin-network-network"] .cbi-button.cbi-button-neutral.reconnect {
+ color: #fff !important;
+ background-color: #337ab7 !important;
+ border-color: #337ab7 !important;
+}
+
+[data-page="admin-network-network"] .cbi-button.cbi-button-neutral.reconnect:hover {
+ background-color: #286090 !important;
+ border-color: #286090 !important;
+}
+
+[data-page="admin-network-network"] .cbi-button.cbi-button-edit {
+ color: #fff !important;
+ background-color: #5ea69b !important;
+ border-color: #5ea69b !important;
+}
+
+[data-page="admin-network-network"] .cbi-button.cbi-button-edit:hover {
+ background-color: #4a8a80 !important;
+ border-color: #4a8a80 !important;
+}
+
+[data-page="admin-network-network"] .cbi-button.cbi-button-add {
+ color: #fff !important;
+ background-color: #337ab7 !important;
+ border-color: #337ab7 !important;
+}
+
+[data-page="admin-network-network"] .cbi-button.cbi-button-add:hover {
+ background-color: #286090 !important;
+ border-color: #286090 !important;
+}
+
+[data-page="admin-network-network"] td > .ifacebadge,
+[data-page="admin-network-network"] .td > .ifacebadge,
+[data-page="admin-network-network"] .cbi-section-table .ifacebadge {
+ background-color: #eef2f3 !important;
+ color: #5f6b72 !important;
+ border: 1px solid #d8e0e3 !important;
+ box-shadow: inset 0 1px 0 rgb(255 255 255 / 70%), 0 1px 2px rgb(0 0 0 / 4%) !important;
+}
+
.th[data-type="button"],
.td[data-type="button"],
.th[data-type="fvalue"],
@@ -2081,9 +2415,11 @@ body.modal-overlay-active #modal_overlay {
td > .ifacebadge,
.td > .ifacebadge {
font-size: .8rem;
- background-color: var(--active_color);
- color: white;
- border-radius: 8px;
+ background-color: #eef2f3;
+ color: #5f6b72;
+ border: 1px solid #d8e0e3;
+ border-radius: 10px;
+ box-shadow: inset 0 1px 0 rgb(255 255 255 / 70%), 0 1px 2px rgb(0 0 0 / 4%);
}
.ifacebadge > em,
@@ -2092,6 +2428,23 @@ td > .ifacebadge,
align-self: flex-start;
}
+[data-page="admin-network-network"] .theme-network-icon,
+[data-page="admin-network-network"] .ifacebadge > img,
+[data-page="admin-network-network"] .cbi-tooltip-container > img.middle {
+ width: 1.65rem;
+ height: 1.65rem;
+ min-width: 1.65rem;
+ object-fit: contain;
+ vertical-align: middle;
+ flex-shrink: 0;
+}
+
+[data-page="admin-network-network"] .cbi-tooltip.ifacebadge.large > img {
+ width: 1.95rem;
+ height: 1.95rem;
+ min-width: 1.95rem;
+}
+
.network-status-table {
display: flex;
flex-wrap: wrap;
@@ -2126,6 +2479,99 @@ td > .ifacebadge,
padding: .5em;
}
+/* wireless overview */
+[data-page="admin-network-wireless"] #maincontent h3:first-of-type,
+.node-admin-network-wireless #maincontent h3:first-of-type {
+ font-size: 1.5em !important;
+ font-weight: 800;
+ padding: 0 12px 12px 12px;
+ line-height: 1.2;
+}
+
+[data-page="admin-network-wireless"] #cbi-wireless .cbi-section-table-row > .td[data-name="_stat"],
+.node-admin-network-wireless #cbi-wireless .cbi-section-table-row > .td[data-name="_stat"] {
+ text-align: left !important;
+}
+
+[data-page="admin-network-wireless"] #cbi-wireless > .table,
+.node-admin-network-wireless #cbi-wireless > .table {
+ table-layout: fixed;
+ width: 100%;
+}
+
+[data-page="admin-network-wireless"] #cbi-wireless .cbi-section-table-row > .td[data-name="_badge"],
+.node-admin-network-wireless #cbi-wireless .cbi-section-table-row > .td[data-name="_badge"] {
+ width: 17rem !important;
+ min-width: 17rem;
+ max-width: 17rem;
+}
+
+[data-page="admin-network-wireless"] #cbi-wireless .wireless-radio-badge,
+.node-admin-network-wireless #cbi-wireless .wireless-radio-badge {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+
+[data-page="admin-network-wireless"] #cbi-wireless .wireless-radio-badge > img,
+.node-admin-network-wireless #cbi-wireless .wireless-radio-badge > img {
+ width: 88px !important;
+ height: 88px !important;
+ min-width: 88px !important;
+}
+
+[data-page="admin-network-wireless"] #cbi-wireless .wireless-radio-status,
+.node-admin-network-wireless #cbi-wireless .wireless-radio-status,
+[data-page="admin-network-wireless"] #cbi-wireless .wireless-network-status,
+.node-admin-network-wireless #cbi-wireless .wireless-network-status {
+ text-align: left;
+ max-width: 100%;
+}
+
+[data-page="admin-network-wireless"] #cbi-wireless .wireless-radio-title,
+.node-admin-network-wireless #cbi-wireless .wireless-radio-title {
+ font-size: 1.08rem;
+ font-weight: 700;
+ line-height: 1.4;
+ color: var(--text_color);
+}
+
+[data-page="admin-network-wireless"] #cbi-wireless .wireless-radio-meta,
+.node-admin-network-wireless #cbi-wireless .wireless-radio-meta,
+[data-page="admin-network-wireless"] #cbi-wireless .wireless-network-status-row,
+.node-admin-network-wireless #cbi-wireless .wireless-network-status-row {
+ margin-top: .3rem;
+ line-height: 1.7;
+ color: var(--text_color);
+ text-align: left;
+}
+
+[data-page="admin-network-wireless"] #cbi-wireless .wireless-network-status-note,
+.node-admin-network-wireless #cbi-wireless .wireless-network-status-note {
+ margin-top: .4rem;
+}
+
+[data-page="admin-network-wireless"] #cbi-wireless .wireless-status-sep,
+.node-admin-network-wireless #cbi-wireless .wireless-status-sep {
+ display: inline-block;
+ padding: 0 .35rem;
+ color: var(--text_color);
+ opacity: .7;
+}
+
+[data-page="admin-network-wireless"] #cbi-wireless .cbi-section-table-row > .td.cbi-section-actions,
+.node-admin-network-wireless #cbi-wireless .cbi-section-table-row > .td.cbi-section-actions {
+ width: 18.5rem !important;
+ min-width: 18.5rem;
+ max-width: 18.5rem;
+}
+
+[data-page="admin-network-wireless"] #cbi-wireless .cbi-section-table-row > .td[data-name="_stat"],
+.node-admin-network-wireless #cbi-wireless .cbi-section-table-row > .td[data-name="_stat"] {
+ width: auto !important;
+}
+
+
/* textarea */
#content_syslog {
padding: 5px;
@@ -2162,11 +2608,14 @@ td > .ifacebadge,
#syslog {
width: 100%;
min-height: 15rem;
- padding: 10px;
+ padding: 12px 14px;
margin-bottom: 20px;
border-radius: 0;
background-color: var(--sectionbg_color);
border: none;
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
+ font-size: 13px !important;
+ line-height: 1.55 !important;
}
#syslog:focus {
@@ -2293,6 +2742,122 @@ td > .ifacebadge,
padding: .25em;
}
+[data-page="admin-status-overview"] .port-status-grid,
+[data-page="admin-status-overview"] .cbi-section > div[style*="grid-template-columns:repeat(auto-fit, minmax(70px, 1fr))"] {
+ display: grid !important;
+ align-items: stretch;
+ justify-items: stretch;
+ width: 100%;
+ max-width: 100%;
+ padding: 0.2rem 0.6rem 0.35rem;
+ margin: 0 auto 1rem !important;
+}
+
+[data-page="admin-status-overview"] .port-status-slot {
+ display: flex;
+ justify-content: center;
+ align-items: stretch;
+ min-width: 0;
+ padding: 0.15rem 0.65rem 0.75rem;
+}
+
+[data-page="admin-status-overview"] .port-status-card,
+[data-page="admin-status-overview"] .cbi-section > div[style*="grid-template-columns:repeat(auto-fit, minmax(70px, 1fr))"] > .ifacebox {
+ margin: 0 !important;
+ width: fit-content;
+ min-width: 76px !important;
+ max-width: 108px !important;
+ border-radius: 10px;
+ overflow: hidden;
+ background: var(--sectionbg_color);
+ box-shadow: 3px 3px 3px rgb(0 0 0 / 5%);
+ text-align: center;
+}
+
+[data-page="admin-status-overview"] .port-status-card .ifacebox-head,
+[data-page="admin-status-overview"] .cbi-section > div[style*="grid-template-columns:repeat(auto-fit, minmax(70px, 1fr))"] > .ifacebox > .ifacebox-head {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 0.24rem 0.45rem 0.22rem;
+ background: #eef2f3;
+ border-radius: 4px 4px 0 0;
+ box-shadow: inset 0 -1px 0 rgb(0 0 0 / 6%);
+ font-size: 0.76rem;
+ font-weight: 700;
+ line-height: 1.2;
+ text-align: center;
+ color: #68757b;
+ letter-spacing: 0.01em;
+ text-transform: none;
+}
+
+[data-page="admin-status-overview"] .port-status-card .ifacebox-head strong,
+[data-page="admin-status-overview"] .cbi-section > div[style*="grid-template-columns:repeat(auto-fit, minmax(70px, 1fr))"] > .ifacebox > .ifacebox-head strong {
+ display: block;
+ width: 100%;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ font-weight: inherit;
+}
+
+[data-page="admin-status-overview"] .port-status-card .ifacebox-body,
+[data-page="admin-status-overview"] .cbi-section > div[style*="grid-template-columns:repeat(auto-fit, minmax(70px, 1fr))"] > .ifacebox > .ifacebox-body {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ padding: 0.4rem 0.45rem;
+ gap: 0.14rem;
+ text-align: center;
+}
+
+[data-page="admin-status-overview"] .port-status-card .ifacebox-body img,
+[data-page="admin-status-overview"] .cbi-section > div[style*="grid-template-columns:repeat(auto-fit, minmax(70px, 1fr))"] > .ifacebox > .ifacebox-body img {
+ background-size: 24px 24px !important;
+ width: 24px !important;
+ height: 24px !important;
+ padding: 0 0 0 24px !important;
+ margin: 0.05rem auto;
+}
+
+[data-page="admin-status-overview"] .port-status-card .ifacebox-body img + br,
+[data-page="admin-status-overview"] .cbi-section > div[style*="grid-template-columns:repeat(auto-fit, minmax(70px, 1fr))"] > .ifacebox > .ifacebox-body img + br {
+ display: none;
+}
+
+[data-page="admin-status-overview"] .port-status-card .ifacebox-body > span,
+[data-page="admin-status-overview"] .cbi-section > div[style*="grid-template-columns:repeat(auto-fit, minmax(70px, 1fr))"] > .ifacebox > .ifacebox-body > span {
+ display: block;
+ width: 100%;
+ text-align: center;
+}
+
+[data-page="admin-status-overview"] .port-status-card .ifacebox-head.cbi-tooltip-container,
+[data-page="admin-status-overview"] .cbi-section > div[style*="grid-template-columns:repeat(auto-fit, minmax(70px, 1fr))"] > .ifacebox > .ifacebox-head.cbi-tooltip-container {
+ display: flex;
+ gap: 0.18rem;
+ padding: 0 0.45rem 0.2rem;
+ background: transparent;
+}
+
+[data-page="admin-status-overview"] .port-status-card .ifacebox-head.cbi-tooltip-container .zonebadge,
+[data-page="admin-status-overview"] .cbi-section > div[style*="grid-template-columns:repeat(auto-fit, minmax(70px, 1fr))"] > .ifacebox > .ifacebox-head.cbi-tooltip-container .zonebadge {
+ flex: 1;
+ height: 4px !important;
+ padding: 0 !important;
+ border-radius: 999px;
+}
+
+[data-page="admin-status-overview"] .port-status-card .ifacebox-body .cbi-tooltip-container,
+[data-page="admin-status-overview"] .cbi-section > div[style*="grid-template-columns:repeat(auto-fit, minmax(70px, 1fr))"] > .ifacebox > .ifacebox-body .cbi-tooltip-container {
+ width: 100%;
+ text-align: center !important;
+ font-size: 0.76rem !important;
+ line-height: 1.35;
+}
+
.cbi-image-button {
margin-left: .5rem;
}
@@ -2355,10 +2920,6 @@ input[type="radio"]:focus {
background-color: #eee;
}
-.cbi-section-table-row > .cbi-value-field .cbi-dropdown {
- min-width: 7rem;
-}
-
.cbi-section-create {
display: inline-flex;
align-items: center;
@@ -2385,10 +2946,6 @@ td.cbi-value-field var,
border-top: thin solid #ccc;
}
-.cbi-dropdown-container {
- position: relative;
-}
-
.cbi-tooltip-container,
span[data-tooltip],
span[data-tooltip] .label {
@@ -2507,6 +3064,45 @@ label[data-index][data-depends] {
box-shadow: none;
}
+[data-page="admin-network-diagnostics"] .td.left {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.65rem;
+}
+
+[data-page="admin-network-diagnostics"] .td.left > input[type="text"],
+[data-page="admin-network-diagnostics"] .td.left > select {
+ margin: 0 !important;
+ align-self: center;
+}
+
+[data-page="admin-network-diagnostics"] .td.left > .diag-action {
+ display: inline-flex;
+ align-items: center;
+ align-self: center;
+ margin: 0;
+}
+
+[data-page="admin-network-diagnostics"] .td.left > .diag-action > .cbi-button {
+ margin: 0 !important;
+ align-self: center;
+}
+
+.cbi-section > .table[width="100%"] {
+ border-collapse: separate;
+ border-spacing: 0 0.55rem;
+}
+
+.cbi-section > .table[width="100%"] tr > td {
+ padding-top: 0.45rem;
+ padding-bottom: 0.45rem;
+ line-height: 1.5;
+}
+
+.cbi-section > .table[width="100%"] tr > td:first-child {
+ padding-left: 0.9rem;
+}
+
input[name="ping"],
input[name="traceroute"],
input[name="nslookup"] {
@@ -2788,6 +3384,38 @@ input[name="nslookup"] {
width: 23rem;
}
+[data-page="admin-network-wireless"] #wifi_assoclist_table .ifacebadge,
+.node-admin-network-wireless #wifi_assoclist_table .ifacebadge {
+ padding: .22rem .5rem;
+ gap: .18rem;
+ border-radius: 8px;
+ align-items: center;
+ line-height: 1.25;
+}
+
+[data-page="admin-network-wireless"] #wifi_assoclist_table .ifacebadge > img,
+.node-admin-network-wireless #wifi_assoclist_table .ifacebadge > img {
+ width: 16px !important;
+ height: 16px !important;
+ min-width: 16px !important;
+ margin-right: .2rem !important;
+ align-self: center;
+}
+
+[data-page="admin-network-wireless"] #wifi_assoclist_table .ifacebadge > span,
+.node-admin-network-wireless #wifi_assoclist_table .ifacebadge > span {
+ display: inline-flex;
+ align-items: baseline;
+ flex-wrap: wrap;
+ gap: .15rem;
+}
+
+[data-page="admin-network-wireless"] #wifi_assoclist_table > .tr > .td,
+.node-admin-network-wireless #wifi_assoclist_table > .tr > .td {
+ padding-top: .45rem;
+ padding-bottom: .45rem;
+}
+
/* firewall */
#iptables {
margin: 0;
@@ -3074,6 +3702,10 @@ input[name="nslookup"] {
width: 100% !important;
}
+ [data-page="admin-network-diagnostics"] .td.left {
+ display: block;
+ }
+
.node-network-diagnostics > .main .cbi-map div.cbi-section > div input[type="text"] {
}
@@ -3208,13 +3840,32 @@ input[name="nslookup"] {
display: block;
overflow: auto;
}
- .node-admin-status-routes #view table,
+.node-admin-status-routes #view table,
.node-admin-status-processes #view table,
.node-admin-status-realtime-connections #view table[id*=connections] {
display: block;
white-space: nowrap;
}
+ #view [data-table] > h3 {
+ margin-top: 1.75rem;
+ margin-bottom: 1.15rem;
+ padding: 12px 12px 12px 12px;
+ line-height: 1.35;
+ }
+
+ #view [data-chain] > h4 {
+ margin-top: 1.15rem;
+ margin-bottom: 0.85rem;
+ padding-top: 0.3rem;
+ padding-bottom: 0.2rem;
+ line-height: 1.35;
+ }
+
+ #view [data-chain] > table {
+ margin-bottom: 1.25rem;
+ }
+
}
@@ -3580,19 +4231,6 @@ td.cbi-button, .cbi-button-apply,
background: none !important;
}
-/* fix */
-.cbi-dropdown.btn.cbi-button.cbi-button-apply.important,
-.cbi-dropdown.btn.cbi-button.cbi-button-negative.important {
- line-height: unset;
- min-width: 105px;
- padding-left: 5px;
-}
-.cbi-dropdown.btn.cbi-button.cbi-button-action {
- line-height: unset;
- min-width: 110px;
- padding-left: 5px;
-}
-
.node-admin-system-ttyd-ttyd iframe {
border-radius: 5px !important;
}
@@ -3624,3 +4262,548 @@ td.cbi-button, .cbi-button-apply,
.node-admin-status-overview > .main #view td:nth-child(2) {
white-space: normal;
}
+
+/* Merged overrides formerly kept in compat-openwrt23.css. */
+
+#view {
+ padding: 0;
+}
+
+#view > * {
+ margin-bottom: 1rem;
+}
+
+.cbi-map {
+ margin-top: 10px;
+}
+
+.cbi-input-text,
+.cbi-input-password,
+.cbi-input-select {
+ color: var(--inputtext_color);
+ padding: 5px 10px;
+ font-size: 0.92rem;
+ border: var(--input_border);
+ background-color: var(--inputbg_color);
+ border-radius: 8px;
+ height: 2.8rem;
+ line-height: 2.8rem;
+ max-width: 550px;
+}
+
+.cbi-input-checkbox,
+.cbi-input-radio {
+ width: 1.2rem;
+ height: 1.2rem;
+ margin-right: 0.5rem;
+ vertical-align: middle;
+ accent-color: var(--active_color);
+}
+
+.btn.cbi-button,
+button.cbi-button {
+ -webkit-appearance: none;
+ appearance: none;
+ text-transform: uppercase;
+ color: #fff;
+ background-color: #337ab7;
+ transition: all 0.2s ease-in-out;
+ display: inline-block;
+ border: none;
+ cursor: pointer;
+ text-align: center;
+ white-space: nowrap;
+ min-width: 80px;
+ padding: 0 8px;
+ height: 35px;
+ line-height: 35px;
+ border-radius: 8px;
+}
+
+.cbi-button-positive,
+.cbi-button-action {
+ color: var(--bttext_color) !important;
+ background-color: var(--active_color) !important;
+}
+
+.cbi-button-positive:hover,
+.cbi-button-action:hover {
+ background-color: #4a8a80 !important;
+}
+
+.cbi-button-negative {
+ color: #fff !important;
+ background-color: #d9534f !important;
+}
+
+.cbi-button-negative:hover {
+ background-color: #c9302c !important;
+}
+
+.cbi-button-neutral {
+ color: #fff !important;
+ background-color: #617486 !important;
+}
+
+.table.cbi-section-table {
+ width: 100%;
+ border-collapse: collapse;
+}
+
+.table.cbi-section-table .tr {
+ display: table-row;
+}
+
+.table.cbi-section-table .th,
+.table.cbi-section-table .td {
+ display: table-cell;
+ padding: 12px;
+ vertical-align: middle;
+}
+
+.tr.cbi-section-table-titles {
+ background-color: var(--inputbg_color);
+ font-weight: bold;
+}
+
+.cbi-dropdown {
+ position: relative;
+ display: inline-flex;
+ min-height: 2.8rem;
+ border: var(--input_border);
+ background-color: var(--inputbg_color);
+ border-radius: 8px;
+}
+
+.cbi-dropdown:not(.btn):not(.cbi-button) {
+ cursor: pointer;
+ color: var(--inputtext_color);
+}
+
+.cbi-dropdown > ul {
+ display: flex;
+ overflow-x: hidden;
+ overflow-y: auto;
+ width: 100%;
+ margin: 0 !important;
+ padding: 0;
+ list-style: none;
+}
+
+.cbi-dropdown:not(.btn):not(.cbi-button) > ul > li {
+ display: none;
+ overflow: hidden;
+ align-items: center;
+ align-self: center;
+ flex-grow: 1;
+ flex-shrink: 1;
+ min-height: 2.8rem;
+ padding: 0.5em 0.75em;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ color: var(--inputtext_color);
+}
+
+.cbi-dropdown:not(.btn):not(.cbi-button) > ul > li[display],
+.cbi-dropdown:not(.btn):not(.cbi-button)[open] > ul.preview,
+.cbi-dropdown:not(.btn):not(.cbi-button)[open] > ul.dropdown > li,
+.cbi-dropdown[multiple] > ul > li > label,
+.cbi-dropdown[multiple][open] > ul.dropdown > li,
+.cbi-dropdown[multiple][more] > .more,
+.cbi-dropdown[multiple][empty] > .more {
+ display: flex;
+ align-items: center;
+ flex-grow: 1;
+}
+
+.cbi-dropdown[empty] > ul > li,
+.cbi-dropdown[optional][open] > ul.dropdown > li[placeholder],
+.cbi-dropdown[multiple][open] > ul.dropdown > li > form {
+ display: block;
+}
+
+.cbi-dropdown:not(.btn):not(.cbi-button) > ul > li[display]:not([display="0"]) {
+ border-left: 1px solid #d9e3e6;
+}
+
+.cbi-dropdown:not(.btn):not(.cbi-button) > ul > li[data-value] {
+ padding-left: 0.75em !important;
+}
+
+.cbi-dropdown:not(.btn):not(.cbi-button) > .open,
+.cbi-dropdown:not(.btn):not(.cbi-button) > .more {
+ color: var(--inputtext_color);
+ line-height: 1;
+}
+
+.cbi-dropdown:not(.btn):not(.cbi-button) > .more,
+.cbi-dropdown:not(.btn):not(.cbi-button) > ul > li[placeholder] {
+ color: #87929a;
+ text-shadow: none;
+}
+
+.cbi-dropdown:not(.btn):not(.cbi-button)[open] > ul.dropdown {
+ position: absolute;
+ z-index: 1100;
+ top: auto;
+ bottom: auto;
+ left: 0;
+ right: auto;
+ display: block;
+ min-width: 100%;
+ width: auto;
+ max-width: none;
+ max-height: 260px !important;
+ overflow-x: hidden;
+ overflow-y: auto;
+ background: var(--sectionbg_color);
+ border: var(--input_border);
+ border-radius: 0 0 8px 8px;
+ box-shadow: 0 8px 18px rgb(0 0 0 / 10%);
+ text-align: left;
+}
+
+.cbi-dropdown:not(.btn):not(.cbi-button)[open] > ul.dropdown > li {
+ width: 100%;
+ padding: 0.55em 0.85em;
+ cursor: pointer;
+ color: var(--inputtext_color);
+ border-bottom: 1px solid #e9eef0;
+ background: transparent;
+}
+
+.cbi-dropdown:not(.btn):not(.cbi-button)[open] > ul.dropdown > li[selected] {
+ background: rgb(94 166 155 / 16%);
+ color: var(--active_color);
+}
+
+.cbi-dropdown:not(.btn):not(.cbi-button)[open] > ul.dropdown > li.focus,
+.cbi-dropdown:not(.btn):not(.cbi-button)[open] > ul.dropdown > li:hover {
+ background: rgb(94 166 155 / 10%);
+ color: var(--inputtext_color);
+}
+
+.cbi-dropdown:not(.btn):not(.cbi-button)[open] > ul.dropdown > li:last-child {
+ margin-bottom: 0;
+ border-bottom: 0;
+ background: transparent;
+}
+
+.cbi-dropdown:not(.btn):not(.cbi-button)[open] > ul.dropdown > li > input.create-item-input:first-child:last-child {
+ width: 100%;
+ height: 2.1rem;
+ padding: 0 0.6em;
+ border: var(--input_border);
+ border-radius: 6px;
+ background: var(--inputbg_color);
+}
+
+.cbi-tabmenu {
+ display: flex;
+ flex-wrap: wrap;
+ border-bottom: var(--tabmenu_bottom);
+ margin-bottom: 1rem;
+}
+
+.cbi-tabmenu > li {
+ display: inline-block;
+ margin-right: 0.5rem;
+}
+
+.cbi-tabmenu > li > a {
+ display: block;
+ padding: 0.5rem 1rem;
+ text-decoration: none;
+ color: var(--text_color);
+ border-bottom: 2px solid transparent;
+ transition: all 0.2s;
+}
+
+.cbi-tabmenu > li.cbi-tab > a,
+.cbi-tabmenu > li > a:hover {
+ color: var(--active_color);
+ border-bottom-color: var(--active_color);
+}
+
+.modal {
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ width: 90%;
+ max-width: 600px;
+ min-height: 32px;
+ margin: 5em auto;
+ padding: 1em;
+ border-radius: 8px;
+ background: var(--model_background);
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
+}
+
+.modal > * {
+ flex-basis: 100%;
+ margin-bottom: 0.5em;
+}
+
+.modal > h4 {
+ color: var(--text_color);
+ margin-bottom: 1em;
+}
+
+.modal > .btn,
+.modal > .cbi-button {
+ flex-basis: auto;
+ margin: 0.25em;
+}
+
+[data-page="admin-network-wireless"] #modal_overlay > .modal.cbi-modal {
+ width: calc(100vw - 2.5rem);
+ max-width: 860px;
+ max-height: calc(100vh - 6.5rem);
+ margin: 2rem auto;
+ padding: 0.85rem 1rem;
+ align-items: flex-start;
+ overflow-y: auto;
+}
+
+body.modal-overlay-active #modal_overlay .modal.cbi-modal [data-tab-active="true"],
+body.modal-overlay-active #modal_overlay .modal.cbi-modal .cbi-section-node,
+body.modal-overlay-active #modal_overlay .modal.cbi-modal .cbi-section-node-tabbed,
+body.modal-overlay-active #modal_overlay .modal.cbi-modal .cbi-value-field.cbi-dropdown-open {
+ overflow: visible !important;
+}
+
+/* Undo generic modal list styling for LuCI dropdown widgets inside wireless edit dialogs. */
+[data-page="admin-network-wireless"] #modal_overlay .modal.cbi-modal .cbi-dropdown > ul,
+[data-page="admin-network-wireless"] #modal_overlay .modal.cbi-modal .cbi-dropdown > ul.preview,
+[data-page="admin-network-wireless"] #modal_overlay .modal.cbi-modal .cbi-dropdown[open] > ul.dropdown {
+ margin-left: 0 !important;
+ padding-left: 0 !important;
+ list-style: none !important;
+}
+
+[data-page="admin-network-wireless"] #modal_overlay .modal.cbi-modal .cbi-dropdown > ul > li,
+[data-page="admin-network-wireless"] #modal_overlay .modal.cbi-modal .cbi-dropdown[open] > ul.dropdown > li {
+ list-style: none !important;
+ margin-left: 0 !important;
+}
+
+/* Keep NetworkSelect choices readable in wireless modal dropdowns. */
+[data-page="admin-network-wireless"] #modal_overlay .modal.cbi-modal .cbi-dropdown[open] > ul.dropdown > li {
+ display: flex !important;
+ align-items: center;
+ color: var(--inputtext_color);
+}
+
+[data-page="admin-network-wireless"] #modal_overlay .modal.cbi-modal .cbi-dropdown[multiple] > ul > li > form,
+[data-page="admin-network-wireless"] #modal_overlay .modal.cbi-modal .cbi-dropdown[multiple][open] > ul.dropdown > li > form {
+ display: block !important;
+ flex: 0 0 auto;
+ margin: 0 !important;
+ padding: 0 !important;
+}
+
+[data-page="admin-network-wireless"] #modal_overlay .modal.cbi-modal .cbi-dropdown[multiple] > ul > li > label,
+[data-page="admin-network-wireless"] #modal_overlay .modal.cbi-modal .cbi-dropdown[multiple][open] > ul.dropdown > li > label {
+ display: flex !important;
+ align-items: center;
+ flex: 1 1 auto;
+ min-width: 0;
+ margin: 0 !important;
+ overflow: visible;
+ color: inherit !important;
+}
+
+[data-page="admin-network-wireless"] #modal_overlay .modal.cbi-modal .cbi-dropdown[multiple][open] > ul.dropdown > li {
+ gap: 0.55rem;
+}
+
+/* Fallback text rendering for NetworkSelect choices when badge markup is hidden by theme rules. */
+[data-page="admin-network-wireless"] #modal_overlay .modal.cbi-modal .cbi-dropdown > ul > li[data-value]:not([data-value=""])::before {
+ content: attr(data-value);
+ display: inline-block;
+ color: inherit;
+ font-size: 0.92rem;
+ line-height: 1.4;
+ white-space: nowrap;
+ margin-right: 0.5rem;
+ flex: 0 0 auto;
+}
+
+[data-page="admin-network-wireless"] #modal_overlay .modal.cbi-modal .cbi-dropdown[open] > ul.dropdown > li[selected]::before {
+ color: #fff;
+}
+
+[data-page="admin-network-wireless"] #modal_overlay .modal.cbi-modal .cbi-dropdown[multiple] > ul > li[data-value]::before,
+[data-page="admin-network-wireless"] #modal_overlay .modal.cbi-modal .cbi-dropdown[multiple][open] > ul.dropdown > li[data-value]::before {
+ content: none;
+ display: none !important;
+}
+
+[data-page="admin-network-wireless"] #modal_overlay .modal.cbi-modal .cbi-dropdown[open] > ul.dropdown > li .ifacebadge,
+[data-page="admin-network-wireless"] #modal_overlay .modal.cbi-modal .cbi-dropdown[open] > ul.dropdown > li .zonebadge {
+ display: inline-flex !important;
+ align-items: center;
+ gap: 0.2rem;
+ max-width: 100%;
+ padding: 0.3rem 0.6rem;
+ color: #5f6b72 !important;
+ background-color: #eef2f3 !important;
+ border: 1px solid #d8e0e3 !important;
+ border-radius: 10px;
+ box-shadow: inset 0 1px 0 rgb(255 255 255 / 70%), 0 1px 2px rgb(0 0 0 / 4%);
+ font-size: 0.85rem;
+ line-height: 1.4;
+ white-space: nowrap;
+ visibility: visible !important;
+ opacity: 1 !important;
+ margin: 0 !important;
+}
+
+[data-page="admin-network-wireless"] #modal_overlay .modal.cbi-modal .cbi-dropdown[open] > ul.dropdown > li .ifacebadge > em,
+[data-page="admin-network-wireless"] #modal_overlay .modal.cbi-modal .cbi-dropdown[open] > ul.dropdown > li .ifacebadge > img {
+ align-self: center;
+}
+
+.cbi-progressbar {
+ position: relative;
+ min-width: 11rem;
+ height: 1.5rem;
+ background-color: var(--progressbar_color);
+ border-radius: 5px;
+ overflow: hidden;
+}
+
+.cbi-progressbar > div {
+ height: 100%;
+ background: var(--progressbar);
+ transition: width 0.25s ease-in;
+}
+
+.cbi-progressbar::after {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ content: attr(title);
+ text-align: center;
+ line-height: 1.5rem;
+ font-size: 0.75rem;
+ color: var(--progressbartxt_color);
+}
+
+.ifacebadge {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.2rem;
+ padding: 0.3rem 0.6rem;
+ background-color: #eef2f3;
+ color: #5f6b72;
+ border: 1px solid #d8e0e3;
+ border-radius: 10px;
+ box-shadow: inset 0 1px 0 rgb(255 255 255 / 70%), 0 1px 2px rgb(0 0 0 / 4%);
+ font-size: 0.85rem;
+}
+
+.ifacebadge > img,
+.ifacebadge > em {
+ width: 16px;
+ height: 16px;
+}
+
+.zonebadge {
+ display: inline-block;
+ padding: 0.2rem 0.5rem;
+ border-radius: 4px;
+}
+
+@media screen and (max-width: 992px) {
+
+ .main-left {
+ transform: translateX(-100%);
+ transition: transform 0.3s ease;
+ }
+
+ .main-left.active,
+ .main-left[style*="width: 17rem"],
+ .main-left:not([style*="width: 0"]) {
+ transform: translateX(0);
+ }
+}
+
+[data-page="admin-status-overview"] .cbi-section {
+ margin-bottom: 1rem;
+}
+
+[data-page="admin-network-network"] .ifacebox {
+ margin: 0.5rem;
+ border-radius: 8px;
+ overflow: hidden;
+}
+
+[data-page="admin-network-wireless"] .cbi-section-table {
+ overflow-x: auto;
+}
+
+[data-page="admin-system-opkg"] .controls {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 0.5rem;
+ margin-bottom: 1rem;
+}
+
+[data-page="admin-system-opkg"] .controls input[type="text"] {
+ flex: 1;
+ min-width: 200px;
+}
+
+@media (prefers-color-scheme: dark) {
+
+ code, pre {
+ background-color: #2d2d2d;
+ color: #f8f8f2;
+ }
+
+
+ .table.cbi-section-table .tr:nth-child(even) {
+ background-color: rgba(255, 255, 255, 0.05);
+ }
+
+
+ .cbi-input-text:focus,
+ .cbi-input-password:focus,
+ .cbi-input-select:focus {
+ border-color: var(--active_color);
+ box-shadow: 0 0 6px var(--active_color);
+ }
+}
+
+@media print {
+ .main-left,
+ .navbar,
+ header,
+ .showSide,
+ .darkMask {
+ display: none !important;
+ }
+
+ .main-right {
+ width: 100% !important;
+ margin: 0 !important;
+ }
+}
+
+:focus-visible {
+ outline: 2px solid var(--active_color);
+ outline-offset: 2px;
+}
+
+@media (prefers-reduced-motion: reduce) {
+ *,
+ *::before,
+ *::after {
+ animation-duration: 0.01ms !important;
+ animation-iteration-count: 1 !important;
+ transition-duration: 0.01ms !important;
+ }
+}
diff --git a/luci-theme-design/htdocs/luci-static/design/favicon.ico b/luci-theme-design/htdocs/luci-static/design/favicon.ico
index f82da9bb2..e65f20310 100644
Binary files a/luci-theme-design/htdocs/luci-static/design/favicon.ico and b/luci-theme-design/htdocs/luci-static/design/favicon.ico differ
diff --git a/luci-theme-design/htdocs/luci-static/design/fonts/GenJyuuGothic-Medium.otf b/luci-theme-design/htdocs/luci-static/design/fonts/GenJyuuGothic-Medium.otf
new file mode 100644
index 000000000..916b4a11d
Binary files /dev/null and b/luci-theme-design/htdocs/luci-static/design/fonts/GenJyuuGothic-Medium.otf differ
diff --git a/luci-theme-design/htdocs/luci-static/design/images/switch.png b/luci-theme-design/htdocs/luci-static/design/images/switch.png
new file mode 100644
index 000000000..ade12a538
Binary files /dev/null and b/luci-theme-design/htdocs/luci-static/design/images/switch.png differ
diff --git a/luci-theme-design/htdocs/luci-static/design/images/switch_disabled.png b/luci-theme-design/htdocs/luci-static/design/images/switch_disabled.png
new file mode 100644
index 000000000..346d75278
Binary files /dev/null and b/luci-theme-design/htdocs/luci-static/design/images/switch_disabled.png differ
diff --git a/luci-theme-design/htdocs/luci-static/design/js/style.js b/luci-theme-design/htdocs/luci-static/design/js/style.js
index 2b641e5be..23da7e5b7 100644
--- a/luci-theme-design/htdocs/luci-static/design/js/style.js
+++ b/luci-theme-design/htdocs/luci-static/design/js/style.js
@@ -1,28 +1,404 @@
(function ($) {
+ function applySafeAreaFix() {
+ var url = self.location.href;
- // 修复某些插件导致在https下env(safe-area-inset-bottom)为0的情况
- var url = self.location.href;
- if ((/(iPhone|iPad|iPod|iOS|Mac|Macintosh)/i.test(navigator.userAgent)) && url.indexOf("openclash") != -1 ) {
- var oMeta = document.createElement('meta');
- oMeta.content = 'width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0,viewport-fit=cover';
- oMeta.name = 'viewport';
- document.getElementsByTagName('head')[0].appendChild(oMeta);
+ // 修复某些插件导致在 https 下 env(safe-area-inset-bottom) 为 0 的情况
+ if ((/(iPhone|iPad|iPod|iOS|Mac|Macintosh)/i.test(navigator.userAgent)) && url.indexOf("openclash") !== -1) {
+ var oMeta = document.createElement('meta');
+ oMeta.content = 'width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0,viewport-fit=cover';
+ oMeta.name = 'viewport';
+ document.getElementsByTagName('head')[0].appendChild(oMeta);
+ }
}
- // 设置indicators图标,(放在menu script执行之前passwall某些代码错误中断导致失败)
- document.getElementById("indicators").addEventListener('DOMSubtreeModified', function () {
- var child = document.getElementById("indicators");
- if (child.firstElementChild.getAttribute("data-indicator") != "uci-changes") {
- child.firstElementChild.textContent = eval("'\ue6b9'")
- }
- }, false);
+ function setHeaderShadow() {
+ if (window.innerWidth <= 992) {
+ $("header").css("box-shadow", "0 2px 4px rgb(0 0 0 / 8%)");
+ } else {
+ $("header").css("box-shadow", "17rem 2px 4px rgb(0 0 0 / 8%)");
+ }
+ }
- // 监听窗口大小,动态设置header box阴影长度
- $(window).resize( function () {
- if (window.innerWidth <= 992) {
- $("header").css("box-shadow", "0 2px 4px rgb(0 0 0 / 8%)")
- } else {
- $("header").css("box-shadow", "17rem 2px 4px rgb(0 0 0 / 8%)")
- }
+ function syncIndicators() {
+ var indicatorRoot = document.getElementById("indicators");
+
+ if (!indicatorRoot) {
+ return;
+ }
+
+ Array.prototype.forEach.call(indicatorRoot.querySelectorAll('[data-indicator]'), function (indicator) {
+ var id = indicator.getAttribute('data-indicator');
+ var label = (indicator.textContent || '').trim();
+
+ if (!label) {
+ label = indicator.getAttribute('aria-label') || indicator.getAttribute('title') || '';
+ }
+
+ if (id === 'poll-status') {
+ indicator.setAttribute('title', label);
+ indicator.setAttribute('aria-label', label);
+ } else if (id === 'uci-changes') {
+ var match = label.match(/(\d+)\s*$/);
+
+ indicator.setAttribute('title', label);
+ indicator.setAttribute('aria-label', label);
+ indicator.setAttribute('data-count', match ? match[1] : '');
+ }
});
-})(jQuery);
\ No newline at end of file
+ }
+
+ function initIndicators() {
+ var indicatorRoot = document.getElementById("indicators");
+
+ if (!indicatorRoot) {
+ return;
+ }
+
+ syncIndicators();
+
+ new MutationObserver(syncIndicators).observe(indicatorRoot, {
+ childList: true,
+ subtree: true,
+ characterData: true,
+ attributes: true,
+ attributeFilter: ['data-style']
+ });
+ }
+
+ function syncOverviewPortStatus() {
+ var view = document.getElementById('view');
+ var portGroups = new Map();
+ var mediaPath = (L.env && L.env.media) ? L.env.media : '/luci-static/design';
+ var iconMap = {
+ 'alias': 'ethernet',
+ 'alias_disabled': 'ethernet_disabled',
+ 'bridge': 'bridge',
+ 'bridge_disabled': 'bridge_disabled',
+ 'ethernet': 'ethernet',
+ 'ethernet_disabled': 'ethernet_disabled',
+ 'switch': 'switch',
+ 'switch_disabled': 'switch_disabled',
+ 'tunnel': 'tunnel',
+ 'tunnel_disabled': 'tunnel_disabled',
+ 'vlan': 'vlan',
+ 'vlan_disabled': 'vlan_disabled',
+ 'wifi': 'wifi',
+ 'wifi_disabled': 'wifi_disabled',
+ 'signal-none': 'signal-none',
+ 'signal-0': 'signal-0',
+ 'signal-0-25': 'signal-0-25',
+ 'signal-25-50': 'signal-25-50',
+ 'signal-50-75': 'signal-50-75',
+ 'signal-75-100': 'signal-75-100',
+ 'signal-000-000': 'signal-0',
+ 'signal-000-025': 'signal-0-25',
+ 'signal-025-050': 'signal-25-50',
+ 'signal-050-075': 'signal-50-75',
+ 'signal-075-100': 'signal-75-100',
+ 'port_up': 'port_up',
+ 'port_down': 'port_down'
+ };
+
+ if (!view || document.body.getAttribute('data-page') !== 'admin-status-overview') {
+ return;
+ }
+
+ Array.prototype.forEach.call(view.querySelectorAll('img[src*="/luci-static/resources/icons/"]'), function (img) {
+ var src = img.getAttribute('src') || '';
+ var match = src.match(/\/icons\/([^/?#]+)\.(?:png|svg)(?:[?#].*)?$/);
+ var key = match ? match[1] : '';
+ var mapped = iconMap[key];
+ var badge = img.closest('.ifacebadge');
+
+ if (!mapped || !badge) {
+ return;
+ }
+
+ var size = key.indexOf('port_') === 0 ? '18px' :
+ key.indexOf('signal-') === 0 ? '16px' : '20px';
+
+ img.setAttribute('src', mediaPath + '/images/' + mapped + '.png');
+ img.style.setProperty('background-image', 'none', 'important');
+ img.style.setProperty('visibility', 'visible', 'important');
+ img.style.setProperty('opacity', '1', 'important');
+ img.style.setProperty('display', 'inline-block', 'important');
+ img.style.setProperty('width', size, 'important');
+ img.style.setProperty('height', size, 'important');
+ img.style.setProperty('min-width', size, 'important');
+ img.style.setProperty('padding', '0', 'important');
+ img.style.setProperty('margin', '0 .25rem 0 0', 'important');
+ img.style.setProperty('vertical-align', 'middle', 'important');
+ img.style.setProperty('object-fit', 'contain', 'important');
+ });
+
+ Array.prototype.forEach.call(view.querySelectorAll('.cbi-section > div'), function (grid) {
+ var isPortGrid = grid &&
+ grid.style &&
+ grid.style.display === 'grid' &&
+ grid.style.gridTemplateColumns.indexOf('minmax(70px, 1fr)') !== -1 &&
+ grid.querySelector('img[src*="/luci-static/resources/icons/port_"]');
+
+ if (!isPortGrid) {
+ return;
+ }
+
+ grid.classList.add('port-status-grid');
+
+ Array.prototype.forEach.call(grid.querySelectorAll('.ifacebox'), function (card) {
+ card.classList.add('port-status-card');
+ });
+ });
+
+ Array.prototype.forEach.call(view.querySelectorAll('img[src*="/luci-static/resources/icons/port_"]'), function (img) {
+ var card = img.closest('.ifacebox');
+ var slot = card ? card.closest('.port-status-slot') : null;
+ var parent = card ? (slot ? slot.parentElement : card.parentElement) : null;
+ var iconType = (img.getAttribute('src') || '').indexOf('port_down.png') !== -1 ? 'down' : 'up';
+ var badge = img.closest('.ifacebadge');
+
+ if (badge) {
+ img.setAttribute('src', mediaPath + '/images/port_' + iconType + '.png');
+ }
+
+ if (!card || !parent) {
+ return;
+ }
+
+ img.setAttribute('src', mediaPath + '/images/port_' + iconType + '.png');
+ img.style.setProperty('display', 'block', 'important');
+ img.style.setProperty('width', '24px', 'important');
+ img.style.setProperty('height', '24px', 'important');
+ img.style.setProperty('padding', '0', 'important');
+ img.style.setProperty('margin', '0.05rem auto', 'important');
+
+ if (img.nextElementSibling && img.nextElementSibling.tagName === 'BR') {
+ img.nextElementSibling.style.setProperty('display', 'none', 'important');
+ }
+
+ if (!portGroups.has(parent)) {
+ portGroups.set(parent, []);
+ }
+
+ if (portGroups.get(parent).indexOf(card) === -1) {
+ portGroups.get(parent).push(card);
+ }
+ });
+
+ portGroups.forEach(function (cards, parent) {
+ var width = window.innerWidth || document.documentElement.clientWidth || 1280;
+ var columns;
+
+ cards.forEach(function (card) {
+ var body = card.querySelector('.ifacebox-body');
+ var slot = card.parentElement;
+
+ if (!slot || !slot.classList.contains('port-status-slot')) {
+ slot = document.createElement('div');
+ slot.className = 'port-status-slot';
+ parent.insertBefore(slot, card);
+ slot.appendChild(card);
+ }
+
+ card.classList.add('port-status-card');
+
+ slot.style.setProperty('display', 'flex', 'important');
+ slot.style.setProperty('justify-content', 'center', 'important');
+ slot.style.setProperty('align-items', 'stretch', 'important');
+ slot.style.setProperty('min-width', '0', 'important');
+ slot.style.setProperty('padding', '0.15rem 0.65rem 0.75rem', 'important');
+
+ card.style.setProperty('margin', '0', 'important');
+ card.style.setProperty('min-width', '76px', 'important');
+ card.style.setProperty('max-width', '108px', 'important');
+ card.style.setProperty('width', 'fit-content', 'important');
+ card.style.setProperty('text-align', 'center', 'important');
+
+ if (body) {
+ body.style.setProperty('text-align', 'center', 'important');
+ body.style.setProperty('align-items', 'center', 'important');
+ body.style.setProperty('justify-content', 'center', 'important');
+ }
+ });
+
+ if (width <= 480) {
+ columns = 1;
+ } else if (width <= 768) {
+ columns = Math.min(cards.length, 2);
+ } else if (cards.length <= 4) {
+ columns = cards.length;
+ } else if (cards.length <= 6) {
+ columns = 3;
+ } else {
+ columns = 4;
+ }
+
+ parent.style.setProperty('display', 'grid', 'important');
+ parent.style.setProperty('grid-template-columns', 'repeat(' + columns + ', minmax(0, 1fr))', 'important');
+ parent.style.setProperty('align-items', 'stretch', 'important');
+ parent.style.setProperty('justify-items', 'stretch', 'important');
+ parent.style.setProperty('width', '100%', 'important');
+ parent.style.setProperty('max-width', '100%', 'important');
+ parent.style.setProperty('padding', '0.2rem 0.6rem 0.35rem', 'important');
+ parent.style.setProperty('margin', '0 auto 1rem', 'important');
+ parent.style.setProperty('row-gap', '0.2rem', 'important');
+ parent.style.setProperty('column-gap', '0', 'important');
+ });
+ }
+
+ function initOverviewPortStatus() {
+ var view = document.getElementById('view');
+
+ if (!view || document.body.getAttribute('data-page') !== 'admin-status-overview') {
+ return;
+ }
+
+ syncOverviewPortStatus();
+
+ new MutationObserver(syncOverviewPortStatus).observe(view, {
+ childList: true,
+ subtree: true
+ });
+ }
+
+ function syncNetworkInterfaceIcons() {
+ var view = document.getElementById('view');
+ var mediaPath = (L.env && L.env.media) ? L.env.media : '/luci-static/design';
+ var iconMap = {
+ 'alias': 'ethernet',
+ 'alias_disabled': 'ethernet_disabled',
+ 'bridge': 'bridge',
+ 'bridge_disabled': 'bridge_disabled',
+ 'ethernet': 'ethernet',
+ 'ethernet_disabled': 'ethernet_disabled',
+ 'switch': 'switch',
+ 'switch_disabled': 'switch_disabled',
+ 'tunnel': 'tunnel',
+ 'tunnel_disabled': 'tunnel_disabled',
+ 'vlan': 'vlan',
+ 'vlan_disabled': 'vlan_disabled',
+ 'wifi': 'wifi',
+ 'wifi_disabled': 'wifi_disabled'
+ };
+
+ if (!view || document.body.getAttribute('data-page') !== 'admin-network-network') {
+ return;
+ }
+
+ Array.prototype.forEach.call(view.querySelectorAll('img[src*="/luci-static/resources/icons/"]'), function (img) {
+ var src = img.getAttribute('src') || '';
+ var match = src.match(/\/icons\/([^/?#]+)\.(?:png|svg)(?:[?#].*)?$/);
+ var key = match ? match[1] : '';
+ var mapped = iconMap[key];
+
+ if (!mapped) {
+ return;
+ }
+
+ img.setAttribute('src', mediaPath + '/images/' + mapped + '.png');
+ img.classList.add('theme-network-icon');
+ img.style.setProperty('background-image', 'none', 'important');
+ img.style.setProperty('object-fit', 'contain', 'important');
+ });
+ }
+
+ function initNetworkInterfaceIcons() {
+ var view = document.getElementById('view');
+
+ if (!view || document.body.getAttribute('data-page') !== 'admin-network-network') {
+ return;
+ }
+
+ syncNetworkInterfaceIcons();
+
+ new MutationObserver(syncNetworkInterfaceIcons).observe(view, {
+ childList: true,
+ subtree: true
+ });
+ }
+
+ function syncWirelessIcons() {
+ var mediaPath = (L.env && L.env.media) ? L.env.media : '/luci-static/design';
+ var iconMap = {
+ 'wifi': 'wifi_big',
+ 'wifi_disabled': 'wifi_big_disabled',
+ 'signal-none': 'signal-none',
+ 'signal-0': 'signal-0',
+ 'signal-0-25': 'signal-0-25',
+ 'signal-25-50': 'signal-25-50',
+ 'signal-50-75': 'signal-50-75',
+ 'signal-75-100': 'signal-75-100',
+ 'signal-000-000': 'signal-0',
+ 'signal-000-025': 'signal-0-25',
+ 'signal-025-050': 'signal-25-50',
+ 'signal-050-075': 'signal-50-75',
+ 'signal-075-100': 'signal-75-100'
+ };
+
+ if (document.body.getAttribute('data-page') !== 'admin-network-wireless') {
+ return;
+ }
+
+ Array.prototype.forEach.call(document.querySelectorAll('img[src*="/luci-static/resources/icons/"]'), function (img) {
+ var src = img.getAttribute('src') || '';
+ var match = src.match(/\/icons\/([^/?#]+)\.(?:png|svg)(?:[?#].*)?$/);
+ var key = match ? match[1] : '';
+ var inAssocList = !!img.closest('#wifi_assoclist_table');
+ var mapped = iconMap[key];
+ var badge = img.closest('.ifacebadge') || img.closest('.center');
+ var isDeviceIcon = (key === 'wifi' || key === 'wifi_disabled');
+ var size = isDeviceIcon ? '64px' : '18px';
+
+ if (!mapped || !badge) {
+ return;
+ }
+
+ if (inAssocList && isDeviceIcon) {
+ mapped = key;
+ size = '16px';
+ }
+
+ img.setAttribute('src', mediaPath + '/images/' + mapped + '.png');
+ img.classList.add('theme-wireless-icon');
+ img.style.setProperty('background-image', 'none', 'important');
+ img.style.setProperty('visibility', 'visible', 'important');
+ img.style.setProperty('opacity', '1', 'important');
+ img.style.setProperty('display', 'inline-block', 'important');
+ img.style.setProperty('width', size, 'important');
+ img.style.setProperty('height', size, 'important');
+ img.style.setProperty('min-width', size, 'important');
+ img.style.setProperty('padding', '0', 'important');
+ img.style.setProperty('margin', (inAssocList && isDeviceIcon) ? '0 .2rem 0 0' : (isDeviceIcon ? '0 .3rem 0 0' : '0 .25rem 0 0'), 'important');
+ img.style.setProperty('vertical-align', 'middle', 'important');
+ img.style.setProperty('object-fit', 'contain', 'important');
+ });
+ }
+
+ function initWirelessIcons() {
+ if (document.body.getAttribute('data-page') !== 'admin-network-wireless') {
+ return;
+ }
+
+ syncWirelessIcons();
+
+ new MutationObserver(syncWirelessIcons).observe(document.body, {
+ childList: true,
+ subtree: true
+ });
+ }
+
+ function init() {
+ applySafeAreaFix();
+ initIndicators();
+ initOverviewPortStatus();
+ initNetworkInterfaceIcons();
+ initWirelessIcons();
+ setHeaderShadow();
+ $(window).on('resize', setHeaderShadow);
+ }
+
+ if (document.readyState === 'loading') {
+ document.addEventListener('DOMContentLoaded', init);
+ } else {
+ init();
+ }
+})(jQuery);
diff --git a/luci-theme-design/htdocs/luci-static/resources/menu-design.js b/luci-theme-design/htdocs/luci-static/resources/menu-design.js
index 235abf0f1..9df02b06d 100644
--- a/luci-theme-design/htdocs/luci-static/resources/menu-design.js
+++ b/luci-theme-design/htdocs/luci-static/resources/menu-design.js
@@ -1,17 +1,73 @@
'use strict';
'require baseclass';
+'require request';
'require ui';
-// 兼容新旧版本 LuCI
-var LuciCompat = {
- isNewVersion: function() {
- return L.env.luci_version && parseFloat(L.env.luci_version.split('.')[0]) >= 23;
- }
-};
-
return baseclass.extend({
__init__: function() {
- ui.menu.load().then(L.bind(this.render, this));
+ var params = new URLSearchParams(window.location.search);
+
+ if (params.get('menu') === 'flush') {
+ ui.menu.flushCache();
+ params.delete('menu');
+ window.history.replaceState(null, '', window.location.pathname +
+ (params.toString() ? '?' + params.toString() : '') +
+ window.location.hash);
+ }
+
+ this.syncConditionalMenuCache()
+ .then(L.bind(function(reloading) {
+ if (reloading)
+ return;
+
+ return ui.menu.load().then(L.bind(this.render, this));
+ }, this));
+ },
+
+ reloadPageWithMenuFlush: function() {
+ var url = new URL(window.location.href);
+
+ url.searchParams.set('menu', 'flush');
+ window.location.replace(url.toString());
+ },
+
+ getConditionalMenuStamp: function() {
+ var googleFuMode = !!document.querySelector('.navbar a[href*="/admin/services/openclash"]');
+
+ return Promise.resolve(JSON.stringify({
+ google_fu_mode: googleFuMode
+ }));
+ },
+
+ flushBackendMenuCache: function() {
+ ui.menu.flushCache();
+
+ return L.resolveDefault(request.get(L.url('admin/services/theme_menu_flush')), null).then(function() {
+ ui.menu.flushCache();
+ }).then(function() {
+ ui.menu.flushCache();
+ });
+ },
+
+ syncConditionalMenuCache: function() {
+ var storageKey = 'design.menu.condition-stamp';
+
+ if (!document.body.classList.contains('logged-in'))
+ return Promise.resolve();
+
+ return this.getConditionalMenuStamp().then(L.bind(function(stamp) {
+ var previousStamp = window.localStorage.getItem(storageKey);
+
+ if (previousStamp === stamp)
+ return false;
+
+ window.localStorage.setItem(storageKey, stamp);
+
+ return this.flushBackendMenuCache().then(L.bind(function() {
+ this.reloadPageWithMenuFlush();
+ return true;
+ }, this));
+ }, this));
},
render: function(tree) {
@@ -243,4 +299,3 @@ return baseclass.extend({
}
},
});
-
diff --git a/luci-theme-design/luasrc/view/themes/design/footer.htm b/luci-theme-design/luasrc/view/themes/design/footer.htm
deleted file mode 100644
index 7f645b7d9..000000000
--- a/luci-theme-design/luasrc/view/themes/design/footer.htm
+++ /dev/null
@@ -1,32 +0,0 @@
-<%#
- Material is a clean HTML5 theme for LuCI. It is based on luci-theme-bootstrap and MUI
-
- luci-theme-material
- Copyright 2015 Lutty Yang
-
- Have a bug? Please create an issue here on GitHub!
- https://github.com/LuttyYang/luci-theme-material/issues
-
- luci-theme-bootstrap:
- Copyright 2008 Steven Barth
- Copyright 2008 Jo-Philipp Wich
- Copyright 2012 David Menting
-
- MUI:
- https://github.com/muicss/mui
-
- Licensed to the public under the Apache License 2.0
--%>
-
-<% local ver = require "luci.version" %>
-
-
-
-
-
-
-
-