diff --git a/.gitignore b/.gitignore index 4fb5a51..d7ce5ee 100644 --- a/.gitignore +++ b/.gitignore @@ -45,3 +45,7 @@ tools/pki-server/*.crt *_key secrets/ password*.txt + +# Documentation +frontend_modification.md +frontend_emoji_list.md \ No newline at end of file diff --git a/README.md b/README.md index 9d1d802..0a94135 100644 --- a/README.md +++ b/README.md @@ -1,36 +1,23 @@ -# TianShanOS +![TianshanOS](assets/tsintro.png) [English](README_EN.md) | [中文](README.md) [![Build Status](https://github.com/thomas-hiddenpeak/TianshanOS/actions/workflows/build.yml/badge.svg)](https://github.com/thomas-hiddenpeak/TianshanOS/actions/workflows/build.yml) -[![Release](https://img.shields.io/github/v/release/thomas-hiddenpeak/TianshanOS)](https://github.com/thomas-hiddenpeak/TianshanOS/releases/latest) [![License](https://img.shields.io/github/license/thomas-hiddenpeak/TianshanOS)](LICENSE) +![ESP-IDF](https://img.shields.io/badge/ESP--IDF-v5.5+-green?logo=espressif) +![C](https://img.shields.io/badge/C-99-blue?logo=c) +![ESP32-S3](https://img.shields.io/badge/ESP32--S3-supported-blue?logo=espressif) +![Configuration Oriented](https://img.shields.io/badge/Configuration-Oriented-orange) > 天山操作系统 - ESP32 机架管理操作系统 > > 天山控制南北两大盆地——北向 AGX 提供 AI 算力,南向 LPMU 提供通用计算和存储服务 -``` -╔══════════════════════════════════════════════════════════════════════╗ -║ ║ -║ ████████╗██╗ █████╗ ███╗ ██╗███████╗██╗ ██╗ █████╗ ███╗ ██╗ ║ -║ ╚══██╔══╝██║██╔══██╗████╗ ██║██╔════╝██║ ██║██╔══██╗████╗ ██║ ║ -║ ██║ ██║███████║██╔██╗ ██║███████╗███████║███████║██╔██╗ ██║ ║ -║ ██║ ██║██╔══██║██║╚██╗██║╚════██║██╔══██║██╔══██║██║╚██╗██║ ║ -║ ██║ ██║██║ ██║██║ ╚████║███████║██║ ██║██║ ██║██║ ╚████║ ║ -║ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═══╝╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═══╝ ║ -║ ║ -║ TianShanOS v0.4.0 ║ -║ ESP32 Rack Management Operating System ║ -║ ║ -╚══════════════════════════════════════════════════════════════════════╝ -``` - --- -## 🚀 项目概述 +## 项目概述 -TianShanOS 是一个**面向配置而非面向代码**的嵌入式操作系统框架,基于 ESP-IDF v5.5+ 开发,用于 NVIDIA Jetson AGX + DFRobot LattePanda Mu 载板的机架管理。 +TianshanOS 是一个**面向配置而非面向代码**的嵌入式操作系统框架,基于 ESP-IDF v5.5+ 开发,用于 NVIDIA Jetson AGX + DFRobot LattePanda Mu 载板的机架管理。 ### 核心特性 @@ -43,38 +30,27 @@ TianShanOS 是一个**面向配置而非面向代码**的嵌入式操作系统 - **跨平台设计** - 支持 ESP32-S3 和 ESP32-P4 - **安全优先** - HTTPS/mTLS、SSH 公钥认证、PKI 证书管理、分级权限 - **统一接口** - CLI 和 WebUI 共享 Core API,行为一致 -- **多语言支持** - 中/英/日/韩/德/法/西/乌克兰 8 种语言界面 +- **多语言支持** - 中/英双语界面 - **CI/CD** - GitHub Actions 自动编译、Release 发布 ### 系统架构 -``` -┌─────────────────────────────────────────────────────────────────┐ -│ 用户交互层 (CLI / WebUI / HTTPS API) │ -├─────────────────────────────────────────────────────────────────┤ -│ Core API 层 (ts_api) │ -├─────────────────────────────────────────────────────────────────┤ -│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────────────┐ │ -│ │ 服务管理层 │ │ 自动化引擎 │ │ 安全模块 │ │ -│ │ (8阶段启动) │ │ (数据源/规则) │ │ (SSH/PKI/mTLS) │ │ -│ └──────────────┘ └──────────────┘ └──────────────────────────┘ │ -├─────────────────────────────────────────────────────────────────┤ -│ 事件/消息总线 (ts_event) │ -├─────────────────────────────────────────────────────────────────┤ -│ 配置管理层 (NVS/SD卡/默认值,优先级:内存>SD>NVS>默认) │ -├─────────────────────────────────────────────────────────────────┤ -│ 硬件抽象层 (GPIO/PWM/I2C/SPI/UART/ADC) │ -├─────────────────────────────────────────────────────────────────┤ -│ 平台适配层 (ESP32-S3 / ESP32-P4) │ -└─────────────────────────────────────────────────────────────────┘ +```mermaid +flowchart TB + UI["CLI / WebUI / HTTPS API"] --> API["Core API (ts_api)"] + API --> S1["服务管理"] & S2["自动化引擎"] & S3["安全模块"] + S1 & S2 & S3 --> Event["事件总线 (ts_event)"] + Event --> Config["配置管理 (NVS/SD卡)"] + Config --> HAL["硬件抽象层 (GPIO/PWM/I2C/SPI/UART/ADC)"] + HAL --> Platform["平台适配层 (ESP32-S3 / ESP32-P4)"] ``` --- -## 📦 项目结构 +## 项目结构 ``` -TianShanOS/ +TianshanOS/ ├── .github/ # GitHub 配置 │ └── workflows/ # CI/CD 工作流 │ └── build.yml # 自动编译 & Release @@ -108,7 +84,7 @@ TianShanOS/ --- -## 🛠️ 开发环境 +## 开发环境 ### 依赖 - ESP-IDF v5.5.2+ @@ -120,7 +96,7 @@ TianShanOS/ ```bash # 克隆项目 git clone https://github.com/thomas-hiddenpeak/TianshanOS.git -cd TianShanOS +cd TianshanOS # 设置 ESP-IDF 环境 . $HOME/esp/v5.5/esp-idf/export.sh @@ -128,7 +104,7 @@ cd TianShanOS # 设置目标芯片 idf.py set-target esp32s3 -# 配置项目 (TianShanOS 选项在顶层菜单) +# 配置项目 (TianshanOS 选项在顶层菜单) idf.py menuconfig # 编译(带版本号更新) @@ -146,7 +122,7 @@ idf.py -p /dev/ttyACM0 flash monitor esptool.py --chip esp32s3 -p /dev/ttyACM0 write_flash \ 0x0 bootloader.bin \ 0x8000 partition-table.bin \ - 0x10000 TianShanOS.bin + 0x10000 TianshanOS.bin ``` ### VS Code 开发 @@ -157,7 +133,7 @@ esptool.py --chip esp32s3 -p /dev/ttyACM0 write_flash \ --- -## 📚 文档 +## 文档 | 文档 | 描述 | |-----|------| @@ -178,10 +154,10 @@ esptool.py --chip esp32s3 -p /dev/ttyACM0 write_flash \ --- -## 🎯 当前状态 +## 当前状态 **版本**: 0.4.0 -**阶段**: Phase 38 完成 - WebUI 多语言支持 (8种语言) +**阶段**: Phase 38 完成 - WebUI 多语言支持 ### 已完成功能 @@ -196,7 +172,7 @@ esptool.py --chip esp32s3 -p /dev/ttyACM0 write_flash \ | 网络 | WiFi、以太网 W5500、HTTP/HTTPS 服务器 | | 安全 | 会话管理、Token 认证、AES-GCM、RSA/EC、SSH 客户端、PKI 证书管理 | | 驱动 | 风扇控制、电源监控 (ADC/INA3221/PZEM)、AGX/LPMU 电源控制、USB MUX | -| WebUI | REST API 网关、WebSocket 广播、前端仪表盘、认证系统、8语言国际化 | +| WebUI | REST API 网关、WebSocket 广播、前端仪表盘、认证系统、中英文国际化 | | OTA | 双分区升级、版本检测、完整性校验、自动回滚 | | 自动化引擎 | 触发器-条件-动作系统、SSH 远程执行、正则解析、变量系统、电压保护集成 | | CI/CD | GitHub Actions 自动编译、Tag 触发 Release 发布 | @@ -234,30 +210,24 @@ esptool.py --chip esp32s3 -p /dev/ttyACM0 write_flash \ --- -## 🌐 多语言支持 +## 多语言支持 -WebUI 支持 8 种语言,根据浏览器设置自动检测: +WebUI 支持中英文界面,根据浏览器设置自动检测: | 语言 | 代码 | |------|------| -| 🇨🇳 简体中文 | zh-CN | -| 🇺🇸 English | en-US | -| 🇯🇵 日本語 | ja-JP | -| 🇰🇷 한국어 | ko-KR | -| 🇩🇪 Deutsch | de-DE | -| 🇫🇷 Français | fr-FR | -| 🇪🇸 Español | es-ES | -| 🇺🇦 Українська | uk-UA | +| 简体中文 | zh-CN | +| English | en-US | --- -## 👥 贡献者 +## 贡献者 - Thomas (项目负责人) - massif-01 --- -## 📄 许可证 +## 许可证 本项目采用 GPL-3.0 许可证,详见 [LICENSE](LICENSE) 文件。 diff --git a/README_EN.md b/README_EN.md index fb9bc2e..49d2eee 100644 --- a/README_EN.md +++ b/README_EN.md @@ -1,32 +1,24 @@ -# TianShanOS +![TianshanOS](assets/tsintro.png) [English](README_EN.md) | [中文](README.md) -> TianShan Operating System - ESP32 Rack Management Operating System -> -> TianShan controls both the northern and southern basins — northward to AGX for AI computing power, southward to LPMU for general computing and storage services +[![Build Status](https://github.com/thomas-hiddenpeak/TianshanOS/actions/workflows/build.yml/badge.svg)](https://github.com/thomas-hiddenpeak/TianshanOS/actions/workflows/build.yml) +[![Release](https://img.shields.io/github/v/release/thomas-hiddenpeak/TianshanOS)](https://github.com/thomas-hiddenpeak/TianshanOS/releases/latest) +[![License](https://img.shields.io/github/license/thomas-hiddenpeak/TianshanOS)](LICENSE) +![ESP-IDF](https://img.shields.io/badge/ESP--IDF-v5.5+-green?logo=espressif) +![C](https://img.shields.io/badge/C-99-blue?logo=c) +![ESP32-S3](https://img.shields.io/badge/ESP32--S3-supported-blue?logo=espressif) +![Configuration Oriented](https://img.shields.io/badge/Configuration-Oriented-orange) -``` -╔══════════════════════════════════════════════════════════════════════╗ -║ ║ -║ ████████╗██╗ █████╗ ███╗ ██╗███████╗██╗ ██╗ █████╗ ███╗ ██╗ ║ -║ ╚══██╔══╝██║██╔══██╗████╗ ██║██╔════╝██║ ██║██╔══██╗████╗ ██║ ║ -║ ██║ ██║███████║██╔██╗ ██║███████╗███████║███████║██╔██╗ ██║ ║ -║ ██║ ██║██╔══██║██║╚██╗██║╚════██║██╔══██║██╔══██║██║╚██╗██║ ║ -║ ██║ ██║██║ ██║██║ ╚████║███████║██║ ██║██║ ██║██║ ╚████║ ║ -║ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═══╝╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═══╝ ║ -║ ║ -║ TianShanOS v0.3.0 ║ -║ ESP32 Rack Management Operating System ║ -║ ║ -╚══════════════════════════════════════════════════════════════════════╝ -``` +> Tianshan Operating System - ESP32 Rack Management Operating System +> +> Tianshan controls both the northern and southern basins — northward to AGX for AI computing power, southward to LPMU for general computing and storage services --- -## 🚀 Project Overview +## Project Overview -TianShanOS is a **configuration-oriented rather than code-oriented** embedded operating system framework, developed based on ESP-IDF v5.5+, designed for rack management of NVIDIA Jetson AGX + DFRobot LattePanda Mu carrier boards. +TianshanOS is a **configuration-oriented rather than code-oriented** embedded operating system framework, developed based on ESP-IDF v5.5+, designed for rack management of NVIDIA Jetson AGX + DFRobot LattePanda Mu carrier boards. ### Core Features @@ -38,38 +30,26 @@ TianShanOS is a **configuration-oriented rather than code-oriented** embedded op - **Cross-Platform Design** - Supports ESP32-S3 and ESP32-P4 - **Security First** - HTTPS/mTLS, SSH public key authentication, PKI certificate management, tiered permissions - **Unified Interface** - CLI and WebUI share Core API with consistent behavior -- **Multi-Language Support** - Chinese, English, Japanese, and Korean interface support +- **Multi-Language Support** - Chinese and English interface support ### System Architecture -``` -┌─────────────────────────────────────────────────────────────────┐ -│ User Interaction Layer (CLI / WebUI / HTTPS API) │ -├─────────────────────────────────────────────────────────────────┤ -│ Core API Layer (ts_api) │ -├─────────────────────────────────────────────────────────────────┤ -│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────────────┐ │ -│ │ Service │ │ Automation │ │ Security Module │ │ -│ │ Management │ │ Engine │ │ (SSH/PKI/mTLS) │ │ -│ │ (8-stage) │ │ (Data/Rules) │ │ │ │ -│ └──────────────┘ └──────────────┘ └──────────────────────────┘ │ -├─────────────────────────────────────────────────────────────────┤ -│ Event/Message Bus (ts_event) │ -├─────────────────────────────────────────────────────────────────┤ -│ Config Management (NVS/SD/Defaults, Priority: Mem>SD>NVS>Def) │ -├─────────────────────────────────────────────────────────────────┤ -│ Hardware Abstraction Layer (GPIO/PWM/I2C/SPI/UART/ADC) │ -├─────────────────────────────────────────────────────────────────┤ -│ Platform Adaptation Layer (ESP32-S3 / ESP32-P4) │ -└─────────────────────────────────────────────────────────────────┘ +```mermaid +flowchart TB + UI["CLI / WebUI / HTTPS API"] --> API["Core API (ts_api)"] + API --> S1["Service Mgmt"] & S2["Automation"] & S3["Security"] + S1 & S2 & S3 --> Event["Event Bus (ts_event)"] + Event --> Config["Config Management (NVS/SD)"] + Config --> HAL["HAL (GPIO/PWM/I2C/SPI/UART/ADC)"] + HAL --> Platform["Platform Layer (ESP32-S3 / ESP32-P4)"] ``` --- -## 📦 Project Structure +## Project Structure ``` -TianShanOS/ +TianshanOS/ ├── components/ # ESP-IDF Components (18 total) │ ├── ts_core/ # Core Framework (config/event/service/log) │ ├── ts_hal/ # Hardware Abstraction Layer (GPIO/PWM/I2C/SPI/UART/ADC) @@ -97,7 +77,7 @@ TianShanOS/ --- -## 🛠️ Development Environment +## Development Environment ### Dependencies - ESP-IDF v5.5.2+ @@ -109,7 +89,7 @@ TianShanOS/ ```bash # Clone the repository git clone https://github.com/thomas-hiddenpeak/TianshanOS.git -cd TianShanOS +cd TianshanOS # Set up ESP-IDF environment . $HOME/esp/v5.5/esp-idf/export.sh @@ -117,7 +97,7 @@ cd TianShanOS # Set target chip idf.py set-target esp32s3 -# Configure project (TianShanOS options are in the top-level menu) +# Configure project (TianshanOS options are in the top-level menu) idf.py menuconfig # Build @@ -135,7 +115,7 @@ For detailed instructions, please refer to the [Quick Start Guide](docs/QUICK_ST --- -## 📚 Documentation +## Documentation | Document | Description | |----------|-------------| @@ -156,7 +136,7 @@ For detailed instructions, please refer to the [Quick Start Guide](docs/QUICK_ST --- -## 🎯 Current Status +## Current Status **Version**: 0.3.0 **Phase**: Phase 20 Complete - Automation Engine, SSH Remote Execution, Variable System @@ -198,7 +178,7 @@ See [Development Progress](docs/DEVELOPMENT_PROGRESS.md) for detailed status. --- -## 👥 Contributors +## Contributors - Thomas (Project Lead) - massif-01 diff --git a/assets/tsintro.png b/assets/tsintro.png new file mode 100644 index 0000000..f475c1b Binary files /dev/null and b/assets/tsintro.png differ diff --git a/components/ts_webui/web/css/style.css b/components/ts_webui/web/css/style.css index 3056401..313f6fc 100644 --- a/components/ts_webui/web/css/style.css +++ b/components/ts_webui/web/css/style.css @@ -10,7 +10,7 @@ --card-bg: #fff; --border-color: #ddd; --header-height: 60px; - --footer-height: 40px; + --footer-height: 50px; } * { @@ -107,6 +107,11 @@ body { font-size: 0.9rem; } +.footer p { + margin: 0; + line-height: 1; +} + /* Cards */ .cards { display: grid; @@ -180,6 +185,17 @@ body { color: #c62828; } +/* MD 规范:运行中、添加 */ +.btn-success { + background: #e8f5e9; + color: #2e7d32; + border: 1px solid #a5d6a7; +} +.btn-success:hover { + background: #c8e6c9; + border-color: #81c784; +} + /* Modal */ .modal { position: fixed; @@ -221,23 +237,43 @@ body { .modal-header { display: flex; align-items: center; - justify-content: space-between; - margin-bottom: 16px; - padding-bottom: 12px; + justify-content: flex-start; + margin-bottom: 12px; + padding-bottom: 10px; border-bottom: 1px solid var(--border-color); + gap: 8px; } .modal-header h2 { margin: 0; - font-size: 1.1rem; + font-size: 1rem; + line-height: 28px; + height: 28px; +} + +#led-modal-header-actions { + display: flex; + gap: 8px; + margin-left: auto; + margin-right: 8px; + align-items: center; +} + +#led-modal-header-actions .btn { + height: 28px; + line-height: 28px; + padding: 0 10px; } .modal-close { - width: 32px; - height: 32px; + width: 28px; + height: 28px; + min-width: 28px; display: flex; align-items: center; justify-content: center; + flex-shrink: 0; + padding: 0; font-size: 1.4rem; color: var(--text-secondary); background: none; @@ -272,6 +308,125 @@ body { max-width: 560px; } +/* 色彩校正模态框 - 紧凑版 (重构) */ +.cc-compact { + padding: 0 !important; + background: #f5f6fa !important; + overflow: hidden; + display: flex; + flex-direction: column; +} + +.cc-compact .modal-header { + padding: 12px 20px !important; + background: #fff; + border-bottom: 1px solid #eee; + margin-bottom: 0; + display: flex; + align-items: flex-start; /* 顶部对齐 */ + justify-content: space-between; + position: relative; +} + +.cc-compact .modal-header h2 { + margin: 0 !important; + padding: 0; + font-size: 1.25rem; + font-weight: 600; + color: #333; + text-align: left; + line-height: 1.2; /* 确保标题紧贴顶部 */ +} + +.cc-compact #led-modal-header-actions, +.cc-compact #command-modal-header-actions { + display: flex; + gap: 8px; + margin-right: 35px; /* 为关闭按钮留位 */ +} + +.cc-compact .modal-close { + position: absolute; + top: 12px; + right: 12px; + font-size: 1.4rem; + background: transparent; + border: none; + cursor: pointer; + color: #888; + line-height: 1; +} + +.cc-compact .modal-header .btn-service-style { + background: #f0f8ff; + color: #007bff; + border: 1px solid #d0e8ff; + padding: 4px 12px; + border-radius: 6px; + font-weight: 400; /* 取消加粗,与底部按钮一致 */ + font-size: 0.9rem; + transition: all 0.2s ease; + line-height: 1.2; /* 与标题对齐的核心 */ +} + +.cc-compact .modal-header .btn-service-style:hover { + background: #007bff; + color: #fff; + box-shadow: 0 2px 6px rgba(0, 123, 255, 0.3); +} + +.cc-compact .modal-body { + padding: 20px; + background: #f5f6fa; + flex: 1; + overflow-y: auto; + max-height: 75vh; +} + +.cc-compact .modal-footer { + padding: 12px 20px; + background: #f5f6fa; + border-top: 1px solid #eee; + display: flex; + justify-content: flex-end; + gap: 12px; +} + +.cc-compact .modal-tabs, +.cc-compact .automation-modal-tabs { + display: flex; + border-bottom: 2px solid var(--border-color); + margin-bottom: 16px; +} + +.cc-compact .modal-tabs .modal-tab, +.cc-compact .automation-modal-tabs .modal-tab { + flex: 1; + padding: 10px 16px; + border: none; + background: transparent; + cursor: pointer; + font-size: 0.95em; + color: var(--text-light); + border-bottom: 2px solid transparent; + margin-bottom: -2px; + transition: all 0.2s; +} + +.cc-compact .modal-tabs .modal-tab:hover, +.cc-compact .automation-modal-tabs .modal-tab:hover { + color: var(--text-color); + background: var(--bg-color); +} + +.cc-compact .modal-tabs .modal-tab.active, +.cc-compact .automation-modal-tabs .modal-tab.active { + background: #f0f8ff; + color: #007bff; + border-bottom-color: #007bff; + font-weight: 500; +} + .led-modal .modal-tabs { display: flex; border-bottom: 2px solid var(--border-color); @@ -447,6 +602,18 @@ body { font-size: 0.85rem; } +/* Matrix 文本显示:字体下拉足够大、易点击 */ +#modal-text-font, +.led-modal .cc-section select#modal-text-font { + min-width: 160px; + min-height: 38px; + padding: 10px 12px; + font-size: 0.95rem; + cursor: pointer; + appearance: auto; + -webkit-appearance: menulist; +} + .config-actions { display: flex; gap: 10px; @@ -454,50 +621,61 @@ body { margin-top: 12px; } -/* Color Correction Modal */ +/* Color Correction Modal Cards (New Design) */ .cc-enable-row { + background: #fff; + padding: 16px 20px; + border-radius: 12px; margin-bottom: 16px; - padding: 12px; - background: var(--bg-color); - border-radius: 8px; + box-shadow: 0 1px 3px rgba(0,0,0,0.05); + border: 1px solid rgba(0,0,0,0.05); } .cc-enable-row label { display: flex; align-items: center; - gap: 8px; + gap: 12px; font-weight: 600; cursor: pointer; + margin: 0; + width: 100%; + font-size: 1rem; } .cc-enable-row input[type="checkbox"] { width: 20px; height: 20px; + accent-color: #007bff; } .cc-section { + background: #fff; + padding: 20px; + border-radius: 12px; margin-bottom: 16px; - padding: 12px; - background: var(--bg-color); - border-radius: 8px; + box-shadow: 0 1px 3px rgba(0,0,0,0.05); + border: 1px solid rgba(0,0,0,0.05); } .cc-section h4 { - font-size: 0.9rem; + font-size: 1rem; + font-weight: 600; margin: 0 0 8px 0; - color: var(--text-color); + color: #333; } .cc-help-text { - font-size: 0.75rem; - color: var(--text-secondary); - margin: 0 0 10px 0; - line-height: 1.4; - opacity: 0.85; + font-size: 0.85rem; + color: #888; + margin: 0 0 20px 0; + line-height: 1.5; } .cc-section .config-row { - margin-bottom: 8px; + display: flex; + align-items: center; + gap: 16px; + margin-bottom: 16px; } .cc-section .config-row:last-child { @@ -506,21 +684,44 @@ body { .cc-section input[type="range"] { flex: 1; - min-width: 100px; + height: 6px; + border-radius: 3px; + background: #eee; +} + +.cc-section input[type="range"]::-webkit-slider-thumb { + appearance: none; + -webkit-appearance: none; + width: 18px; + height: 18px; + border-radius: 50%; + background: #007bff; + box-shadow: 0 2px 4px rgba(0, 123, 255, 0.3); + cursor: pointer; } .cc-section span { - min-width: 45px; + min-width: 50px; text-align: right; - font-family: monospace; - font-size: 0.85rem; + font-weight: 500; + color: #333; + font-family: inherit; + font-size: 1rem; } -.cc-storage-row { +.cc-actions { + margin-top: 20px; + padding: 0; + background: transparent; display: flex; - gap: 8px; - justify-content: center; - margin-bottom: 12px; + justify-content: flex-end; + gap: 12px; +} + +.cc-actions .btn { + padding: 8px 20px; + font-size: 0.95rem; + border-radius: 6px; } /* 文件选择器模态框 - 需要比其他模态框更高的 z-index,因为它会从其他模态框内打开 */ @@ -668,7 +869,7 @@ body { font-weight: 500; } -.form-group input, +.form-group input:not([type="checkbox"]):not([type="radio"]), .form-group select, .form-group textarea { width: 100%; @@ -678,6 +879,46 @@ body { font-size: 1rem; } +.form-group input[type="checkbox"] { + width: auto; + min-width: 18px; + height: 18px; + margin: 0 8px 0 0; + vertical-align: middle; + accent-color: #007bff; +} + +.form-group-checkbox-label { + display: inline-flex; + align-items: center; + gap: 6px; + font-weight: 500; + cursor: pointer; +} +.form-group-checkbox-label input[type="checkbox"] { + flex-shrink: 0; +} + +.form-group-hint { + display: flex; + align-items: flex-start; + gap: 6px; + margin-top: 4px; + font-size: 0.85em; + color: #666; +} +.form-group-hint i { + flex-shrink: 0; + margin-top: 2px; +} +.form-group-hint span { + flex: 1; + min-width: 0; +} +.form-group-hint-warning { + color: #e67e22; +} + .form-group input:focus, .form-group select:focus, .form-group textarea:focus { @@ -741,7 +982,7 @@ body { } .ws-status.connected { - background: #2ecc71; + background: #2e7d32; } /* 语言切换按钮 */ @@ -965,9 +1206,23 @@ body { font-size: 0.85rem; } +.time-sync-btn { + border: 1px solid transparent; +} +.time-sync-btn:active { + background: #f0f8ff; + color: #007bff; + border-color: #d0e8ff; +} + .btn-success { - background: var(--secondary-color); - color: white; + background: #e8f5e9; + color: #2e7d32; + border: 1px solid #a5d6a7; +} +.btn-success:hover { + background: #c8e6c9; + border-color: #81c784; } .btn-warning { @@ -1091,6 +1346,22 @@ body { .led-quick-actions { display: flex; gap: 8px; + position: relative; + z-index: 1; +} +.led-refresh-btn { + min-width: 32px; + min-height: 32px; + cursor: pointer; + display: inline-flex; + align-items: center; + justify-content: center; + border: 1px solid transparent; +} +.led-refresh-btn:active { + background: #f0f8ff; + color: #007bff; + border-color: #d0e8ff; } /* LED 设备网格 */ @@ -1102,7 +1373,7 @@ body { /* LED 设备卡片 */ .led-device-card { - background: var(--card-bg); + background: #ffffff; border-radius: 16px; border: 2px solid var(--border-color); overflow: hidden; @@ -1115,8 +1386,8 @@ body { } .led-device-card.is-on { - border-color: #48bb78; - box-shadow: 0 0 20px rgba(72, 187, 120, 0.2); + border-color: #007bff; + box-shadow: 0 0 20px rgba(0, 123, 255, 0.2); } /* 卡片头部 */ @@ -1125,8 +1396,7 @@ body { align-items: center; gap: 12px; padding: 16px 20px; - background: linear-gradient(135deg, var(--bg-color) 0%, var(--card-bg) 100%); - border-bottom: 1px solid var(--border-color); + background: #ffffff; } .led-device-icon { @@ -1178,8 +1448,9 @@ body { } .led-device-status.effect { - background: rgba(90, 103, 216, 0.2); - color: var(--primary-color); + background: #f0f8ff; + color: #007bff; + border: 1px solid #d0e8ff; } /* 卡片控制区域 */ @@ -1188,6 +1459,7 @@ body { display: flex; flex-direction: column; gap: 14px; + background: #ffffff; } /* 亮度控制行 */ @@ -1217,12 +1489,11 @@ body { .led-brightness-slider::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; - width: 18px; - height: 18px; - background: linear-gradient(135deg, var(--primary-color) 0%, #4361ee 100%); + width: 16px; + height: 16px; + background: var(--primary-color); border-radius: 50%; cursor: pointer; - box-shadow: 0 2px 6px rgba(0,0,0,0.2); } .led-brightness-row .brightness-value { @@ -1233,53 +1504,102 @@ body { color: var(--text-secondary); } -/* 颜色控制行 */ +/* 颜色控制行 - Modern Redesign (缩小约 1/3) */ .led-color-row { display: flex; align-items: center; gap: 10px; + padding: 5px 0; } -.led-color-picker { - width: 44px; - height: 44px; - border: none; - border-radius: 10px; +/* Modern Picker */ +.modern-picker-wrapper { + position: relative; + width: 32px; + height: 32px; + flex-shrink: 0; +} + +.modern-picker-input { + width: 100%; + height: 100%; + opacity: 0; + position: absolute; + top: 0; + left: 0; cursor: pointer; - padding: 0; - background: transparent; + z-index: 2; } -.led-color-picker::-webkit-color-swatch-wrapper { - padding: 0; +.modern-picker-visual { + width: 100%; + height: 100%; + border-radius: 50%; + background: conic-gradient(from 180deg at 50% 50%, #FF0000 0deg, #FFFF00 60deg, #00FF00 120deg, #00FFFF 180deg, #0000FF 240deg, #FF00FF 300deg, #FF0000 360deg); + border: 2px solid white; + box-shadow: 0 0 0 2px var(--border-color), 0 1px 3px rgba(0,0,0,0.1); + position: relative; + transition: transform 0.2s ease; } -.led-color-picker::-webkit-color-swatch { - border: 2px solid var(--border-color); - border-radius: 10px; +.modern-picker-wrapper:hover .modern-picker-visual { + transform: scale(1.05); + box-shadow: 0 0 0 2px var(--primary-color), 0 4px 6px rgba(0,0,0,0.1); } -.led-color-presets { - display: flex; - gap: 6px; - flex-wrap: wrap; +.modern-picker-icon { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + color: white; + font-size: 0.85rem; + text-shadow: 0 1px 2px rgba(0,0,0,0.3); + pointer-events: none; +} + +/* Modern Presets */ +.modern-presets-container { flex: 1; + overflow-x: auto; + padding: 4px; + scrollbar-width: none; + -ms-overflow-style: none; + display: flex; + align-items: center; } +.modern-presets-container::-webkit-scrollbar { display: none; } -.color-dot { - width: 28px; - height: 28px; - border: 2px solid var(--border-color); +.modern-presets-list { + display: flex; + gap: 8px; + align-items: center; +} + +.modern-color-dot { + width: 24px; + height: 24px; border-radius: 50%; + border: 2px solid rgba(0,0,0,0.05); cursor: pointer; - transition: all 0.15s ease; - padding: 0; + transition: all 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275); + position: relative; + box-shadow: 0 1px 3px rgba(0,0,0,0.1); } -.color-dot:hover { - transform: scale(1.15); - border-color: white; - box-shadow: 0 2px 8px rgba(0,0,0,0.3); +.modern-color-dot:hover { + transform: scale(1.15) translateY(-2px); + box-shadow: 0 4px 6px rgba(0,0,0,0.1); + z-index: 10; +} + +.modern-color-dot:active { + transform: scale(0.95); +} + +/* White color needs a border */ +.modern-color-dot[style*="#ffffff"] { + border: 1px solid var(--border-color); } /* 特效控制行 */ @@ -1299,9 +1619,10 @@ body { .led-quick-effect { width: 36px; height: 36px; - border: 1px solid var(--border-color); - border-radius: 8px; - background: var(--bg-color); + border: 1px solid #d0e8ff; + border-radius: 4px; + background: #f0f8ff; + color: #007bff; cursor: pointer; font-size: 1rem; display: flex; @@ -1311,15 +1632,13 @@ body { } .led-quick-effect:hover { - background: var(--primary-color); - border-color: var(--primary-color); - color: white; - transform: translateY(-2px); + background: #e0f0ff; + border-color: #b0d8ff; } .led-quick-effect.active { - background: var(--primary-color); - border-color: var(--primary-color); + background: #007bff; + border-color: #007bff; color: white; } @@ -1328,20 +1647,31 @@ body { font-weight: 600; } +.led-matrix-btns { + display: flex; + gap: 6px; + margin-left: auto; +} + .led-stop-btn { - width: 36px; - height: 36px; - border: 1px solid #e74c3c; - border-radius: 8px; - background: rgba(231, 76, 60, 0.1); - color: #e74c3c; + display: flex; + align-items: center; + gap: 4px; + padding: 4px 10px; + border: 1px solid #ef9a9a; + border-radius: 6px; + background: #ffebee; + color: #c62828; cursor: pointer; - font-size: 0.9rem; + font-size: 0.75rem; + font-weight: 500; + white-space: nowrap; transition: all 0.15s ease; } .led-stop-btn:hover { - background: #e74c3c; + background: #c62828; + border-color: #c62828; color: white; } @@ -1350,42 +1680,33 @@ body { display: flex; gap: 8px; padding: 12px 20px 16px; - background: var(--bg-color); - border-top: 1px solid var(--border-color); + background: #ffffff; flex-wrap: wrap; } .led-power-btn { display: flex; align-items: center; - gap: 6px; - padding: 8px 16px; - border: 1px solid var(--border-color); - border-radius: 8px; - background: var(--card-bg); + justify-content: center; + padding: 0; + border: none; + background: transparent; cursor: pointer; transition: all 0.2s ease; - font-size: 0.85rem; + font-size: 1.8rem; + color: #c62828; } .led-power-btn:hover { - background: var(--primary-color); - border-color: var(--primary-color); - color: white; + opacity: 0.8; } .led-power-btn.on { - background: linear-gradient(135deg, #48bb78 0%, #38a169 100%); - border-color: #38a169; - color: white; + color: #2e7d32; } .led-power-btn .power-icon { - font-size: 1rem; -} - -.led-power-btn .power-text { - font-weight: 500; + font-size: 1.8rem; } .led-func-btn { @@ -1414,21 +1735,19 @@ body { .led-save-btn { margin-left: auto; - width: 40px; - height: 40px; - border: 1px solid var(--secondary-color); - border-radius: 8px; - background: var(--secondary-color); - color: white; + border: none; + background: transparent; + color: #007bff; cursor: pointer; - font-size: 1rem; + font-size: 1.5rem; transition: all 0.2s ease; + display: flex; + align-items: center; + justify-content: center; } .led-save-btn:hover { - background: #27ae60; - border-color: #27ae60; - transform: translateY(-1px); + opacity: 0.8; } /* LED 空状态 */ @@ -2114,13 +2433,13 @@ body { } .btn-success { - background: #28a745; - border-color: #28a745; - color: white; + background: #e8f5e9; + color: #2e7d32; + border: 1px solid #a5d6a7; } - .btn-success:hover { - background: #218838; + background: #c8e6c9; + border-color: #81c784; } /* 空状态提示 */ @@ -2131,6 +2450,19 @@ body { text-align: center; } +.commands-list .empty-state { + min-height: 220px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 8px; +} + +.commands-list .empty-state p { + margin: 0 0 6px 0; +} + .empty-state p { margin: 8px 0; } @@ -2218,7 +2550,7 @@ body { /* 风扇卡片 - 简洁版 */ .fan-card { - background: var(--bg-color); + background: #fff; padding: 20px; border-radius: 12px; border: 2px solid var(--border-color); @@ -2316,11 +2648,6 @@ body { background: #6b7280; } -.fan-mode-tab.manual { - border-radius: 4px; - border: 1px solid var(--border-color); -} - .fan-mode-tab.active.manual { background: #fff8e1; color: #f57c00; @@ -2328,11 +2655,15 @@ body { } .fan-mode-tab.active.auto { - background: #10b981; + background: #e8f5e9; + color: #2e7d32; + border: 1px solid #a5d6a7; } .fan-mode-tab.active.curve { - background: #3b82f6; + background: #f0f8ff; + color: #007bff; + border: 1px solid #d0e8ff; } /* 滑块区域 */ @@ -2402,10 +2733,10 @@ body { .fan-curve-btn { width: 100%; padding: 10px; - background: transparent; - border: 1px dashed var(--border-color); + background: #f0f8ff; + border: 1px solid #d0e8ff; border-radius: 8px; - color: var(--text-light); + color: #007bff; font-size: 0.9rem; cursor: pointer; transition: all 0.2s; @@ -2413,9 +2744,9 @@ body { } .fan-curve-btn:hover { - border-color: var(--primary-color); - color: var(--primary-color); - background: rgba(79, 195, 247, 0.1); + border-color: #007bff; + color: #007bff; + background: #e0f0ff; } /* 温度信息 */ @@ -2638,6 +2969,52 @@ body { color: #c0392b; } +/* 导出加密配置包:文件列表排版(网格固定列,避免错位) */ +.pack-export-file-list-inner { + padding: 4px; +} +.pack-export-file-row { + display: grid; + grid-template-columns: 20px 22px 1fr auto; + align-items: center; + gap: 8px; + padding: 8px 12px; + border-bottom: 1px solid #eee; +} +.pack-export-dir-row { + grid-template-columns: 22px 1fr; + cursor: pointer; +} +.pack-export-row-cb { + margin: 0; + justify-self: start; +} +.pack-export-row-icon { + color: #666; + display: flex; + align-items: center; + justify-content: center; +} +.pack-export-row-icon i { + font-size: 1rem; +} +.pack-export-row-name { + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.pack-export-row-label { + cursor: pointer; + margin: 0; + min-width: 0; +} +.pack-export-row-size { + color: #999; + font-size: 0.9em; + justify-self: end; +} + /* Hidden */ .hidden { display: none !important; @@ -2649,6 +3026,24 @@ body { .page-network h1, .page-device h1, .page-config h1, +/* 安全页面:第一个 section 与顶栏间距与指令等页面一致 */ +.page-security .section:first-child { + margin-top: 0; +} + +/* 安全页按钮统一为 btn-sm 尺寸 */ +.page-security .btn, +.page-security .btn-sm { + padding: 5px 12px; + font-size: 0.85rem; +} + +.page-security .form-actions .btn, +.page-security .form-actions .btn-sm { + padding: 5px 12px; + font-size: 0.85rem; +} + .page-security h1, .dashboard h1 { font-size: 1.8rem; @@ -2822,6 +3217,23 @@ body { .file-actions { display: flex; gap: 8px; + position: relative; + z-index: 1; +} + +.page-files .files-refresh-btn { + min-width: 32px; + min-height: 32px; + cursor: pointer; + display: inline-flex; + align-items: center; + justify-content: center; + border: 1px solid transparent; +} +.page-files .files-refresh-btn:active { + background: #f0f8ff; + color: #007bff; + border-color: #d0e8ff; } /* 文件页面白色卡片容器 */ @@ -3943,8 +4355,7 @@ body { } .led-power-btn { - padding: 6px 12px; - font-size: 0.8rem; + font-size: 1.5rem; } .color-dot { @@ -4378,9 +4789,18 @@ body { display: flex; flex-direction: column; align-items: center; + justify-content: space-between; + min-height: 72px; gap: 4px; } +.status-card .status-card-value-row { + display: flex; + align-items: center; + justify-content: center; + gap: 6px; +} + .status-card.primary { background: linear-gradient(135deg, var(--primary-color), var(--primary-dark)); color: white; @@ -4443,6 +4863,10 @@ body { align-items: flex-start; } +.status-card .status-card-value-row .status-icon { + flex-shrink: 0; +} + /* Section 通用样式 */ .page-automation .section { margin-bottom: 24px; @@ -4464,6 +4888,22 @@ body { .page-automation .section-actions { display: flex; gap: 6px; + position: relative; + z-index: 1; +} +.page-automation .automation-refresh-btn { + min-width: 32px; + min-height: 32px; + cursor: pointer; + display: inline-flex; + align-items: center; + justify-content: center; + border: 1px solid transparent; +} +.page-automation .automation-refresh-btn:active { + background: #f0f8ff; + color: #007bff; + border-color: #d0e8ff; } /* 紧凑卡片 */ @@ -4735,9 +5175,11 @@ body { background: var(--bg-color); } +/* 与 OTA/btn-service-style 一致:浅蓝底、蓝色字、蓝边框 */ .automation-modal .modal-tab.active { - color: var(--primary-color); - border-bottom-color: var(--primary-color); + background: #f0f8ff; + color: #007bff; + border-bottom-color: #007bff; font-weight: 500; } @@ -4808,6 +5250,63 @@ body { font-size: 0.9rem; } +/* 添加规则模态框:表单项左对齐 */ +#add-rule-modal .form-group label, +#add-rule-modal .config-section, +#add-rule-modal .icon-type-tabs, +#add-rule-modal .icon-picker { + text-align: left; +} + +/* 规则图标选择器:左对齐、布局整齐 */ +#add-rule-modal .icon-type-tabs { + justify-content: flex-start; + margin-bottom: 10px; +} + +#add-rule-modal .icon-picker { + justify-content: flex-start; + align-items: flex-start; + width: 100%; + box-sizing: border-box; +} + +#add-rule-modal .icon-picker .emoji-custom-input { + flex-basis: 100%; + width: 100%; + margin-bottom: 8px; +} + +#add-rule-modal .icon-picker .icon-btn { + flex-shrink: 0; +} + +#add-rule-modal .actions-hint-block { + text-align: center; +} + +#add-rule-modal .form-row.three-col { + display: flex; + flex-wrap: nowrap; + align-items: flex-start; + gap: 12px; +} + +/* 条件逻辑缩短,避免与冷却时间、立即启用挤在一起 */ +#add-rule-modal .form-row.three-col .form-group-logic { + flex: 0 0 90px; + min-width: 0; +} + +#add-rule-modal .form-row.three-col .form-group:nth-of-type(2) { + flex: 0 0 120px; + min-width: 0; +} + +#add-rule-modal .form-row.three-col .checkbox-label { + flex: 0 0 auto; +} + /* 条件行 */ .condition-row { display: flex; @@ -5922,6 +6421,15 @@ body { margin-left: 8px; } +/* 浅蓝标签(与 btn-service-style 配色一致:安全页密钥类型/SSH/HTTPS/部署密钥、配置包类型等) */ +.badge-service-style, +.badge-info { + background: #f0f8ff !important; + color: #007bff !important; + border: 1px solid #d0e8ff; + margin-left: 0; +} + /* ===== SSH Command Icon Picker ===== */ /* Icon type tabs */ @@ -6209,6 +6717,26 @@ body { min-width: 0; } +/* 风扇控制标题栏按钮:确保可点击、点击时蓝色底色(遵循文档 btn-service-style) */ +.fan-control-section .fan-section-actions { + position: relative; + z-index: 1; +} +.fan-refresh-btn { + min-width: 32px; + min-height: 32px; + cursor: pointer; + display: inline-flex; + align-items: center; + justify-content: center; + border: 1px solid transparent; +} +.fan-refresh-btn:active { + background: #f0f8ff; + color: #007bff; + border-color: #d0e8ff; +} + /* 风扇温度状态栏 */ .fan-temp-status-bar { display: flex; @@ -6385,7 +6913,7 @@ body { .data-widgets-empty { text-align: center; - padding: 40px 20px; + padding: 30px 20px; color: var(--text-light); } @@ -6396,7 +6924,7 @@ body { } .data-widgets-empty p { - margin-bottom: 16px; + margin-bottom: 0; } /* 组件卡片 */ @@ -6851,6 +7379,7 @@ body { .dw-manager-item { display: flex; align-items: center; + flex-wrap: nowrap; gap: 8px; padding: 8px 10px; background: var(--card-bg); @@ -6875,6 +7404,7 @@ body { .dw-manager-item-label { flex: 1; + min-width: 0; font-weight: 500; font-size: 0.9em; white-space: nowrap; @@ -6891,12 +7421,15 @@ body { } .dw-manager-item-actions { - display: none; + flex-shrink: 0; + margin-left: auto; + display: flex; gap: 2px; + opacity: 0; } .dw-manager-item:hover .dw-manager-item-actions { - display: flex; + opacity: 1; } .dw-manager-item-actions .dw-btn-icon { @@ -6985,6 +7518,30 @@ body { max-width: 500px; } +.dw-edit-panel .form-row { + align-items: flex-start; + gap: 16px; +} + +.dw-edit-panel .form-row .form-group { + min-width: 0; +} + +/* 仅第一行(图标+颜色):图标占剩余宽度,颜色固定一列,避免拥挤不对齐 */ +.dw-edit-panel .form-row:first-of-type .form-group:first-child { + flex: 1; +} + +.dw-edit-panel .form-row:first-of-type .form-group:last-child { + flex: 0 0 100px; +} + +.dw-edit-panel .form-row:first-of-type .form-group:last-child .input-color { + width: 100%; + min-width: 56px; + max-width: 80px; +} + .dw-edit-header { margin-bottom: 16px; } @@ -6992,8 +7549,9 @@ body { .dw-edit-type-badge { display: inline-block; padding: 4px 12px; - background: var(--primary-color); - color: white; + background: #f0f8ff; + color: #007bff; + border: 1px solid #d0e8ff; border-radius: 20px; font-size: 0.85em; } @@ -7013,8 +7571,9 @@ body { .dw-expression-group .badge { font-size: 0.65em; - background: var(--primary-color); - color: white; + background: #f0f8ff; + color: #007bff; + border: 1px solid #d0e8ff; padding: 2px 6px; border-radius: 3px; } @@ -7366,7 +7925,18 @@ body { .ri-download-cloud-line, .ri-refresh-line, .ri-time-line, -.ri-usb-line { +.ri-usb-line, +.ri-information-line, +.ri-add-line, +.ri-upload-line, +.ri-download-line, +.ri-rocket-line, +.ri-alert-line, +.ri-error-warning-line, +.ri-lock-unlock-line, +.ri-close-line, +.ri-eye-line, +.ri-delete-bin-line { font-style: normal; line-height: 1; display: inline-block; diff --git a/components/ts_webui/web/fonts/remixicon.css b/components/ts_webui/web/fonts/remixicon.css index 9f3d671..aace1d6 100644 --- a/components/ts_webui/web/fonts/remixicon.css +++ b/components/ts_webui/web/fonts/remixicon.css @@ -67,6 +67,78 @@ .ri-toggle-fill:before { content: "\f218"; } .ri-eject-line:before { content: "\ec88"; } .ri-lightbulb-line:before { content: "\eea9"; } +.ri-lightbulb-fill:before { content: "\eea6"; } .ri-lightbulb-flash-line:before { content: "\eea8"; } .ri-information-line:before { content: "\ee59"; } -.ri-question-answer-line:before { content: "\f04e"; } \ No newline at end of file +.ri-question-answer-line:before { content: "\f04e"; } +.ri-save-line:before { content: "\f0b3"; } +.ri-save-fill:before { content: "\f0b2"; } +.ri-shut-down-fill:before { content: "\f125"; } +.ri-shut-down-line:before { content: "\f126"; } +.ri-contrast-line:before { content: "\ebda"; } +.ri-palette-line:before { content: "\efc5"; } +.ri-hourglass-line:before { content: "\f339"; } +.ri-alert-line:before { content: "\ea21"; } +.ri-sun-line:before { content: "\f1bf"; } +.ri-stop-circle-line:before { content: "\f19f"; } +.ri-qr-code-line:before { content: "\f03d"; } +.ri-text:before { content: "\f201"; } +.ri-color-filter-line:before { content: "\f42e"; } + +/* Icons for Commands page icon picker */ +.ri-rocket-line:before { content: "\f096"; } +.ri-thunderstorms-line:before { content: "\f209"; } +.ri-tools-line:before { content: "\f21b"; } +.ri-bar-chart-line:before { content: "\ea9e"; } +.ri-search-line:before { content: "\f0d1"; } +.ri-stop-line:before { content: "\f1a1"; } +.ri-play-line:before { content: "\f00b"; } +.ri-settings-line:before { content: "\f0ee"; } +.ri-settings-3-line:before { content: "\f0e6"; } +.ri-run-line:before { content: "\f0a5"; } + +/* Host card icon */ +.ri-server-line:before { content: "\f0e0"; } + +/* Automation page icons */ +.ri-bar-chart-box-line:before { content: "\ea98"; } +.ri-upload-2-line:before { content: "\f24a"; } +.ri-pause-line:before { content: "\efd8"; } +.ri-play-circle-line:before { content: "\f009"; } +.ri-notification-line:before { content: "\ef9a"; } +.ri-plug-line:before { content: "\f019"; } +.ri-file-text-line:before { content: "\ed0f"; } +.ri-database-2-line:before { content: "\ec16"; } +.ri-global-line:before { content: "\edcf"; } +.ri-movie-line:before { content: "\ef81"; } +.ri-music-line:before { content: "\ef85"; } +.ri-smartphone-line:before { content: "\f15a"; } +.ri-computer-line:before { content: "\ebca"; } +.ri-shield-line:before { content: "\f108"; } +.ri-focus-line:before { content: "\ed4e"; } +.ri-timer-line:before { content: "\f215"; } +.ri-shield-keyhole-line:before { content: "\f107"; } +.ri-terminal-box-line:before { content: "\f1f6"; } +.ri-folder-open-line:before { content: "\ed70"; } +.ri-image-line:before { content: "\ee4b"; } + +/* Security page */ +.ri-lock-unlock-line:before { content: "\eed2"; } +.ri-eye-line:before { content: "\ecb5"; } +.ri-error-warning-line:before { content: "\eca1"; } +.ri-arrow-up-s-line:before { content: "\ea78"; } +.ri-checkbox-blank-circle-line:before { content: "\eb7d"; } + +/* Data widget manager - types and presets */ +.ri-dashboard-line:before { content: "\ec14"; } +.ri-progress-6-line:before { content: "\f485"; } +.ri-numbers-line:before { content: "\efaa"; } +.ri-record-circle-fill:before { content: "\f059"; } +.ri-emotion-line:before { content: "\ec90"; } +.ri-percent-line:before { content: "\efe6"; } +.ri-file-list-line:before { content: "\ecf1"; } +.ri-cpu-line:before { content: "\ebf0"; } +.ri-brain-line:before { content: "\f2f7"; } +.ri-hard-drive-line:before { content: "\edfb"; } +.ri-gamepad-line:before { content: "\edab"; } +.ri-ruler-line:before { content: "\f0a3"; } \ No newline at end of file diff --git a/components/ts_webui/web/index.html b/components/ts_webui/web/index.html index 7adacf8..68b2440 100644 --- a/components/ts_webui/web/index.html +++ b/components/ts_webui/web/index.html @@ -55,7 +55,7 @@ @@ -92,7 +92,8 @@

登录 Tia - +