From 7a7d3aeaaacc86214fbdde01d30fb09ae177f2e3 Mon Sep 17 00:00:00 2001 From: skyle1995 Date: Sat, 28 Mar 2026 23:30:02 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=A1=B9=E7=9B=AE=E4=B8=BA?= =?UTF-8?q?=E5=89=8D=E5=90=8E=E7=AB=AF=E5=88=86=E7=A6=BB=E6=96=B9=E6=A1=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 +- LICENSE | 2 +- README.md | 195 +- cmd/root.go | 5 +- cmd/server.go | 397 +- config/config.go | 138 +- config/validator.go | 10 +- constants/status.go | 2 +- controllers/admin/api.go | 27 +- controllers/admin/app.go | 36 +- controllers/admin/auth.go | 116 +- controllers/admin/captcha.go | 3 + controllers/admin/dashboard.go | 108 +- controllers/admin/function.go | 11 - controllers/admin/login_log.go | 26 +- controllers/admin/operation_log.go | 24 +- controllers/admin/profile.go | 300 +- controllers/admin/settings.go | 105 +- controllers/admin/variable.go | 11 - controllers/base.go | 3 +- controllers/default/handlers.go | 26 +- controllers/install/install.go | 93 +- database/database.go | 233 +- database/migrate.go | 4 +- database/settings.go | 561 +- go.mod | 21 +- go.sum | 42 +- middleware/cors.go | 21 + middleware/devmode.go | 26 +- middleware/install.go | 63 +- middleware/logging.go | 2 +- middleware/maintenance.go | 76 +- models/operation_log.go | 2 +- models/user.go | 16 +- server/admin.go | 275 +- server/default.go | 16 +- server/install.go | 7 +- server/routes.go | 63 +- services/query.go | 10 +- services/settings.go | 14 + web/assets/logo.svg | 11 - web/assets/themes.json | 355 - web/public.go | 67 - web/static/css/admin.css | 93 - web/static/js/admin.js | 463 - web/static/lib/README.md | 83 - web/static/lib/colorMode.js | 191 - web/static/lib/drawer/drawer.css | 317 - web/static/lib/drawer/drawer.js | 200 - web/static/lib/echarts/echarts.min.js | 45 - web/static/lib/include.js | 142 - web/static/lib/jquery/jquery.min.js | 2 - web/static/lib/layui/css/layui.css | 2 - web/static/lib/layui/font/iconfont.ttf | Bin 54588 -> 0 bytes web/static/lib/layui/font/iconfont.woff2 | Bin 30004 -> 0 bytes web/static/lib/layui/layui.js | 2 - web/static/lib/less.js | 11360 ---------------- web/static/src/css-variables.css | 202 - web/static/src/layui-theme-dark-selector.css | 1899 --- .../src/layui-theme-dark-selector.css.map | 1 - web/static/src/layui-theme-dark.css | 738 - web/static/src/layui-theme-dark.css.map | 1 - web/static/src/override.css | 534 - web/static/tpl/theme.html | 240 - web/template/admin/apis.html | 661 - web/template/admin/apps.html | 1232 -- web/template/admin/dashboard.html | 181 - web/template/admin/functions.html | 489 - web/template/admin/layout.html | 83 - web/template/admin/login.html | 280 - web/template/admin/login_logs.html | 171 - web/template/admin/operation_logs.html | 155 - web/template/admin/profile.html | 340 - web/template/admin/settings.html | 508 - web/template/admin/variables.html | 489 - web/template/default/index.html | 374 - web/template/install/install.html | 209 - 77 files changed, 1447 insertions(+), 23765 deletions(-) create mode 100644 middleware/cors.go delete mode 100644 web/assets/logo.svg delete mode 100644 web/assets/themes.json delete mode 100644 web/public.go delete mode 100644 web/static/css/admin.css delete mode 100755 web/static/js/admin.js delete mode 100644 web/static/lib/README.md delete mode 100755 web/static/lib/colorMode.js delete mode 100644 web/static/lib/drawer/drawer.css delete mode 100755 web/static/lib/drawer/drawer.js delete mode 100644 web/static/lib/echarts/echarts.min.js delete mode 100755 web/static/lib/include.js delete mode 100644 web/static/lib/jquery/jquery.min.js delete mode 100644 web/static/lib/layui/css/layui.css delete mode 100644 web/static/lib/layui/font/iconfont.ttf delete mode 100644 web/static/lib/layui/font/iconfont.woff2 delete mode 100644 web/static/lib/layui/layui.js delete mode 100755 web/static/lib/less.js delete mode 100644 web/static/src/css-variables.css delete mode 100644 web/static/src/layui-theme-dark-selector.css delete mode 100644 web/static/src/layui-theme-dark-selector.css.map delete mode 100644 web/static/src/layui-theme-dark.css delete mode 100644 web/static/src/layui-theme-dark.css.map delete mode 100644 web/static/src/override.css delete mode 100644 web/static/tpl/theme.html delete mode 100644 web/template/admin/apis.html delete mode 100644 web/template/admin/apps.html delete mode 100644 web/template/admin/dashboard.html delete mode 100644 web/template/admin/functions.html delete mode 100644 web/template/admin/layout.html delete mode 100644 web/template/admin/login.html delete mode 100644 web/template/admin/login_logs.html delete mode 100644 web/template/admin/operation_logs.html delete mode 100644 web/template/admin/profile.html delete mode 100644 web/template/admin/settings.html delete mode 100644 web/template/admin/variables.html delete mode 100644 web/template/default/index.html delete mode 100644 web/template/install/install.html diff --git a/.gitignore b/.gitignore index 2af79b9..70ea303 100644 --- a/.gitignore +++ b/.gitignore @@ -40,7 +40,7 @@ log/ *.swo *~ node.txt -模板 +frontend # IDE 和编辑器 .vscode/settings.json diff --git a/LICENSE b/LICENSE index 53986ed..6f9eb8b 100644 --- a/LICENSE +++ b/LICENSE @@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index 2fa8a3d..a951152 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# NetworkAuth(开发中) +# NetworkAuth(网络授权服务) -一个基于 Go 语言开发的网络应用管理系统,提供应用程序管理、API接口管理、变量管理、用户认证等功能的 Web 管理平台。 +网络授权服务 (NetworkAuth) 是一个专注于应用鉴权、接口管理和动态逻辑分发的后端系统。它基于 Go 语言开发,提供应用程序管理、API接口管理、变量管理、用户认证等核心服务。 ## 功能特性 @@ -11,115 +11,46 @@ - **函数管理**: 支持自定义函数代码管理,可绑定特定应用或全局使用 - **用户管理**: 完整的用户认证和权限管理系统 - **系统设置**: 灵活的系统配置和参数管理 -- **系统安装**: 提供可视化的安装向导,轻松完成数据库和管理员配置 -- **仪表盘**: 实时系统状态监控和统计数据展示 +- **系统初始化**: 提供引导式的数据表初始化和默认设置注入 - **日志审计**: 详细的登录日志和操作日志记录,保障系统安全 ### 🔧 技术特性 - **RESTful API**: 标准的 REST API 接口设计 - **JWT 认证**: 基于 JWT 的安全认证机制 - **多种加密算法**: 支持 RC4、RSA、RSA动态、易加密等多种加密方式 -- **数据库支持**: 支持 MySQL 和 SQLite 数据库 +- **数据库支持**: 兼容 MySQL 和 SQLite 数据库 (通过 GORM) - **Redis 缓存**: 集成 Redis 缓存提升性能(可选) -- **Excel 导出**: 支持数据导出为 Excel 文件 -- **日志系统**: 完整的日志记录和管理,支持日志切割 +- **日志系统**: 完整的日志记录和管理,支持日志切割 (Logrus + Lumberjack) - **配置管理**: 基于 Viper 的灵活配置系统 - -### 🎨 界面特性 -- **响应式设计**: 支持多种设备和屏幕尺寸 -- **现代化 UI**: 基于 LayUI 的现代化管理界面 -- **主题支持**: 支持明暗主题切换 -- **实时更新**: 支持数据的实时刷新和更新 -- **片段化加载**: 采用 AJAX 片段加载提升用户体验 +- **命令行工具**: 基于 Cobra 的强悍 CLI 管理工具 ## 技术栈 -- **后端**: Go 1.25.0 -- **Web 框架**: Gin + 自定义路由 -- **数据库**: GORM + MySQL/SQLite +- **语言**: Go 1.25.0 +- **Web 框架**: Gin +- **数据库 ORM**: GORM - **缓存**: Redis(可选) - **认证**: JWT + 验证码 - **日志**: Logrus + Lumberjack -- **配置**: Viper -- **前端**: LayUI + JavaScript -- **工具**: Excelize (Excel导出) +- **配置管理**: Viper +- **命令行**: Cobra - **加密**: 自定义加密工具包 ## 项目结构 ``` -networkDev/ -├── cmd/ # 命令行工具 -│ ├── root.go # 根命令定义 -│ └── server.go # 服务器启动命令 -├── config/ # 配置文件和配置管理 -│ ├── config.go # 配置加载和验证 -│ ├── security.go # 安全配置 -│ └── validator.go # 配置验证器 -├── constants/ # 常量定义 -│ └── status.go # 状态常量 -├── controllers/ # 控制器层 -│ ├── admin/ # 管理后台控制器 -│ │ ├── api.go # API接口管理 -│ │ ├── app.go # 应用管理 -│ │ ├── auth.go # 认证管理 -│ │ ├── captcha.go # 验证码管理 -│ │ ├── function.go # 函数管理 -│ │ ├── handlers.go # 通用处理器 -│ │ ├── login_log.go # 登录日志 -│ │ ├── operation_log.go # 操作日志 -│ │ ├── profile.go # 个人资料 -│ │ ├── settings.go # 系统设置 -│ │ ├── user.go # 用户管理 -│ │ └── variable.go # 变量管理 -│ ├── default/ # 默认控制器 -│ ├── install/ # 安装向导控制器 -│ └── base.go # 基础控制器 -├── database/ # 数据库相关 -│ ├── database.go # 数据库连接 -│ ├── migrate.go # 数据库迁移 -│ └── settings.go # 默认设置初始化 -├── middleware/ # 中间件 -│ ├── devmode.go # 开发模式中间件 -│ ├── install.go # 安装检查中间件 -│ ├── logging.go # 日志中间件 -│ └── maintenance.go # 维护模式中间件 -├── models/ # 数据模型 -│ ├── api.go # API接口模型 -│ ├── app.go # 应用模型 -│ ├── function.go # 函数模型 -│ ├── login_log.go # 登录日志模型 -│ ├── operation_log.go # 操作日志模型 -│ ├── settings.go # 系统设置模型 -│ ├── user.go # 用户模型 -│ └── variable.go # 变量模型 -├── server/ # 服务器路由配置 -│ ├── admin.go # 管理后台路由 -│ ├── default.go # 默认路由 -│ ├── install.go # 安装路由 -│ └── routes.go # 路由注册 -├── services/ # 业务逻辑层 -│ ├── log_cleanup.go # 日志清理服务 -│ ├── operation_log.go # 操作日志服务 -│ ├── query.go # 查询服务 -│ └── settings.go # 设置服务 -├── utils/ # 工具函数 -│ ├── encrypt/ # 加密工具包 -│ ├── excel/ # Excel工具 -│ ├── logger/ # 日志工具 -│ ├── timeutil/ # 时间工具 -│ ├── cookie.go # Cookie工具 -│ ├── crypto.go # 加密工具 -│ ├── csrf.go # CSRF防护 -│ ├── database.go # 数据库工具 -│ └── errors.go # 错误处理 -└── web/ # Web 资源 - ├── assets/ # 资源文件 - ├── static/ # 静态资源 - └── template/ # 模板文件 - ├── admin/ # 管理后台模板 - ├── default/ # 默认模板 - └── install/ # 安装向导模板 +NetworkAuth/ +├── cmd/ # Cobra 命令行工具定义 +├── config/ # 配置文件模型与校验逻辑 +├── constants/ # 全局常量定义 (版本号、状态码等) +├── controllers/ # 控制器层 (处理 HTTP 请求) +├── database/ # 数据库连接、迁移与默认数据填充 +├── middleware/ # Gin 中间件 (日志、认证、维护模式等) +├── models/ # GORM 数据模型定义 +├── server/ # HTTP 服务器路由注册 +├── services/ # 核心业务逻辑层 +├── utils/ # 通用工具函数 (加密、日志、时间等) +└── main.go # 项目入口 ``` ## 快速开始 @@ -128,14 +59,14 @@ networkDev/ - Go 1.25.0 或更高版本 - MySQL 5.7+ 或 SQLite 3 -- Redis (可选,用于缓存) +- Redis (可选) -### 安装步骤 +### 安装与运行 1. **克隆项目** ```bash - git clone - cd networkDev + git clone https://github.com/skyle1995/NetworkAuth.git + cd NetworkAuth ``` 2. **安装依赖** @@ -143,96 +74,56 @@ networkDev/ go mod download ``` -3. **运行项目** +3. **运行服务器** ```bash # 直接运行 - ./networkDev server - - # 或使用 go run go run main.go server + + # 或者编译后运行 + go build -o networkauth main.go + ./networkauth server ``` -4. **系统初始化** - - 打开浏览器访问: `http://localhost:8080/install` - - 根据安装向导提示,配置数据库连接和管理员账号即可完成初始化。 - ### 命令行工具 -项目基于 Cobra CLI 框架,提供了丰富的命令行工具支持: +项目基于 Cobra CLI 框架,提供了丰富的命令行工具: ```bash # 查看帮助信息 -./networkDev --help +./networkauth --help # 启动服务器 -./networkDev server +./networkauth server # 指定配置文件启动 -./networkDev --config ./config.json server +./networkauth --config ./config.json server # 指定端口启动 (覆盖配置文件) -./networkDev server -p 8080 +./networkauth server -p 8080 ``` -## API 文档 - -### 认证接口 -- `POST /admin/api/auth/login` - 用户登录 -- `POST /admin/api/auth/logout` - 用户登出 -- `GET /admin/api/auth/captcha` - 获取验证码 - -### 应用管理接口 -- `GET /admin/api/apps/list` - 获取应用列表 -- `POST /admin/api/apps/create` - 创建应用 -- `POST /admin/api/apps/update` - 更新应用 -- `POST /admin/api/apps/delete` - 删除应用 -- `POST /admin/api/apps/batch_delete` - 批量删除应用 - -### 变量管理接口 -- `GET /admin/variable/list` - 获取变量列表 -- `POST /admin/variable/create` - 创建变量 -- `POST /admin/variable/update` - 更新变量 -- `POST /admin/variable/delete` - 删除变量 -- `POST /admin/variable/batch_delete` - 批量删除变量 - -### 函数管理接口 -- `GET /admin/function/list` - 获取函数列表 -- `POST /admin/function/create` - 创建函数 -- `POST /admin/function/update` - 更新函数 -- `POST /admin/function/delete` - 删除函数 -- `POST /admin/function/batch_delete` - 批量删除函数 - -### 系统管理接口 -- `GET /admin/api/settings` - 获取系统设置 -- `POST /admin/api/settings/update` - 更新系统设置 -- `GET /admin/api/logs` - 获取操作日志 -- `GET /admin/api/login_logs` - 获取登录日志 - ## 部署 ### Docker 部署 ```bash # 构建镜像 -docker build -t networkdev . +docker build -t networkauth . # 运行容器 -docker run -d -p 8080:8080 networkdev +docker run -d -p 8080:8080 networkauth ``` ### 生产环境部署 1. 编译生产版本 ```bash - go build -o networkdev main.go + go build -o networkauth main.go ``` -2. 配置生产环境配置文件 - -3. 使用进程管理工具(如 systemd)管理服务 +2. 准备配置文件(可参考默认配置)。 +3. 使用进程管理工具(如 systemd 或 supervisor)管理后端服务进程。 ## 许可证 -本项目采用 MIT 许可证 - 查看 [LICENSE](LICENSE) 文件了解详情。 +本项目采用 MIT 许可证 - 查看 [LICENSE](LICENSE) 文件了解详情。 \ No newline at end of file diff --git a/cmd/root.go b/cmd/root.go index 2923677..ebf331c 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -61,11 +61,12 @@ func setupLogrusForNonHTTP() { // 设置输出目标(稍后会根据配置文件调整) logrus.SetOutput(os.Stdout) + + // 初始化配置(优先使用命令行参数,否则默认 config.json) + // 注意:如果文件不存在,配置系统将在内存中生成默认配置 if cfgFile != "" { - // 使用命令行指定的配置文件 config.Init(cfgFile) } else { - // 使用默认配置文件路径 config.Init("./config.json") } diff --git a/cmd/server.go b/cmd/server.go index 4fe1fc3..6ce9922 100644 --- a/cmd/server.go +++ b/cmd/server.go @@ -1,201 +1,196 @@ -package cmd - -import ( - "context" - "fmt" - "net/http" - "os" - "os/signal" - "syscall" - "time" - - "NetworkAuth/database" - "NetworkAuth/middleware" - "NetworkAuth/server" - "NetworkAuth/services" - "NetworkAuth/utils" - "NetworkAuth/utils/logger" - "NetworkAuth/web" - - "github.com/gin-gonic/gin" - "github.com/sirupsen/logrus" - "github.com/spf13/cobra" - "github.com/spf13/viper" -) - -// serverCmd 代表服务器命令 -var serverCmd = &cobra.Command{ - Use: "server", - Short: "启动网络授权服务", - Long: `启动 NetworkAuth HTTP 服务器,监听配置文件中指定的端口,提供 Web 管理界面和 API 服务。`, - Run: runServer, -} - -func init() { - // 将服务器命令添加到根命令 - rootCmd.AddCommand(serverCmd) - - // 添加服务器特定的标志 - serverCmd.Flags().StringP("host", "H", "", "服务器监听地址 (覆盖配置文件)") - serverCmd.Flags().IntP("port", "p", 0, "服务器监听端口 (覆盖配置文件)") -} - -// runServer 运行HTTP服务器 -func runServer(cmd *cobra.Command, args []string) { - // 获取配置 - host := getServerHost(cmd) - port := getServerPort(cmd) - addr := fmt.Sprintf("%s:%d", host, port) - - // 获取全局日志实例 - logger := logger.GetLogger() - logger.LogServerStart(host, port) - - // 重定向 Gin 框架内部日志到 Logrus - // 这将捕获 [GIN-debug] 路由注册日志和其他框架级输出 - gin.DefaultWriter = logger.WriterLevel(logrus.DebugLevel) - gin.DefaultErrorWriter = logger.WriterLevel(logrus.ErrorLevel) - - // 设置 Gin 模式 - if !viper.GetBool("server.dev_mode") { - gin.SetMode(gin.ReleaseMode) - } - - // 初始化Redis(如果配置存在,失败不致命) - utils.InitRedis() - - // 初始化数据库(根据 viper 配置选择 SQLite 或 MySQL) - // 如果初始化失败则回退并退出 - db, err := database.Init() - if err != nil { - logrus.WithError(err).Fatal("数据库初始化失败") - } - - if db != nil { - // 执行自动迁移(确保表结构存在) - if err := database.AutoMigrate(); err != nil { - logrus.WithError(err).Fatal("数据库自动迁移失败") - } - // 初始化默认系统设置 - if err := database.SeedDefaultSettings(); err != nil { - logrus.WithError(err).Fatal("默认系统设置初始化失败") - } - - // 初始化加密管理器 - // 从数据库设置中获取加密密钥 - encryptionKey := services.GetSettingsService().GetEncryptionKey() - if err := utils.InitEncryption(encryptionKey); err != nil { - logrus.WithError(err).Fatal("加密管理器初始化失败") - } - - // 启动日志清理定时任务 - services.StartLogCleanupTask() - } else { - logrus.Info("系统处于未初始化状态,跳过数据库自动迁移和设置加载") - } - - // 创建HTTP服务器 - server := createHTTPServer(addr) - - // 启动服务器 - startServer(server) -} - -// getServerHost 获取服务器监听地址 -func getServerHost(cmd *cobra.Command) string { - if host, _ := cmd.Flags().GetString("host"); host != "" { - return host - } - return viper.GetString("server.host") -} - -// getServerPort 获取服务器监听端口 -func getServerPort(cmd *cobra.Command) int { - if port, _ := cmd.Flags().GetInt("port"); port != 0 { - return port - } - return viper.GetInt("server.port") -} - -// createHTTPServer 创建HTTP服务器 -func createHTTPServer(addr string) *http.Server { - // 创建 Gin 引擎 - r := gin.New() - - // 使用默认的 Recovery 中间件 - r.Use(gin.Recovery()) - - // 添加日志中间件 - // 默认为 true,只有显式设置为 false 才关闭 - enableAccessLog := true - if viper.IsSet("server.access_log") { - enableAccessLog = viper.GetBool("server.access_log") - } - if enableAccessLog { - r.Use(middleware.WrapHandler()) - } - - // 添加安装检查中间件 - r.Use(middleware.InstallCheckMiddleware()) - - // 添加维护模式中间件 - r.Use(middleware.MaintenanceMiddleware()) - - // 添加开发模式中间件(统一管理开发模式功能:模板热重载等) - r.Use(middleware.DevModeMiddleware(r)) - - // 加载并设置 HTML 模板 - if tmpl, err := web.ParseTemplates(); err == nil { - r.SetHTMLTemplate(tmpl) - } else { - logrus.WithError(err).Error("HTML模板加载失败") - } - - // 注册路由 - registerRoutes(r) - - return &http.Server{ - Addr: addr, - Handler: r, - } -} - -// registerRoutes 注册HTTP路由 -func registerRoutes(r *gin.Engine) { - // 使用server包中的路由注册函数 - server.RegisterRoutes(r) -} - -// startServer 启动服务器并处理优雅关闭 -func startServer(server *http.Server) { - // 获取全局日志实例 - logger := logger.GetLogger() - - // 创建一个通道来接收操作系统信号 - sigChan := make(chan os.Signal, 1) - signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM) - - // 在goroutine中启动服务器 - go func() { - logger.WithField("addr", server.Addr).Info("HTTP服务器已启动") - if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed { - logger.LogError(err, "服务器启动失败") - os.Exit(1) - } - }() - - // 等待中断信号 - <-sigChan - logger.Info("收到关闭信号,正在优雅关闭服务器...") - - // 创建一个带超时的上下文 - ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) - defer cancel() - - // 优雅关闭服务器 - if err := server.Shutdown(ctx); err != nil { - logger.LogError(err, "服务器关闭时出错") - } else { - logger.LogServerStop() - } -} +package cmd + +import ( + "context" + "fmt" + "net/http" + "os" + "os/signal" + "syscall" + "time" + + "NetworkAuth/database" + "NetworkAuth/middleware" + "NetworkAuth/server" + "NetworkAuth/services" + "NetworkAuth/utils" + "NetworkAuth/utils/logger" + + "github.com/gin-gonic/gin" + "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +// serverCmd 代表服务器命令 +var serverCmd = &cobra.Command{ + Use: "server", + Short: "启动 NetworkAuth 系统服务器", + Long: `启动 NetworkAuth 系统 HTTP 服务器,监听配置文件中指定的端口,提供 Web 管理界面和 API 服务。`, + Run: runServer, +} + +func init() { + // 将服务器命令添加到根命令 + rootCmd.AddCommand(serverCmd) + + // 添加服务器特定的标志 + serverCmd.Flags().StringP("host", "H", "", "服务器监听地址 (覆盖配置文件)") + serverCmd.Flags().IntP("port", "p", 0, "服务器监听端口 (覆盖配置文件)") +} + +// runServer 运行HTTP服务器 +func runServer(cmd *cobra.Command, args []string) { + // 获取配置 + host := getServerHost(cmd) + port := getServerPort(cmd) + addr := fmt.Sprintf("%s:%d", host, port) + + // 获取全局日志实例 + logger := logger.GetLogger() + logger.LogServerStart(host, port) + + // 重定向 Gin 框架内部日志到 Logrus + // 这将捕获 [GIN-debug] 路由注册日志和其他框架级输出 + gin.DefaultWriter = logger.WriterLevel(logrus.DebugLevel) + gin.DefaultErrorWriter = logger.WriterLevel(logrus.ErrorLevel) + + // 设置 Gin 模式 + if !viper.GetBool("server.dev_mode") { + gin.SetMode(gin.ReleaseMode) + } + + // 初始化Redis(如果配置存在,失败不致命) + utils.InitRedis() + + // 初始化数据库(根据 viper 配置选择 SQLite 或 MySQL) + // 如果初始化失败(例如 MySQL 连不上),则打印错误并退出 + db, err := database.Init() + if err != nil { + logrus.WithError(err).Fatal("数据库初始化失败,请检查配置或确认是否已安装") + } + + if db != nil { + // 执行自动迁移(确保表结构存在) + if err := database.AutoMigrate(); err != nil { + logrus.WithError(err).Fatal("数据库自动迁移失败") + } + // 初始化默认系统设置 + if err := database.SeedDefaultSettings(); err != nil { + logrus.WithError(err).Fatal("默认系统设置初始化失败") + } + + // 初始化加密管理器 + // 从数据库设置中获取加密密钥 + encryptionKey := services.GetSettingsService().GetEncryptionKey() + if err := utils.InitEncryption(encryptionKey); err != nil { + logrus.WithError(err).Fatal("加密管理器初始化失败") + } + + // 启动日志清理定时任务 + services.StartLogCleanupTask() + } else { + logrus.Info("系统处于未初始化状态,跳过数据库自动迁移和设置加载") + } + + // 创建HTTP服务器 + server := createHTTPServer(addr) + + // 启动服务器 + startServer(server) +} + +// getServerHost 获取服务器监听地址 +func getServerHost(cmd *cobra.Command) string { + if host, _ := cmd.Flags().GetString("host"); host != "" { + return host + } + return viper.GetString("server.host") +} + +// getServerPort 获取服务器监听端口 +func getServerPort(cmd *cobra.Command) int { + if port, _ := cmd.Flags().GetInt("port"); port != 0 { + return port + } + return viper.GetInt("server.port") +} + +// createHTTPServer 创建HTTP服务器 +func createHTTPServer(addr string) *http.Server { + // 创建 Gin 引擎 + r := gin.New() + + // 使用默认的 Recovery 中间件 + r.Use(gin.Recovery()) + + // 启用 CORS 中间件,支持前后端分离 + r.Use(middleware.CorsMiddleware()) + + // 添加日志中间件 + // 默认为 true,只有显式设置为 false 才关闭 + enableAccessLog := true + if viper.IsSet("server.access_log") { + enableAccessLog = viper.GetBool("server.access_log") + } + if enableAccessLog { + r.Use(middleware.WrapHandler()) + } + + // 添加开发模式中间件(统一管理开发模式功能) + r.Use(middleware.DevModeMiddleware()) + + // 添加安装检查中间件 + r.Use(middleware.InstallCheckMiddleware()) + + // 添加维护模式中间件 + r.Use(middleware.MaintenanceMiddleware()) + + // 注册路由 + registerRoutes(r) + + return &http.Server{ + Addr: addr, + Handler: r, + } +} + +// registerRoutes 注册HTTP路由 +func registerRoutes(r *gin.Engine) { + // 使用server包中的路由注册函数 + server.RegisterRoutes(r) +} + +// startServer 启动服务器并处理优雅关闭 +func startServer(server *http.Server) { + // 获取全局日志实例 + logger := logger.GetLogger() + + // 创建一个通道来接收操作系统信号 + sigChan := make(chan os.Signal, 1) + signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM) + + // 在goroutine中启动服务器 + go func() { + logger.WithField("addr", server.Addr).Info("HTTP服务器已启动") + if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed { + logger.LogError(err, "服务器启动失败") + os.Exit(1) + } + }() + + // 等待中断信号 + <-sigChan + logger.Info("收到关闭信号,正在优雅关闭服务器...") + + // 创建一个带超时的上下文 + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + // 优雅关闭服务器 + if err := server.Shutdown(ctx); err != nil { + logger.LogError(err, "服务器关闭时出错") + } else { + logger.LogServerStop() + } +} diff --git a/config/config.go b/config/config.go index 511fc7a..387ed89 100644 --- a/config/config.go +++ b/config/config.go @@ -3,14 +3,15 @@ package config import ( "bytes" "encoding/json" - "errors" - "io/fs" + "os" "path/filepath" log "github.com/sirupsen/logrus" "github.com/spf13/viper" ) +var currentConfigFilePath string + // ============================================================================ // 结构体定义 // ============================================================================ @@ -127,63 +128,67 @@ func GetDefaultAppConfig() *AppConfig { // Init 初始化配置文件 func Init(cfgFilePath string) { + currentConfigFilePath = cfgFilePath viper.SetConfigFile(cfgFilePath) viper.SetConfigType("json") viper.AddConfigPath(".") - if err := viper.ReadInConfig(); err != nil { - var pathError *fs.PathError - if errors.As(err, &pathError) { - log.Warn("未找到配置文件,使用默认配置在内存中运行(需通过安装页面初始化)") + // 检查配置文件是否存在,如果不存在则使用内存默认配置,并创建默认配置文件 + if _, err := os.Stat(cfgFilePath); os.IsNotExist(err) { + log.WithField("file", cfgFilePath).Info("配置文件不存在,将在本地生成默认配置") + defaultConfig := GetDefaultAppConfig() - // 使用默认配置 - defaultConfig := GetDefaultAppConfig() - - // 将配置结构体转换为JSON - configBytes, marshalErr := json.MarshalIndent(defaultConfig, "", " ") - if marshalErr != nil { - log.WithFields( - log.Fields{ - "err": marshalErr, - }, - ).Fatal("序列化默认配置失败") - return - } - - // 将配置加载到viper中,但不写入文件 - err = viper.ReadConfig(bytes.NewBuffer(configBytes)) - if err != nil { - log.WithFields( - log.Fields{ - "err": err, - }, - ).Error("读取默认配置失败") - } else { - log.Info("已成功在内存中加载默认配置") - } - - // 不在这里写入文件了,安装完成后通过 UpdateConfig 写入 - } else { + configBytes, err := json.MarshalIndent(defaultConfig, "", " ") + if err != nil { log.WithFields( log.Fields{ "err": err, }, - ).Fatal("配置文件解析错误") + ).Fatal("默认配置序列化错误") } - } else { - // 只显示配置文件名,不显示完整路径 - configFile := viper.ConfigFileUsed() - if configFile != "" { - // 统一使用 filepath.Clean 和 filepath.Base 处理路径展示 - cleanPath := filepath.Clean(configFile) + + // 创建默认配置文件 + if err := os.WriteFile(cfgFilePath, configBytes, 0644); err != nil { log.WithFields( log.Fields{ - "file": cleanPath, + "err": err, }, - ).Info("使用配置文件") + ).Fatal("创建默认配置文件失败") } + + // 将配置加载到viper中 + err = viper.ReadConfig(bytes.NewBuffer(configBytes)) + if err != nil { + log.WithFields( + log.Fields{ + "err": err, + }, + ).Error("读取默认配置失败") + } else { + log.Info("已成功在内存中加载默认配置") + } + + // 明确设置当前配置路径为待保存的路径,以便后续安装时保存 + currentConfigFilePath = cfgFilePath + return } + if err := viper.ReadInConfig(); err != nil { + log.WithFields( + log.Fields{ + "err": err, + }, + ).Fatal("配置文件解析错误") + } + + // 统一使用 filepath.Clean 和 filepath.Base 处理路径展示 + cleanPath := filepath.Clean(cfgFilePath) + log.WithFields( + log.Fields{ + "file": cleanPath, + }, + ).Info("使用配置文件") + // 验证配置 if _, err := ValidateConfig(); err != nil { log.WithFields( @@ -194,6 +199,32 @@ func Init(cfgFilePath string) { } } +func SaveConfig(appConfig *AppConfig) error { + if err := ValidateConfigValue(appConfig); err != nil { + return err + } + if currentConfigFilePath == "" { + currentConfigFilePath = "./config.json" + } + if err := os.MkdirAll(filepath.Dir(currentConfigFilePath), 0755); err != nil { + return err + } + configBytes, err := json.MarshalIndent(appConfig, "", " ") + if err != nil { + return err + } + if err := os.WriteFile(currentConfigFilePath, configBytes, 0644); err != nil { + return err + } + viper.SetConfigFile(currentConfigFilePath) + viper.SetConfigType("json") + if err := viper.ReadInConfig(); err != nil { + return err + } + syncViperConfig(appConfig) + return nil +} + // UpdateConfig 更新配置文件 // 接收一个回调函数,在回调函数中修改配置对象,然后保存到文件 func UpdateConfig(updateFn func(*AppConfig)) error { @@ -206,18 +237,16 @@ func UpdateConfig(updateFn func(*AppConfig)) error { // 2. 执行更新回调 updateFn(¤tConfig) - // 3. 将更新后的配置写回 Viper - // 注意:这里需要手动设置回 viper,否则 viper.WriteConfig() 写入的还是旧配置 - // 也可以直接序列化 currentConfig 写入文件 + return SaveConfig(¤tConfig) +} - // 更新 Server 配置 +func syncViperConfig(currentConfig *AppConfig) { viper.Set("server.host", currentConfig.Server.Host) viper.Set("server.port", currentConfig.Server.Port) viper.Set("server.dist", currentConfig.Server.Dist) viper.Set("server.dev_mode", currentConfig.Server.DevMode) viper.Set("server.access_log", currentConfig.Server.AccessLog) - // 更新 Database 配置 viper.Set("database.type", currentConfig.Database.Type) viper.Set("database.mysql.host", currentConfig.Database.MySQL.Host) viper.Set("database.mysql.port", currentConfig.Database.MySQL.Port) @@ -229,27 +258,14 @@ func UpdateConfig(updateFn func(*AppConfig)) error { viper.Set("database.mysql.max_open_conns", currentConfig.Database.MySQL.MaxOpenConns) viper.Set("database.sqlite.path", currentConfig.Database.SQLite.Path) - // 更新 Redis 配置 viper.Set("redis.host", currentConfig.Redis.Host) viper.Set("redis.port", currentConfig.Redis.Port) viper.Set("redis.password", currentConfig.Redis.Password) viper.Set("redis.db", currentConfig.Redis.DB) - // 更新 Log 配置 viper.Set("log.level", currentConfig.Log.Level) viper.Set("log.file", currentConfig.Log.File) viper.Set("log.max_size", currentConfig.Log.MaxSize) viper.Set("log.max_backups", currentConfig.Log.MaxBackups) viper.Set("log.max_age", currentConfig.Log.MaxAge) - - // 4. 保存到文件 - if err := viper.WriteConfig(); err != nil { - // 如果配置文件不存在(比如只用了默认配置没写文件),则尝试 SafeWriteConfig - if _, ok := err.(viper.ConfigFileNotFoundError); ok { - return viper.SafeWriteConfig() - } - return err - } - - return nil } diff --git a/config/validator.go b/config/validator.go index ad153a9..50e3943 100644 --- a/config/validator.go +++ b/config/validator.go @@ -27,7 +27,7 @@ func ValidateConfig() (*AppConfig, error) { } // 验证配置 - if err := validateConfig(&config); err != nil { + if err := ValidateConfigValue(&config); err != nil { return nil, fmt.Errorf("配置验证失败: %w", err) } @@ -35,12 +35,8 @@ func ValidateConfig() (*AppConfig, error) { return &config, nil } -// ============================================================================ -// 私有函数 -// ============================================================================ - -// validateConfig 验证配置 -func validateConfig(config *AppConfig) error { +// ValidateConfigValue 验证配置 +func ValidateConfigValue(config *AppConfig) error { // 验证服务器配置 if err := validateServerConfig(&config.Server); err != nil { return fmt.Errorf("服务器配置错误: %w", err) diff --git a/constants/status.go b/constants/status.go index 29c86ae..31afc96 100644 --- a/constants/status.go +++ b/constants/status.go @@ -7,5 +7,5 @@ package constants // 应用程序版本信息 const ( // AppVersion 应用程序版本号 - AppVersion = "1.0.3" + AppVersion = "2.0.1" ) diff --git a/controllers/admin/api.go b/controllers/admin/api.go index 09c88e3..c10935b 100644 --- a/controllers/admin/api.go +++ b/controllers/admin/api.go @@ -21,17 +21,6 @@ import ( // 创建基础控制器实例 var apiBaseController = controllers.NewBaseController() -// ============================================================================ -// 页面处理器 -// ============================================================================ - -// APIFragmentHandler 接口列表页面片段处理器 -func APIFragmentHandler(c *gin.Context) { - c.HTML(http.StatusOK, "apis.html", gin.H{ - "Title": "接口设置", - }) -} - // ============================================================================ // API处理器 // ============================================================================ @@ -122,18 +111,12 @@ func APIListHandler(c *gin.Context) { responseAPIs = append(responseAPIs, responseAPI) } - // 计算分页信息 - totalPages := (total + int64(limit) - 1) / int64(limit) - + // 返回结果 response := gin.H{ - "success": true, - "data": gin.H{ - "apis": responseAPIs, - "total": total, - "page": page, - "limit": limit, - "total_pages": totalPages, - }, + "code": 0, + "msg": "success", + "count": total, + "data": responseAPIs, } c.JSON(http.StatusOK, response) diff --git a/controllers/admin/app.go b/controllers/admin/app.go index 3427501..81d4d4b 100644 --- a/controllers/admin/app.go +++ b/controllers/admin/app.go @@ -21,17 +21,6 @@ import ( var appBaseController = controllers.NewBaseController() -// ============================================================================ -// 页面处理器 -// ============================================================================ - -// AppsFragmentHandler 应用列表页面片段处理器 -func AppsFragmentHandler(c *gin.Context) { - c.HTML(http.StatusOK, "apps.html", gin.H{ - "Title": "应用程序", - }) -} - // ============================================================================ // API处理器 // ============================================================================ @@ -359,6 +348,7 @@ func AppCreateHandler(c *gin.Context) { } // 提交事务 + if err := tx.Commit().Error; err != nil { logrus.WithError(err).Error("Failed to commit transaction") c.JSON(http.StatusInternalServerError, gin.H{ @@ -531,6 +521,28 @@ func AppDeleteHandler(c *gin.Context) { return } + // 删除相关的变量记录 + if err := tx.Where("app_uuid = ?", app.UUID).Delete(&models.Variable{}).Error; err != nil { + tx.Rollback() + logrus.WithError(err).Error("Failed to delete related variables") + c.JSON(http.StatusInternalServerError, gin.H{ + "code": 1, + "msg": "删除相关变量失败", + }) + return + } + + // 删除相关的函数记录 + if err := tx.Where("app_uuid = ?", app.UUID).Delete(&models.Function{}).Error; err != nil { + tx.Rollback() + logrus.WithError(err).Error("Failed to delete related functions") + c.JSON(http.StatusInternalServerError, gin.H{ + "code": 1, + "msg": "删除相关函数失败", + }) + return + } + // 删除应用 if err := tx.Delete(&app).Error; err != nil { tx.Rollback() @@ -569,7 +581,7 @@ func AppDeleteHandler(c *gin.Context) { logrus.WithFields(logrus.Fields{ "app_id": app.ID, "app_uuid": app.UUID, - }).Debug("Successfully deleted app and related APIs") + }).Debug("Successfully deleted app and related APIs, Variables and Functions") c.JSON(http.StatusOK, gin.H{ "code": 0, diff --git a/controllers/admin/auth.go b/controllers/admin/auth.go index cae9667..a5e76f2 100644 --- a/controllers/admin/auth.go +++ b/controllers/admin/auth.go @@ -24,54 +24,30 @@ import ( var authBaseController = controllers.NewBaseController() // ============================================================================ -// 页面处理器 +// API处理器 // ============================================================================ -// LoginPageHandler 管理员登录页渲染处理器 -// - 如果已登录则重定向到 /admin -// - 否则渲染 web/template/admin/login.html 模板 -// - 自动清理失效的JWT Cookie,避免刷新时的问题 -func LoginPageHandler(c *gin.Context) { - // 使用带清理功能的JWT校验,避免失效Cookie在登录页面造成问题 - if IsAdminAuthenticatedWithCleanup(c) { - c.Redirect(http.StatusFound, "/admin") - return - } - - // 获取或生成CSRF令牌 - var token string +// CSRFTokenHandler 获取CSRF令牌接口 +func CSRFTokenHandler(c *gin.Context) { // 尝试从Cookie获取 + var token string if cookie, err := c.Cookie(CSRFCookieName); err == nil && cookie != "" { token = cookie } else { - // 生成新的CSRF令牌并设置到Cookie newToken, err := utils.GenerateCSRFToken() if err != nil { - c.HTML(http.StatusInternalServerError, "error.html", gin.H{ - "Error": "生成CSRF令牌失败", - }) + authBaseController.HandleInternalError(c, "生成CSRF令牌失败", err) return } token = newToken setCSRFToken(c, token) } - // 准备模板数据 - data := authBaseController.GetDefaultTemplateData() - if sysName, ok := data["SystemName"].(string); ok && sysName != "" { - data["Title"] = sysName + " - 管理员登录" - } else { - data["Title"] = "管理员登录" - } - data["CSRFToken"] = token - - c.HTML(http.StatusOK, "login.html", data) + authBaseController.HandleSuccess(c, "success", gin.H{ + "csrf_token": token, + }) } -// ============================================================================ -// API处理器 -// ============================================================================ - // LoginHandler 管理员登录接口 // - 接收JSON: {username, password, captcha, csrf_token} // - 验证CSRF令牌 @@ -112,35 +88,30 @@ func LoginHandler(c *gin.Context) { return } - // 获取系统设置服务 - settingsService := services.GetSettingsService() - adminUsername := settingsService.GetString("admin_username", "admin") - adminPasswordHash := settingsService.GetString("admin_password", "") - adminPasswordSalt := settingsService.GetString("admin_password_salt", "") - - // 验证密码为空的情况(首次登录需要初始化) - if adminPasswordHash == "" || adminPasswordSalt == "" { - recordLoginLog(c, body.Username, 0, "管理员账号未初始化") - authBaseController.HandleInternalError(c, "管理员账号未初始化,请联系系统管理员", nil) + // 从数据库中查找对应的用户 + db, err := database.GetDB() + if err != nil { + recordLoginLog(c, body.Username, 0, "数据库连接失败") + authBaseController.HandleInternalError(c, "数据库连接失败", err) return } - // 验证用户名 - if body.Username != adminUsername { - recordLoginLog(c, body.Username, 0, "用户名错误") + var user models.User + if err := db.Where("username = ? AND role = ?", body.Username, 0).First(&user).Error; err != nil { + recordLoginLog(c, body.Username, 0, "用户不存在或非管理员") authBaseController.HandleValidationError(c, "用户不存在或密码错误") return } // 验证密码(使用盐值校验) - if !utils.VerifyPasswordWithSalt(body.Password, adminPasswordSalt, adminPasswordHash) { + if !utils.VerifyPasswordWithSalt(body.Password, user.PasswordSalt, user.Password) { recordLoginLog(c, body.Username, 0, "密码错误") authBaseController.HandleValidationError(c, "用户不存在或密码错误") return } // 生成JWT令牌 - token, err := generateJWTTokenForAdmin(body.Username, adminPasswordHash) + token, err := generateJWTTokenForAdmin(user.Username, user.Password, user.UUID) if err != nil { recordLoginLog(c, body.Username, 0, "生成令牌失败") authBaseController.HandleInternalError(c, "生成令牌失败", err) @@ -149,6 +120,7 @@ func LoginHandler(c *gin.Context) { // 设置JWT Cookie(HttpOnly,安全) // 使用系统配置的Cookie参数 + settingsService := services.GetSettingsService() secure, sameSite, domain, maxAge := settingsService.GetCookieConfig() cookie := utils.CreateSecureCookie("admin_session", token, maxAge, domain, secure, sameSite) c.SetCookie(cookie.Name, cookie.Value, cookie.MaxAge, cookie.Path, cookie.Domain, cookie.Secure, cookie.HttpOnly) @@ -156,6 +128,9 @@ func LoginHandler(c *gin.Context) { recordLoginLog(c, body.Username, 1, "登录成功") authBaseController.HandleSuccess(c, "登录成功", gin.H{ "redirect": "/admin", + "avatar": user.Avatar, + "nickname": user.Nickname, + "username": user.Username, }) } @@ -282,7 +257,7 @@ type JWTClaims struct { // - 包含管理员用户名信息和密码哈希 // - 设置过期时间 // - 使用HMAC-SHA256签名 -func generateJWTTokenForAdmin(username, passwordHash string) (string, error) { +func generateJWTTokenForAdmin(username, passwordHash string, adminUUID string) (string, error) { // 生成密码哈希摘要(使用SHA256) // 注意:传入的 passwordHash 已经是数据库存的 Hash,这里我们再次 Hash 还是直接用? // atomicLibrary 的实现是: utils.GenerateSHA256Hash(adminUser.Password) @@ -292,9 +267,6 @@ func generateJWTTokenForAdmin(username, passwordHash string) (string, error) { // 所以这里也应该对数据库里的值进行 Hash。 passwordHashDigest := utils.GenerateSHA256Hash(passwordHash) - // 获取虚拟管理员UUID (NetworkAuth 项目默认为 admin-uuid-001) - adminUUID := services.GetSettingsService().GetString("admin_uuid", "admin-uuid-001") - claims := JWTClaims{ Username: username, UUID: adminUUID, @@ -352,16 +324,16 @@ func validateAdminPasswordHash(claims *JWTClaims, c *gin.Context) bool { return false } - // 获取当前数据库中的管理员密码 - var adminPassword models.Settings - if err := db.Where("name = ?", "admin_password").First(&adminPassword).Error; err != nil { - fmt.Printf("[SECURITY WARNING] Admin password not found in database - Username=%s, IP=%s\n", + // 获取当前数据库中的管理员用户 + var adminUser models.User + if err := db.Where("username = ? AND role = ?", claims.Username, 0).First(&adminUser).Error; err != nil { + fmt.Printf("[SECURITY WARNING] Admin user not found in database - Username=%s, IP=%s\n", claims.Username, c.ClientIP()) return false } // 生成当前数据库密码的哈希摘要 - currentPasswordHash := utils.GenerateSHA256Hash(adminPassword.Value) + currentPasswordHash := utils.GenerateSHA256Hash(adminUser.Password) // 验证JWT中的密码哈希是否与当前数据库中的密码哈希一致 if claims.PasswordHash != currentPasswordHash { @@ -417,12 +389,13 @@ func IsAdminAuthenticatedHttp(r *http.Request) bool { return false } - var adminPassword models.Settings - if err := db.Where("name = ?", "admin_password").First(&adminPassword).Error; err != nil { + var adminUser models.User + if err := db.Where("username = ? AND role = ?", claims.Username, 0).First(&adminUser).Error; err != nil { return false } - currentPasswordHash := utils.GenerateSHA256Hash(adminPassword.Value) + // 验证密码哈希 + currentPasswordHash := utils.GenerateSHA256Hash(adminUser.Password) if claims.PasswordHash != currentPasswordHash { return false } @@ -518,11 +491,11 @@ func GetCurrentAdminUserWithRefresh(c *gin.Context) (*JWTClaims, bool, error) { if time.Until(claims.ExpiresAt.Time) < refreshThreshold { // 获取当前的 PasswordHash db, _ := database.GetDB() - var adminPassword models.Settings - db.Where("name = ?", "admin_password").First(&adminPassword) + var adminUser models.User + db.Where("username = ? AND role = ?", claims.Username, 0).First(&adminUser) // 使用新的有效期生成令牌 - newToken, err := generateJWTTokenForAdmin(claims.Username, adminPassword.Value) + newToken, err := generateJWTTokenForAdmin(claims.Username, adminUser.Password, claims.UUID) if err == nil { tokenToSet = newToken refreshed = true @@ -553,19 +526,12 @@ func AdminAuthRequired() gin.HandlerFunc { // 自动清理失效的JWT Cookie,提升安全性和用户体验 clearInvalidJWTCookie(c) - // 中文注释:区分普通页面请求与AJAX/JSON请求 - accept := c.GetHeader("Accept") - xrw := strings.ToLower(strings.TrimSpace(c.GetHeader("X-Requested-With"))) - if strings.Contains(accept, "application/json") || xrw == "xmlhttprequest" { - c.JSON(http.StatusUnauthorized, gin.H{ - "success": false, - "message": "未登录或会话已过期", - "data": nil, - }) - c.Abort() - return - } - c.Redirect(http.StatusFound, "/admin/login") + // API 请求直接返回 401 JSON + c.JSON(http.StatusUnauthorized, gin.H{ + "success": false, + "message": "未登录或会话已过期", + "data": nil, + }) c.Abort() return } diff --git a/controllers/admin/captcha.go b/controllers/admin/captcha.go index 51ebcbf..028630f 100644 --- a/controllers/admin/captcha.go +++ b/controllers/admin/captcha.go @@ -11,6 +11,7 @@ import ( "github.com/gin-gonic/gin" "github.com/mojocn/base64Captcha" + "github.com/sirupsen/logrus" ) // ============================================================================ @@ -100,8 +101,10 @@ func VerifyCaptcha(c *gin.Context, captchaValue string) bool { // 从cookie中获取验证码ID captchaId, err := c.Cookie("captcha_id") if err != nil || captchaId == "" { + logrus.WithError(err).Warn("验证码验证失败:无法从Cookie获取captcha_id") return false } + logrus.Infof("VerifyCaptcha: received captchaId=%s, captchaValue=%s", captchaId, captchaValue) // 先尝试原始值验证 if store.Verify(captchaId, captchaValue, false) { diff --git a/controllers/admin/dashboard.go b/controllers/admin/dashboard.go index a542e7e..382d989 100644 --- a/controllers/admin/dashboard.go +++ b/controllers/admin/dashboard.go @@ -6,9 +6,7 @@ import ( "NetworkAuth/middleware" "NetworkAuth/models" "NetworkAuth/services" - "NetworkAuth/utils" "NetworkAuth/utils/timeutil" - "net/http" "github.com/gin-gonic/gin" "github.com/spf13/viper" @@ -42,86 +40,12 @@ func formatDBType(dbType string) string { } } -// ============================================================================ -// 页面处理器 -// ============================================================================ - -// AdminIndexHandler 后台首页处理器/admin 与 /admin/ 根路径入口 -// - 未登录:重定向到 /admin/login -// - 已登录:渲染后台布局页(或重定向到 /admin/layout) -// - 自动清理失效的JWT Cookie -func AdminIndexHandler(c *gin.Context) { - if IsAdminAuthenticatedWithCleanup(c) { - // 直接渲染布局页,保持URL为 /admin - AdminLayoutHandler(c) - return - } - c.Redirect(http.StatusFound, "/admin/login") -} - -// AdminLayoutHandler 后台布局页渲染 -// - 渲染 layout.html,包含顶部导航、侧边栏与动态内容容器 -func AdminLayoutHandler(c *gin.Context) { - // 获取或生成CSRF令牌 - var token string - if existingToken := utils.GetCSRFTokenFromCookie(c); existingToken != "" { - // 重用现有的Cookie令牌 - token = existingToken - } else { - // 生成新的CSRF令牌并设置到Cookie - newToken, err := utils.GenerateCSRFToken() - if err != nil { - handlersBaseController.HandleInternalError(c, "生成CSRF令牌失败", err) - return - } - token = newToken - utils.SetCSRFToken(c, token) - } - - // 准备模板数据 - data := handlersBaseController.GetDefaultTemplateData() - data["CSRFToken"] = token - - // 从数据库读取站点标题,如果失败则使用默认值 - settingsSvc := services.GetSettingsService() - data["Title"] = settingsSvc.GetString("site_title", "后台管理") - - // 合并其他数据(如果有的话) - extraData := gin.H{} - for key, value := range extraData { - data[key] = value - } - - c.HTML(http.StatusOK, "layout.html", data) -} - -// DashboardFragmentHandler 仪表盘片段渲染 -// - 展示系统信息:版本、开发模式、数据库类型、启动时长 -func DashboardFragmentHandler(c *gin.Context) { - version := constants.AppVersion - mode := middleware.IsDevModeFromContext(c) - dbType := viper.GetString("database.type") - if dbType == "" { - dbType = "sqlite" - } - uptime := timeutil.GetServerUptimeString() - - data := gin.H{ - "Version": version, - "Mode": mode, - "DBType": formatDBType(dbType), - "Uptime": uptime, - } - - c.HTML(http.StatusOK, "dashboard.html", data) -} - // ============================================================================ // API处理器 // ============================================================================ // SystemInfoHandler 系统信息API接口 -// - 返回系统运行状态的JSON数据,用于前端定时刷新 +// 返回系统运行状态的JSON数据,用于前端定时刷新 func SystemInfoHandler(c *gin.Context) { version := constants.AppVersion mode := middleware.IsDevModeFromContext(c) @@ -130,19 +54,21 @@ func SystemInfoHandler(c *gin.Context) { dbType = "sqlite" } uptime := timeutil.GetServerUptimeString() + uptimeSeconds := int64(timeutil.GetServerUptime().Seconds()) data := gin.H{ - "version": version, - "mode": mode, - "db_type": formatDBType(dbType), - "uptime": uptime, + "version": version, + "mode": mode, + "db_type": formatDBType(dbType), + "uptime": uptime, + "uptime_seconds": uptimeSeconds, } handlersBaseController.HandleSuccess(c, "ok", data) } // DashboardStatsHandler 仪表盘统计数据API接口 -// - 返回应用统计数据的JSON数据,包括全部/启用/禁用/变量数量 +// - 返回应用统计数据的JSON数据,包括全部/启用/变量数量 func DashboardStatsHandler(c *gin.Context) { // 获取数据库连接 db, ok := handlersBaseController.GetDB(c) @@ -152,8 +78,7 @@ func DashboardStatsHandler(c *gin.Context) { // 统计应用数据 var totalApps int64 - var enabledApps int64 - var disabledApps int64 + var totalFunctions int64 var totalVariables int64 // 统计全部应用数量 @@ -162,15 +87,9 @@ func DashboardStatsHandler(c *gin.Context) { return } - // 统计启用应用数量 - if err := db.Model(&models.App{}).Where("status = ?", 1).Count(&enabledApps).Error; err != nil { - handlersBaseController.HandleInternalError(c, "统计启用应用数量失败", err) - return - } - - // 统计禁用应用数量 - if err := db.Model(&models.App{}).Where("status = ?", 0).Count(&disabledApps).Error; err != nil { - handlersBaseController.HandleInternalError(c, "统计禁用应用数量失败", err) + // 统计函数数量 + if err := db.Model(&models.Function{}).Count(&totalFunctions).Error; err != nil { + handlersBaseController.HandleInternalError(c, "统计函数数量失败", err) return } @@ -182,8 +101,7 @@ func DashboardStatsHandler(c *gin.Context) { data := gin.H{ "total_apps": totalApps, - "enabled_apps": enabledApps, - "disabled_apps": disabledApps, + "total_functions": totalFunctions, "total_variables": totalVariables, } diff --git a/controllers/admin/function.go b/controllers/admin/function.go index 88517ab..726b4c6 100644 --- a/controllers/admin/function.go +++ b/controllers/admin/function.go @@ -20,17 +20,6 @@ import ( // 创建基础控制器实例 var functionBaseController = controllers.NewBaseController() -// ============================================================================ -// 页面处理器 -// ============================================================================ - -// FunctionFragmentHandler 公共函数列表页面片段处理器 -func FunctionFragmentHandler(c *gin.Context) { - c.HTML(http.StatusOK, "functions.html", gin.H{ - "Title": "公共函数", - }) -} - // ============================================================================ // API处理器 // ============================================================================ diff --git a/controllers/admin/login_log.go b/controllers/admin/login_log.go index cc00382..ee80947 100644 --- a/controllers/admin/login_log.go +++ b/controllers/admin/login_log.go @@ -4,7 +4,6 @@ import ( "NetworkAuth/controllers" "NetworkAuth/models" "NetworkAuth/services" - "net/http" "strconv" "strings" "time" @@ -45,13 +44,6 @@ func RecordLoginLog(c *gin.Context, username string, status int, message string) } } -// LoginLogsFragmentHandler 登录日志页面片段处理器 -func LoginLogsFragmentHandler(c *gin.Context) { - c.HTML(http.StatusOK, "login_logs.html", gin.H{ - "Title": "登录日志", - }) -} - // ============================================================================ // API处理器 // ============================================================================ @@ -61,7 +53,7 @@ func LoginLogsListHandler(c *gin.Context) { // 获取分页参数 page, limit := loginLogBaseController.GetPaginationParams(c) - // 构建查询 + // 获取数据库连接 db, ok := loginLogBaseController.GetDB(c) if !ok { return @@ -132,17 +124,19 @@ func LoginLogsClearHandler(c *gin.Context) { } // 记录操作日志 - // 由于 NetworkAuth 中没有 SystemAdminUser 全局变量,这里暂时使用 "admin" - operator := "admin" - // 尝试从上下文获取用户名(如果中间件设置了的话) - // if user, exists := c.Get("username"); exists { - // operator = user.(string) - // } + var operator, operatorUUID string + if claims, _, err := GetCurrentAdminUserWithRefresh(c); err == nil && claims != nil { + operator = claims.Username + operatorUUID = claims.UUID + } else { + operator = "admin" + operatorUUID = "00000000-0000-0000-0000-000000000000" + } log := models.OperationLog{ OperationType: "清空登录日志", Operator: operator, - OperatorUUID: "", // NetworkAuth 中暂时无法获取 UUID + OperatorUUID: operatorUUID, Details: "管理员清空了所有登录日志", CreatedAt: time.Now(), } diff --git a/controllers/admin/operation_log.go b/controllers/admin/operation_log.go index d0709bd..6df2a3d 100644 --- a/controllers/admin/operation_log.go +++ b/controllers/admin/operation_log.go @@ -4,7 +4,6 @@ import ( "NetworkAuth/controllers" "NetworkAuth/models" "NetworkAuth/services" - "net/http" "strings" "time" @@ -19,17 +18,6 @@ import ( var logBaseController = controllers.NewBaseController() -// ============================================================================ -// 页面处理器 -// ============================================================================ - -// LogsFragmentHandler 日志操作页面片段处理器 -func LogsFragmentHandler(c *gin.Context) { - c.HTML(http.StatusOK, "operation_logs.html", gin.H{ - "Title": "操作日志", - }) -} - // ============================================================================ // API处理器 // ============================================================================ @@ -92,11 +80,19 @@ func LogsClearHandler(c *gin.Context) { } // 记录操作日志 (因为刚刚清空了,这条将是第一条) - operator := "admin" + var operator, operatorUUID string + if claims, _, err := GetCurrentAdminUserWithRefresh(c); err == nil && claims != nil { + operator = claims.Username + operatorUUID = claims.UUID + } else { + operator = "admin" + operatorUUID = "00000000-0000-0000-0000-000000000000" + } + log := models.OperationLog{ OperationType: "清空日志", Operator: operator, - OperatorUUID: "", + OperatorUUID: operatorUUID, Details: "管理员清空了所有操作日志", CreatedAt: time.Now(), } diff --git a/controllers/admin/profile.go b/controllers/admin/profile.go index 6cdd611..e49e818 100644 --- a/controllers/admin/profile.go +++ b/controllers/admin/profile.go @@ -5,38 +5,41 @@ import ( "NetworkAuth/models" "NetworkAuth/services" "NetworkAuth/utils" - "net/http" + "fmt" "strings" "github.com/gin-gonic/gin" "gorm.io/gorm" ) -// ProfileFragmentHandler 个人资料片段渲染 -// - 渲染个人资料与修改密码表单 -func ProfileFragmentHandler(c *gin.Context) { - c.HTML(http.StatusOK, "profile.html", map[string]interface{}{}) -} - -// ProfileInfoHandler 查询当前登录管理员的基本信息 -// - 返回 username 字段 -func ProfileInfoHandler(c *gin.Context) { - _, _, err := GetCurrentAdminUserWithRefresh(c) +// ProfileQueryHandler 获取当前登录管理员的用户名和昵称等信息 +// - 返回 JSON: {username, nickname, avatar} +// - 从数据库获取最新信息 +func ProfileQueryHandler(c *gin.Context) { + claims, _, err := GetCurrentAdminUserWithRefresh(c) if err != nil { - c.JSON(http.StatusUnauthorized, gin.H{ - "code": 1, - "msg": "未登录或会话已过期", - "data": nil, - }) + authBaseController.HandleValidationError(c, "未登录或会话已过期") return } // 获取最新设置 - settingsService := services.GetSettingsService() - username := settingsService.GetString("admin_username", "admin") + db, ok := authBaseController.GetDB(c) + if !ok { + return + } + var adminUser models.User + if err := db.Where("uuid = ?", claims.UUID).First(&adminUser).Error; err != nil { + authBaseController.HandleInternalError(c, "获取管理员信息失败", err) + return + } + username := adminUser.Username + nickname := adminUser.Nickname + avatar := adminUser.Avatar - authBaseController.HandleSuccess(c, "ok", map[string]interface{}{ + authBaseController.HandleSuccess(c, "ok", gin.H{ "username": username, + "nickname": nickname, + "avatar": avatar, }) } @@ -44,31 +47,34 @@ func ProfileInfoHandler(c *gin.Context) { // - 接收 JSON: {old_password, new_password, confirm_password} // - 校验旧密码正确性、新密码与确认一致性 // - 成功后更新密码哈希 +// - 自动刷新接近过期的JWT令牌 func ProfilePasswordUpdateHandler(c *gin.Context) { - _, _, err := GetCurrentAdminUserWithRefresh(c) - if err != nil { - c.JSON(http.StatusUnauthorized, gin.H{ - "code": 1, - "msg": "未登录或会话已过期", - "data": nil, - }) - return - } - var body struct { OldPassword string `json:"old_password"` NewPassword string `json:"new_password"` ConfirmPassword string `json:"confirm_password"` } + if !authBaseController.BindJSON(c, &body) { return } - // 基础校验 - if body.OldPassword == "" || body.NewPassword == "" || body.ConfirmPassword == "" { - authBaseController.HandleValidationError(c, "旧密码/新密码/确认密码均不能为空") + // 获取当前用户信息用于日志记录 + claims, _, err := GetCurrentAdminUserWithRefresh(c) + if err != nil { + authBaseController.HandleValidationError(c, "未登录或会话已过期") return } + + // 基础校验 + if !authBaseController.ValidateRequired(c, map[string]interface{}{ + "旧密码": body.OldPassword, + "新密码": body.NewPassword, + "确认密码": body.ConfirmPassword, + }) { + return + } + if len(body.NewPassword) < 6 { authBaseController.HandleValidationError(c, "新密码长度不能少于6位") return @@ -82,10 +88,29 @@ func ProfilePasswordUpdateHandler(c *gin.Context) { return } - // 获取当前密码设置 - settingsService := services.GetSettingsService() - currentHash := settingsService.GetString("admin_password", "") - currentSalt := settingsService.GetString("admin_password_salt", "") + // 注释:由于使用了AdminAuthRequired中间件,已确保是管理员用户 + + // 获取数据库连接 + db, ok := authBaseController.GetDB(c) + if !ok { + return + } + + // 从数据库获取当前管理员信息 + var adminUser models.User + if err := db.Where("uuid = ?", claims.UUID).First(&adminUser).Error; err != nil { + authBaseController.HandleInternalError(c, "获取管理员信息失败", err) + return + } + + currentHash := adminUser.Password + currentSalt := adminUser.PasswordSalt + + // 检查必要的设置是否存在 + if currentHash == "" || currentSalt == "" { + authBaseController.HandleInternalError(c, "管理员密码设置不完整", nil) + return + } // 校验旧密码 if !utils.VerifyPasswordWithSalt(body.OldPassword, currentSalt, currentHash) { @@ -93,91 +118,58 @@ func ProfilePasswordUpdateHandler(c *gin.Context) { return } - // 生成新盐值和哈希 + // 生成新的密码盐值 newSalt, err := utils.GenerateRandomSalt() if err != nil { - authBaseController.HandleInternalError(c, "生成盐值失败", err) + authBaseController.HandleInternalError(c, "生成密码盐失败", err) return } + // 生成新密码哈希 newHash, err := utils.HashPasswordWithSalt(body.NewPassword, newSalt) if err != nil { authBaseController.HandleInternalError(c, "生成密码哈希失败", err) return } - // 更新数据库 - db, ok := authBaseController.GetDB(c) - if !ok { - return - } + // 更新到数据库 + err = db.Transaction(func(tx *gorm.DB) error { + // 更新密码和盐值 + return tx.Model(&models.User{}).Where("uuid = ?", claims.UUID).Updates(map[string]interface{}{ + "password": newHash, + "password_salt": newSalt, + }).Error + }) - // 更新 admin_password - if err := updateSetting(db, "admin_password", newHash); err != nil { + if err != nil { authBaseController.HandleInternalError(c, "更新密码失败", err) return } - // 更新 admin_password_salt - if err := updateSetting(db, "admin_password_salt", newSalt); err != nil { - authBaseController.HandleInternalError(c, "更新盐值失败", err) - return - } - - // 刷新缓存 - settingsService.RefreshCache() - - // 清除相关缓存键 - _ = utils.RedisDel(c.Request.Context(), "setting:admin_password", "setting:admin_password_salt") - - // 获取当前用户名 - currentUsername := settingsService.GetString("admin_username", "admin") - - // 重新签发JWT并写入Cookie - token, err := generateJWTTokenForAdmin(currentUsername, newHash) - if err != nil { - authBaseController.HandleInternalError(c, "生成新令牌失败", err) - return - } - - secure, sameSite, domain, maxAge := settingsService.GetCookieConfig() - cookie := utils.CreateSecureCookie("admin_session", token, maxAge, domain, secure, sameSite) - c.SetCookie(cookie.Name, cookie.Value, cookie.MaxAge, cookie.Path, cookie.Domain, cookie.Secure, cookie.HttpOnly) - // 记录操作日志 - operator := c.GetString("admin_username") - if operator == "" { - operator = "unknown" - } - operatorUUID := c.GetString("admin_uuid") + services.RecordOperationLog("修改密码", claims.Username, claims.UUID, "管理员修改了登录密码") - services.RecordOperationLog( - "修改密码", - operator, - operatorUUID, - "管理员修改了登录密码", - ) - - authBaseController.HandleSuccess(c, "密码修改成功", nil) + authBaseController.HandleSuccess(c, "密码修改成功,请重新登录", gin.H{ + "redirect": "/admin/login", + }) } -// ProfileUpdateHandler 修改当前登录管理员的用户名 -// - 接收 JSON: {username} -// - 校验用户名非空、长度 +// ProfileUpdateHandler 修改当前登录管理员的资料(用户名、昵称、头像) +// - 接收 JSON: {username, nickname, avatar, old_password} +// - 校验旧密码正确性 // - 更新数据库后重新签发JWT并写入 Cookie,保持前端展示的一致性 +// - 自动刷新接近过期的JWT令牌 func ProfileUpdateHandler(c *gin.Context) { - _, _, err := GetCurrentAdminUserWithRefresh(c) + claims, _, err := GetCurrentAdminUserWithRefresh(c) if err != nil { - c.JSON(http.StatusUnauthorized, gin.H{ - "code": 1, - "msg": "未登录或会话已过期", - "data": nil, - }) + authBaseController.HandleValidationError(c, "未登录或会话已过期") return } var body struct { Username string `json:"username"` + Nickname string `json:"nickname"` + Avatar string `json:"avatar"` OldPassword string `json:"old_password"` } if !authBaseController.BindJSON(c, &body) { @@ -185,6 +177,9 @@ func ProfileUpdateHandler(c *gin.Context) { } username := strings.TrimSpace(body.Username) + nickname := strings.TrimSpace(body.Nickname) + avatar := strings.TrimSpace(body.Avatar) + if username == "" { authBaseController.HandleValidationError(c, "用户名不能为空") return @@ -193,75 +188,86 @@ func ProfileUpdateHandler(c *gin.Context) { authBaseController.HandleValidationError(c, "用户名长度不能超过64字符") return } - - settingsService := services.GetSettingsService() - currentUsername := settingsService.GetString("admin_username", "admin") - - // 如果未变化则直接返回成功 - if strings.EqualFold(username, currentUsername) { - authBaseController.HandleSuccess(c, "保存成功", map[string]interface{}{ - "username": username, - }) + if len(nickname) > 64 { + authBaseController.HandleValidationError(c, "昵称长度不能超过64字符") + return + } + if len(avatar) > 255 { + authBaseController.HandleValidationError(c, "头像URL长度不能超过255字符") return } - // 修改用户名需要进行当前密码校验 - if strings.TrimSpace(body.OldPassword) == "" { - authBaseController.HandleValidationError(c, "修改用户名需要提供当前密码") - return - } - - currentHash := settingsService.GetString("admin_password", "") - currentSalt := settingsService.GetString("admin_password_salt", "") - - // 校验旧密码 - if !utils.VerifyPasswordWithSalt(body.OldPassword, currentSalt, currentHash) { - authBaseController.HandleValidationError(c, "当前密码不正确") - return - } - - // 更新数据库 db, ok := authBaseController.GetDB(c) if !ok { return } - if err := updateSetting(db, "admin_username", username); err != nil { - authBaseController.HandleInternalError(c, "更新用户名失败", err) + // 注释:由于使用了AdminAuthRequired中间件,已确保是管理员用户 + + // 从数据库获取当前管理员信息 + var adminUser models.User + if err := db.Where("uuid = ?", claims.UUID).First(&adminUser).Error; err != nil { + authBaseController.HandleInternalError(c, "获取管理员信息失败", err) return } - // 刷新缓存 - settingsService.RefreshCache() - _ = utils.RedisDel(c.Request.Context(), "setting:admin_username") + adminUsername := adminUser.Username + adminNickname := adminUser.Nickname + adminAvatar := adminUser.Avatar + adminPassword := adminUser.Password + adminPasswordSalt := adminUser.PasswordSalt + + // 检查必要的设置是否存在 + if adminUsername == "" || adminPassword == "" || adminPasswordSalt == "" { + authBaseController.HandleInternalError(c, "管理员设置不完整", nil) + return + } + + // 如果用户名、昵称和头像都未变化则直接返回成功(无需校验旧密码) + if strings.EqualFold(username, adminUsername) && nickname == adminNickname && avatar == adminAvatar { + authBaseController.HandleSuccess(c, "保存成功", gin.H{ + "username": username, + "nickname": nickname, + "avatar": avatar, + }) + return + } + + // 如果只修改昵称或头像,不需要验证密码 + if !strings.EqualFold(username, adminUsername) { + // 修改用户名需要进行当前密码校验 + if strings.TrimSpace(body.OldPassword) == "" { + authBaseController.HandleValidationError(c, "修改账号需要提供当前密码") + return + } + + // 使用盐值验证当前密码 + if !utils.VerifyPasswordWithSalt(body.OldPassword, adminPasswordSalt, adminPassword) { + authBaseController.HandleValidationError(c, "当前密码不正确") + return + } + } + + // 更新管理员资料 + if dbErr := db.Model(&models.User{}).Where("uuid = ?", claims.UUID).Updates(map[string]interface{}{ + "username": username, + "nickname": nickname, + "avatar": avatar, + }).Error; dbErr != nil { + authBaseController.HandleInternalError(c, "更新管理员资料失败", dbErr) + return + } + + // 获取当前管理员并刷新Token(这会生成包含新用户名的Token并更新Cookie) + _, _, _ = GetCurrentAdminUserWithRefresh(c) // 记录操作日志 - operator := c.GetString("admin_username") - if operator == "" { - operator = "unknown" - } - operatorUUID := c.GetString("admin_uuid") + services.RecordOperationLog("修改资料", claims.Username, claims.UUID, fmt.Sprintf("管理员修改资料为 用户名: %s, 昵称: %s, 头像: %s", username, nickname, avatar)) - services.RecordOperationLog( - "修改账号", - operator, - operatorUUID, - "管理员修改了用户名为: "+username, - ) - - // 重新签发JWT并写入Cookie - token, err := generateJWTTokenForAdmin(username, currentHash) - if err != nil { - authBaseController.HandleInternalError(c, "生成新令牌失败", err) - return - } - - secure, sameSite, domain, maxAge := settingsService.GetCookieConfig() - cookie := utils.CreateSecureCookie("admin_session", token, maxAge, domain, secure, sameSite) - c.SetCookie(cookie.Name, cookie.Value, cookie.MaxAge, cookie.Path, cookie.Domain, cookie.Secure, cookie.HttpOnly) - - authBaseController.HandleSuccess(c, "用户名修改成功", map[string]interface{}{ + authBaseController.HandleSuccess(c, "保存成功", gin.H{ "username": username, + "nickname": nickname, + "avatar": avatar, }) } diff --git a/controllers/admin/settings.go b/controllers/admin/settings.go index 37018aa..6253871 100644 --- a/controllers/admin/settings.go +++ b/controllers/admin/settings.go @@ -13,12 +13,6 @@ import ( "github.com/sirupsen/logrus" ) -// SettingsFragmentHandler 设置片段渲染 -// - 渲染设置表单(通过前端JS调用API加载/保存) -func SettingsFragmentHandler(c *gin.Context) { - c.HTML(http.StatusOK, "settings.html", map[string]interface{}{}) -} - // SubAccountSimpleListHandler 子账号简单列表API处理器 (Mock) func SubAccountSimpleListHandler(c *gin.Context) { // Mock implementation for NetworkAuth which has no subaccounts @@ -67,6 +61,11 @@ func SettingsUpdateHandler(c *gin.Context) { return } + var categoryStr string + if category, ok := directBody["category"].(string); ok { + categoryStr = category + } + // 提取设置数据 var settingsData map[string]string @@ -87,6 +86,9 @@ func SettingsUpdateHandler(c *gin.Context) { // 直接字段格式 settingsData = make(map[string]string) for k, v := range directBody { + if k == "category" { + continue // 忽略 category 字段,不保存到设置表 + } if str, ok := v.(string); ok { settingsData[k] = str } else if v != nil { @@ -119,59 +121,6 @@ func SettingsUpdateHandler(c *gin.Context) { // 批量处理设置项 for k, v := range settingsData { - // 特殊处理 admin_password - if k == "admin_password" { - // 如果密码为空,跳过更新(保留原密码) - if v == "" { - continue - } - - // 记录操作日志 - // 由于 NetworkAuth 中没有 SystemAdminUser 全局变量,这里暂时使用 "admin" - // operator := "admin" - // 尝试从上下文获取用户名(如果中间件设置了的话) - // if user, exists := c.Get("username"); exists { - // operator = user.(string) - // } - - // 生成随机盐值 - salt, err := utils.GenerateRandomSalt() - if err != nil { - authBaseController.HandleInternalError(c, "生成盐值失败", err) - return - } - - // 使用盐值哈希密码 - hash, err := utils.HashPasswordWithSalt(v, salt) - if err != nil { - authBaseController.HandleInternalError(c, "密码哈希失败", err) - return - } - - // 更新 salt 设置项(如果不存在则创建) - var saltSetting models.Settings - if err := db.Where("name = ?", "admin_password_salt").First(&saltSetting).Error; err != nil { - saltSetting = models.Settings{Name: "admin_password_salt", Value: salt} - if err := db.Create(&saltSetting).Error; err != nil { - logrus.WithError(err).Error("创建admin_password_salt失败") - authBaseController.HandleInternalError(c, "保存盐值失败", err) - return - } - } else { - if err := db.Model(&saltSetting).Update("value", salt).Error; err != nil { - logrus.WithError(err).Error("更新admin_password_salt失败") - authBaseController.HandleInternalError(c, "更新盐值失败", err) - return - } - } - - // 将盐值相关的缓存键加入清理列表 - keysToDel = append(keysToDel, "setting:admin_password_salt") - - // 将当前处理的值替换为哈希后的密码 - v = hash - } - var s models.Settings if err := db.Where("name = ?", k).First(&s).Error; err != nil { // 不存在则创建 @@ -201,6 +150,23 @@ func SettingsUpdateHandler(c *gin.Context) { // 刷新内存中的设置缓存,保证后续读取一致 services.GetSettingsService().RefreshCache() + // 获取当前操作人信息 + claims, _, err := GetCurrentAdminUserWithRefresh(c) + var operator, operatorUUID string + if err == nil && claims != nil { + operator = claims.Username + operatorUUID = claims.UUID + } else { + operator = "system" + } + + // 记录操作日志 + logType := "系统设置" + if categoryStr != "" { + logType = fmt.Sprintf("系统设置-%s", categoryStr) + } + services.RecordOperationLog(logType, operator, operatorUUID, fmt.Sprintf("管理员更新了系统设置,包含 %d 个配置项", len(settingsData))) + authBaseController.HandleSuccess(c, "保存成功", nil) } @@ -253,3 +219,24 @@ func SettingsGenerateKeyHandler(c *gin.Context) { authBaseController.HandleSuccess(c, "生成成功", map[string]string{"key": key}) } + +// SettingsPublicHandler 公开设置查询API +// - 仅返回允许公开的设置项以及所有前端平台配置 +func SettingsPublicHandler(c *gin.Context) { + db, ok := authBaseController.GetDB(c) + if !ok { + return + } + + var list []models.Settings + // 查询公开的基本信息、维护模式和所有前端平台配置 + if err := db.Where("name IN ? OR name LIKE ?", []string{"site_title", "site_description", "site_keywords", "site_logo", "contact_email", "maintenance_mode"}, "platform_%").Find(&list).Error; err != nil { + authBaseController.HandleInternalError(c, "查询失败", err) + return + } + res := map[string]string{} + for _, s := range list { + res[s.Name] = s.Value + } + authBaseController.HandleSuccess(c, "ok", res) +} diff --git a/controllers/admin/variable.go b/controllers/admin/variable.go index 209a6c8..4d03b9a 100644 --- a/controllers/admin/variable.go +++ b/controllers/admin/variable.go @@ -20,17 +20,6 @@ import ( // 创建基础控制器实例 var variableBaseController = controllers.NewBaseController() -// ============================================================================ -// 页面处理器 -// ============================================================================ - -// VariableFragmentHandler 公共变量列表页面片段处理器 -func VariableFragmentHandler(c *gin.Context) { - c.HTML(http.StatusOK, "variables.html", gin.H{ - "Title": "公共变量", - }) -} - // ============================================================================ // API处理器 // ============================================================================ diff --git a/controllers/base.go b/controllers/base.go index eb1e76a..81b1bf1 100644 --- a/controllers/base.go +++ b/controllers/base.go @@ -237,8 +237,7 @@ func (bc *BaseController) BindURI(c *gin.Context, obj interface{}) bool { func (bc *BaseController) GetDefaultTemplateData() gin.H { settings := services.GetSettingsService() return gin.H{ - "Title": settings.GetString("site_title", "NetworkAuth"), - "SystemName": settings.GetString("site_title", "NetworkAuth"), + "Title": settings.GetString("site_title", "NetworkAuth 系统"), "FooterText": settings.GetString("footer_text", "Copyright © 2026 NetworkAuth. All Rights Reserved."), "ICPRecord": settings.GetString("icp_record", ""), "ICPRecordLink": settings.GetString("icp_record_link", "https://beian.miit.gov.cn"), diff --git a/controllers/default/handlers.go b/controllers/default/handlers.go index 934d63a..61d6fc9 100644 --- a/controllers/default/handlers.go +++ b/controllers/default/handlers.go @@ -3,30 +3,26 @@ package default_ctrl import ( "NetworkAuth/services" "net/http" - "time" "github.com/gin-gonic/gin" ) // RootHandler 根路径处理器 -// 使用模板渲染服务器信息页面 +// 返回服务器信息 JSON func RootHandler(c *gin.Context) { // 获取设置服务 settings := services.GetSettingsService() - // 传递模板数据 - data := map[string]interface{}{ - "Title": settings.GetString("site_title", "NetworkAuth Server"), - "Keywords": settings.GetString("site_keywords", ""), - "Description": settings.GetString("site_description", ""), - "SystemName": "系统提醒", // 对应 H1 - "WarningText": "🚫 未授权,拒绝访问", - "InfoText": "💬 如有问题,请联系网站管理员", - "FooterText": settings.GetString("footer_text", "Copyright © 2026 NetworkAuth. All Rights Reserved."), - "ICPRecord": settings.GetString("icp_record", ""), - "ICPRecordLink": settings.GetString("icp_record_link", "https://beian.miit.gov.cn"), - "CurrentYear": time.Now().Year(), + // 传递数据 + data := gin.H{ + "title": settings.GetString("site_title", "NetworkAuth Server"), + "description": settings.GetString("site_description", ""), + "status": "running", + "message": "NetworkAuth API Server is running", } - c.HTML(http.StatusOK, "index.html", data) + c.JSON(http.StatusOK, gin.H{ + "code": 200, + "data": data, + }) } diff --git a/controllers/install/install.go b/controllers/install/install.go index ac14bfc..34a0035 100644 --- a/controllers/install/install.go +++ b/controllers/install/install.go @@ -6,20 +6,15 @@ import ( "NetworkAuth/models" "NetworkAuth/services" "NetworkAuth/utils" + "fmt" "net/http" "strings" "github.com/gin-gonic/gin" + "gorm.io/driver/mysql" + "gorm.io/gorm" ) -// InstallPageHandler 渲染安装页面 -func InstallPageHandler(c *gin.Context) { - // 由于前端是通过模板渲染的,我们返回一个安装页面 - c.HTML(http.StatusOK, "install.html", gin.H{ - "title": "NetworkAuth 系统初始化", - }) -} - // InstallSubmitHandler 处理安装表单提交 func InstallSubmitHandler(c *gin.Context) { var req struct { @@ -58,7 +53,24 @@ func InstallSubmitHandler(c *gin.Context) { return } - // 2. 重新初始化数据库连接并执行迁移 + // 2. 使用新配置尝试连接数据库 + var testDB *gorm.DB + if req.DbType == "mysql" { + dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local", + req.DbUser, req.DbPass, req.DbHost, req.DbPort, req.DbName) + testDB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{}) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"code": 1, "msg": "连接 MySQL 数据库失败,请检查配置是否正确: " + err.Error()}) + return + } + sqlDB, err := testDB.DB() + if err != nil || sqlDB.Ping() != nil { + c.JSON(http.StatusInternalServerError, gin.H{"code": 1, "msg": "连接 MySQL 数据库失败,无法 Ping 通,请检查配置是否正确"}) + return + } + } + + // 3. 重新初始化全局数据库连接并执行迁移 db, err := database.ReInit() if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"code": 1, "msg": "连接数据库失败: " + err.Error()}) @@ -66,7 +78,7 @@ func InstallSubmitHandler(c *gin.Context) { } if db == nil { - c.JSON(http.StatusInternalServerError, gin.H{"code": 1, "msg": "获取数据库实例失败"}) + c.JSON(http.StatusInternalServerError, gin.H{"code": 1, "msg": "获取数据库实例失败,请检查数据库配置是否正确"}) return } @@ -91,17 +103,55 @@ func InstallSubmitHandler(c *gin.Context) { return } - // 4. 更新设置表 - settingsToUpdate := map[string]string{ - "site_title": req.SiteTitle, - "admin_username": strings.TrimSpace(req.AdminUsername), - "admin_password": adminPasswordHash, - "admin_password_salt": adminSalt, - "is_installed": "1", // 标记为已安装 - } - // 开启事务进行更新 tx := db.Begin() + + // 更新或创建超级管理员账号 + var adminUser models.User + if err := tx.Where("uuid = ?", "00000000-0000-0000-0000-000000000000").First(&adminUser).Error; err != nil { + // 如果不存在则创建 + adminUser = models.User{ + UUID: "00000000-0000-0000-0000-000000000000", + Username: strings.TrimSpace(req.AdminUsername), + Password: adminPasswordHash, + PasswordSalt: adminSalt, + Nickname: "管理员", + Avatar: "", + Role: 0, + Status: 1, + Remark: "系统默认超级管理员", + } + // 使用 Select("Role") 确保 Role 字段(值为0时是零值)被显式插入,避免使用数据库默认值 1 + if err := tx.Select("UUID", "Username", "Password", "PasswordSalt", "Nickname", "Avatar", "Role", "Status", "Remark").Create(&adminUser).Error; err != nil { + tx.Rollback() + c.JSON(http.StatusInternalServerError, gin.H{"code": 1, "msg": "创建管理员账号失败"}) + return + } + } else { + // 存在则更新 + adminUser.Username = strings.TrimSpace(req.AdminUsername) + adminUser.Password = adminPasswordHash + adminUser.PasswordSalt = adminSalt + adminUser.Nickname = "管理员" + adminUser.Role = 0 + if err := tx.Save(&adminUser).Error; err != nil { + tx.Rollback() + c.JSON(http.StatusInternalServerError, gin.H{"code": 1, "msg": "更新管理员账号失败"}) + return + } + // 确保角色被更新为0(GORM的Save可能忽略零值,所以额外Update一次) + tx.Model(&adminUser).Update("Role", 0) + } + + // 如果是新创建的,再额外确保一次 Role 为 0,避免 default 标签导致的零值问题 + tx.Model(&adminUser).Update("Role", 0) + + // 4. 更新设置表 + settingsToUpdate := map[string]string{ + "site_title": req.SiteTitle, + "is_installed": "1", // 标记为已安装 + } + for name, value := range settingsToUpdate { // 先尝试更新,如果没有该记录,则忽略(因为 AutoMigrate 已经创建了默认记录) if err := tx.Model(&models.Settings{}).Where("name = ?", name).Update("value", value).Error; err != nil { @@ -113,10 +163,7 @@ func InstallSubmitHandler(c *gin.Context) { tx.Commit() // 5. 更新内存缓存 - settingsService := services.GetSettingsService() - for name, value := range settingsToUpdate { - settingsService.Set(name, value) - } + services.ResetSettingsService() c.JSON(http.StatusOK, gin.H{"code": 0, "msg": "安装成功"}) } diff --git a/database/database.go b/database/database.go index 4aeb45a..80ec360 100644 --- a/database/database.go +++ b/database/database.go @@ -1,6 +1,7 @@ package database import ( + appconfig "NetworkAuth/config" "NetworkAuth/utils" "context" "fmt" @@ -40,7 +41,7 @@ var ( func Init() (*gorm.DB, error) { var initErr error once.Do(func() { - initErr = performInit() + initErr = performInitFromViper() }) return dbInstance, initErr } @@ -57,83 +58,101 @@ func GetDB() (*gorm.DB, error) { // ReInit 重新初始化数据库连接 // 用于在修改配置后重新连接数据库 func ReInit() (*gorm.DB, error) { - // 如果已有连接,尝试关闭它 - if dbInstance != nil { - if healthCheckCancel != nil { - healthCheckCancel() - healthCheckCancel = nil - } - if sqlDB, err := dbInstance.DB(); err == nil { - sqlDB.Close() - } - } - dbInstance = nil + closeCurrentDB() - // 重新执行初始化逻辑(不经过 once.Do) - return dbInstance, performInit() + // 在 ReInit 时,强制从 viper 重新读取配置并连接,忽略"系统尚未安装"的检查 + // 因为这是安装过程触发的 + var cfg appconfig.AppConfig + if err := viper.Unmarshal(&cfg); err != nil { + return nil, err + } + + if err := performInitWithConfig(&cfg); err != nil { + return nil, err + } + + if dbInstance == nil { + return nil, fmt.Errorf("数据库实例初始化后为空") + } + + return dbInstance, nil } -func performInit() error { - // 检查是否已经有配置文件(通过检查文件是否存在) +func InitWithAppConfig(cfg *appconfig.AppConfig) (*gorm.DB, error) { + closeCurrentDB() + if err := performInitWithConfig(cfg); err != nil { + return nil, err + } + return dbInstance, nil +} + +func performInitFromViper() error { configFile := viper.ConfigFileUsed() - // 如果 viper 没有使用配置文件(可能是因为没找到文件而使用了默认配置), - // 或者配置文件路径为空,我们应该假设处于未安装状态。 - // 但 viper.ConfigFileUsed() 在 ReadInConfig 成功后会返回文件名。 - // 如果 ReadInConfig 失败(因为文件不存在),viper 可能会返回空或者我们在 config.go 中设置的路径。 - - // 在 config.go 中,如果文件不存在,我们加载了默认配置但没有写文件。 - // 此时 viper.ConfigFileUsed() 可能是空的或者我们设置的路径。 - // 让我们检查该路径对应的文件是否存在。 - if configFile == "" { configFile = "config.json" } - _, err := os.Stat(configFile) - isConfigExists := !os.IsNotExist(err) - - // 如果配置文件不存在,说明还没有经过安装初始化,暂时不连接数据库 - if !isConfigExists { - logrus.Info("尚未初始化配置,跳过数据库连接") - return nil + // 从 viper 中读取配置 + var cfg appconfig.AppConfig + if err := viper.Unmarshal(&cfg); err != nil { + return err } - var initErr error - dbType := viper.GetString("database.type") - switch dbType { + // 检查数据库类型,如果文件或配置不存在,说明系统尚未安装,跳过数据库连接 + switch cfg.Database.Type { + case "sqlite": + dbPath := cfg.Database.SQLite.Path + if dbPath == "" { + dbPath = "./database.db" + } + if _, err := os.Stat(dbPath); os.IsNotExist(err) { + logrus.Info("SQLite 数据库文件不存在,系统尚未安装,跳过数据库连接") + return nil + } case "mysql": - initErr = initMySQL() + // 只有在明确配置了 host 并且不是安装请求时才去连接 MySQL + // 我们通过检查是否已有有效配置来判断,比如检查 database 是否为空 + if cfg.Database.MySQL.Database == "" { + logrus.Info("MySQL 数据库名称未配置,说明系统尚未安装,跳过数据库连接") + return nil + } + } + + return performInitWithConfig(&cfg) +} + +func performInitWithConfig(cfg *appconfig.AppConfig) error { + if cfg == nil { + return fmt.Errorf("应用配置不能为空") + } + if err := appconfig.ValidateConfigValue(cfg); err != nil { + return err + } + var initErr error + switch cfg.Database.Type { + case "mysql": + initErr = initMySQL(&cfg.Database.MySQL, cfg.Log.Level) + if initErr != nil { + logrus.WithError(initErr).Error("MySQL 数据库连接失败,请检查配置或重新安装") + // 既然 MySQL 连不上,说明系统无法正常工作,直接返回错误,由外层决定是否退出 + return initErr + } default: - initErr = initSQLite() + initErr = initSQLite(&cfg.Database.SQLite, cfg.Log.Level) } - - // 如果数据库初始化成功,配置连接池和启动健康检查 - if initErr == nil && dbInstance != nil { - // 加载数据库配置 - var configPrefix string - if dbType == "mysql" { - configPrefix = "database.mysql" - } else { - configPrefix = "database.sqlite" - } - - dbConfig := utils.LoadDatabaseConfig(configPrefix) - - // 验证配置 - if err := utils.ValidateDatabaseConfig(dbConfig); err != nil { - logrus.WithError(err).Warn("数据库配置验证失败,使用默认配置") - dbConfig = utils.GetDefaultDatabaseConfig() - } - - // 配置连接池 - if err := utils.ConfigureConnectionPool(dbInstance, dbConfig); err != nil { - logrus.WithError(err).Error("配置数据库连接池失败") - } - - // 启动健康检查 - healthCheckCancel = utils.StartHealthCheck(dbInstance, dbConfig) + if initErr != nil || dbInstance == nil { + return initErr } - return initErr + dbConfig := buildPoolConfig(cfg) + if err := utils.ValidateDatabaseConfig(dbConfig); err != nil { + logrus.WithError(err).Warn("数据库配置验证失败,使用默认配置") + dbConfig = utils.GetDefaultDatabaseConfig() + } + if err := utils.ConfigureConnectionPool(dbInstance, dbConfig); err != nil { + logrus.WithError(err).Error("配置数据库连接池失败") + } + healthCheckCancel = utils.StartHealthCheck(dbInstance, dbConfig) + return nil } // SetDB 设置全局 *gorm.DB 实例(用于测试) @@ -145,16 +164,38 @@ func SetDB(db *gorm.DB) { // 私有函数 // ============================================================================ -// initSQLite 初始化 SQLite 数据库 -// 使用 viper 中的 database.sqlite.path 作为数据库文件路径 -func initSQLite() error { - path := viper.GetString("database.sqlite.path") - if path == "" { - path = "./recharge.db" +func closeCurrentDB() { + if healthCheckCancel != nil { + healthCheckCancel() + healthCheckCancel = nil } - dsn := fmt.Sprintf("file:%s?cache=shared&_busy_timeout=5000&_fk=1", path) + if dbInstance != nil { + if sqlDB, err := dbInstance.DB(); err == nil { + sqlDB.Close() + } + } + dbInstance = nil +} + +func buildPoolConfig(cfg *appconfig.AppConfig) *utils.DatabaseConfig { + dbConfig := utils.GetDefaultDatabaseConfig() + if cfg.Database.Type == "mysql" { + if cfg.Database.MySQL.MaxIdleConns > 0 { + dbConfig.MaxIdleConns = cfg.Database.MySQL.MaxIdleConns + } + if cfg.Database.MySQL.MaxOpenConns > 0 { + dbConfig.MaxOpenConns = cfg.Database.MySQL.MaxOpenConns + } + return dbConfig + } + dbConfig.MaxIdleConns = 1 + dbConfig.MaxOpenConns = 1 + return dbConfig +} + +func buildGormLogger(level string) gLogger.Interface { var logLevel gLogger.LogLevel - switch viper.GetString("logger.level") { + switch level { case "debug": logLevel = gLogger.Info case "error": @@ -162,55 +203,45 @@ func initSQLite() error { default: logLevel = gLogger.Warn } - gl := gLogger.New(log.New(os.Stdout, "\r\n", log.LstdFlags), gLogger.Config{SlowThreshold: 2 * time.Second, LogLevel: logLevel, IgnoreRecordNotFoundError: true, Colorful: false}) - db, err := gorm.Open(sqlite.Open(dsn), &gorm.Config{Logger: gl}) + return gLogger.New(log.New(os.Stdout, "\r\n", log.LstdFlags), gLogger.Config{SlowThreshold: 2 * time.Second, LogLevel: logLevel, IgnoreRecordNotFoundError: true, Colorful: false}) +} + +func initSQLite(sqliteConfig *appconfig.SQLiteConfig, logLevel string) error { + path := sqliteConfig.Path + if path == "" { + path = "./database.db" + } + dsn := fmt.Sprintf("file:%s?cache=shared&_busy_timeout=5000&_fk=1", path) + db, err := gorm.Open(sqlite.Open(dsn), &gorm.Config{Logger: buildGormLogger(logLevel)}) if err != nil { logrus.WithError(err).Error("SQLite 初始化失败") return err } - - // SQLite 连接池配置(SQLite 对连接池支持有限,但仍可设置基本参数) if sqlDB, err := db.DB(); err == nil { - // SQLite 通常使用单连接,但可以设置一些基本参数 - sqlDB.SetMaxOpenConns(1) // SQLite 建议使用单连接 + sqlDB.SetMaxOpenConns(1) sqlDB.SetMaxIdleConns(1) } - dbInstance = db logrus.WithField("path", path).Info("SQLite 连接已建立") return nil } -// initMySQL 初始化 MySQL 数据库 -// 从 viper 读取 database.mysql.* 配置构建 DSN -func initMySQL() error { - host := viper.GetString("database.mysql.host") - port := viper.GetInt("database.mysql.port") - user := viper.GetString("database.mysql.username") - pass := viper.GetString("database.mysql.password") - dbname := viper.GetString("database.mysql.database") - charset := viper.GetString("database.mysql.charset") +func initMySQL(mysqlConfig *appconfig.MySQLConfig, logLevel string) error { + host := mysqlConfig.Host + port := mysqlConfig.Port + user := mysqlConfig.Username + pass := mysqlConfig.Password + dbname := mysqlConfig.Database + charset := mysqlConfig.Charset if charset == "" { charset = "utf8mb4" } - dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=%s&parseTime=True&loc=Local", user, pass, host, port, dbname, charset) - var logLevel gLogger.LogLevel - switch viper.GetString("logger.level") { - case "debug": - logLevel = gLogger.Info - case "error": - logLevel = gLogger.Error - default: - logLevel = gLogger.Warn - } - gl := gLogger.New(log.New(os.Stdout, "\r\n", log.LstdFlags), gLogger.Config{SlowThreshold: 2 * time.Second, LogLevel: logLevel, IgnoreRecordNotFoundError: true, Colorful: false}) - db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{Logger: gl}) + db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{Logger: buildGormLogger(logLevel)}) if err != nil { logrus.WithError(err).Error("MySQL 初始化失败") return err } - dbInstance = db logrus.WithField("host", host).WithField("database", dbname).Info("MySQL 连接已建立") return nil diff --git a/database/migrate.go b/database/migrate.go index 46d43b5..d1ef641 100644 --- a/database/migrate.go +++ b/database/migrate.go @@ -18,11 +18,11 @@ func AutoMigrate() error { &models.Settings{}, &models.OperationLog{}, &models.LoginLog{}, + &models.User{}, &models.App{}, &models.API{}, - &models.Function{}, &models.Variable{}, - &models.User{}, + &models.Function{}, ); err != nil { logrus.WithError(err).Error("AutoMigrate 执行失败") return err diff --git a/database/settings.go b/database/settings.go index 818084d..07823d3 100644 --- a/database/settings.go +++ b/database/settings.go @@ -1,232 +1,329 @@ -package database - -import ( - "NetworkAuth/config" - "NetworkAuth/models" - "NetworkAuth/utils" - - "github.com/sirupsen/logrus" -) - -// ============================================================================ -// 公共函数 -// ============================================================================ - -// SeedDefaultSettings 初始化默认系统设置 -// - 检查各项设置是否已存在,如不存在则创建默认值 -// - 包含站点基本信息、SEO设置等常用配置项 -func SeedDefaultSettings() error { - db, err := GetDB() - if err != nil { - return err - } - - // 生成安全的随机密钥 - jwtSecret, err := config.GenerateSecureJWTSecret() - if err != nil { - return err - } - encryptionKey, err := config.GenerateSecureEncryptionKey() - if err != nil { - return err - } - - // 生成默认管理员密码(admin123)的盐值和哈希 - // 这样可以确保admin_password和admin_password_salt在初始化时就有值 - adminSalt, err := utils.GenerateRandomSalt() - if err != nil { - return err - } - adminPasswordHash, err := utils.HashPasswordWithSalt("admin123", adminSalt) - if err != nil { - return err - } - - // 检查是否已有 admin_password,如果有,说明是旧版本升级,应该把 is_installed 默认设为 1 - var adminPwdCount int64 - db.Model(&models.Settings{}).Where("name = ?", "admin_password").Count(&adminPwdCount) - isInstalledDefault := "0" - if adminPwdCount > 0 { - isInstalledDefault = "1" - } - - // 定义默认设置项 - defaultSettings := []models.Settings{ - // ===== 系统安装状态 ===== - { - Name: "is_installed", - Value: isInstalledDefault, - Description: "系统是否已初始化安装,0=未安装,1=已安装", - }, - // ===== 管理员账号相关默认项 ===== - { - Name: "admin_username", - Value: "admin", - Description: "管理员用户名", - }, - { - Name: "admin_password", - Value: adminPasswordHash, - Description: "管理员密码哈希值", - }, - { - Name: "admin_password_salt", - Value: adminSalt, - Description: "管理员密码加密盐值", - }, - // ===== 系统和安全相关默认项 ===== - { - Name: "maintenance_mode", - Value: "0", - Description: "维护模式,0=关闭维护模式,1=开启维护模式", - }, - { - Name: "encryption_key", - Value: encryptionKey, - Description: "数据加密密钥", - }, - { - Name: "jwt_secret", - Value: jwtSecret, - Description: "JWT签名密钥", - }, - { - Name: "jwt_refresh", - Value: "6", - Description: "JWT令牌刷新阈值(小时)", - }, - { - Name: "jwt_expire", - Value: "24", - Description: "JWT令牌有效期(小时)", - }, - { - Name: "session_timeout", - Value: "3600", - Description: "会话超时时间(秒),默认1小时", - }, - { - Name: "max_upload_size", - Value: "10485760", - Description: "文件上传最大尺寸(字节),默认10MB", - }, - { - Name: "default_user_role", - Value: "1", - Description: "新用户默认角色,0=管理员,1=普通用户", - }, - // ===== 日志清理策略默认项 ===== - { - Name: "login_log_cleanup_days", - Value: "30", - Description: "登录日志保留天数(0表示不按天清理)", - }, - { - Name: "login_log_cleanup_limit", - Value: "10000", - Description: "登录日志保留条数(0表示不按数量清理)", - }, - { - Name: "operation_log_cleanup_days", - Value: "30", - Description: "操作日志保留天数(0表示不按天清理)", - }, - { - Name: "operation_log_cleanup_limit", - Value: "10000", - Description: "操作日志保留条数(0表示不按数量清理)", - }, - // ===== Cookie相关默认项 ===== - { - Name: "cookie_secure", - Value: "true", - Description: "Cookie Secure属性(是否只在HTTPS下发送)", - }, - { - Name: "cookie_same_site", - Value: "Lax", - Description: "Cookie SameSite属性(Strict/Lax/None)", - }, - { - Name: "cookie_domain", - Value: "", - Description: "Cookie域名", - }, - { - Name: "cookie_max_age", - Value: "86400", - Description: "Cookie最大存活时间(秒)", - }, - // ===== 站点基本信息默认项 ===== - { - Name: "site_title", - Value: "NetworkAuth", - Description: "网站标题,显示在浏览器标题栏和页面顶部", - }, - { - Name: "site_keywords", - Value: "NetworkAuth,鉴权,API管理,GoLang", - Description: "网站关键词,用于SEO优化,多个关键词用逗号分隔", - }, - { - Name: "site_description", - Value: "NetworkAuth 网络授权服务,专注于应用鉴权与接口管理", - Description: "网站描述,用于SEO优化和社交媒体分享", - }, - { - Name: "site_logo", - Value: "/static/logo.png", - Description: "网站Logo图片路径", - }, - { - Name: "contact_email", - Value: "admin@example.com", - Description: "联系邮箱,用于客服和业务咨询", - }, - // ===== 页脚与备案相关默认项 ===== - { - Name: "footer_text", - Value: "Copyright © 2026 NetworkAuth. All Rights Reserved.", - Description: "页脚展示的版权或说明信息", - }, - { - Name: "icp_record", - Value: "", - Description: "ICP备案号,留空则不显示", - }, - { - Name: "icp_record_link", - Value: "https://beian.miit.gov.cn", - Description: "工信部ICP备案查询链接,留空则不显示", - }, - { - Name: "psb_record", - Value: "", - Description: "公安备案号,留空则不显示", - }, - { - Name: "psb_record_link", - Value: "", - Description: "公安备案查询链接,留空则不显示", - }, - } - - // 逐个检查并创建不存在的设置项 - for _, setting := range defaultSettings { - var count int64 - if err := db.Model(&models.Settings{}).Where("name = ?", setting.Name).Count(&count).Error; err != nil { - return err - } - - if count == 0 { - if err := db.Create(&setting).Error; err != nil { - logrus.WithError(err).WithField("name", setting.Name).Error("创建默认设置失败") - return err - } - logrus.WithField("name", setting.Name).WithField("value", setting.Value).Debug("创建默认设置项") - } - } - - logrus.Info("默认系统设置初始化完成") - return nil -} +package database + +import ( + "NetworkAuth/config" + "NetworkAuth/models" + + "github.com/sirupsen/logrus" +) + +// ============================================================================ +// 公共函数 +// ============================================================================ + +// SeedDefaultSettings 初始化默认系统设置 +// - 检查各项设置是否已存在,如不存在则创建默认值 +// - 包含站点基本信息、SEO设置等常用配置项 +func SeedDefaultSettings() error { + db, err := GetDB() + if err != nil { + return err + } + + // 生成安全的随机密钥 + jwtSecret, err := config.GenerateSecureJWTSecret() + if err != nil { + return err + } + encryptionKey, err := config.GenerateSecureEncryptionKey() + if err != nil { + return err + } + + isInstalledDefault := "0" + + // 定义默认设置项 + var defaultSettings []models.Settings + + // ===== 系统安装状态 ===== + defaultSettings = append(defaultSettings, []models.Settings{ + { + Name: "is_installed", + Value: isInstalledDefault, + Description: "系统是否已初始化安装,0=未安装,1=已安装", + }, + }...) + + // ===== 系统和安全相关默认项 ===== + defaultSettings = append(defaultSettings, []models.Settings{ + { + Name: "maintenance_mode", + Value: "0", + Description: "维护模式,0=关闭维护模式,1=开启维护模式", + }, + { + Name: "encryption_key", + Value: encryptionKey, + Description: "数据加密密钥", + }, + { + Name: "jwt_secret", + Value: jwtSecret, + Description: "JWT签名密钥", + }, + { + Name: "jwt_refresh", + Value: "6", + Description: "JWT令牌刷新阈值(小时)", + }, + { + Name: "jwt_expire", + Value: "24", + Description: "JWT令牌有效期(小时)", + }, + { + Name: "session_timeout", + Value: "3600", + Description: "会话超时时间(秒),默认1小时", + }, + { + Name: "max_upload_size", + Value: "10", + Description: "文件上传最大尺寸", + }, + { + Name: "max_upload_size_unit", + Value: "MB", + Description: "文件上传大小单位(B/KB/MB/GB)", + }, + }...) + + // ===== 日志清理策略默认项 ===== + defaultSettings = append(defaultSettings, []models.Settings{ + { + Name: "login_log_cleanup_days", + Value: "30", + Description: "登录日志保留天数(0表示不按天清理)", + }, + { + Name: "login_log_cleanup_limit", + Value: "10000", + Description: "登录日志保留条数(0表示不按数量清理)", + }, + { + Name: "operation_log_cleanup_days", + Value: "30", + Description: "操作日志保留天数(0表示不按天清理)", + }, + { + Name: "operation_log_cleanup_limit", + Value: "10000", + Description: "操作日志保留条数(0表示不按数量清理)", + }, + }...) + + // ===== Cookie相关默认项 ===== + defaultSettings = append(defaultSettings, []models.Settings{ + { + Name: "cookie_secure", + Value: "true", + Description: "Cookie Secure属性(是否只在HTTPS下发送)", + }, + { + Name: "cookie_same_site", + Value: "Lax", + Description: "Cookie SameSite属性(Strict/Lax/None)", + }, + { + Name: "cookie_domain", + Value: "", + Description: "Cookie域名", + }, + { + Name: "cookie_max_age", + Value: "86400", + Description: "Cookie最大存活时间(秒)", + }, + }...) + + // ===== 站点基本信息默认项 ===== + defaultSettings = append(defaultSettings, []models.Settings{ + { + Name: "site_title", + Value: "NetworkAuth", + Description: "网站标题,显示在浏览器标题栏和页面顶部", + }, + { + Name: "site_keywords", + Value: "NetworkAuth,网络授权服务,GoLang,Web服务", + Description: "网站关键词,用于SEO优化,多个关键词用逗号分隔", + }, + { + Name: "site_description", + Value: "网络授权服务 (NetworkAuth) 是一个专注于应用鉴权、接口管理和动态逻辑分发的后端系统", + Description: "网站描述,用于SEO优化和社交媒体分享", + }, + { + Name: "site_logo", + Value: "/logo.svg", + Description: "网站Logo图片路径", + }, + { + Name: "contact_email", + Value: "admin@example.com", + Description: "联系邮箱,用于客服和业务咨询", + }, + }...) + + // ===== 页脚与备案相关默认项 ===== + defaultSettings = append(defaultSettings, []models.Settings{ + { + Name: "footer_text", + Value: "Copyright © 2026 NetworkAuth. All Rights Reserved.", + Description: "页脚展示的版权或说明信息", + }, + { + Name: "icp_record", + Value: "", + Description: "ICP备案号,留空则不显示", + }, + { + Name: "icp_record_link", + Value: "https://beian.miit.gov.cn", + Description: "工信部ICP备案查询链接,留空则不显示", + }, + { + Name: "psb_record", + Value: "", + Description: "公安备案号,留空则不显示", + }, + { + Name: "psb_record_link", + Value: "", + Description: "公安备案查询链接,留空则不显示", + }, + }...) + + // ===== 前端平台配置相关默认项 ===== + defaultSettings = append(defaultSettings, []models.Settings{ + { + Name: "platform_fixed_header", + Value: "1", + Description: "是否固定页头 (0 = 关闭,1 = 开启)", + }, + { + Name: "platform_hidden_side_bar", + Value: "0", + Description: "是否隐藏侧边栏 (0 = 关闭,1 = 开启)", + }, + { + Name: "platform_multi_tags_cache", + Value: "0", + Description: "是否开启多标签页缓存 (0 = 关闭,1 = 开启)", + }, + { + Name: "platform_keep_alive", + Value: "1", + Description: "是否开启组件缓存 (0 = 关闭,1 = 开启)", + }, + { + Name: "platform_layout", + Value: "vertical", + Description: "布局模式 (vertical/horizontal/mix/comprehensive)", + }, + { + Name: "platform_theme", + Value: "light", + Description: "主题配色 (light/dark)", + }, + { + Name: "platform_dark_mode", + Value: "0", + Description: "是否开启暗黑模式 (0 = 关闭,1 = 开启)", + }, + { + Name: "platform_overall_style", + Value: "light", + Description: "整体风格", + }, + { + Name: "platform_grey", + Value: "0", + Description: "是否开启灰色模式 (0 = 关闭,1 = 开启)", + }, + { + Name: "platform_weak", + Value: "0", + Description: "是否开启色弱模式 (0 = 关闭,1 = 开启)", + }, + { + Name: "platform_hide_tabs", + Value: "0", + Description: "是否隐藏标签页 (0 = 关闭,1 = 开启)", + }, + { + Name: "platform_hide_footer", + Value: "0", + Description: "是否隐藏页脚 (0 = 关闭,1 = 开启)", + }, + { + Name: "platform_stretch", + Value: "0", + Description: "是否开启页面宽度拉伸 (0 = 关闭,1 = 开启)", + }, + { + Name: "platform_sidebar_status", + Value: "1", + Description: "侧边栏状态 (0 = 折叠,1 = 展开)", + }, + { + Name: "platform_ep_theme_color", + Value: "#409EFF", + Description: "Element Plus 主题色", + }, + { + Name: "platform_show_logo", + Value: "1", + Description: "是否显示Logo (0 = 关闭,1 = 开启)", + }, + { + Name: "platform_show_model", + Value: "smart", + Description: "显示模式 (smart等)", + }, + { + Name: "platform_menu_arrow_icon_no_transition", + Value: "0", + Description: "菜单箭头图标是否取消过渡动画 (0 = 关闭,1 = 开启)", + }, + { + Name: "platform_caching_async_routes", + Value: "0", + Description: "是否缓存异步路由 (0 = 关闭,1 = 开启)", + }, + { + Name: "platform_tooltip_effect", + Value: "light", + Description: "提示框效果 (light/dark)", + }, + { + Name: "platform_responsive_storage_name_space", + Value: "responsive-", + Description: "响应式存储命名空间", + }, + { + Name: "platform_menu_search_history", + Value: "6", + Description: "菜单搜索历史最大记录数", + }, + }...) + + // 逐个检查并创建不存在的设置项 + for _, setting := range defaultSettings { + var count int64 + if err := db.Model(&models.Settings{}).Where("name = ?", setting.Name).Count(&count).Error; err != nil { + return err + } + + if count == 0 { + if err := db.Create(&setting).Error; err != nil { + logrus.WithError(err).WithField("name", setting.Name).Error("创建系统设置失败") + return err + } + logrus.WithField("name", setting.Name).WithField("value", setting.Value).Debug("创建系统设置项") + } + } + + logrus.Info("系统设置初始化完成") + return nil +} diff --git a/go.mod b/go.mod index e74a761..5466899 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module NetworkAuth go 1.25.0 require ( + github.com/gin-contrib/cors v1.7.6 github.com/gin-gonic/gin v1.12.0 github.com/glebarez/sqlite v1.11.0 github.com/golang-jwt/jwt/v5 v5.3.0 @@ -13,7 +14,7 @@ require ( github.com/spf13/cobra v1.9.1 github.com/spf13/viper v1.20.1 github.com/xuri/excelize/v2 v2.10.1 - golang.org/x/crypto v0.48.0 + golang.org/x/crypto v0.49.0 gopkg.in/natefinch/lumberjack.v2 v2.2.1 gorm.io/driver/mysql v1.6.0 gorm.io/gorm v1.30.1 @@ -21,7 +22,7 @@ require ( require ( filippo.io/edwards25519 v1.1.0 // indirect - github.com/bytedance/gopkg v0.1.3 // indirect + github.com/bytedance/gopkg v0.1.4 // indirect github.com/bytedance/sonic v1.15.0 // indirect github.com/bytedance/sonic/loader v0.5.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect @@ -29,7 +30,7 @@ require ( github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/fsnotify/fsnotify v1.8.0 // indirect - github.com/gabriel-vasile/mimetype v1.4.12 // indirect + github.com/gabriel-vasile/mimetype v1.4.13 // indirect github.com/gin-contrib/sse v1.1.0 // indirect github.com/glebarez/go-sqlite v1.21.2 // indirect github.com/go-playground/locales v0.14.1 // indirect @@ -37,7 +38,7 @@ require ( github.com/go-playground/validator/v10 v10.30.1 // indirect github.com/go-sql-driver/mysql v1.8.1 // indirect github.com/go-viper/mapstructure/v2 v2.2.1 // indirect - github.com/goccy/go-json v0.10.5 // indirect + github.com/goccy/go-json v0.10.6 // indirect github.com/goccy/go-yaml v1.19.2 // indirect github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect @@ -49,7 +50,7 @@ require ( github.com/mattn/go-isatty v0.0.20 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/pelletier/go-toml/v2 v2.2.4 // indirect + github.com/pelletier/go-toml/v2 v2.3.0 // indirect github.com/quic-go/qpack v0.6.0 // indirect github.com/quic-go/quic-go v0.59.0 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect @@ -69,12 +70,12 @@ require ( go.mongodb.org/mongo-driver/v2 v2.5.0 // indirect go.uber.org/atomic v1.11.0 // indirect go.uber.org/multierr v1.9.0 // indirect - golang.org/x/arch v0.22.0 // indirect + golang.org/x/arch v0.25.0 // indirect golang.org/x/image v0.25.0 // indirect - golang.org/x/net v0.51.0 // indirect - golang.org/x/sys v0.41.0 // indirect - golang.org/x/text v0.34.0 // indirect - google.golang.org/protobuf v1.36.10 // indirect + golang.org/x/net v0.52.0 // indirect + golang.org/x/sys v0.42.0 // indirect + golang.org/x/text v0.35.0 // indirect + google.golang.org/protobuf v1.36.11 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect modernc.org/libc v1.22.5 // indirect modernc.org/mathutil v1.5.0 // indirect diff --git a/go.sum b/go.sum index 992af06..7727d31 100644 --- a/go.sum +++ b/go.sum @@ -4,8 +4,8 @@ github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= -github.com/bytedance/gopkg v0.1.3 h1:TPBSwH8RsouGCBcMBktLt1AymVo2TVsBVCY4b6TnZ/M= -github.com/bytedance/gopkg v0.1.3/go.mod h1:576VvJ+eJgyCzdjS+c4+77QF3p7ubbtiKARP3TxducM= +github.com/bytedance/gopkg v0.1.4 h1:oZnQwnX82KAIWb7033bEwtxvTqXcYMxDBaQxo5JJHWM= +github.com/bytedance/gopkg v0.1.4/go.mod h1:v1zWfPm21Fb+OsyXN2VAHdL6TBb2L88anLQgdyje6R4= github.com/bytedance/sonic v1.15.0 h1:/PXeWFaR5ElNcVE84U0dOHjiMHQOwNIx3K4ymzh/uSE= github.com/bytedance/sonic v1.15.0/go.mod h1:tFkWrPz0/CUCLEF4ri4UkHekCIcdnkqXw9VduqpJh0k= github.com/bytedance/sonic/loader v0.5.0 h1:gXH3KVnatgY7loH5/TkeVyXPfESoqSBSBEiDd5VjlgE= @@ -26,8 +26,10 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= -github.com/gabriel-vasile/mimetype v1.4.12 h1:e9hWvmLYvtp846tLHam2o++qitpguFiYCKbn0w9jyqw= -github.com/gabriel-vasile/mimetype v1.4.12/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s= +github.com/gabriel-vasile/mimetype v1.4.13 h1:46nXokslUBsAJE/wMsp5gtO500a4F3Nkz9Ufpk2AcUM= +github.com/gabriel-vasile/mimetype v1.4.13/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s= +github.com/gin-contrib/cors v1.7.6 h1:3gQ8GMzs1Ylpf70y8bMw4fVpycXIeX1ZemuSQIsnQQY= +github.com/gin-contrib/cors v1.7.6/go.mod h1:Ulcl+xN4jel9t1Ry8vqph23a60FwH9xVLd+3ykmTjOk= github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w= github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM= github.com/gin-gonic/gin v1.12.0 h1:b3YAbrZtnf8N//yjKeU2+MQsh2mY5htkZidOM7O0wG8= @@ -48,8 +50,8 @@ github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpv github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= -github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= -github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= +github.com/goccy/go-json v0.10.6 h1:p8HrPJzOakx/mn/bQtjgNjdTcN+/S6FcG2CTtQOrHVU= +github.com/goccy/go-json v0.10.6/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM= github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= @@ -89,8 +91,8 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mojocn/base64Captcha v1.3.8 h1:rrN9BhCwXKS8ht1e21kvR3iTaMgf4qPC9sRoV52bqEg= github.com/mojocn/base64Captcha v1.3.8/go.mod h1:QFZy927L8HVP3+VV5z2b1EAEiv1KxVJKZbAucVgLUy4= -github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= -github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= +github.com/pelletier/go-toml/v2 v2.3.0 h1:k59bC/lIZREW0/iVaQR8nDHxVq8OVlIzYCOJf421CaM= +github.com/pelletier/go-toml/v2 v2.3.0/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8= @@ -162,15 +164,15 @@ go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU= go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= -golang.org/x/arch v0.22.0 h1:c/Zle32i5ttqRXjdLyyHZESLD/bB90DCU1g9l/0YBDI= -golang.org/x/arch v0.22.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A= +golang.org/x/arch v0.25.0 h1:qnk6Ksugpi5Bz32947rkUgDt9/s5qvqDPl/gBKdMJLE= +golang.org/x/arch v0.25.0/go.mod h1:0X+GdSIP+kL5wPmpK7sdkEVTt2XoYP0cSjQSbZBwOi8= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= -golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= -golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= +golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4= +golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA= golang.org/x/image v0.23.0/go.mod h1:wJJBTdLfCCf3tiHa1fNxpZmUI4mmoZvwMCPP0ddoNKY= golang.org/x/image v0.25.0 h1:Y6uW6rH1y5y/LK1J8BPWZtr6yZ7hrsy6hFrXjgsc2fQ= golang.org/x/image v0.25.0/go.mod h1:tCAmOEGthTtkalusGp1g3xa2gke8J6c2N565dTyl9Rs= @@ -187,8 +189,8 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= -golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo= -golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y= +golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0= +golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -208,8 +210,8 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= -golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= +golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -227,8 +229,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= -golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= +golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8= +golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= @@ -236,8 +238,8 @@ golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= -google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/middleware/cors.go b/middleware/cors.go new file mode 100644 index 0000000..c375562 --- /dev/null +++ b/middleware/cors.go @@ -0,0 +1,21 @@ +package middleware + +import ( + "time" + + "github.com/gin-contrib/cors" + "github.com/gin-gonic/gin" +) + +// CorsMiddleware 处理跨域请求 +// 允许 Vue 等前端分离架构在开发和生产环境下访问后端 API +func CorsMiddleware() gin.HandlerFunc { + return cors.New(cors.Config{ + AllowOriginFunc: func(origin string) bool { return true }, // 允许所有来源 + AllowMethods: []string{"GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"}, + AllowHeaders: []string{"Origin", "Content-Length", "Content-Type", "Authorization", "X-CSRF-Token", "Accept"}, + ExposeHeaders: []string{"Content-Length"}, + AllowCredentials: true, + MaxAge: 12 * time.Hour, + }) +} diff --git a/middleware/devmode.go b/middleware/devmode.go index 4f6ba66..6d24c65 100644 --- a/middleware/devmode.go +++ b/middleware/devmode.go @@ -1,8 +1,6 @@ package middleware import ( - "NetworkAuth/web" - "github.com/gin-gonic/gin" "github.com/spf13/viper" ) @@ -13,8 +11,6 @@ import ( // DevModeConfig 开发模式配置 type DevModeConfig struct { - // 是否启用模板热重载 - EnableTemplateReload bool // 是否跳过验证码验证 SkipCaptcha bool // 是否显示详细错误信息 @@ -29,7 +25,7 @@ type DevModeConfig struct { // DevModeMiddleware 开发模式中间件 // 统一管理所有开发模式相关的功能 -func DevModeMiddleware(engine *gin.Engine) gin.HandlerFunc { +func DevModeMiddleware() gin.HandlerFunc { return func(c *gin.Context) { // 检查是否为开发模式 if IsDevMode() { @@ -37,12 +33,6 @@ func DevModeMiddleware(engine *gin.Engine) gin.HandlerFunc { c.Set("dev_mode", true) c.Set("dev_config", GetDevModeConfig()) - // 如果启用了模板热重载,则重新加载模板 - config := GetDevModeConfig() - if config.EnableTemplateReload { - reloadTemplates(engine) - } - // 设置开发模式相关的响应头 c.Header("X-Dev-Mode", "true") } else { @@ -69,10 +59,9 @@ func GetDevModeConfig() DevModeConfig { } return DevModeConfig{ - EnableTemplateReload: true, // 开发模式下默认启用模板热重载 - SkipCaptcha: true, // 开发模式下默认跳过验证码 - ShowDetailedErrors: true, // 开发模式下显示详细错误 - EnableDebugLog: true, // 开发模式下启用调试日志 + SkipCaptcha: true, // 开发模式下默认跳过验证码 + ShowDetailedErrors: true, // 开发模式下显示详细错误 + EnableDebugLog: true, // 开发模式下启用调试日志 } } @@ -107,10 +96,3 @@ func ShouldSkipCaptcha(c *gin.Context) bool { // ============================================================================ // 私有函数 // ============================================================================ - -// reloadTemplates 重新加载模板(内部函数) -func reloadTemplates(engine *gin.Engine) { - if tmpl, err := web.ParseTemplates(); err == nil { - engine.SetHTMLTemplate(tmpl) - } -} diff --git a/middleware/install.go b/middleware/install.go index f5a13d9..1cdb1f9 100644 --- a/middleware/install.go +++ b/middleware/install.go @@ -3,9 +3,10 @@ package middleware import ( "NetworkAuth/services" "net/http" - "strings" + "os" "github.com/gin-gonic/gin" + "github.com/spf13/viper" ) // InstallCheckMiddleware 检查系统是否已安装 @@ -13,38 +14,52 @@ func InstallCheckMiddleware() gin.HandlerFunc { return func(c *gin.Context) { path := c.Request.URL.Path - // 放行静态资源和favicon - if strings.HasPrefix(path, "/static/") || strings.HasPrefix(path, "/assets/") || path == "/favicon.ico" { - c.Next() - return - } - - // 检查是否为安装相关的路由 - isInstallRoute := path == "/install" || path == "/api/install" + isInstallRoute := path == "/api/install" || path == "/api/install/" // 获取系统的安装状态 - // 在没有数据库的时候,GetSettingsService().GetString 会返回默认值 "0" - isInstalled := services.GetSettingsService().GetString("is_installed", "0") == "1" + isInstalledStr := services.GetSettingsService().GetString("is_installed", "0") + isInstalled := isInstalledStr == "1" - // 如果未安装且当前不是访问安装页面,则重定向到安装页面 - if !isInstalled && !isInstallRoute { - // 对于 API 请求,返回 JSON 提示 - if strings.HasPrefix(path, "/api/") || strings.Contains(path, "/api/") { - c.JSON(http.StatusForbidden, gin.H{ - "code": 403, - "msg": "系统未初始化,请先完成安装", - }) - c.Abort() - return + // 如果设置服务没获取到(因为未连接数据库),再结合文件判断 + if !isInstalled { + // 检查数据库文件是否存在(如果是 sqlite) + dbType := viper.GetString("database.type") + switch dbType { + case "sqlite": + dbPath := viper.GetString("database.sqlite.path") + if dbPath == "" { + dbPath = "./database.db" + } + if _, err := os.Stat(dbPath); os.IsNotExist(err) { + isInstalled = false + } else { + isInstalled = true + } + case "mysql": + // 如果是 mysql 且配置了 database,我们认为是已安装 + dbName := viper.GetString("database.mysql.database") + if dbName != "" { + isInstalled = true + } } - c.Redirect(http.StatusTemporaryRedirect, "/install") + } + + // 如果未安装且不是访问安装接口,则返回 403 JSON + if !isInstalled && !isInstallRoute { + c.JSON(http.StatusForbidden, gin.H{ + "code": 403, + "msg": "系统未初始化,请先完成安装", + }) c.Abort() return } - // 如果已安装但尝试访问安装页面,则重定向到首页或后台 + // 如果已安装但尝试访问安装接口,则返回 403 JSON if isInstalled && isInstallRoute { - c.Redirect(http.StatusTemporaryRedirect, "/admin") + c.JSON(http.StatusForbidden, gin.H{ + "code": 403, + "msg": "系统已安装,请勿重复初始化", + }) c.Abort() return } diff --git a/middleware/logging.go b/middleware/logging.go index 9ea25bf..9201840 100644 --- a/middleware/logging.go +++ b/middleware/logging.go @@ -36,7 +36,7 @@ func NewLoggingMiddleware(logger *logger.Logger) *LoggingMiddleware { // ============================================================================ // Handler 返回Gin中间件函数,用于记录HTTP请求日志 -// 记录格式参考了更灵活的 NetworkAuth 实现,支持配置开关和日志级别检查 +// 记录格式参考了更灵活的NetworkAuth实现,支持配置开关和日志级别检查 func (lm *LoggingMiddleware) Handler() gin.HandlerFunc { return func(c *gin.Context) { // 检查是否启用了访问日志 diff --git a/middleware/maintenance.go b/middleware/maintenance.go index b9c8aef..942c339 100644 --- a/middleware/maintenance.go +++ b/middleware/maintenance.go @@ -19,81 +19,21 @@ func MaintenanceMiddleware() gin.HandlerFunc { return } - // 白名单检查(路径前缀匹配) path := c.Request.URL.Path - // 1. 允许静态资源 - if strings.HasPrefix(path, "/static/") || strings.HasPrefix(path, "/assets/") || path == "/favicon.ico" { - c.Next() - return - } - - // 2. 允许管理员后台相关接口(以便管理员登录关闭维护模式) + // 允许管理员后台相关接口(以便管理员登录关闭维护模式) // 包括登录页、登录接口、API接口、CSRF Token等 - if strings.HasPrefix(path, "/admin") { + if strings.HasPrefix(path, "/api/admin") { c.Next() return } - // 3. 检查请求类型 - // AJAX/JSON 请求返回 503 JSON - accept := c.GetHeader("Accept") - xrw := strings.ToLower(strings.TrimSpace(c.GetHeader("X-Requested-With"))) - if strings.Contains(accept, "application/json") || xrw == "xmlhttprequest" || strings.HasPrefix(path, "/api/") { - c.JSON(http.StatusServiceUnavailable, gin.H{ - "code": 503, - "success": false, - "msg": "系统正在维护中,请稍后再试", - }) - c.Abort() - return - } - - // 4. 普通页面请求渲染维护页面 - c.Header("Content-Type", "text/html; charset=utf-8") - c.Status(http.StatusServiceUnavailable) - c.Writer.WriteString(maintenanceHTML) + // 返回 503 JSON + c.JSON(http.StatusServiceUnavailable, gin.H{ + "code": 503, + "success": false, + "msg": "系统正在维护中,请稍后再试", + }) c.Abort() } } - -// 简单的维护页面 HTML -const maintenanceHTML = ` - - - - - 系统维护中 - - - -
-
⚠️
-

系统维护中

-

为了提供更好的服务,系统正在进行升级维护。
请稍后访问,给您带来的不便敬请谅解。

-
- -` diff --git a/models/operation_log.go b/models/operation_log.go index c6dd46b..becc9a3 100644 --- a/models/operation_log.go +++ b/models/operation_log.go @@ -9,7 +9,7 @@ type OperationLog struct { ID uint `gorm:"primarykey" json:"id"` // 操作信息 - OperationType string `gorm:"type:varchar(50);index;comment:操作方式" json:"operation_type"` + OperationType string `gorm:"type:varchar(50);index;comment:操作方式" json:"operation_type"` // 如:入库成功、凭证分配等 // 操作人信息 Operator string `gorm:"type:varchar(100);index;comment:操作账号" json:"operator"` diff --git a/models/user.go b/models/user.go index bcfd10f..f97b8ea 100644 --- a/models/user.go +++ b/models/user.go @@ -13,15 +13,21 @@ import ( // ============================================================================ // User 用户表模型 -// 此表只存储普通用户,管理员账号存储在settings表中 +// 存储所有账号,包括超级管理员(Role=0)和子账号(Role=1等) // CreatedAt/UpdatedAt 由 GORM 自动维护 type User struct { - ID uint `gorm:"primaryKey;comment:用户ID,自增主键"` - UUID string `gorm:"uniqueIndex;size:36;not null;comment:用户的唯一标识符" json:"uuid"` - Username string `gorm:"uniqueIndex;size:64;not null;comment:用户名,唯一索引"` + ID uint `gorm:"primaryKey;comment:账号ID,自增主键"` + UUID string `gorm:"uniqueIndex;size:36;not null;comment:唯一标识符" json:"uuid"` + Username string `gorm:"uniqueIndex;size:64;not null;comment:账号名,唯一索引" json:"username"` Password string `gorm:"size:255;not null;comment:密码哈希值"` PasswordSalt string `gorm:"size:64;not null;comment:密码加密盐值"` - CreatedAt time.Time `gorm:"comment:创建时间"` + Status int `gorm:"not null;default:1;comment:状态:0禁用,1启用" json:"status"` + Role int `gorm:"not null;default:2;comment:角色类型:0超级管理员,1代理成员,2普通成员" json:"role"` + Permissions string `gorm:"size:255;comment:权限列表,逗号分隔" json:"permissions"` + Nickname string `gorm:"size:64;comment:用户昵称" json:"nickname"` + Remark string `gorm:"size:255;comment:备注信息" json:"remark"` + Avatar string `gorm:"size:255;comment:用户头像URL" json:"avatar"` + CreatedAt time.Time `gorm:"autoCreateTime;comment:创建时间" json:"created_at"` UpdatedAt time.Time `gorm:"comment:更新时间"` } diff --git a/server/admin.go b/server/admin.go index d72b85b..8fa6132 100644 --- a/server/admin.go +++ b/server/admin.go @@ -1,167 +1,108 @@ -package server - -import ( - adminctl "NetworkAuth/controllers/admin" - "NetworkAuth/utils" - - "github.com/gin-gonic/gin" -) - -// RegisterAdminRoutes 注册管理员后台相关路由 -// - /admin/login: 支持GET渲染登录页、POST提交登录 -// - /admin/logout: 管理员退出登录 -// - /admin/dashboard: 管理员仪表盘 -// - /admin/fragment/*: 布局内动态片段加载 -// - /admin/api/*: 各种业务API -func RegisterAdminRoutes(r *gin.Engine) { - // /admin 根与前缀统一入口:根据是否登录跳转 - r.GET("/admin", adminctl.AdminIndexHandler) - r.GET("/admin/", adminctl.AdminIndexHandler) - - // Admin 认证相关路由 - r.GET("/admin/login", adminctl.LoginPageHandler) - r.POST("/admin/login", adminctl.LoginHandler) - - // 退出登录 - r.GET("/admin/logout", adminctl.LogoutHandler) - r.POST("/admin/logout", adminctl.LogoutHandler) - - // 验证码生成路由(无需认证) - r.GET("/admin/captcha", adminctl.CaptchaHandler) - - // CSRF令牌获取API(无需认证,但需要在登录页面等地方获取) - r.GET("/admin/api/csrf-token", func(c *gin.Context) { - // 生成新的CSRF令牌 - token, err := utils.GenerateCSRFToken() - if err != nil { - c.JSON(500, gin.H{"success": false, "message": "生成CSRF令牌失败"}) - return - } - - // 设置令牌到Cookie和响应头 - utils.SetCSRFToken(c, token) - - // 返回令牌给前端 - c.JSON(200, gin.H{ - "code": 0, // 统一使用 code 0 表示成功 - "success": true, - "message": "CSRF令牌生成成功", - "data": gin.H{ - "csrf_token": token, - }, - }) - }) - - // 需要认证的路由组 - authorized := r.Group("/admin") - authorized.Use(adminctl.AdminAuthRequired()) - { - // 后台布局页 - authorized.GET("/layout", adminctl.AdminLayoutHandler) - - // 片段路由 - authorized.GET("/dashboard", adminctl.DashboardFragmentHandler) - authorized.GET("/profile", adminctl.ProfileFragmentHandler) - authorized.GET("/settings", adminctl.SettingsFragmentHandler) - authorized.GET("/operation_logs", adminctl.LogsFragmentHandler) - authorized.GET("/login_logs", adminctl.LoginLogsFragmentHandler) - authorized.GET("/apps", adminctl.AppsFragmentHandler) - authorized.GET("/apis", adminctl.APIFragmentHandler) - authorized.GET("/variables", adminctl.VariableFragmentHandler) - authorized.GET("/functions", adminctl.FunctionFragmentHandler) - - // 系统信息API - authorized.GET("/api/system/info", adminctl.SystemInfoHandler) - // 仪表盘数据 - authorized.GET("/api/dashboard/stats", adminctl.DashboardStatsHandler) - authorized.GET("/api/dashboard/login-logs", adminctl.DashboardLoginLogsHandler) - - // API 路由组 - api := authorized.Group("/api") - { - // 个人资料API - profileGroup := api.Group("/profile") - { - profileGroup.GET("/info", adminctl.ProfileInfoHandler) - profileGroup.POST("/update", adminctl.ProfileUpdateHandler) - profileGroup.POST("/password", adminctl.ProfilePasswordUpdateHandler) - } - - // 系统设置API - settingsGroup := api.Group("/settings") - { - settingsGroup.GET("", adminctl.SettingsQueryHandler) - settingsGroup.POST("/update", adminctl.SettingsUpdateHandler) - settingsGroup.POST("/generate-key", adminctl.SettingsGenerateKeyHandler) - } - - // 操作日志API - logsGroup := api.Group("/logs") - { - logsGroup.GET("", adminctl.LogsListHandler) - logsGroup.POST("/clear", adminctl.LogsClearHandler) - } - - // 登录日志API - loginLogsGroup := api.Group("/login_logs") - { - loginLogsGroup.GET("", adminctl.LoginLogsListHandler) - loginLogsGroup.POST("/clear", adminctl.LoginLogsClearHandler) - } - - // 应用管理API - appsGroup := api.Group("/apps") - { - appsGroup.GET("/list", adminctl.AppsListHandler) - appsGroup.GET("/simple", adminctl.AppsSimpleListHandler) - appsGroup.POST("/create", adminctl.AppCreateHandler) - appsGroup.POST("/update", adminctl.AppUpdateHandler) - appsGroup.POST("/delete", adminctl.AppDeleteHandler) - appsGroup.POST("/batch_delete", adminctl.AppsBatchDeleteHandler) - appsGroup.POST("/batch_update_status", adminctl.AppsBatchUpdateStatusHandler) - appsGroup.POST("/update_status", adminctl.AppUpdateStatusHandler) - appsGroup.POST("/reset_secret", adminctl.AppResetSecretHandler) - appsGroup.GET("/get_app_data", adminctl.AppGetAppDataHandler) - appsGroup.POST("/update_app_data", adminctl.AppUpdateAppDataHandler) - appsGroup.GET("/get_announcement", adminctl.AppGetAnnouncementHandler) - appsGroup.POST("/update_announcement", adminctl.AppUpdateAnnouncementHandler) - appsGroup.GET("/get_multi_config", adminctl.AppGetMultiConfigHandler) - appsGroup.POST("/update_multi_config", adminctl.AppUpdateMultiConfigHandler) - appsGroup.GET("/get_bind_config", adminctl.AppGetBindConfigHandler) - appsGroup.POST("/update_bind_config", adminctl.AppUpdateBindConfigHandler) - appsGroup.GET("/get_register_config", adminctl.AppGetRegisterConfigHandler) - appsGroup.POST("/update_register_config", adminctl.AppUpdateRegisterConfigHandler) - } - - // API接口管理API - apisGroup := api.Group("/apis") - { - apisGroup.GET("/list", adminctl.APIListHandler) - apisGroup.POST("/update", adminctl.APIUpdateHandler) - apisGroup.POST("/update_status", adminctl.APIUpdateStatusHandler) - apisGroup.GET("/types", adminctl.APIGetTypesHandler) - apisGroup.POST("/generate_keys", adminctl.APIGenerateKeysHandler) - } - } - - // 变量管理API - variableGroup := authorized.Group("/variable") - { - variableGroup.GET("/list", adminctl.VariableListHandler) - variableGroup.POST("/create", adminctl.VariableCreateHandler) - variableGroup.POST("/update", adminctl.VariableUpdateHandler) - variableGroup.POST("/delete", adminctl.VariableDeleteHandler) - variableGroup.POST("/batch_delete", adminctl.VariablesBatchDeleteHandler) - } - - // 函数管理API - functionGroup := authorized.Group("/function") - { - functionGroup.GET("/list", adminctl.FunctionListHandler) - functionGroup.POST("/create", adminctl.FunctionCreateHandler) - functionGroup.POST("/update", adminctl.FunctionUpdateHandler) - functionGroup.POST("/delete", adminctl.FunctionDeleteHandler) - functionGroup.POST("/batch_delete", adminctl.FunctionsBatchDeleteHandler) - } - } -} +package server + +import ( + adminctl "NetworkAuth/controllers/admin" + + "github.com/gin-gonic/gin" +) + +// RegisterAdminRoutes 注册管理员后台相关路由 +func RegisterAdminRoutes(rg *gin.RouterGroup) { + admin := rg.Group("/admin") + + // Admin 认证相关路由 + admin.GET("/captcha", adminctl.CaptchaHandler) + admin.GET("/csrf", adminctl.CSRFTokenHandler) + admin.POST("/login", adminctl.LoginHandler) + + // 公开设置API + admin.GET("/settings/public", adminctl.SettingsPublicHandler) + + // 退出登录 + admin.POST("/logout", adminctl.LogoutHandler) + + // 需要认证的路由组 + authorized := admin.Group("/") + authorized.Use(adminctl.AdminAuthRequired()) + { + // 系统信息API + authorized.GET("/system/info", adminctl.SystemInfoHandler) + authorized.GET("/dashboard/stats", adminctl.DashboardStatsHandler) + authorized.GET("/dashboard/login-logs", adminctl.DashboardLoginLogsHandler) + + // 个人资料API + authorized.GET("/profile", adminctl.ProfileQueryHandler) + authorized.POST("/profile/update", adminctl.ProfileUpdateHandler) + authorized.POST("/profile/password", adminctl.ProfilePasswordUpdateHandler) + + // 设置API + authorized.GET("/settings", adminctl.SettingsQueryHandler) + authorized.POST("/settings/update", adminctl.SettingsUpdateHandler) + authorized.POST("/settings/generate-key", adminctl.SettingsGenerateKeyHandler) + + // 操作日志API + authorized.GET("/logs", adminctl.LogsListHandler) + authorized.POST("/logs/clear", adminctl.LogsClearHandler) + + // 登录日志API + authorized.GET("/login_logs", adminctl.LoginLogsListHandler) + authorized.POST("/login_logs/clear", adminctl.LoginLogsClearHandler) + + // 子账号相关API (Mock) + authorized.GET("/subaccounts/simple", adminctl.SubAccountSimpleListHandler) + + // 应用管理API + appsGroup := authorized.Group("/apps") + { + appsGroup.GET("/list", adminctl.AppsListHandler) + appsGroup.GET("/simple", adminctl.AppsSimpleListHandler) + appsGroup.POST("/create", adminctl.AppCreateHandler) + appsGroup.POST("/update", adminctl.AppUpdateHandler) + appsGroup.POST("/delete", adminctl.AppDeleteHandler) + appsGroup.POST("/batch_delete", adminctl.AppsBatchDeleteHandler) + appsGroup.POST("/batch_update_status", adminctl.AppsBatchUpdateStatusHandler) + appsGroup.POST("/update_status", adminctl.AppUpdateStatusHandler) + appsGroup.POST("/reset_secret", adminctl.AppResetSecretHandler) + appsGroup.GET("/get_app_data", adminctl.AppGetAppDataHandler) + appsGroup.POST("/update_app_data", adminctl.AppUpdateAppDataHandler) + appsGroup.GET("/get_announcement", adminctl.AppGetAnnouncementHandler) + appsGroup.POST("/update_announcement", adminctl.AppUpdateAnnouncementHandler) + appsGroup.GET("/get_multi_config", adminctl.AppGetMultiConfigHandler) + appsGroup.POST("/update_multi_config", adminctl.AppUpdateMultiConfigHandler) + appsGroup.GET("/get_bind_config", adminctl.AppGetBindConfigHandler) + appsGroup.POST("/update_bind_config", adminctl.AppUpdateBindConfigHandler) + appsGroup.GET("/get_register_config", adminctl.AppGetRegisterConfigHandler) + appsGroup.POST("/update_register_config", adminctl.AppUpdateRegisterConfigHandler) + } + + // API接口管理API + apisGroup := authorized.Group("/apis") + { + apisGroup.GET("/list", adminctl.APIListHandler) + apisGroup.POST("/update", adminctl.APIUpdateHandler) + apisGroup.POST("/update_status", adminctl.APIUpdateStatusHandler) + apisGroup.GET("/types", adminctl.APIGetTypesHandler) + apisGroup.POST("/generate_keys", adminctl.APIGenerateKeysHandler) + } + + // 变量管理API + variableGroup := authorized.Group("/variable") + { + variableGroup.GET("/list", adminctl.VariableListHandler) + variableGroup.POST("/create", adminctl.VariableCreateHandler) + variableGroup.POST("/update", adminctl.VariableUpdateHandler) + variableGroup.POST("/delete", adminctl.VariableDeleteHandler) + variableGroup.POST("/batch_delete", adminctl.VariablesBatchDeleteHandler) + } + + // 函数管理API + functionGroup := authorized.Group("/function") + { + functionGroup.GET("/list", adminctl.FunctionListHandler) + functionGroup.POST("/create", adminctl.FunctionCreateHandler) + functionGroup.POST("/update", adminctl.FunctionUpdateHandler) + functionGroup.POST("/delete", adminctl.FunctionDeleteHandler) + functionGroup.POST("/batch_delete", adminctl.FunctionsBatchDeleteHandler) + } + } +} diff --git a/server/default.go b/server/default.go index c60712d..f626f04 100644 --- a/server/default.go +++ b/server/default.go @@ -1,18 +1,16 @@ package server import ( - default_ctrl "NetworkAuth/controllers/default" + defaultctrl "NetworkAuth/controllers/default" "github.com/gin-gonic/gin" ) -// ============================================================================ -// 路由注册函数 -// ============================================================================ - // RegisterDefaultRoutes 注册默认路由 -// 只包含根路径,用于默认主页功能 -func RegisterDefaultRoutes(r *gin.Engine) { - // 根路径 - 主页 - r.GET("/", default_ctrl.RootHandler) +// 包含根路径、健康检查、API信息等基础端点 +func RegisterDefaultRoutes(rg *gin.RouterGroup) { + homeGroup := rg.Group("/home") + + // 根路径 + homeGroup.GET("", defaultctrl.RootHandler) } diff --git a/server/install.go b/server/install.go index 62c0e6a..386a74f 100644 --- a/server/install.go +++ b/server/install.go @@ -7,10 +7,9 @@ import ( ) // RegisterInstallRoutes 注册安装相关的路由 -func RegisterInstallRoutes(r *gin.Engine) { - // 安装向导页面 - r.GET("/install", install.InstallPageHandler) +func RegisterInstallRoutes(rg *gin.RouterGroup) { + installGroup := rg.Group("/install") // 提交安装表单 - r.POST("/api/install", install.InstallSubmitHandler) + installGroup.POST("", install.InstallSubmitHandler) } diff --git a/server/routes.go b/server/routes.go index a063ec4..f107d0c 100644 --- a/server/routes.go +++ b/server/routes.go @@ -1,48 +1,15 @@ -package server - -import ( - "NetworkAuth/web" - "io/fs" - "log" - "net/http" - - "github.com/gin-gonic/gin" -) - -// RegisterRoutes 聚合注册所有路由 -func RegisterRoutes(r *gin.Engine) { - registerStaticRoutes(r) - registerFaviconRoute(r) - RegisterInstallRoutes(r) - RegisterDefaultRoutes(r) - RegisterAdminRoutes(r) -} - -// registerStaticRoutes 注册静态资源路由 -// 静态资源服务,将 /static/ 和 /assets/ 映射到嵌入的文件系统 -func registerStaticRoutes(r *gin.Engine) { - if fsys, err := web.GetStaticFS(); err == nil { - // 为 /static/ 路径创建子文件系统 - if staticSubFS, staticErr := fs.Sub(fsys, "static"); staticErr == nil { - r.StaticFS("/static", http.FS(staticSubFS)) - } else { - log.Printf("创建静态资源子文件系统失败: %v", staticErr) - } - // 为 /assets/ 路径创建子文件系统 - if assetsSubFS, assetsErr := fs.Sub(fsys, "assets"); assetsErr == nil { - r.StaticFS("/assets", http.FS(assetsSubFS)) - } else { - log.Printf("创建资产资源子文件系统失败: %v", assetsErr) - } - } else { - log.Printf("初始化静态资源文件系统失败: %v", err) - } -} - -// registerFaviconRoute 注册favicon路由 -func registerFaviconRoute(r *gin.Engine) { - // 将 /favicon.ico 重定向到 /assets/favicon.svg - r.GET("/favicon.ico", func(c *gin.Context) { - c.Redirect(http.StatusMovedPermanently, "/assets/favicon.svg") - }) -} +package server + +import ( + "github.com/gin-gonic/gin" +) + +// RegisterRoutes 聚合注册所有路由 +func RegisterRoutes(r *gin.Engine) { + // 所有路由基于 /api + apiGroup := r.Group("/api") + + RegisterInstallRoutes(apiGroup) + RegisterDefaultRoutes(apiGroup) + RegisterAdminRoutes(apiGroup) +} diff --git a/services/query.go b/services/query.go index a956bd6..186d7e0 100644 --- a/services/query.go +++ b/services/query.go @@ -1,10 +1,10 @@ package services import ( - "NetworkAuth/models" - "NetworkAuth/utils" "context" "fmt" + "NetworkAuth/models" + "NetworkAuth/utils" "time" "gorm.io/gorm" @@ -104,7 +104,11 @@ func FindEntitiesByCondition(model interface{}, result interface{}, condition st // 返回: 是否存在和错误 func CheckEntityExists(model interface{}, condition string, db *gorm.DB, args ...interface{}) (bool, error) { var count int64 - err := db.Model(model).Where(condition, args...).Count(&count).Error + query := db.Model(model) + if condition != "" { + query = query.Where(condition, args...) + } + err := query.Count(&count).Error return count > 0, err } diff --git a/services/settings.go b/services/settings.go index 906334d..f27d229 100644 --- a/services/settings.go +++ b/services/settings.go @@ -42,6 +42,14 @@ func GetSettingsService() *SettingsService { return settingsService } +// ResetSettingsService 充置设置服务单例,主要用于重新加载设置(比如安装后) +func ResetSettingsService() { + settingsService = &SettingsService{ + cache: make(map[string]string), + } + settingsService.loadAllSettings() +} + // ============================================================================ // 私有函数 // ============================================================================ @@ -58,6 +66,12 @@ func (s *SettingsService) loadAllSettings() { return } + // 检查 settings 表是否存在,如果不存在则不查询 + if !db.Migrator().HasTable(&models.Settings{}) { + logrus.Info("settings 表不存在,跳过加载设置") + return + } + var settings []models.Settings if err := db.Find(&settings).Error; err != nil { logrus.WithError(err).Error("加载设置失败") diff --git a/web/assets/logo.svg b/web/assets/logo.svg deleted file mode 100644 index 38e64e5..0000000 --- a/web/assets/logo.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/web/assets/themes.json b/web/assets/themes.json deleted file mode 100644 index 0f09267..0000000 --- a/web/assets/themes.json +++ /dev/null @@ -1,355 +0,0 @@ -{ - "Default": { - "--color-white": "#FFFFFF", - "--color-black": "#000000", - "--lay-color-white": "#FAFAFA", - "--lay-color-black": "#333333", - "--lay-color-red-1": "#FFF1E8", - "--lay-color-red-2": "#FFD7C0", - "--lay-color-red-3": "#FFBB99", - "--lay-color-red-4": "#FF9C71", - "--lay-color-red-5": "#FF7A4A", - "--lay-color-red-6": "#FF5722", - "--lay-color-red-7": "#D23B15", - "--lay-color-red-8": "#A6250B", - "--lay-color-red-9": "#791404", - "--lay-color-red-10": "#4D0800", - "--lay-color-blue-1": "#E8F9FF", - "--lay-color-blue-2": "#C0ECFF", - "--lay-color-blue-3": "#97DCFF", - "--lay-color-blue-4": "#6FCAFF", - "--lay-color-blue-5": "#46B5FF", - "--lay-color-blue-6": "#1E9FFF", - "--lay-color-blue-7": "#1379D2", - "--lay-color-blue-8": "#0A58A6", - "--lay-color-blue-9": "#043A79", - "--lay-color-blue-10": "#00214D", - "--lay-color-lightblue-1": "#E8FDFF", - "--lay-color-lightblue-2": "#C1F4FB", - "--lay-color-lightblue-3": "#9CEAF7", - "--lay-color-lightblue-4": "#77DDF4", - "--lay-color-lightblue-5": "#53CEF0", - "--lay-color-lightblue-6": "#31BDEC", - "--lay-color-lightblue-7": "#1F95C4", - "--lay-color-lightblue-8": "#10709C", - "--lay-color-lightblue-9": "#064E74", - "--lay-color-lightblue-10": "#002F4D", - "--lay-color-layuigreen-1": "#E8FFF9", - "--lay-color-layuigreen-2": "#B5F1E3", - "--lay-color-layuigreen-3": "#87E3D1", - "--lay-color-layuigreen-4": "#5DD6C1", - "--lay-color-layuigreen-5": "#37C8B5", - "--lay-color-layuigreen-6": "#16BAAA", - "--lay-color-layuigreen-7": "#0E9F95", - "--lay-color-layuigreen-8": "#08837F", - "--lay-color-layuigreen-9": "#036868", - "--lay-color-layuigreen-10": "#004A4D", - "--lay-color-green-1": "#E8FFF2", - "--lay-color-green-2": "#B5F1D1", - "--lay-color-green-3": "#86E2B4", - "--lay-color-green-4": "#5CD49C", - "--lay-color-green-5": "#37C588", - "--lay-color-green-6": "#16B777", - "--lay-color-green-7": "#0E9C68", - "--lay-color-green-8": "#088259", - "--lay-color-green-9": "#036749", - "--lay-color-green-10": "#004D38", - "--lay-color-orange-1": "#FFFCE8", - "--lay-color-orange-2": "#FFF5BA", - "--lay-color-orange-3": "#FFEA8B", - "--lay-color-orange-4": "#FFDC5D", - "--lay-color-orange-5": "#FFCB2E", - "--lay-color-orange-6": "#FFB800", - "--lay-color-orange-7": "#D29000", - "--lay-color-orange-8": "#A66C00", - "--lay-color-orange-9": "#794B00", - "--lay-color-orange-10": "#4D2D00", - "--lay-color-cyan-1": "#E8F6FF", - "--lay-color-cyan-2": "#B9CEDD", - "--lay-color-cyan-3": "#8FA7BB", - "--lay-color-cyan-4": "#6A829A", - "--lay-color-cyan-5": "#4A5F78", - "--lay-color-cyan-6": "#2F4056", - "--lay-color-cyan-7": "#223654", - "--lay-color-cyan-8": "#162C51", - "--lay-color-cyan-9": "#0B214F", - "--lay-color-cyan-10": "#00174D", - "--lay-color-purple-1": "#FDE8FF", - "--lay-color-purple-2": "#EDBEF4", - "--lay-color-purple-3": "#DC97E8", - "--lay-color-purple-4": "#C972DD", - "--lay-color-purple-5": "#B651D1", - "--lay-color-purple-6": "#A233C6", - "--lay-color-purple-7": "#8120A8", - "--lay-color-purple-8": "#631289", - "--lay-color-purple-9": "#48076B", - "--lay-color-purple-10": "#2F004D", - "--lay-color-black-1": "#E8F8FF", - "--lay-color-black-2": "#BFD0D8", - "--lay-color-black-3": "#98A8B1", - "--lay-color-black-4": "#73818A", - "--lay-color-black-5": "#505B63", - "--lay-color-black-6": "#2F363C", - "--lay-color-black-7": "#23303C", - "--lay-color-black-8": "#18293C", - "--lay-color-black-9": "#0C213C", - "--lay-color-black-10": "#00183C", - "--lay-color-gray-1": "#FAFAFA", - "--lay-color-gray-2": "#F6F6F6", - "--lay-color-gray-3": "#EEEEEE", - "--lay-color-gray-4": "#E2E2E2", - "--lay-color-gray-5": "#DDDDDD", - "--lay-color-gray-6": "#D2D2D2", - "--lay-color-gray-7": "#CCCCCC", - "--lay-color-gray-8": "#C2C2C2", - "--lay-color-gray-9": "#AAAAAA", - "--lay-color-gray-10": "#939393", - "--lay-color-gray-11": "#858585", - "--lay-color-gray-12": "#7b7b7b", - "--lay-color-gray-13": "#686868", - "--lay-color-primary": "var(--lay-color-layuigreen-6)", - "--lay-color-primary-hover": "var(--lay-color-layuigreen-5)", - "--lay-color-primary-active": "var(--lay-color-layuigreen-7)", - "--lay-color-primary-disabled": "var(--lay-color-layuigreen-3)", - "--lay-color-primary-light": "var(--lay-color-layuigreen-4)", - "--lay-color-secondary": "var(--lay-color-green-6)", - "--lay-color-secondary-hover": "var(--lay-color-green-5)", - "--lay-color-secondary-active": "var(--lay-color-green-7)", - "--lay-color-secondary-disabled": "var(--lay-color-green-3)", - "--lay-color-secondary-light": "var(--lay-color-green-4)", - "--lay-color-info": "var(--lay-color-lightblue-6)", - "--lay-color-info-hover": "var(--lay-color-lightblue-5)", - "--lay-color-info-active": "var(--lay-color-lightblue-7)", - "--lay-color-info-disabled": "var(--lay-color-lightblue-3)", - "--lay-color-info-light": "var(--lay-color-lightblue-4)", - "--lay-color-normal": "var(--lay-color-blue-6)", - "--lay-color-normal-hover": "var(--lay-color-blue-5)", - "--lay-color-normal-active": "var(--lay-color-blue-7)", - "--lay-color-normal-disabled": "var(--lay-color-blue-3)", - "--lay-color-normal-light": "var(--lay-color-blue-4)", - "--lay-color-warning": "var(--lay-color-orange-6)", - "--lay-color-warning-hover": "var(--lay-color-orange-5)", - "--lay-color-warning-active": "var(--lay-color-orange-7)", - "--lay-color-warning-disabled": "var(--lay-color-orange-3)", - "--lay-color-warning-light": "var(--lay-color-orange-4)", - "--lay-color-success": "var(--lay-color-green-6)", - "--lay-color-success-hover": "var(--lay-color-green-5)", - "--lay-color-success-active": "var(--lay-color-green-7)", - "--lay-color-success-disabled": "var(--lay-color-green-3)", - "--lay-color-success-light": "var(--lay-color-green-4)", - "--lay-color-danger": "var(--lay-color-red-6)", - "--lay-color-danger-hover": "var(--lay-color-red-5)", - "--lay-color-danger-active": "var(--lay-color-red-7)", - "--lay-color-danger-disabled": "var(--lay-color-red-3)", - "--lay-color-danger-light": "var(--lay-color-red-4)", - "--lay-color-bg-1": "#17171A", - "--lay-color-bg-2": "#232324", - "--lay-color-bg-3": "#2a2a2b", - "--lay-color-bg-4": "#313132", - "--lay-color-bg-5": "#373739", - "--lay-color-bg-white": "#f6f6f6", - "--lay-color-text-1": "rgba(255,255,255,.9)", - "--lay-color-text-2": "rgba(255,255,255,.7)", - "--lay-color-text-3": "rgba(255,255,255,.5)", - "--lay-color-text-4": "rgba(255,255,255,.3)", - "--lay-color-border-1": "#2e2e30", - "--lay-color-border-2": "#484849", - "--lay-color-border-3": "#5f5f60", - "--lay-color-border-4": "#929293", - "--lay-color-fill-1": "rgba(255,255,255,.04)", - "--lay-color-fill-2": "rgba(255,255,255,.08)", - "--lay-color-fill-3": "rgba(255,255,255,.12)", - "--lay-color-fill-4": "rgba(255,255,255,.16)", - "--lay-color-hover": "var(--lay-color-fill-3)", - "--lay-color-active": "var(--lay-color-fill-3)", - "--lay-shadow-1": "0 4px 6px rgba(0, 0, 0, 6%), 0 1px 10px rgba(0, 0, 0, 8%), 0 2px 4px rgba(0, 0, 0, 12%)", - "--lay-shadow-2": "0 8px 10px rgba(0, 0, 0, 12%), 0 3px 14px rgba(0, 0, 0, 10%), 0 5px 5px rgba(0, 0, 0, 16%)", - "--lay-shadow-3": "0 16px 24px rgba(0, 0, 0, 14%), 0 6px 30px rgba(0, 0, 0, 12%), 0 8px 10px rgba(0, 0, 0, 20%)" - }, - "ColorPaletteDark": { - "--lay-color-red-1": "#4D0800", - "--lay-color-red-2": "#791505", - "--lay-color-red-3": "#A62A11", - "--lay-color-red-4": "#D24622", - "--lay-color-red-5": "#FF6839", - "--lay-color-red-6": "#FF7948", - "--lay-color-red-7": "#FF9C71", - "--lay-color-red-8": "#FFBC9A", - "--lay-color-red-9": "#FFD9C3", - "--lay-color-red-10": "#FFF3EB", - "--lay-color-blue-1": "#00214D", - "--lay-color-blue-2": "#033A79", - "--lay-color-blue-3": "#0F5AA6", - "--lay-color-blue-4": "#1F7FD2", - "--lay-color-blue-5": "#35A9FF", - "--lay-color-blue-6": "#44B4FF", - "--lay-color-blue-7": "#70CAFF", - "--lay-color-blue-8": "#9BDDFF", - "--lay-color-blue-9": "#C6EEFF", - "--lay-color-blue-10": "#F2FCFF", - "--lay-color-lightblue-1": "#002F4D", - "--lay-color-lightblue-2": "#044D74", - "--lay-color-lightblue-3": "#12719C", - "--lay-color-lightblue-4": "#2797C4", - "--lay-color-lightblue-5": "#42C1EC", - "--lay-color-lightblue-6": "#56CFF0", - "--lay-color-lightblue-7": "#79DDF4", - "--lay-color-lightblue-8": "#9DEAF7", - "--lay-color-lightblue-9": "#C3F4FB", - "--lay-color-lightblue-10": "#EAFDFF", - "--lay-color-layuigreen-1": "#004A4D", - "--lay-color-layuigreen-2": "#046868", - "--lay-color-layuigreen-3": "#0E837F", - "--lay-color-layuigreen-4": "#1C9F96", - "--lay-color-layuigreen-5": "#2EBAAC", - "--lay-color-layuigreen-6": "#40C8B6", - "--lay-color-layuigreen-7": "#64D6C2", - "--lay-color-layuigreen-8": "#8CE3D2", - "--lay-color-layuigreen-9": "#B9F1E4", - "--lay-color-layuigreen-10": "#EAFFFA", - "--lay-color-green-1": "#004D38", - "--lay-color-green-2": "#046749", - "--lay-color-green-3": "#0E825B", - "--lay-color-green-4": "#1C9C6D", - "--lay-color-green-5": "#2EB780", - "--lay-color-green-6": "#3FC58B", - "--lay-color-green-7": "#64D4A0", - "--lay-color-green-8": "#8CE2B7", - "--lay-color-green-9": "#BAF1D3", - "--lay-color-green-10": "#EBFFF4", - "--lay-color-orange-1": "#4D2D00", - "--lay-color-orange-2": "#794C04", - "--lay-color-orange-3": "#A66F0A", - "--lay-color-orange-4": "#D29613", - "--lay-color-orange-5": "#FFC11F", - "--lay-color-orange-6": "#FFC926", - "--lay-color-orange-7": "#FFDB57", - "--lay-color-orange-8": "#FFE987", - "--lay-color-orange-9": "#FFF5B8", - "--lay-color-orange-10": "#FFFCE8", - "--lay-color-cyan-1": "#00174D", - "--lay-color-cyan-2": "#0B214F", - "--lay-color-cyan-3": "#162C51", - "--lay-color-cyan-4": "#233754", - "--lay-color-cyan-5": "#304056", - "--lay-color-cyan-6": "#546478", - "--lay-color-cyan-7": "#75879A", - "--lay-color-cyan-8": "#99ABBB", - "--lay-color-cyan-9": "#C2D2DD", - "--lay-color-cyan-10": "#EFF9FF", - "--lay-color-purple-1": "#2F004D", - "--lay-color-purple-2": "#47056B", - "--lay-color-purple-3": "#631389", - "--lay-color-purple-4": "#8326A8", - "--lay-color-purple-5": "#A53FC6", - "--lay-color-purple-6": "#B755D1", - "--lay-color-purple-7": "#CA77DD", - "--lay-color-purple-8": "#DD9BE8", - "--lay-color-purple-9": "#EEC3F4", - "--lay-color-purple-10": "#FDEDFF" - }, - "ColorPaletteLight": { - "--lay-color-red-1": "#FFF1E8", - "--lay-color-red-2": "#FFD7C0", - "--lay-color-red-3": "#FFBB99", - "--lay-color-red-4": "#FF9C71", - "--lay-color-red-5": "#FF7A4A", - "--lay-color-red-6": "#FF5722", - "--lay-color-red-7": "#D23B15", - "--lay-color-red-8": "#A6250B", - "--lay-color-red-9": "#791404", - "--lay-color-red-10": "#4D0800", - "--lay-color-blue-1": "#E8F9FF", - "--lay-color-blue-2": "#C0ECFF", - "--lay-color-blue-3": "#97DCFF", - "--lay-color-blue-4": "#6FCAFF", - "--lay-color-blue-5": "#46B5FF", - "--lay-color-blue-6": "#1E9FFF", - "--lay-color-blue-7": "#1379D2", - "--lay-color-blue-8": "#0A58A6", - "--lay-color-blue-9": "#043A79", - "--lay-color-blue-10": "#00214D", - "--lay-color-lightblue-1": "#E8FDFF", - "--lay-color-lightblue-2": "#C1F4FB", - "--lay-color-lightblue-3": "#9CEAF7", - "--lay-color-lightblue-4": "#77DDF4", - "--lay-color-lightblue-5": "#53CEF0", - "--lay-color-lightblue-6": "#31BDEC", - "--lay-color-lightblue-7": "#1F95C4", - "--lay-color-lightblue-8": "#10709C", - "--lay-color-lightblue-9": "#064E74", - "--lay-color-lightblue-10": "#002F4D", - "--lay-color-layuigreen-1": "#E8FFF9", - "--lay-color-layuigreen-2": "#B5F1E3", - "--lay-color-layuigreen-3": "#87E3D1", - "--lay-color-layuigreen-4": "#5DD6C1", - "--lay-color-layuigreen-5": "#37C8B5", - "--lay-color-layuigreen-6": "#16BAAA", - "--lay-color-layuigreen-7": "#0E9F95", - "--lay-color-layuigreen-8": "#08837F", - "--lay-color-layuigreen-9": "#036868", - "--lay-color-layuigreen-10": "#004A4D", - "--lay-color-green-1": "#E8FFF2", - "--lay-color-green-2": "#B5F1D1", - "--lay-color-green-3": "#86E2B4", - "--lay-color-green-4": "#5CD49C", - "--lay-color-green-5": "#37C588", - "--lay-color-green-6": "#16B777", - "--lay-color-green-7": "#0E9C68", - "--lay-color-green-8": "#088259", - "--lay-color-green-9": "#036749", - "--lay-color-green-10": "#004D38", - "--lay-color-orange-1": "#FFFCE8", - "--lay-color-orange-2": "#FFF5BA", - "--lay-color-orange-3": "#FFEA8B", - "--lay-color-orange-4": "#FFDC5D", - "--lay-color-orange-5": "#FFCB2E", - "--lay-color-orange-6": "#FFB800", - "--lay-color-orange-7": "#D29000", - "--lay-color-orange-8": "#A66C00", - "--lay-color-orange-9": "#794B00", - "--lay-color-orange-10": "#4D2D00", - "--lay-color-cyan-1": "#E8F6FF", - "--lay-color-cyan-2": "#B9CEDD", - "--lay-color-cyan-3": "#8FA7BB", - "--lay-color-cyan-4": "#6A829A", - "--lay-color-cyan-5": "#4A5F78", - "--lay-color-cyan-6": "#2F4056", - "--lay-color-cyan-7": "#223654", - "--lay-color-cyan-8": "#162C51", - "--lay-color-cyan-9": "#0B214F", - "--lay-color-cyan-10": "#00174D", - "--lay-color-purple-1": "#FDE8FF", - "--lay-color-purple-2": "#EDBEF4", - "--lay-color-purple-3": "#DC97E8", - "--lay-color-purple-4": "#C972DD", - "--lay-color-purple-5": "#B651D1", - "--lay-color-purple-6": "#A233C6", - "--lay-color-purple-7": "#8120A8", - "--lay-color-purple-8": "#631289", - "--lay-color-purple-9": "#48076B", - "--lay-color-purple-10": "#2F004D" - }, - "editable": { - "--lay-color-bg-1": "#17171A", - "--lay-color-bg-2": "#232324", - "--lay-color-bg-3": "#2a2a2b", - "--lay-color-bg-4": "#313132", - "--lay-color-bg-5": "#373739", - "--lay-color-bg-white": "#f6f6f6", - "--lay-color-text-1": "rgba(255,255,255,.9)", - "--lay-color-text-2": "rgba(255,255,255,.7)", - "--lay-color-text-3": "rgba(255,255,255,.5)", - "--lay-color-text-4": "rgba(255,255,255,.3)", - "--lay-color-border-1": "#2e2e30", - "--lay-color-border-2": "#484849", - "--lay-color-border-3": "#5f5f60", - "--lay-color-border-4": "#929293", - "--lay-color-fill-1": "rgba(255,255,255,.04)", - "--lay-color-fill-2": "rgba(255,255,255,.08)", - "--lay-color-fill-3": "rgba(255,255,255,.12)", - "--lay-color-fill-4": "rgba(255,255,255,.16)", - "--lay-color-hover": "var(--lay-color-fill-3)", - "--lay-color-active": "var(--lay-color-fill-3)" - } -} diff --git a/web/public.go b/web/public.go deleted file mode 100644 index 8097ecc..0000000 --- a/web/public.go +++ /dev/null @@ -1,67 +0,0 @@ -package web - -import ( - "embed" - "html/template" - "io/fs" - "log" - "os" - "path/filepath" - - "github.com/spf13/viper" -) - -// TemplatesFS 嵌入模板的文件系统 -// -//go:embed template/*/*.html -var templatesFS embed.FS - -// StaticFS 嵌入静态资源的文件系统(包含 CSS/JS 的 static 与 图片/字体等资源的 assets) -// -//go:embed static/* assets/* -var staticFS embed.FS - -// getDistRootFS 获取基于 server.dist 的本地文件系统 -// 当 server.dist 非空且路径存在时,返回对应的本地只读 FS;否则返回 nil -func getDistRootFS() fs.FS { - // 从配置中读取 server.dist - distPath := viper.GetString("server.dist") - if distPath == "" { - return nil - } - // 归一化路径,兼容相对/绝对 - absPath := distPath - if !filepath.IsAbs(distPath) { - if p, err := filepath.Abs(distPath); err == nil { - absPath = p - } - } - // 检查目录是否存在 - if info, err := os.Stat(absPath); err == nil && info.IsDir() { - return os.DirFS(absPath) - } - log.Printf("server.dist 路径无效或不可访问:%s,将回退使用嵌入资源", distPath) - return nil -} - -// ParseTemplates 解析模板 -// 优先从 server.dist 指定目录加载(当配置非空且有效),否则回退到嵌入模板 -func ParseTemplates() (*template.Template, error) { // Go 顶级函数不支持箭头写法 - if distFS := getDistRootFS(); distFS != nil { - // 期望 dist 目录下存在 template 与 template/admin 结构 - // 如:{dist}/template/*.html 与 {dist}/template/admin/*.html - return template.ParseFS(distFS, "template/*/*.html") - } - // 默认:使用嵌入模板 - return template.ParseFS(templatesFS, "template/*/*.html") -} - -// GetStaticFS 返回静态资源文件系统(包含 static 与 assets 目录) -// 优先使用 server.dist 指定的本地目录;否则回退到嵌入静态资源 -func GetStaticFS() (fs.FS, error) { // Go 顶级函数不支持箭头写法 - if distFS := getDistRootFS(); distFS != nil { - // 直接返回以 dist 根为起点的 FS,routes 中会再基于此 FS Sub 出 static 与 assets - return distFS, nil - } - return staticFS, nil -} diff --git a/web/static/css/admin.css b/web/static/css/admin.css deleted file mode 100644 index 3e94952..0000000 --- a/web/static/css/admin.css +++ /dev/null @@ -1,93 +0,0 @@ -wc-include{padding: 15px;display: block;} -#app {display: none;} -.layui-layout-right .layui-nav-bar {background-color: unset !important;} -.layui-layout-admin .layui-side {top: 0 !important;z-index: 1001;} -.layui-layout-admin .layui-logo {position: relative !important;height: 60px !important;top: -2px !important;} -.layui-side, -.layui-header, -.layui-body, -.layui-footer {transition: left 0.3s;} -.collapse .layui-layout-admin .layui-side, -.collapse .layui-layout-admin .layui-header {left: -200px;} -.collapse .layui-layout-admin .layui-footer, -.collapse .layui-layout-admin .layui-body {left: 0px;} - -::view-transition-old(root), -::view-transition-new(root) {animation: none;mix-blend-mode: normal;} -::view-transition-old(root) {z-index: 9999;} -::view-transition-new(root) {z-index: 1;} -.dark::view-transition-old(root) {z-index: 1;} -.dark::view-transition-new(root) {z-index: 9999;} - -/* 以下为自定义样式 */ -.system-info-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 16px; margin-bottom: 20px; } -.system-info-item { padding: 16px; border-radius: 8px; background: var(--card); border: 1px solid var(--border); } -.system-info-label { font-size: 14px; color: var(--muted); margin-bottom: 8px; } -.system-info-value { font-size: 16px; font-weight: 600; color: var(--fg); } - -/* ===================== 滚动条美化与布局约束(右侧滑块条) ===================== */ -/* - 作用: - 1. 统一 Admin 布局下内容区(.layui-body)为局部滚动容器,只在头部与页脚之间滚动 - 2. 美化 .layui-body 的滚动条样式,增强可用性与观感 - 3. 不影响登录页等非 Admin 布局页面(仅在 .layui-layout-admin 作用域内生效) -*/ -:root { - /* 头部与页脚的高度变量,便于后续维护/调整 */ - --admin-header-h: 60px; - --admin-footer-h: 0px; /* 当前页脚未启用,如启用可改为 44px 等 */ -} - -/* Admin 主容器占满视口,高度锁定,避免出现浏览器右侧全局滚动条 */ -.layui-layout-admin { - position: relative; - height: 100vh; - overflow: hidden; -} - -/* 头部/页脚高度同步到变量,确保与内容区上下边界垂直齐平 */ -.layui-layout-admin .layui-header { - height: var(--admin-header-h); - line-height: var(--admin-header-h); -} -.layui-layout-admin .layui-footer { - height: var(--admin-footer-h); - line-height: var(--admin-footer-h); -} - -/* 内容区设为局部滚动容器,顶部/底部与头部/页脚精确对齐 */ -.layui-layout-admin .layui-body { - /* 仅约束垂直方向,左右定位保持与 Layui 默认一致,兼容现有折叠动画 */ - top: var(--admin-header-h) !important; - bottom: var(--admin-footer-h) !important; - overflow: auto; - - /* Firefox 滚动条样式(细滚动条+自定义颜色) */ - scrollbar-width: thin; /* 细滚动条 */ - scrollbar-color: var(--lay-color-secondary) var(--lay-color-bg-3); /* thumb 与 track 颜色 */ -} - -/* WebKit 滚动条样式(Chrome/Edge/Safari) */ -.layui-layout-admin .layui-body::-webkit-scrollbar { - width: 10px; - height: 10px; -} -.layui-layout-admin .layui-body::-webkit-scrollbar-track { - background: var(--lay-color-bg-2); - border-left: 1px solid var(--lay-color-border-2); -} -.layui-layout-admin .layui-body::-webkit-scrollbar-thumb { - /* 渐变+内边透明边框,获得圆润质感 */ - background: linear-gradient(180deg, var(--lay-color-gray-7), var(--lay-color-gray-9)); - border-radius: 8px; - border: 2px solid transparent; - background-clip: padding-box; -} -.layui-layout-admin .layui-body::-webkit-scrollbar-thumb:hover { - background: var(--lay-color-secondary); /* 悬停高亮,强化可交互性 */ -} -.layui-layout-admin .layui-body::-webkit-scrollbar-corner { - background: transparent; -} - -/* ===================== END 滚动条美化与布局约束 ===================== */ diff --git a/web/static/js/admin.js b/web/static/js/admin.js deleted file mode 100755 index 46f2fc6..0000000 --- a/web/static/js/admin.js +++ /dev/null @@ -1,463 +0,0 @@ -const VERSION = '2.9.20'; // Using local version -const layuicss = '/static/lib/layui/css/layui.css'; -const layuijs = '/static/lib/layui/layui.js'; -const rootPath = (function (src) { - src = (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') ? document.currentScript.src : document.scripts[document.scripts.length - 1].src; - return src.substring(0, src.lastIndexOf('/') + 1); -})(); - -// CSRF令牌管理 -const CSRFManager = { - // 缓存的CSRF令牌 - token: null, - - // 获取CSRF令牌 - async getToken() { - if (this.token) { - return this.token; - } - - try { - const response = await fetch('/admin/api/csrf-token', { - method: 'GET', - headers: { - 'X-Requested-With': 'XMLHttpRequest' - } - }); - - if (response.ok) { - const data = await response.json(); - if (data.code === 0 && data.data && data.data.csrf_token) { - this.token = data.data.csrf_token; - return this.token; - } - } - } catch (error) { - console.error('获取CSRF令牌失败:', error); - } - - return null; - }, - - // 清除缓存的令牌 - clearToken() { - this.token = null; - }, - - // 为fetch请求添加CSRF令牌 - async addCSRFHeader(headers = {}) { - const token = await this.getToken(); - if (token) { - headers['X-CSRF-Token'] = token; - } - return headers; - } -}; - -// 增强的fetch函数,自动添加CSRF令牌 -window.fetchWithCSRF = async function(url, options = {}) { - const headers = await CSRFManager.addCSRFHeader(options.headers || {}); - return fetch(url, { - ...options, - headers - }); -}; - -const app = document.querySelector('#app') - -addLink({ href: layuicss }).then(() => { - app.style.display = 'block'; -}); - -addLink({ id: 'layui_theme_css', href: `/static/src/layui-theme-dark-selector.css` }); - -loadScript(layuijs, function () { - layui - .config({ - base: '/static/lib/', - }) - .extend({ - drawer: 'drawer/drawer', - }); - layui.use(['drawer', 'colorMode', 'jquery', 'layer'], async function () { - const { $, element, form, layer, util, dropdown, drawer, colorMode } = layui; - - // --- CSRF Setup for jQuery --- - // Ensure token is loaded - await CSRFManager.getToken(); - - $.ajaxSetup({ - beforeSend: function(xhr) { - if (CSRFManager.token) { - xhr.setRequestHeader('X-CSRF-Token', CSRFManager.token); - } - }, - complete: function(xhr) { - if (xhr.status === 401) { - window.location.href = '/admin/login'; - } - } - }); - // ----------------------------- - - const APPERANCE_KEY = 'layui-theme-demo-prefer-dark'; - - const theme = colorMode.init({ - selector: 'html', - attribute: 'class', - initialValue: 'dark', - modes: { - light: '', - dark: 'dark', - }, - storageKey: APPERANCE_KEY, - onChanged(mode, defaultHandler) { - const isAppearanceTransition = document.startViewTransition && !window.matchMedia(`(prefers-reduced-motion: reduce)`).matches; - const isDark = mode === 'dark'; - - $('#change-theme').attr('class', `layui-icon layui-icon-${isDark ? 'moon' : 'light'}`); - - if (!isAppearanceTransition) { - defaultHandler(); - } else { - rippleViewTransition(isDark, function () { - defaultHandler(); - }); - } - }, - }); - - routerTo({path: location.hash.slice(1) || 'dashboard'}); - - dropdown.render({ - elem: '#change-theme', - align: 'center', - data: [ - { - title: '深色模式', - id: 'dark', - icon: 'layui-icon-moon', - }, - { - title: '浅色模式', - id: 'light', - icon: 'layui-icon-light', - }, - { - title: '跟随系统', - id: 'auto', - icon: 'layui-icon-console', - }, - ], - templet(d) { - return ` - - - ${d.title} - `.trim(); - }, - click(obj) { - const { id: mode } = obj; - theme.setMode(mode); - }, - }); - - util.event('lay-header-event', { - menuLeft() { - $('body').toggleClass('collapse'); - }, - menuRight() { - drawer.open({ - area: '600px', - url: './static/tpl/theme.html', - hideOnClose: true, - id: 'drawer-theme-tpl', - shade: 0.01, - }); - }, - }); - - element.on('nav(nav-side)', function (elem) { - var path = elem.data('path'); - if (path) { - routerTo({path}); - if ($(window).width() <= 768) { - $('body').toggleClass('collapse', false); - } - } - }); - - $('#layuiv').text(layui.v); - - /* - * 后台通用脚本 - * 说明:统一处理全局的退出登录逻辑 - */ - - // 绑定退出登录按钮事件 - const bindLogout = () => { - const btn = document.getElementById('logout-btn'); - if (!btn) return; - btn.addEventListener('click', (e) => { - e.preventDefault(); - handleLogout(); - }); - }; - - // 执行退出登录 - const handleLogout = () => { - layer.confirm('确定要退出登录吗?', { - icon: 3, - title: '提示' - }, (index) => { - layer.close(index); - - const loadIndex = layer.load(2, { - content: '正在退出登录...' - }); - - fetchWithCSRF('/admin/logout', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'X-Requested-With': 'XMLHttpRequest' - } - }) - .then(response => response.json()) - .then(data => { - layer.close(loadIndex); - const ok = data && (data.code === 0 || data.success); - const msg = (data && (data.msg || data.message)) || (ok ? '退出登录成功' : '退出登录失败'); - if (ok) { - layer.msg(msg, { - icon: 1, - time: 1000 - }, () => { - const redirect = (data && data.data && data.data.redirect) || '/admin/login'; - window.location.href = redirect; - }); - } else { - layer.msg(msg, { icon: 2 }); - } - }) - .catch(error => { - layer.close(loadIndex); - console.error('登出请求失败:', error); - layer.msg('网络错误,请重试', { icon: 2 }); - }); - }); - }; - - (() => { - if (document.readyState === 'loading') { - document.addEventListener('DOMContentLoaded', bindLogout); - } else { - bindLogout(); - } - })(); - - // 刷新页面功能处理 - const handleRefresh = () => { - layer.confirm('确定要刷新内容吗?', { - icon: 3, - title: '提示' - }, (index) => { - layer.close(index); - - let currentPath = window.location.hash.replace('#', '') || 'dashboard'; - - const loadIndex = layer.load(2, { - content: '正在刷新...' - }); - - setTimeout(() => { - routerTo({ path: currentPath }); - layer.close(loadIndex); - }, 500); - }); - }; - - $('#refresh-btn').on('click', handleRefresh); - - // 统一的Tips提示功能 - $(document).off('click', '[data-tips]').on('click', '[data-tips]', function() { - var tipsType = $(this).data('tips'); - var tipsContent = getTipsContent(tipsType); - layer.tips(tipsContent, this, { - tips: [2, '#16b777'], - time: 3000 - }); - }); - - function getTipsContent(type) { - var tips = { - 'user-username': '用户名:用于登录的用户名,可以修改但需要保证唯一性', - 'user-old-password': '旧密码:修改密码时需要输入当前密码进行验证,不修改密码时可留空', - 'user-new-password': '新密码:要设置的新密码,长度至少6位,不修改密码时可留空', - 'site-title': '站点标题:网站的主标题,显示在浏览器标题栏和搜索引擎结果中', - 'site-keywords': '关键词:网站的SEO关键词,用于搜索引擎优化,多个关键词用逗号分隔', - 'site-description': '站点描述:网站的简要描述,用于SEO和搜索引擎结果展示', - 'site-logo': '站点Logo:网站的标志图片路径,建议使用SVG格式', - 'maintenance-mode': '维护模式:开启后网站将进入维护模式,普通用户无法访问', - 'default-user-role': '默认角色:新注册用户的默认权限级别,0为管理员,1为普通成员', - 'session-timeout': '会话超时:用户登录会话的有效时间,单位为秒,超时后需要重新登录', - 'footer-text': '页脚文本:显示在网站底部的版权信息或其他文本', - 'icp-record': 'ICP备案:网站的ICP备案号,中国大陆网站必须显示', - 'icp-record-link': 'ICP备案链接:ICP备案号对应的查询链接,通常指向工信部备案网站', - 'psb-record': '公安备案:网站的公安备案号,部分地区要求显示', - 'psb-record-link': '公安备案链接:公安备案号对应的查询链接,通常指向公安部备案网站', - 'app-name': '应用名称:设置应用的显示名称,用户在客户端看到的应用标识', - 'app-version': '应用版本:当前应用的版本号,用于版本控制和更新检测', - 'app-status': '应用状态:控制应用是否可用,禁用后用户无法使用该应用', - 'force-update': '强制更新:开启后用户必须更新到最新版本才能使用', - 'download-type': '更新方式:设置应用的更新下载方式,支持不同的分发渠道', - 'download-url': '下载地址:应用安装包的下载链接地址', - 'login-type': '登录方式:设置用户登录验证的方式,如账号密码、卡密等', - 'multi-open-scope': '多开范围:设置多开功能的作用范围,如全局或特定应用', - 'clean-interval': '清理间隔:系统自动清理无效会话的时间间隔(分钟)', - 'check-interval': '校验间隔:系统检查用户状态的时间间隔(分钟)', - 'multi-open-count': '多开数量:允许用户同时运行的应用实例数量', - 'machine-verify': '机器码验证:控制是否启用机器码验证功能,用于限制软件在特定设备上运行', - 'machine-rebind': '机器码重绑:允许用户重新绑定机器码,当设备更换或重装系统时使用', - 'machine-rebind-limit': '重绑限制:设置重绑的时间限制,每天表示每天可重绑,永久表示不限制重绑时间', - 'machine-free-count': '免费次数:用户可以免费重绑机器码的次数', - 'machine-rebind-count': '重绑次数:用户总共可以重绑机器码的次数限制', - 'machine-rebind-deduct': '重绑扣除:每次重绑机器码时扣除的时间(分钟)', - 'ip-verify': 'IP地址验证:控制是否启用IP地址验证,关闭/开启/开启(市)/开启(省)分别对应不同的验证级别', - 'ip-rebind': 'IP地址重绑:允许用户重新绑定IP地址,当网络环境变化时使用', - 'ip-rebind-limit': '重绑限制:设置IP重绑的时间限制,每天表示每天可重绑,永久表示不限制重绑时间', - 'ip-free-count': '免费次数:用户可以免费重绑IP地址的次数', - 'ip-rebind-count': '重绑次数:用户总共可以重绑IP地址的次数限制', - 'ip-rebind-deduct': '重绑扣除:每次重绑IP地址时扣除的时间(分钟)', - 'register-enabled': '账号注册:控制是否允许新用户注册账号', - 'register-limit': '注册限制:设置注册的限制规则,如时间限制等', - 'register-limit-time': '限制时间:注册限制的时间周期,每天或永久', - 'register-count': '注册次数:在限制时间内允许注册的账号数量', - 'trial-enabled': '领取试用:控制是否允许用户领取试用时间', - 'trial-limit-time': '限制时间:试用领取的时间限制周期', - 'trial-time': '试用时间:用户可以领取的试用时长(分钟)', - 'submit-algorithm': '提交算法:客户端向服务器提交数据时使用的加密算法
• 不加密:数据明文传输,适用于内网环境
• RC4:对称加密,速度快,适用于一般场景
• RSA:非对称加密,安全性高,适用于敏感数据
• RSA(动态):动态生成密钥的RSA加密,安全性最高
• 易加密:自定义对称加密算法,使用15-30位整数密钥数组', - 'submit-keys': '提交密钥:用于加密客户端提交数据的密钥
• RC4:16位十六进制密钥,用于对称加密
• RSA:公钥用于客户端加密,私钥用于服务器解密
• 易加密:15-30位整数数组,逗号分隔
• 密钥由系统自动生成,确保安全性', - 'return-algorithm': '返回算法:服务器向客户端返回数据时使用的加密算法
• 不加密:数据明文传输,适用于内网环境
• RC4:对称加密,速度快,适用于一般场景
• RSA:非对称加密,安全性高,适用于敏感数据
• RSA(动态):动态生成密钥的RSA加密,安全性最高
• 易加密:自定义对称加密算法,使用15-30位整数密钥数组', - 'return-keys': '返回密钥:用于加密服务器返回数据的密钥
• RC4:16位十六进制密钥,用于对称加密
• RSA:公钥用于服务器加密,私钥用于客户端解密
• 易加密:15-30位整数数组,逗号分隔
• 密钥由系统自动生成,确保安全性', - 'api-status': '接口状态:控制当前API接口是否可用
• 启用:接口正常工作,客户端可以调用
• 禁用:接口暂停服务,客户端调用将返回错误', - 'variable-alias': '变量别名:变量的唯一标识符,必须以英文字母开头,只能包含数字和英文字母,用于在代码中引用该变量', - 'variable-app': '关联应用:选择变量所属的应用,选择"全局变量"表示该变量可在所有应用中使用', - 'variable-data': '变量数据:存储的具体数据内容,可以是文本、数字、JSON等格式,根据实际需要填写', - 'variable-remark': '备注:对该变量的说明和描述,帮助理解变量的用途和使用场景,可选填写', - 'function-alias': '函数别名:函数的唯一标识符,必须以英文字母开头,只能包含数字和英文字母,用于在代码中调用该函数', - 'function-app': '关联应用:选择函数所属的应用,选择"全局函数"表示该函数可在所有应用中使用', - 'function-code': '函数代码:存储的JavaScript代码内容,使用Goja引擎执行,支持ES5语法和部分ES6特性', - 'function-remark': '备注:对该函数的说明和描述,帮助理解函数的功能和使用场景,可选填写' - }; - return tips[type] || '暂无说明'; - } - - function routerTo({ - elem = '#router-view', - path = 'dashboard', - prefix = '/admin/', //路由前缀 - suffix = '', //路由后缀 - } = {}) { - var routerView = $(elem); - var url = prefix + path + suffix; - - var loadTimer = setTimeout(() => { - layer.load(2); - }, 100); - - history.replaceState({}, '', `#${path}`); - routerView.attr('src', url) - routerView.off('load').on('load',function(){ - element.render(); - form.render(); - clearTimeout(loadTimer); - layer.closeLast('loading'); - }) - - // 选中, 展开菜单 - $('#ws-nav-side') - .find("[data-path='" + path + "']") - .parent('dd') - .addClass('layui-this') - .closest('.layui-nav-item') - .addClass('layui-nav-itemed'); - } - - }); -}); - -function rippleViewTransition(isDark, callback) { - // 移植自 https://github.com/vuejs/vitepress/pull/2347 - // 支持 Chrome 111+ - - // 兼容 jQuery 3 下隐式 event 全局对象不可用的问题 - if (!window.event) { - window.event = new MouseEvent('click', { - clientX: document.documentElement.clientWidth, - clientY: 60, - }); - } - - const x = event.clientX; - const y = event.clientY; - const endRadius = Math.hypot(Math.max(x, innerWidth - x), Math.max(y, innerHeight - y)); - const transition = document.startViewTransition(function () { - callback && callback(); - }); - transition.ready.then(function () { - var clipPath = [`circle(0px at ${x}px ${y}px)`, `circle(${endRadius}px at ${x}px ${y}px)`]; - document.documentElement.animate( - { - clipPath: isDark ? clipPath : [...clipPath].reverse(), - }, - { - duration: 300, - easing: 'ease-in', - pseudoElement: isDark ? '::view-transition-new(root)' : '::view-transition-old(root)', - } - ); - }); -} - -function addStyle(id, cssStr) { - const el = document.getElementById(id) || document.createElement('style'); - if (!el.isConnected) { - el.type = 'text/css'; - el.id = id; - document.head.appendChild(el); - } - el.textContent = cssStr; -} - -function addLink(opt) { - return new Promise((resolve) => { - const link = Object.assign(document.createElement('link'), { - rel: 'stylesheet', - onload: () => resolve({ ...opt, status: 'success' }), - onerror: () => resolve({ ...opt, status: 'error' }), // 为了在 Promise.all 的使用场景 - ...opt, - }); - document.head.appendChild(link); - }); -} - -function loadScript(url, callback) { - const script = document.createElement('script'); - script.type = 'text/javascript'; - script.async = 'async'; - script.src = url; - document.body.appendChild(script); - if (script.readyState) { - script.onreadystatechange = function () { - if (script.readyState == 'complete' || script.readyState == 'loaded') { - script.onreadystatechange = null; - callback && callback(); - } - }; - } else { - script.onload = function () { - callback && callback(); - }; - } -} \ No newline at end of file diff --git a/web/static/lib/README.md b/web/static/lib/README.md deleted file mode 100644 index fffcd70..0000000 --- a/web/static/lib/README.md +++ /dev/null @@ -1,83 +0,0 @@ -# ColorMode 模块(WIP) - -开箱即用的主题切换(深色/浅色/自定义)模块,具有自动数据持久性。 - -**基本使用** - -```js -layui.use(['colorMode'], function () { - var colorMode = layui.colorMode - - var theme = colorMode.init() - - } -); -``` - -**配置** - -模块仅处理 DOM 属性更改,以便在 CSS 中应用正确的选择器,不会处理实际的样式,主题或 CSS。 -默认情况下,使用 auto 模式(与用户的浏览器首选项匹配),将类 dark 应用于 html 标签时启用深色模式,返回一个对象,用来获取和改变主题。 - -```js -var theme = colorMode.init() - -theme.mode() // 'dark' | 'light' - -theme.setMode('dark') // 设置为深色模式并持久化到 localstorage - -theme.setMode('auto') // 设置为 auto 模式 -``` - -也可以自定义以使其适用于大多数场景 - -```js -var theme = colorMode.init({ - selector: 'body', - attribute: 'theme-mode', - initialValue: 'light', - modes: { - auto: '', - light: 'light', - dark: 'dark', - contrast: 'dark contrast', - }, - storage: localStorage, - storageKey: 'xxx-theme-mode', - disableTransition: true, -}) -``` - -如果上述配置仍不能满足您的需求,可以使用 onChanged 选项完全控制处理更新的方式 - -```js -var theme = colorMode.init({ - onChanged: function(mode, defaultHandler){ - // 自定义更新方式 - } -}) -``` - -**API** - -```ts -/** - * @typedef {object} initOptions - * @prop {string} [selector='html'] - 应用于目标元素的 CSS 选择器 - * @prop {string} [attribute='class'] - 应用于目标元素的 HTML 属性 - * @prop {string} [initialValue='auto'] - 初始颜色模式 - * @prop {Object.} [modes]- 颜色模式。value 为添加到 HTML 属性上的值 - * @prop {(mode: string, defaultHandler: () => void) => void} [onChanged] - 用于处理更新的自定义处理程序,指定时,默认行为将被覆盖。mode 为颜色模式,defaultHandler 为默认处理程序 - * @prop {Storage} [storage=localStorage] - 将数据持久化到 localStorage/sessionStorage 的键。传递 `null` 以禁用持久性 - * @prop {string | null} [storageKey='color-scheme'] - 持久化使用的 key - * @prop {boolean} [disableTransition=true] - 禁用切换时的过渡 {@link https://paco.me/writing/disable-theme-transitions} - * - */ - -/** - * - * @param {initOptions} options - * @returns {{ mode: () => string; setMode: (mode: string) => void;}} - */ -colorMode.init(options) -``` diff --git a/web/static/lib/colorMode.js b/web/static/lib/colorMode.js deleted file mode 100755 index 1956241..0000000 --- a/web/static/lib/colorMode.js +++ /dev/null @@ -1,191 +0,0 @@ -/** - * WIP - * 移植自 https://github.com/vueuse/vueuse/tree/main/packages/core/useColorMode - */ -// @ts-ignore -layui.define(['jquery'], function (exports) { - 'use strict'; - - /** @type {jQuery}*/ - var $ = layui.jquery; - - var MOD_NAME = 'colorMode'; - var defaultWindow = window; - var document = defaultWindow.document; - - var colorMode = { - /** - * @typedef {object} initOptions - * @prop {string} [selector="html"] - 应用于目标元素的 CSS 选择器 - * @prop {string} [attribute="class"] - 应用于目标元素的 HTML 属性 - * @prop {string} [initialValue='auto'] - 初始颜色模式 - * @prop {Object.} [modes]- 颜色模式。value 为添加到 HTML 属性上的值 - * @prop {(mode: string, defaultHandler: (window?: Window) => void) => void} [onChanged] - 用于处理更新的自定义处理程序,指定时,默认行为将被覆盖。 - * @prop {Storage} [storage=localStorage] - 将数据持久化到 localStorage/sessionStorage 的键。传递 `null` 以禁用持久性 - * @prop {string | null} [storageKey='color-scheme'] - 持久化使用的 key - * @prop {boolean} [disableTransition=true] - 禁用切换时的过渡 {@link https://paco.me/writing/disable-theme-transitions} - * - */ - - /** - * - * @param {initOptions} options - * @returns {{mode: () => string; setMode: (mode: string, window?: Window) => void; }} - */ - init: function (options) { - var defaults = { - selector: 'html', - attribute: 'class', - initialValue: 'auto', - modes: { - auto: '', - light: 'light', - dark: 'dark', - }, - storage: localStorage, - storageKey: 'color-scheme', - disableTransition: true, - }; - - var opts = $.extend(true, {}, defaults, options); - - // 当前颜色模式 - var state; - // 系统颜色模式 - var system; - // 初始化 storage - var store = - opts.storageKey == null - ? opts.initialValue - : (function () { - var v = opts.storage.getItem(opts.storageKey); - if (!v) { - opts.storage.setItem(opts.storageKey, opts.initialValue); - return opts.initialValue; - } - return v; - })(); - - /** - * 更新 HTML 属性值 - * @param {String} selector - * @param {String} attribute - * @param {String} value - * @param {Window} win - */ - var updateHTMLAttrs = function (selector, attribute, value, win) { - win = win || defaultWindow; - var document = win.document; - var el = typeof selector === 'string' ? document.querySelector(selector) : undefined; - if (!el) return; - - /**@type HTMLStyleElement */ - var style; - - if (opts.disableTransition) { - style = document.createElement('style'); - style.appendChild( - document.createTextNode( - '*,*::before,*::after{-webkit-transition:none!important;-moz-transition:none!important;-o-transition:none!important;-ms-transition:none!important;transition:none!important}' - ) - ); - document.head.appendChild(style); - } - - if (attribute === 'class') { - var current = value.split(/\s/g); - $.each(opts.modes, function (_, modeval) { - $.each((modeval || '').split(/\s/g), function (_, v) { - if (!v) return; - if (current.indexOf(v) !== -1) { - el.classList.add(v); - } else { - el.classList.remove(v); - } - }); - }); - } else { - el.setAttribute(attribute, value); - } - - if (opts.disableTransition) { - // 调用 getComputedStyle 强制浏览器重绘 - // @ts-expect-error 未使用的变量 - var _ = window.getComputedStyle(style).opacity; - document.head.removeChild(style); - } - }; - - /** - * 更新状态 - * @param {String} mode - 颜色模式 - */ - var updateState = function (mode) { - store = opts.storageKey == null ? mode : opts.storage.getItem(opts.storageKey); - - state = store === 'auto' ? system : store; - }; - - var prefersColorScheme = function () { - var isSupported = window && 'matchMedia' in window && typeof window.matchMedia === 'function'; - if (!isSupported) { - system = 'light'; - onChanged(system); - return; - } - - var darkThemeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); - var update = function () { - var preferredDark = darkThemeMediaQuery.matches; - system = preferredDark ? 'dark' : 'light'; - onChanged(system); - }; - update(); - if ('addEventListener' in darkThemeMediaQuery) { - darkThemeMediaQuery.addEventListener('change', update); - } else { - // @ts-ignore 已弃用 - darkThemeMediaQuery.addListener(update); - } - }; - - prefersColorScheme(); - - function defaultOnChanged(win) { - updateHTMLAttrs(opts.selector, opts.attribute, opts.modes[state], win); - } - - function onChanged(mode, win) { - updateState(mode); - if (opts.onChanged) { - opts.onChanged(state, defaultOnChanged); - } else { - defaultOnChanged(win); - } - } - - return { - setMode: function (mode, win) { - if (opts.storageKey) { - opts.storage.setItem(opts.storageKey, mode); - } - onChanged(mode, win); - }, - mode: function () { - return state; - }, - }; - }, - addStyle: function (id, cssStr) { - var el = /** @type {HTMLStyleElement} */ (document.getElementById(id) || document.createElement('style')); - if (!el.isConnected) { - el.type = 'text/css'; - el.id = id; - document.head.appendChild(el); - } - el.textContent = cssStr; - }, - }; - - exports(MOD_NAME, colorMode); -}); diff --git a/web/static/lib/drawer/drawer.css b/web/static/lib/drawer/drawer.css deleted file mode 100644 index de1ecae..0000000 --- a/web/static/lib/drawer/drawer.css +++ /dev/null @@ -1,317 +0,0 @@ -.layer-drawer.layui-layer { - border-radius: 0 !important; - overflow: auto; -} - -.layer-drawer.layui-layer.position-absolute { - position: absolute !important; -} - -.layer-drawer-anim, -.layer-drawer-anim.layui-anim { - -webkit-animation-duration: .3s; - animation-duration: .3s; - -webkit-animation-timing-function: cubic-bezier(0.7, 0.3, 0.1, 1); - animation-timing-function: cubic-bezier(0.7, 0.3, 0.1, 1); -} - -/* right to left */ -@keyframes layer-rl { - from { - -webkit-transform: translate3d(100%, 0, 0); - -ms-transform: translate3d(100%, 0, 0); - transform: translate3d(100%, 0, 0); - opacity: 1; - - } - - to { - -webkit-transform: translate3d(0, 0, 0); - -ms-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - opacity: 1; - } -} - -@-webkit-keyframes layer-rl { - from { - -webkit-transform: translate3d(100%, 0, 0); - -ms-transform: translate3d(100%, 0, 0); - transform: translate3d(100%, 0, 0); - opacity: 1; - - } - - to { - -webkit-transform: translate3d(0, 0, 0); - -ms-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - opacity: 1; - } -} - -.layer-anim-rl { - -webkit-animation-name: layer-rl; - animation-name: layer-rl; -} - -/* right to left close */ -@keyframes layer-rl-close { - from { - -webkit-transform: translate3d(0, 0, 0); - -ms-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } - - to { - -webkit-transform: translate3d(100%, 0, 0); - -ms-transform: translate3d(100%, 0, 0); - transform: translate3d(100%, 0, 0); - } -} - -@-webkit-keyframes layer-rl-close { - from { - -webkit-transform: translate3d(0, 0, 0); - -ms-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - - } - - to { - -webkit-transform: translate3d(100%, 0, 0); - -ms-transform: translate3d(100%, 0, 0); - transform: translate3d(100%, 0, 0); - } -} - -.layer-anim-rl-close, -.layer-anim-rl.layer-anim-close { - -webkit-animation-name: layer-rl-close; - animation-name: layer-rl-close; -} - -/* left to right */ -@-webkit-keyframes layer-lr { - from { - -webkit-transform: translate3d(0, 0, 0); - -ms-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - opacity: 1 - } - - to { - -webkit-transform: translate3d(-100%, 0, 0); - -ms-transform: translate3d(-100%, 0, 0); - transform: translate3d(-100%, 0, 0); - opacity: 1 - } -} - -@keyframes layer-lr { - from { - -webkit-transform: translate3d(-100%, 0, 0); - -ms-transform: translate3d(-100%, 0, 0); - transform: translate3d(-100%, 0, 0); - opacity: 1 - } - - to { - -webkit-transform: translate3d(0, 0, 0); - -ms-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - opacity: 1 - } -} - -.layer-anim-lr { - -webkit-animation-name: layer-lr; - animation-name: layer-lr -} - -/* left to right close */ -@-webkit-keyframes layer-lr-close { - from { - -webkit-transform: translate3d(0, 0, 0); - -ms-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } - - to { - -webkit-transform: translate3d(-100%, 0, 0); - -ms-transform: translate3d(-100%, 0, 0); - transform: translate3d(-100%, 0, 0); - } -} - -@keyframes layer-lr-close { - from { - -webkit-transform: translate3d(0, 0, 0); - -ms-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } - - to { - -webkit-transform: translate3d(-100%, 0, 0); - -ms-transform: translate3d(-100%, 0, 0); - transform: translate3d(-100%, 0, 0); - } -} - -.layer-anim-lr-close, -.layer-anim-lr.layer-anim-close { - -webkit-animation-name: layer-lr-close; - animation-name: layer-lr-close -} - -/* top to bottom */ -@-webkit-keyframes layer-tb { - from { - -webkit-transform: translate3d(0, -100%, 0); - -ms-transform: translate3d(0, -100%, 0); - transform: translate3d(0, -100%, 0); - opacity: 1; - animation-timing-function: cubic-bezier(0.7, 0.3, 0.1, 1); - } - - to { - -webkit-transform: translate3d(0, 0, 0); - -ms-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - opacity: 1; - animation-timing-function: cubic-bezier(0.7, 0.3, 0.1, 1); - } -} - -@keyframes layer-tb { - from { - -webkit-transform: translate3d(0, -100%, 0); - -ms-transform: translate3d(0, -100%, 0); - transform: translate3d(0, -100%, 0); - opacity: 1; - animation-timing-function: cubic-bezier(0.7, 0.3, 0.1, 1); - } - - to { - -webkit-transform: translate3d(0, 0, 0); - -ms-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - opacity: 1; - animation-timing-function: cubic-bezier(0.7, 0.3, 0.1, 1); - } -} - -.layer-anim-tb { - -webkit-animation-name: layer-tb; - animation-name: layer-tb -} - -/* top to bottom close */ -@-webkit-keyframes layer-tb-close { - from { - -webkit-transform: translate3d(0, 0, 0); - -ms-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } - - to { - -webkit-transform: translate3d(0, -100%, 0); - -ms-transform: translate3d(0, -100%, 0); - transform: translate3d(0, -100%, 0); - } -} - -@keyframes layer-tb-close { - from { - -webkit-transform: translate3d(0, 0, 0); - -ms-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } - - to { - -webkit-transform: translate3d(0, -100%, 0); - -ms-transform: translate3d(0, -100%, 0); - transform: translate3d(0, -100%, 0); - } -} - -.layer-anim-tb-close, -.layer-anim-tb.layer-anim-close { - -webkit-animation-name: layer-tb-close; - animation-name: layer-tb-close -} - -/* bottom to top */ -@-webkit-keyframes layer-bt { - from { - -webkit-transform: translate3d(0, 100%, 0); - -ms-transform: translate3d(0, 100%, 0); - transform: translate3d(0, 100%, 0); - opacity: 1 - } - - to { - -webkit-transform: translate3d(0, 0, 0); - -ms-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - opacity: 1 - } -} - -@keyframes layer-bt { - from { - -webkit-transform: translate3d(0, 100%, 0); - -ms-transform: translate3d(0, 100%, 0); - transform: translate3d(0, 100%, 0); - opacity: 1 - } - - to { - -webkit-transform: translate3d(0, 0, 0); - -ms-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - opacity: 1 - } -} - -.layer-anim-bt { - -webkit-animation-name: layer-bt; - animation-name: layer-bt -} - -/* bottom to top close */ -@-webkit-keyframes layer-bt-close { - from { - -webkit-transform: translate3d(0, 0, 0); - -ms-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } - - to { - -webkit-transform: translate3d(0, 100%, 0); - -ms-transform: translate3d(0, 100%, 0); - transform: translate3d(0, 100%, 0); - } -} - -@keyframes layer-bt-close { - from { - -webkit-transform: translate3d(0, 0, 0); - -ms-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - - } - - to { - -webkit-transform: translate3d(0, 100%, 0); - -ms-transform: translate3d(0, 100%, 0); - transform: translate3d(0, 100%, 0); - - } -} - -.layer-anim-bt-close, -.layer-anim-bt.layer-anim-close { - -webkit-animation-name: layer-bt-close; - animation-name: layer-bt-close -} \ No newline at end of file diff --git a/web/static/lib/drawer/drawer.js b/web/static/lib/drawer/drawer.js deleted file mode 100755 index e37b398..0000000 --- a/web/static/lib/drawer/drawer.js +++ /dev/null @@ -1,200 +0,0 @@ -/** - * 抽屉模块 - */ -layui.define(['jquery', 'layer'], function (exports) { - ('use strict'); - - var MOD_NAME = 'drawer'; - var $ = layui.jquery; - var layer = layui.layer; - - layui.link(layui.cache.base + 'drawer/drawer.css'); - var drawer = new (function () { - this.open = function (option) { - return layerDrawer(option); - }; - this.title = layer.title; - this.style = layer.style; - this.close = layer.close; - this.closeAll = layer.closeAll; - })(); - - /** - * - * 封装 layer.open - * - * @param {object} option, `type`, `anim`, `move`, `fixed`, `skin`,`maxWidth`, `maxHeight`, `moveOut`, `moveEnd` 不可用,其它参数和 layer.open 一致, 新增 `iframe`和 `url`参数 - * @returns {number} 原生 layer 的 index - */ - function layerDrawer(option) { - var opt = normalizeOption(option); - if (opt.target) appendToTarget(opt); - if (opt.url) loadFragment(opt); - if (opt.shade) { - $('"].join(""),a=f(o.layHeader.html());a.append(o.layMain.find("table").html()),a.append(o.layTotal.find("table").html()),a.find("th.layui-table-patch").remove(),a.find("thead>tr>th."+F).filter(function(e,t){return!f(t).children("."+u).length}).remove(),a.find("tbody>tr>td."+F).remove(),t.document.write(e+a.prop("outerHTML")),t.document.close(),layui.device("edg").edg?(t.onafterprint=t.close,t.print()):(t.print(),t.close())}}});"object"==typeof e.defaultToolbar&&(l=[],e.defaultToolbar=f.map(e.defaultToolbar,function(e,t){var a="string"==typeof e,i=a?n[e]:e;return i&&(!(i=i.name&&n[i.name]?f.extend({},n[i.name],i):i).name&&a&&(i.name=e),l.push('
')),i}),o.layTool.find(".layui-table-tool-self").html(l.join("")))},n.prototype.renderPagebar=function(){var e,t=this.config,a=this.layPagebar=f('
');t.pagebar&&((e=f(t.pagebar).html()||"")&&a.append(m(e).render(t)),this.layPage.append(a))},n.prototype.setParentCol=function(e,t){var a=this.config,i=this.layHeader.find('th[data-key="'+t+'"]'),l=parseInt(i.attr("colspan"))||0;i[0]&&(t=t.split("-"),t=a.cols[t[1]][t[2]],e?l--:l++,i.attr("colspan",l),i[l?"removeClass":"addClass"](W),t.colspan2=l,t.hide=l<1,a=i.data("parentkey"))&&this.setParentCol(e,a)},n.prototype.setColsPatch=function(){var a=this,e=a.config;layui.each(e.cols,function(e,t){layui.each(t,function(e,t){t.hide&&a.setParentCol(t.hide,t.parentKey)})})},n.prototype.setGroupWidth=function(i){var e,l=this;l.config.cols.length<=1||((e=l.layHeader.find((i?"th[data-key="+i.data("parentkey")+"]>":"")+"."+u)).css("width",0),layui.each(e.get().reverse(),function(){var e=f(this),t=e.parent().data("key"),a=0;l.layHeader.eq(0).find("th[data-parentkey="+t+"]").width(function(e,t){f(this).hasClass(W)||0o.layMain.prop("clientHeight")&&(e.style.width=parseFloat(e.style.width)-i+"px")}),!p&&h?y.width(o.getContentWidth(l)):y.width("auto"),o.setGroupWidth()},n.prototype.resize=function(){var e=this;e.layMain&&("isConnected"in e.layMain[0]?e.layMain[0].isConnected:f.contains(document.body,e.layMain[0]))&&(e.fullSize(),e.setColsWidth(),e.scrollPatch())},n.prototype.reload=function(e,t,a){var i=this;e=e||{},delete i.haveInit,layui.each(e,function(e,t){"array"===layui.type(t)&&delete i.config[e]}),i.config=f.extend(t,{},i.config,e),"reloadData"!==a&&(layui.each(i.config.cols,function(e,t){layui.each(t,function(e,t){delete t.colspan2})}),delete i.config.HAS_SET_COLS_PATCH),i.render(a)},n.prototype.errorView=function(e){var t=this,a=t.layMain.find("."+h),e=f('
'+(e||"Error")+"
");a[0]&&(t.layNone.remove(),a.remove()),t.layFixed.addClass(W),t.layMain.find("tbody").html(""),t.layMain.append(t.layNone=e),t.layTotal.addClass(y),t.layPage.find(P).addClass(y),k.cache[t.key]=[],t.syncCheckAll(),t.renderForm(),t.setColsWidth(),t.loading(!1)},n.prototype.page=1,n.prototype.pullData=function(i,l){var e,t,n=this,o=n.config,a=(o.HAS_SET_COLS_PATCH||n.setColsPatch(),o.HAS_SET_COLS_PATCH=!0,o.request),d=o.response,r=function(){"object"==typeof o.initSort&&n.sort({field:o.initSort.field,type:o.initSort.type,reloadType:l.type})},c=function(e,t){n.setColsWidth(),n.loading(!1),"function"==typeof o.done&&o.done(e,i,e[d.countName],t)};l=l||{},"function"==typeof o.before&&o.before(o),n.startTime=(new Date).getTime(),l.renderData?((e={})[d.dataName]=k.cache[n.key],e[d.countName]=o.url?"object"===layui.type(o.page)?o.page.count:e[d.dataName].length:o.data.length,"object"==typeof o.totalRow&&(e[d.totalRowName]=f.extend({},n.totalRow)),n.renderData({res:e,curr:i,count:e[d.countName],type:l.type,sort:!0}),c(e,"renderData")):o.url?(t={},o.page&&(t[a.pageName]=i,t[a.limitName]=o.limit),a=f.extend(t,o.where),o.contentType&&0==o.contentType.indexOf("application/json")&&(a=JSON.stringify(a)),n.loading(!0),f.ajax({type:o.method||"get",url:o.url,contentType:o.contentType,data:a,dataType:o.dataType||"json",jsonpCallback:o.jsonpCallback,headers:o.headers||{},complete:"function"==typeof o.complete?o.complete:undefined,success:function(e){var t,a;(e="function"==typeof o.parseData?o.parseData(e)||e:e)[d.statusName]!=d.statusCode?n.errorView(e[d.msgName]||'\u8fd4\u56de\u7684\u6570\u636e\u4e0d\u7b26\u5408\u89c4\u8303\uff0c\u6b63\u786e\u7684\u6210\u529f\u72b6\u6001\u7801\u5e94\u4e3a\uff1a"'+d.statusName+'": '+d.statusCode):(t=e[d.countName],(a=Math.ceil(t/o.limit)||1)','
"+function(){var e,t=f.extend(!0,{LAY_COL:l},o),a=k.config.checkName,i=k.config.disabledName;switch(l.type){case"checkbox":return'';case"radio":return'';case"numbers":return c}return l.toolbar?m(f(l.toolbar).html()||"").render(t):T.call(s,{item3:l,content:n,tplData:t})}(),"
"].join(""),i.push(e),l.fixed&&"right"!==l.fixed&&d.push(e),"right"===l.fixed&&r.push(e))}),e=['data-index="'+e+'"'],o[k.config.checkName]&&e.push('class="'+A+'"'),e=e.join(" "),y.push(""+i.join("")+""),h.push(""+d.join("")+""),p.push(""+r.join("")+""))}),{trs:y,trs_fixed:h,trs_fixed_r:p}},k.getTrHtml=function(e,t){e=C(e);return e.getTrHtml(t,null,e.page)},n.prototype.renderData=function(e){var a=this,i=a.config,t=e.res,l=e.curr,n=a.count=e.count,o=e.sort,d=t[i.response.dataName]||[],t=t[i.response.totalRowName],r=[],c=[],s=[],u=function(){if(!o&&a.sortKey)return a.sort({field:a.sortKey.field,type:a.sortKey.sort,pull:!0,reloadType:e.type});a.getTrHtml(d,o,l,{trs:r,trs_fixed:c,trs_fixed_r:s}),"fixed"===i.scrollPos&&"reloadData"===e.type||a.layBody.scrollTop(0),"reset"===i.scrollPos&&a.layBody.scrollLeft(0),a.layMain.find("."+h).remove(),a.layMain.find("tbody").html(r.join("")),a.layFixLeft.find("tbody").html(c.join("")),a.layFixRight.find("tbody").html(s.join("")),a.syncCheckAll(),a.renderForm(),a.fullSize(),a.haveInit?a.scrollPatch():setTimeout(function(){a.scrollPatch()},50),a.haveInit=!0,g.close(a.tipsIndex)};return k.cache[a.key]=d,a.layTotal[0==d.length?"addClass":"removeClass"](y),a.layPage[i.page||i.pagebar?"removeClass":"addClass"](W),a.layPage.find(P)[!i.page||0==n||0===d.length&&1==l?"addClass":"removeClass"](y),0===d.length?a.errorView(i.text.none):(a.layFixLeft.removeClass(W),o?u():(u(),a.renderTotal(d,t),a.layTotal&&a.layTotal.removeClass(W),void(i.page&&(i.page=f.extend({elem:"layui-table-page"+i.index,count:n,limit:i.limit,limits:i.limits||[10,20,30,40,50,60,70,80,90],groups:3,layout:["prev","page","next","skip","count","limit"],prev:'',next:'',jump:function(e,t){t||(a.page=e.curr,i.limit=e.limit,a.pullData(e.curr))}},i.page),i.page.count=n,p.render(i.page)))))},k.renderData=function(e){e=C(e);e&&e.pullData(e.page,{renderData:!0,type:"reloadData"})},n.prototype.renderTotal=function(e,o){var d,r=this,c=r.config,s={};c.totalRow&&(layui.each(e,function(e,i){"array"===layui.type(i)&&0===i.length||r.eachCols(function(e,t){var e=t.field||e,a=i[e];t.totalRow&&(s[e]=(s[e]||0)+(parseFloat(a)||0))})}),r.dataTotal=[],d=[],r.eachCols(function(e,t){var e=t.field||e,a=o&&o[t.field],i="totalRowDecimals"in t?t.totalRowDecimals:2,i=s[e]?parseFloat(s[e]||0).toFixed(i):"",i=(n=t.totalRowText||"",(l={LAY_COL:t})[e]=i,l=t.totalRow&&T.call(r,{item3:t,content:i,tplData:l})||n,a||l),l="string"==typeof(n=t.totalRow||c.totalRow)?m(n).render(f.extend({TOTAL_NUMS:a||s[e],TOTAL_ROW:o||{},LAY_COL:t},t)):i,n=(t.field&&r.dataTotal.push({field:t.field,total:f("
"+l+"
").text()}),['','
"+l,"
"].join(""));d.push(n)}),e=r.layTotal.find(".layui-table-patch"),r.layTotal.find("tbody").html(""+d.join("")+(e.length?e.get(0).outerHTML:"")+""))},n.prototype.getColElem=function(e,t){return e.eq(0).find(".laytable-cell-"+t+":eq(0)")},n.prototype.renderForm=function(e){this.config;var t=this.elem.attr("lay-filter");i.render(e,t)},n.prototype.renderFormByElem=function(a){layui.each(["input","select"],function(e,t){i.render(a.find(t))})},n.prototype.syncCheckAll=function(){var a,e=this,i=e.config,t=e.layHeader.find('input[name="layTableCheckbox"]'),l=k.checkStatus(e.key);t[0]&&(a=l.isAll,e.eachCols(function(e,t){"checkbox"===t.type&&(t[i.checkName]=a)}),t.prop({checked:l.isAll,indeterminate:!l.isAll&&l.data.length}))},n.prototype.setRowActive=function(e,t,a){this.config;e=this.layBody.find('tr[data-index="'+e+'"]');if(t=t||"layui-table-click",a)return e.removeClass(t);e.addClass(t),e.siblings("tr").removeClass(t)},n.prototype.setRowChecked=function(i){var a,e,l,t,n,o,d,r=this,c=r.config,s="all"===i.index,u="array"===layui.type(i.index),y=s||u;c.tree&&c.tree.view||y&&(r.layBox.addClass(O),"radio"===i.type)||(u&&(a={},layui.each(i.index,function(e,t){a[t]=!0}),i.index=a),e=r.layBody.children(".layui-table").children("tbody"),d=y?"tr":'tr[data-index="'+i.index+'"]',d=e.children(d),e=s?d:d.filter(u?function(){var e=f(this).data("index");return i.index[e]}:'[data-index="'+i.index+'"]'),i=f.extend({type:"checkbox"},i),l=k.cache[r.key],t="checked"in i,n=function(e){return"radio"===i.type||(t?i.checked:!e)},e.each(function(){var e=f(this),t=e.attr("data-index"),a=l[t];t&&"array"!==layui.type(a)&&!a[c.disabledName]&&(a=a[c.checkName]=n(e.hasClass(A)),e.toggleClass(A,!!a),"radio"===i.type)&&(o=t,e.siblings().removeClass(A))}),o&&layui.each(l,function(e,t){Number(o)!==Number(e)&&delete t[c.checkName]}),d=(u=(s=e.children("td").children(".layui-table-cell").children('input[lay-type="'+({radio:"layTableRadio",checkbox:"layTableCheckbox"}[i.type]||"checkbox")+'"]:not(:disabled)')).last()).closest(I),("radio"===i.type&&d.hasClass(W)?s.first():s).prop("checked",n(u.prop("checked"))),r.syncCheckAll(),y&&setTimeout(function(){r.layBox.removeClass(O)},100))},n.prototype.sort=function(l){var e,t=this,a={},i=t.config,n=i.elem.attr("lay-filter"),o=k.cache[t.key];"string"==typeof(l=l||{}).field&&(d=l.field,t.layHeader.find("th").each(function(e,t){var a=f(this),i=a.data("field");if(i===l.field)return l.field=a,d=i,!1}));try{var d=d||l.field.data("field"),r=l.field.data("key");if(t.sortKey&&!l.pull&&d===t.sortKey.field&&l.type===t.sortKey.sort)return;var c=t.layHeader.find("th .laytable-cell-"+r).find(E);t.layHeader.find("th").find(E).removeAttr("lay-sort"),c.attr("lay-sort",l.type||null),t.layFixed.find("th")}catch(s){b.error("Table modules: sort field '"+d+"' not matched")}t.sortKey={field:d,sort:l.type},i.autoSort&&("asc"===l.type?e=layui.sort(o,d,null,!0):"desc"===l.type?e=layui.sort(o,d,!0,!0):(e=layui.sort(o,k.config.initIndexName,null,!0),delete t.sortKey,delete i.initSort)),a[i.response.dataName]=e||o,t.renderData({res:a,curr:t.page,count:t.count,sort:!0,type:l.reloadType}),l.fromEvent&&(i.initSort={field:d,type:l.type},layui.event.call(l.field,R,"sort("+n+")",f.extend({config:i},i.initSort)))},n.prototype.loading=function(e){this.config.loading&&this.layBox.find(".layui-table-init").toggleClass(W,!e)},n.prototype.cssRules=function(t,a){var e=this.elem.children("style")[0];r.getStyleRules(e,function(e){if(e.selectorText===".laytable-cell-"+t)return a(e),!0})},n.prototype.fullSize=function(){var e,a,i=this,t=i.config,l=t.height;i.fullHeightGap?(l=d.height()-i.fullHeightGap)<135&&(l=135):i.parentDiv&&i.parentHeightGap?(l=f(i.parentDiv).height()-i.parentHeightGap)<135&&(l=135):i.customHeightFunc&&(l=i.customHeightFunc())<135&&(l=135),1
')).find("div").css({width:a}),e.find("tr").append(t)):e.find(".layui-table-patch").remove()};n(e.layHeader),n(e.layTotal);n=e.layMain.height()-i;e.layFixed.find(L).css("height",t.height()>=n?n:"auto").scrollTop(e.layMain.scrollTop()),e.layFixRight[k.cache[e.key]&&k.cache[e.key].length&&0');a.html(t),s.height&&a.css("max-height",s.height-(c.layTool.outerHeight()||50)),i.find("."+S)[0]||i.append(a),c.renderForm(),a.on("click",function(e){layui.stope(e)}),e.done&&e.done(a,t)};layui.stope(e),z.trigger("table.tool.panel.remove"),g.close(c.tipsIndex),layui.each(s.defaultToolbar,function(e,t){if(t.layEvent===a)return"function"==typeof t.onClick&&t.onClick({data:l,config:s,openPanel:n,elem:i}),!0}),layui.event.call(this,R,"toolbar("+o+")",f.extend({event:a,config:s},{}))}),c.layHeader.on("click","*[lay-event]",function(e){var t=f(this),a=t.attr("lay-event"),t=t.closest("th").data("key"),t=c.col(t);layui.event.call(this,R,"colTool("+o+")",f.extend({event:a,config:s,col:t},{}))}),c.layPagebar.on("click","*[lay-event]",function(e){var t=f(this).attr("lay-event");layui.event.call(this,R,"pagebar("+o+")",f.extend({event:t,config:s},{}))}),e.on("mousemove",function(e){var t=f(this),a=t.offset().left,e=e.clientX-a;t.data("unresize")||w.eventMoveElem||(r.allowResize=t.width()-e<=10,d.css("cursor",r.allowResize?"col-resize":""))}).on("mouseleave",function(){f(this);w.eventMoveElem||(r.allowResize=!1,d.css("cursor",""))}).on("mousedown",function(e){var t,a=f(this);r.allowResize&&(t=a.data("key"),e.preventDefault(),r.offset=[e.clientX,e.clientY],c.cssRules(t,function(e){var t=e.style.width||a.outerWidth();r.rule=e,r.ruleWidth=parseFloat(t),r.minWidth=a.data("minwidth")||s.cellMinWidth,r.maxWidth=a.data("maxwidth")||s.cellMaxWidth}),a.data(j,r),w.eventMoveElem=a)}),w.docEvent||z.on("mousemove",function(e){var t,a;w.eventMoveElem&&(t=w.eventMoveElem.data(j)||{},w.eventMoveElem.data("resizing",1),e.preventDefault(),t.rule)&&(e=t.ruleWidth+e.clientX-t.offset[0],a=w.eventMoveElem.closest("."+D).attr(N),a=C(a))&&((e=et.maxWidth&&(e=t.maxWidth),t.rule.style.width=e+"px",a.setGroupWidth(w.eventMoveElem),g.close(c.tipsIndex))}).on("mouseup",function(e){var t,a,i,l,n;w.eventMoveElem&&(i=(t=w.eventMoveElem).closest("."+D).attr(N),a=C(i))&&(i=t.data("key"),l=a.col(i),n=a.config.elem.attr("lay-filter"),r={},d.css("cursor",""),a.scrollPatch(),t.removeData(j),delete w.eventMoveElem,a.cssRules(i,function(e){l.width=parseFloat(e.style.width),layui.event.call(t[0],R,"colResized("+n+")",{col:l,config:a.config})}))}),w.docEvent=!0,e.on("click",function(e){var t=f(this),a=t.find(E),i=a.attr("lay-sort");if(!a[0]||1===t.data("resizing"))return t.removeData("resizing");c.sort({field:t,type:"asc"===i?"desc":"desc"===i?null:"asc",fromEvent:!0})}).find(E+" .layui-edge ").on("click",function(e){var t=f(this),a=t.index(),t=t.parents("th").eq(0).data("field");layui.stope(e),0===a?c.sort({field:t,type:"asc",fromEvent:!0}):c.sort({field:t,type:"desc",fromEvent:!0})}),c.commonMember=function(e){var a=f(this).parents("tr").eq(0).data("index"),t=c.layBody.find('tr[data-index="'+a+'"]'),i=(k.cache[c.key]||[])[a]||{},l={tr:t,config:s,data:k.clearCacheKey(i),dataCache:i,index:a,del:function(){k.cache[c.key][a]=[],t.remove(),c.scrollPatch()},update:function(e,t){c.updateRow({index:a,data:e=e||{},related:t},function(e,t){l.data[e]=t})},setRowChecked:function(e){c.setRowChecked(f.extend({index:a},e))}};return f.extend(l,e)}),t=(c.elem.on("click",'input[name="layTableCheckbox"]+',function(e){var t=f(this),a=t.closest("td"),t=t.prev(),i=(c.layBody.find('input[name="layTableCheckbox"]'),t.parents("tr").eq(0).data("index")),l=t[0].checked,n="layTableAllChoose"===t.attr("lay-filter");t[0].disabled||(n?c.setRowChecked({index:"all",checked:l}):c.setRowChecked({index:i,checked:l}),layui.stope(e),layui.event.call(t[0],R,"checkbox("+o+")",y.call(t[0],{checked:l,type:n?"all":"one",getCol:function(){return c.col(a.data("key"))}})))}),c.elem.on("click",'input[lay-type="layTableRadio"]+',function(e){var t=f(this),a=t.closest("td"),t=t.prev(),i=t[0].checked,l=t.parents("tr").eq(0).data("index");if(layui.stope(e),t[0].disabled)return!1;c.setRowChecked({type:"radio",index:l}),layui.event.call(t[0],R,"radio("+o+")",y.call(t[0],{checked:i,getCol:function(){return c.col(a.data("key"))}}))}),c.layBody.on("mouseenter","tr",function(){var e=f(this),t=e.index();e.data("off")||c.layBody.find("tr:eq("+t+")").addClass(_)}).on("mouseleave","tr",function(){var e=f(this),t=e.index();e.data("off")||c.layBody.find("tr:eq("+t+")").removeClass(_)}).on("click","tr",function(e){t.call(this,"row",e)}).on("dblclick","tr",function(e){t.call(this,"rowDouble",e)}).on("contextmenu","tr",function(e){s.defaultContextmenu||e.preventDefault(),t.call(this,"rowContextmenu",e)}),function(e,t){var a=f(this);if(!a.data("off")){if("rowContextmenu"!==e){var i=[".layui-form-checkbox",".layui-form-switch",".layui-form-radio","[lay-unrow]"].join(",");if(f(t.target).is(i)||f(t.target).closest(i)[0])return}layui.event.call(this,R,e+"("+o+")",y.call(a.children("td")[0],{e:t}))}}),n=function(e,t){var a,i,l;(e=f(e)).data("off")||(l=e.data("field"),i=e.data("key"),i=c.col(i),a=e.closest("tr").data("index"),a=k.cache[c.key][a],e.children(u),(i="function"==typeof i.edit?i.edit(a):i.edit)&&((i=f("textarea"===i?'':''))[0].value=(l=e.data("content")||a[l])===undefined||null===l?"":l,e.find("."+M)[0]||e.append(i),i.focus(),t)&&layui.stope(t))},i=(c.layBody.on("change","."+M,function(){var e=f(this),t=e.parent(),a=this.value,i=e.parent().data("field"),e=e.closest("tr").data("index"),e=k.cache[c.key][e],l=y.call(t[0],{value:a,field:i,oldValue:e[i],td:t,reedit:function(){setTimeout(function(){n(l.td);var e={};e[i]=l.oldValue,l.update(e)})},getCol:function(){return c.col(t.data("key"))}}),e={};e[i]=a,l.update(e),layui.event.call(t[0],R,"edit("+o+")",l)}).on("blur","."+M,function(){f(this).remove()}),c.layBody.on(s.editTrigger,"td",function(e){n(this,e)}).on("mouseenter","td",function(){a.call(this)}).on("mouseleave","td",function(){a.call(this,"hide")}),c.layTotal.on("mouseenter","td",function(){a.call(this)}).on("mouseleave","td",function(){a.call(this,"hide")}),"layui-table-grid-down"),a=function(e){var t=f(this),a=t.children(u);t.data("off")||t.parent().hasClass(H)||(e?t.find(".layui-table-grid-down").remove():!(a.prop("scrollWidth")>a.prop("clientWidth")||0'))},l=function(e,t){var a=f(this),i=a.parent(),l=i.data("key"),n=c.col(l),o=i.parent().data("index"),d=i.children(u),i="layui-table-cell-c",r=f('');"tips"===(t=t||n.expandedMode||s.cellExpandedMode)?c.tipsIndex=g.tips(['
',d.html(),"
",''].join(""),d[0],{tips:[3,""],time:-1,anim:-1,maxWidth:x.ios||x.android?300:c.elem.width()/2,isOutAnim:!1,skin:"layui-table-tips",success:function(e,t){e.find(".layui-table-tips-c").on("click",function(){g.close(t)})}}):(c.elem.find("."+i).trigger("click"),c.cssRules(l,function(e){var t=e.style.width,a=n.expandedWidth||s.cellExpandedWidth;atr").each(function(i){n.cols[i]=[],f(this).children().each(function(e){var t=f(this),a=t.attr("lay-data"),a=r.options(this,{attr:a?"lay-data":null,errorText:d+(a||t.attr("lay-options"))}),t=f.extend({title:t.text(),colspan:parseInt(t.attr("colspan"))||1,rowspan:parseInt(t.attr("rowspan"))||1},a);n.cols[i].push(t)})}),e.find("tbody>tr")),t=k.render(n);!a.length||o.data||t.config.url||(l=0,k.eachCols(t.config.id,function(e,i){a.each(function(e){n.data[e]=n.data[e]||{};var t=f(this),a=i.field;n.data[e][a]=t.children("td").eq(l).html()}),l++}),t.reloadData({data:n.data}))}),this},w.that={},w.config={},function(a,i,e,l){var n,o;l.colGroup&&(n=0,a++,l.CHILD_COLS=[],o=e+(parseInt(l.rowspan)||1),layui.each(i[o],function(e,t){t.parentKey?t.parentKey===l.key&&(t.PARENT_COL_INDEX=a,l.CHILD_COLS.push(t),c(a,i,o,t)):t.PARENT_COL_INDEX||1<=n&&n==(l.colspan||1)||(t.PARENT_COL_INDEX=a,l.CHILD_COLS.push(t),n+=parseInt(1td').filter('[data-field="'+e+'"]')}}})).replace(/"/g,'""'),n.push(a='"'+a+'"')):t.field&&"normal"!==t.type&&0==i&&(u[t.field]=!0)}),c.push(n.join(","))}),o&&layui.each(o.dataTotal,function(e,t){u[t.field]||s.push('"'+(t.total||"")+'"')}),r.join(",")+"\r\n"+c.join("\r\n")+"\r\n"+s.join(","))),d.download=(a.title||l.title||"table_"+(l.index||""))+"."+i,document.body.appendChild(d),d.click(),document.body.removeChild(d)},k.getOptions=l,k.hideCol=function(e,l){var n=C(e);n&&("boolean"===layui.type(l)?n.eachCols(function(e,t){var a=t.key,i=n.col(a),t=t.parentKey;i.hide!=l&&(i=i.hide=l,n.elem.find('*[data-key="'+a+'"]')[i?"addClass":"removeClass"](W),n.setParentCol(i,t))}):(l=layui.isArray(l)?l:[l],layui.each(l,function(e,l){n.eachCols(function(e,t){var a,i;l.field===t.field&&(a=t.key,i=n.col(a),t=t.parentKey,"hide"in l)&&i.hide!=l.hide&&(i=i.hide=!!l.hide,n.elem.find('*[data-key="'+a+'"]')[i?"addClass":"removeClass"](W),n.setParentCol(i,t))})})),f("."+S).remove(),n.resize())},k.reload=function(e,t,a,i){if(l(e))return(e=C(e)).reload(t,a,i),w.call(e)},k.reloadData=function(){var a=f.extend([],arguments),i=(a[3]="reloadData",new RegExp("^("+["elem","id","cols","width","height","maxHeight","toolbar","defaultToolbar","className","css","pagebar"].join("|")+")$"));return layui.each(a[1],function(e,t){i.test(e)&&delete a[1][e]}),k.reload.apply(null,a)},k.render=function(e){e=new n(e);return w.call(e)},k.clearCacheKey=function(e){return delete(e=f.extend({},e))[k.config.checkName],delete e[k.config.indexName],delete e[k.config.initIndexName],delete e[k.config.numbersName],delete e[k.config.disabledName],e},f(function(){k.init()}),s(R,k)});layui.define(["table"],function(e){"use strict";var A=layui.$,h=layui.form,P=layui.table,y=layui.hint(),B={config:{},on:P.on,eachCols:P.eachCols,index:P.index,set:function(e){var t=this;return t.config=A.extend({},t.config,e),t},resize:P.resize,getOptions:P.getOptions,hideCol:P.hideCol,renderData:P.renderData},i=function(){var a=this,e=a.config,n=e.id||e.index;return{config:e,reload:function(e,t){a.reload.call(a,e,t)},reloadData:function(e,t){B.reloadData(n,e,t)}}},j=function(e){var t=i.that[e];return t||y.error(e?"The treeTable instance with ID '"+e+"' not found":"ID argument required"),t||null},F="lay-table-id",L="layui-hide",s=".layui-table-body",q=".layui-table-main",R=".layui-table-fixed-l",Y=".layui-table-fixed-r",l="layui-table-checked",m="layui-table-tree",z="LAY_DATA_INDEX",b="LAY_DATA_INDEX_HISTORY",p="LAY_PARENT_INDEX",g="LAY_CHECKBOX_HALF",H="LAY_EXPAND",X="LAY_HAS_EXPANDED",V="LAY_ASYNC_STATUS",n=["all","parent","children","none"],t=/<[^>]+?>/,f=["flexIconClose","flexIconOpen","iconClose","iconOpen","iconLeaf","icon"],a=function(e){var t=this;t.index=++B.index,t.config=A.extend(!0,{},t.config,B.config,e),t.init(),t.render()},x=function(n,i,e){var l=P.cache[n];layui.each(e||l,function(e,t){var a=t[z]||"";-1!==a.indexOf("-")&&(l[a]=t),t[i]&&x(n,i,t[i])})},d=function(d,a,e){var r=j(d),o=("reloadData"!==e&&(r.status={expand:{}}),A.extend(!0,{},r.getOptions(),a)),n=o.tree,c=n.customName.children,i=n.customName.id,l=(delete a.hasNumberCol,delete a.hasChecboxCol,delete a.hasRadioCol,P.eachCols(null,function(e,t){"numbers"===t.type?a.hasNumberCol=!0:"checkbox"===t.type?a.hasChecboxCol=!0:"radio"===t.type&&(a.hasRadioCol=!0)},o.cols),a.parseData),u=a.done;"reloadData"===e&&"fixed"===o.scrollPos&&(r.scrollTopCache=r.config.elem.next().find(s).scrollTop()),o.url?e&&(!l||l.mod)||(a.parseData=function(){var e=this,t=arguments,a=t[0],t=("function"===layui.type(l)&&(a=l.apply(e,t)||t[0]),e.response.dataName);return n.data.isSimpleData&&!n["async"].enable&&(a[t]=r.flatToTree(a[t])),N(a[t],function(e){e[H]=H in e?e[H]:e[i]!==undefined&&r.status.expand[e[i]]},c),e.autoSort&&e.initSort&&e.initSort.type&&layui.sort(a[t],e.initSort.field,"desc"===e.initSort.type,!0),r.initData(a[t]),a},a.parseData.mod=!0):a.data!==undefined&&(a.data=a.data||[],n.data.isSimpleData&&(a.data=r.flatToTree(a.data)),r.initData(a.data)),e&&(!u||u.mod)||(a.done=function(){var e,t=arguments,a=t[3],n="renderData"===a,i=(n||delete r.isExpandAll,this.elem.next()),l=(r.updateStatus(null,{LAY_HAS_EXPANDED:!1}),x(d,c),i.find('[name="layTableCheckbox"][lay-filter="layTableAllChoose"]'));if(l.length&&(e=B.checkStatus(d),l.prop({checked:e.isAll&&e.data.length,indeterminate:!e.isAll&&e.data.length})),!n&&o.autoSort&&o.initSort&&o.initSort.type&&B.sort(d),r.renderTreeTable(i),"reloadData"===a&&"fixed"===this.scrollPos&&i.find(s).scrollTop(r.scrollTopCache),"function"===layui.type(u))return u.apply(this,t)},a.done.mod=!0),a&&a.tree&&a.tree.view&&layui.each(f,function(e,t){a.tree.view[t]!==undefined&&(a.tree.view[t]=r.normalizedIcon(a.tree.view[t]))})};a.prototype.init=function(){var e=this.config,t=e.tree.data.cascade,t=(-1===n.indexOf(t)&&(e.tree.data.cascade="all"),P.render(A.extend({},e,{data:[],url:"",done:null}))),a=t.config.id;(i.that[a]=this).tableIns=t,d(a,e)},a.prototype.config={tree:{customName:{children:"children",isParent:"isParent",name:"name",id:"id",pid:"parentId",icon:"icon"},view:{indent:14,flexIconClose:'',flexIconOpen:'',showIcon:!0,icon:"",iconClose:'',iconOpen:'',iconLeaf:'',showFlexIconIfNotParent:!1,dblClickExpand:!0,expandAllDefault:!1},data:{isSimpleData:!1,rootPid:null,cascade:"all"},"async":{enable:!1,url:"",type:null,contentType:null,headers:null,where:null,autoParam:[]},callback:{beforeExpand:null,onExpand:null}}},a.prototype.normalizedIcon=function(e){return e?t.test(e)?e:'':""},a.prototype.getOptions=function(){return this.tableIns?P.getOptions(this.tableIns.config.id):this.config},a.prototype.flatToTree=function(e){var n,i,l,d,r,o,c,u,t=this.getOptions(),a=t.tree,s=a.customName,t=t.id;return e=e||P.cache[t],t=e,n=s.id,i=s.pid,l=s.children,d=a.data.rootPid,n=n||"id",i=i||"parentId",l=l||"children",c={},u=[],layui.each(t,function(e,t){r=n+t[n],o=n+t[i],c[r]||(c[r]={},c[r][l]=[]);var a={};a[l]=c[r][l],c[r]=A.extend({},t,a),((d?c[r][i]===d:!c[r][i])?u:(c[o]||(c[o]={},c[o][l]=[]),c[o][l])).push(c[r])}),u},a.prototype.treeToFlat=function(e,n,i){var l=this,d=l.getOptions().tree.customName,r=d.children,o=d.pid,c=[];return layui.each(e,function(e,t){var e=(i?i+"-":"")+e,a=A.extend({},t);a[o]="undefined"!=typeof t[o]?t[o]:n,c.push(a),c=c.concat(l.treeToFlat(t[r],t[d.id],e))}),c},a.prototype.getTreeNode=function(e){var t,a,n=this;return e?(a=(t=n.getOptions()).tree,t.id,a.customName,{data:e,dataIndex:e[z],getParentNode:function(){return n.getNodeByIndex(e[p])}}):y.error("\u627e\u4e0d\u5230\u8282\u70b9\u6570\u636e")},a.prototype.getNodeByIndex=function(t){var a,e,n=this,i=n.getNodeDataByIndex(t);return i?((e=n.getOptions()).tree.customName.parent,a=e.id,(e={data:i,dataIndex:i[z],getParentNode:function(){return n.getNodeByIndex(i[p])},update:function(e){return B.updateNode(a,t,e)},remove:function(){return B.removeNode(a,t)},expand:function(e){return B.expandNode(a,A.extend({},e,{index:t}))},setChecked:function(e){return B.setRowChecked(a,A.extend({},e,{index:t}))}}).dataIndex=t,e):y.error("\u627e\u4e0d\u5230\u8282\u70b9\u6570\u636e")},a.prototype.getNodeById=function(a){var e=this.getOptions(),n=e.tree.customName.id,i="",e=B.getData(e.id,!0);if(layui.each(e,function(e,t){if(t[n]===a)return i=t[z],!0}),i)return this.getNodeByIndex(i)},a.prototype.getNodeDataByIndex=function(e,t,a){var n=this.getOptions(),i=n.tree,n=n.id,n=P.cache[n],l=n[e];if("delete"!==a&&l)return A.extend(l,a),t?A.extend({},l):l;for(var d=n,r=String(e).split("-"),o=0,c=i.customName.children;o
'),N=function(e){y[V]="success",y[s.children]=e,c.initData(y[s.children],y[z]),J(t,!0,!p&&n,i,l)},C=m.format,"function"===layui.type(C)?C(y,o,N):(I=A.extend({},m.where||o.where),C=m.autoParam,layui.each(C,function(e,t){t=t.split("=");I[t[0].trim()]=y[(t[1]||t[0]).trim()]}),(C=m.contentType||o.contentType)&&0==C.indexOf("application/json")&&(I=JSON.stringify(I)),O=m.method||o.method,D=m.dataType||o.dataType,T=m.jsonpCallback||o.jsonpCallback,_=m.headers||o.headers,k=m.parseData||o.parseData,w=m.response||o.response,A.ajax({type:O||"get",url:b,contentType:C,data:I,dataType:D||"json",jsonpCallback:T,headers:_||{},success:function(e){(e="function"==typeof k?k.call(o,e)||e:e)[w.statusName]!=w.statusCode?(y[V]="error",y[H]=!1,g.html('')):N(e[w.dataName])},error:function(e,t){y[V]="error",y[H]=!1,"function"==typeof o.error&&o.error(e,t)}})),h;y[X]=!0,v.length&&(!o.initSort||o.url&&!o.autoSort||((m=o.initSort).type?layui.sort(v,m.field,"desc"===m.type,!0):layui.sort(v,P.config.indexName,null,!0)),c.initData(y[s.children],y[z]),O=P.getTrHtml(r,v,null,null,e),S={trs:A(O.trs.join("")),trs_fixed:A(O.trs_fixed.join("")),trs_fixed_r:A(O.trs_fixed_r.join(""))},E=(e.split("-").length-1||0)+1,layui.each(v,function(e,t){S.trs.eq(e).attr({"data-index":t[z],"lay-data-index":t[z],"data-level":E}).data("index",t[z]),S.trs_fixed.eq(e).attr({"data-index":t[z],"lay-data-index":t[z],"data-level":E}).data("index",t[z]),S.trs_fixed_r.eq(e).attr({"data-index":t[z],"lay-data-index":t[z],"data-level":E}).data("index",t[z])}),d.find(q).find('tbody tr[lay-data-index="'+e+'"]').after(S.trs),d.find(R).find('tbody tr[lay-data-index="'+e+'"]').after(S.trs_fixed),d.find(Y).find('tbody tr[lay-data-index="'+e+'"]').after(S.trs_fixed_r),c.renderTreeTable(S.trs,E),n)&&!p&&layui.each(v,function(e,t){J({dataIndex:t[z],trElem:d.find('tr[lay-data-index="'+t[z]+'"]').first(),tableViewElem:d,tableId:r,options:o},a,n,i,l)})}else c.isExpandAll=!1,(n&&!p?(layui.each(v,function(e,t){J({dataIndex:t[z],trElem:d.find('tr[lay-data-index="'+t[z]+'"]').first(),tableViewElem:d,tableId:r,options:o},a,n,i,l)}),d.find(v.map(function(e,t,a){return'tr[lay-data-index="'+e[z]+'"]'}).join(","))):(b=c.treeToFlat(v,y[s.id],e),d.find(b.map(function(e,t,a){return'tr[lay-data-index="'+e[z]+'"]'}).join(",")))).addClass(L);U("resize-"+r,function(){B.resize(r)},0)(),l&&"loading"!==y[V]&&(C=u.callback.onExpand,"function"===layui.type(C))&&C(r,y,x)}return h},v=(B.expandNode=function(e,t){var a,n,i,e=j(e);if(e)return a=(t=t||{}).index,n=t.expandFlag,i=t.inherit,t=t.callbackFlag,e=e.getOptions().elem.next(),J({trElem:e.find('tr[lay-data-index="'+a+'"]').first()},n,i,null,t)},B.expandAll=function(a,e){if("boolean"!==layui.type(e))return y.error("expandAll \u7684\u5c55\u5f00\u72b6\u6001\u53c2\u6570\u53ea\u63a5\u6536true/false");var t=j(a);if(t){t.isExpandAll=e;var n=t.getOptions(),i=n.tree,l=n.elem.next(),d=i.customName.isParent,r=i.customName.id,o=i.view.showFlexIconIfNotParent;if(e){e=B.getData(a,!0);if(i["async"].enable){var c=!0;if(layui.each(e,function(e,t){if(t[d]&&!t[V])return!(c=!1)}),!c)return void layui.each(B.getData(a),function(e,t){B.expandNode(a,{index:t[z],expandFlag:!0,inherit:!0})})}var u=!0;if(layui.each(e,function(e,t){if(t[d]&&!t[X])return!(u=!1)}),u)t.updateStatus(null,function(e){(e[d]||o)&&(e[H]=!0,e[r]!==undefined)&&(t.status.expand[e[r]]=!0)}),l.find('tbody tr[data-level!="0"]').removeClass(L),l.find(".layui-table-tree-flexIcon").html(i.view.flexIconOpen),i.view.showIcon&&l.find(".layui-table-tree-nodeIcon:not(.layui-table-tree-iconCustom,.layui-table-tree-iconLeaf)").html(i.view.iconOpen);else{if(t.updateStatus(null,function(e){(e[d]||o)&&(e[H]=!0,e[X]=!0,e[r]!==undefined)&&(t.status.expand[e[r]]=!0)}),n.initSort&&n.initSort.type&&n.autoSort)return B.sort(a);var s,n=P.getTrHtml(a,e),f={trs:A(n.trs.join("")),trs_fixed:A(n.trs_fixed.join("")),trs_fixed_r:A(n.trs_fixed_r.join(""))};layui.each(e,function(e,t){var a=t[z].split("-").length-1;s={"data-index":t[z],"lay-data-index":t[z],"data-level":a},f.trs.eq(e).attr(s).data("index",t[z]),f.trs_fixed.eq(e).attr(s).data("index",t[z]),f.trs_fixed_r.eq(e).attr(s).data("index",t[z])}),layui.each(["main","fixed-l","fixed-r"],function(e,t){l.find(".layui-table-"+t+" tbody").html(f[["trs","trs_fixed","trs_fixed_r"][e]])}),t.renderTreeTable(l,0,!1)}}else t.updateStatus(null,function(e){(e[d]||o)&&(e[H]=!1,e[r]!==undefined)&&(t.status.expand[e[r]]=!1)}),l.find('.layui-table-box tbody tr[data-level!="0"]').addClass(L),l.find(".layui-table-tree-flexIcon").html(i.view.flexIconClose),i.view.showIcon&&l.find(".layui-table-tree-nodeIcon:not(.layui-table-tree-iconCustom,.layui-table-tree-iconLeaf)").html(i.view.iconClose);B.resize(a)}},a.prototype.updateNodeIcon=function(e){var t=this.getOptions().tree||{},a=e.scopeEl,n=e.isExpand,e=e.isParent;a.find(".layui-table-tree-flexIcon").css("visibility",e||t.view.showFlexIconIfNotParent?"visible":"hidden").html(n?t.view.flexIconOpen:t.view.flexIconClose),t.view.showIcon&&(a=a.find(".layui-table-tree-nodeIcon:not(.layui-table-tree-iconCustom)"),n=e?n?t.view.iconOpen:t.view.iconClose:t.view.iconLeaf,a.toggleClass("layui-table-tree-iconLeaf",!e).html(n))},a.prototype.renderTreeTable=function(e,t,a){var l=this,n=l.getOptions(),d=n.elem.next(),i=(d.hasClass(m)||d.addClass(m),n.id),r=n.tree||{},o=(r.data,r.view||{}),c=r.customName||{},u=c.isParent,s=(d.attr("lay-filter"),l),f=n.data.length,y=((t=t||0)||(d.find(".layui-table-body tr:not([data-level])").attr("data-level",t),layui.each(P.cache[i],function(e,t){f&&(t[z]=String(e));t=t[z];d.find('.layui-table-main tbody tr[data-level="0"]:eq('+e+")").attr("lay-data-index",t),d.find('.layui-table-fixed-l tbody tr[data-level="0"]:eq('+e+")").attr("lay-data-index",t),d.find('.layui-table-fixed-r tbody tr[data-level="0"]:eq('+e+")").attr("lay-data-index",t)})),null),p=c.name,x=o.indent||14;if(layui.each(e.find('td[data-field="'+p+'"]'),function(e,t){var a,n,i=(t=A(t)).closest("tr"),t=t.children(".layui-table-cell");t.hasClass("layui-table-tree-item")||(n=i.attr("lay-data-index"))&&(i=d.find('tr[lay-data-index="'+n+'"]'),(a=s.getNodeDataByIndex(n))[H]&&a[u]&&((y=y||{})[n]=!0),a[g]&&i.find('input[type="checkbox"][name="layTableCheckbox"]').prop("indeterminate",!0),n=t.html(),(t=i.find('td[data-field="'+p+'"]>div.layui-table-cell')).addClass("layui-table-tree-item"),t.html(['
',a[H]?o.flexIconOpen:o.flexIconClose,"
",o.showIcon?'
'+(l.normalizedIcon(a[c.icon])||o.icon||(a[u]?a[H]?o.iconOpen:o.iconClose:o.iconLeaf)||"")+"
":"",n].join("")).find(".layui-table-tree-flexIcon").on("click",function(e){layui.stope(e),J({trElem:i},null,null,null,!0)}))}),!t&&r.view.expandAllDefault&&l.isExpandAll===undefined)return B.expandAll(i,!0);(!1!==a&&y?(layui.each(y,function(e,t){e=d.find('tr[lay-data-index="'+e+'"]');e.find(".layui-table-tree-flexIcon").html(o.flexIconOpen),J({trElem:e.first()},!0)}),U("renderTreeTable2-"+i,function(){h.render(A(".layui-table-tree["+F+'="'+i+'"]'))},0)):U("renderTreeTable-"+i,function(){n.hasNumberCol&&v(l),h.render(A(".layui-table-tree["+F+'="'+i+'"]'))},0))()},function(a){var e=a.getOptions(),t=e.elem.next(),n=0,i=t.find(".layui-table-main tbody tr"),l=t.find(".layui-table-fixed-l tbody tr"),d=t.find(".layui-table-fixed-r tbody tr");layui.each(a.treeToFlat(P.cache[e.id]),function(e,t){t.LAY_HIDE||(a.getNodeDataByIndex(t[z]).LAY_NUM=++n,i.eq(e).find(".laytable-cell-numbers").html(n),l.eq(e).find(".laytable-cell-numbers").html(n),d.eq(e).find(".laytable-cell-numbers").html(n))})}),N=(a.prototype.render=function(e){var t=this;t.tableIns=P["reloadData"===e?"reloadData":"reload"](t.tableIns.config.id,A.extend(!0,{},t.config)),t.config=t.tableIns.config},a.prototype.reload=function(e,t,a){var n=this;e=e||{},delete n.haveInit,layui.each(e,function(e,t){"array"===layui.type(t)&&delete n.config[e]}),d(n.getOptions().id,e,a||!0),n.config=A.extend(t,{},n.config,e),n.render(a)},B.reloadData=function(){var e=A.extend(!0,[],arguments);return e[3]="reloadData",B.reload.apply(null,e)},function(e,a,n,i){var l=[];return layui.each(e,function(e,t){"function"===layui.type(a)?a(t):A.extend(t,a),l.push(A.extend({},t)),i||(l=l.concat(N(t[n],a,n,i)))}),l}),o=(a.prototype.updateStatus=function(e,t,a){var n=this.getOptions(),i=n.tree;return e=e||P.cache[n.id],N(e,t,i.customName.children,a)},a.prototype.getTableData=function(){var e=this.getOptions();return P.cache[e.id]},B.updateStatus=function(e,t,a){var e=j(e),n=e.getOptions();return a=a||(n.url?P.cache[n.id]:n.data),e.updateStatus(a,t)},B.sort=function(e){var t,a,i,l,n,d=j(e);d&&(n=(t=d.getOptions()).tree,a=B.getData(e),i=n.customName.children,l=function(e,a,n){layui.sort(e,a,n,!0),layui.each(e,function(e,t){l(t[i]||[],a,n)})},t.autoSort)&&((n=t.initSort).type?l(a,n.field,"desc"===n.type):l(a,P.config.indexName,null),P.cache[e]=a,d.initData(a),B.renderData(e))},function(n){var t=n.config.id,i=j(t),a=n.data=B.getNodeDataByIndex(t,n.index),l=a[z],d=(n.dataIndex=l,n.update);n.update=function(){var e=arguments,t=(A.extend(i.getNodeDataByIndex(l),e[0]),d.apply(this,e)),a=n.config.tree.customName.name;return a in e[0]&&n.tr.find('td[data-field="'+a+'"]').children("div.layui-table-cell").removeClass("layui-table-tree-item"),i.renderTreeTable(n.tr,n.tr.attr("data-level"),!1),t},n.del=function(){B.removeNode(t,a)},n.setRowChecked=function(e){B.setRowChecked(t,{index:a,checked:e})}}),u=(B.updateNode=function(e,a,t){var n,i,l,d,r,o=j(e);o&&((d=o.getOptions()).tree,d=(n=d.elem.next()).find('tr[lay-data-index="'+a+'"]'),i=d.attr("data-index"),l=d.attr("data-level"),t)&&(d=o.getNodeDataByIndex(a,!1,t),r=P.getTrHtml(e,[d]),layui.each(["main","fixed-l","fixed-r"],function(e,t){n.find(".layui-table-"+t+' tbody tr[lay-data-index="'+a+'"]').replaceWith(A(r[["trs","trs_fixed","trs_fixed_r"][e]].join("")).attr({"data-index":i,"lay-data-index":a,"data-level":l}).data("index",i))}),o.renderTreeTable(n.find('tr[lay-data-index="'+a+'"]'),l))},B.removeNode=function(e,t,a){var n=j(e);if(n){var i,l=n.getOptions(),d=l.tree,r=d.customName.isParent,o=d.customName.children,c=l.elem.next(),u=[],s=P.cache[e],t=n.getNodeDataByIndex("string"===layui.type(t)?t:t[z],!1,"delete"),f=n.getNodeDataByIndex(t[p]),d=(n.updateCheckStatus(f),n.treeToFlat([t],t[d.customName.pid],t[p])),t=(layui.each(d,function(e,t){t=t[z];u.push('tr[lay-data-index="'+t+'"]'),-1!==t.indexOf("-")&&delete s[t]}),c.find(u.join(",")).remove(),n.initData());for(i in s)-1!==i.indexOf("-")&&i!==s[i][z]&&delete s[i];layui.each(n.treeToFlat(t),function(e,t){t[b]&&t[b]!==t[z]&&c.find('tr[lay-data-index="'+t[b]+'"]').attr({"data-index":t[z],"lay-data-index":t[z]}).data("index",t[z])}),layui.each(s,function(e,t){c.find('tr[data-level="0"][lay-data-index="'+t[z]+'"]').attr("data-index",e).data("index",e)}),l.hasNumberCol&&v(n),f&&(d=c.find('tr[lay-data-index="'+f[z]+'"]'),a||(f[r]=!(!f[o]||!f[o].length)),n.updateNodeIcon({scopeEl:d,isExpand:f[H],isParent:f[r]})),B.resize(e)}},B.addNodes=function(e,t){var a=j(e);if(a){var n=a.getOptions(),i=n.tree,l=n.elem.next(),d=P.config.checkName,r=(t=t||{}).parentIndex,o=t.index,c=t.data,t=t.focus,u=(r="number"===layui.type(r)?r.toString():r)?a.getNodeDataByIndex(r):null,o="number"===layui.type(o)?o:-1,c=A.extend(!0,[],layui.isArray(c)?c:[c]);layui.each(c,function(e,t){d in t||!u||(t[d]=u[d])}),a.getTableData();if(u){var s=i.customName.isParent,f=i.customName.children;u[s]=!0;var y=(y=u[f])?(p=y.splice(-1===o?y.length:o),u[f]=y.concat(c,p)):u[f]=c,f=(a.updateStatus(y,function(e){(e[s]||i.view.showFlexIconIfNotParent)&&(e[X]=!1)}),a.treeToFlat(y));l.find(f.map(function(e){return'tr[lay-data-index="'+e[z]+'"]'}).join(",")).remove(),a.initData(),u[X]=!1,u[V]="local",J({trElem:l.find('tr[lay-data-index="'+r+'"]')},!0)}else{var p=P.cache[e].splice(-1===o?P.cache[e].length:o);if(P.cache[e]=P.cache[e].concat(c,p),n.url||(n.page?(y=n.page,n.data.splice.apply(n.data,[y.limit*(y.curr-1),y.limit].concat(P.cache[e]))):n.data=P.cache[e]),a.initData(),l.find(".layui-none").length)return P.renderData(e),c;var x,f=P.getTrHtml(e,c),h={trs:A(f.trs.join("")),trs_fixed:A(f.trs_fixed.join("")),trs_fixed_r:A(f.trs_fixed_r.join(""))},r=(layui.each(c,function(e,t){x={"data-index":t[z],"lay-data-index":t[z],"data-level":"0"},h.trs.eq(e).attr(x).data("index",t[z]),h.trs_fixed.eq(e).attr(x).data("index",t[z]),h.trs_fixed_r.eq(e).attr(x).data("index",t[z])}),parseInt(c[0][z])-1),y=l.find(q),n=l.find(R),f=l.find(Y);-1==r?y.find('tr[data-level="0"][data-index="0"]')[0]?(y.find('tr[data-level="0"][data-index="0"]').before(h.trs),n.find('tr[data-level="0"][data-index="0"]').before(h.trs_fixed),f.find('tr[data-level="0"][data-index="0"]').before(h.trs_fixed_r)):(y.find("tbody").prepend(h.trs),n.find("tbody").prepend(h.trs_fixed),f.find("tbody").prepend(h.trs_fixed_r)):-1===o?(y.find("tbody").append(h.trs),n.find("tbody").append(h.trs_fixed),f.find("tbody").append(h.trs_fixed_r)):(r=p[0][b],y.find('tr[data-level="0"][data-index="'+r+'"]').before(h.trs),n.find('tr[data-level="0"][data-index="'+r+'"]').before(h.trs_fixed),f.find('tr[data-level="0"][data-index="'+r+'"]').before(h.trs_fixed_r)),layui.each(P.cache[e],function(e,t){l.find('tr[data-level="0"][lay-data-index="'+t[z]+'"]').attr("data-index",e).data("index",e)}),a.renderTreeTable(l.find(c.map(function(e,t,a){return'tr[lay-data-index="'+e[z]+'"]'}).join(",")))}return a.updateCheckStatus(u),u&&(o=l.find('tr[lay-data-index="'+u[z]+'"]'),a.updateNodeIcon({scopeEl:o,isExpand:u[H],isParent:u[s]})),B.resize(e),t&&l.find(q).find('tr[lay-data-index="'+c[0][z]+'"]').get(0).scrollIntoViewIfNeeded(),c}},B.checkStatus=function(e,n){var i,t,a,l=j(e);if(l)return l=l.getOptions().tree,i=P.config.checkName,t=B.getData(e,!0).filter(function(e,t,a){return e[i]||n&&e[g]}),a=!0,layui.each("all"===l.data.cascade?P.cache[e]:B.getData(e,!0),function(e,t){if(!t[i])return!(a=!1)}),{data:t,isAll:a}},B.on("sort",function(e){var e=e.config,t=e.elem.next(),e=e.id;t.hasClass(m)&&B.sort(e)}),B.on("row",function(e){e.config.elem.next().hasClass(m)&&o(e)}),B.on("rowDouble",function(e){var t=e.config,a=t.elem.next();t.id;a.hasClass(m)&&(o(e),(t.tree||{}).view.dblClickExpand)&&J({trElem:e.tr.first()},null,null,null,!0)}),B.on("rowContextmenu",function(e){var t=e.config,a=t.elem.next();t.id;a.hasClass(m)&&o(e)}),B.on("tool",function(e){var t=e.config,a=t.elem.next();t.id;a.hasClass(m)&&o(e)}),B.on("edit",function(e){var t=e.config,a=t.elem.next();t.id;a.hasClass(m)&&(o(e),e.field===t.tree.customName.name)&&((a={})[e.field]=e.value,e.update(a))}),B.on("radio",function(e){var t=e.config,a=t.elem.next(),t=t.id;a.hasClass(m)&&(a=j(t),o(e),u.call(a,e.tr,e.checked))}),a.prototype.setRowCheckedClass=function(e,t){var a=this.getOptions(),n=(e.data("index"),a.elem.next());e[t?"addClass":"removeClass"](l),e.each(function(){var e=A(this).data("index");n.find('.layui-table-fixed-r tbody tr[data-index="'+e+'"]')[t?"addClass":"removeClass"](l)})},a.prototype.updateCheckStatus=function(e,t){var a,n,i,l,d,r,o,c=this,u=c.getOptions();return!!u.hasChecboxCol&&(a=u.tree,n=u.id,i=u.elem.next(),l=P.config.checkName,"all"!==(d=a.data.cascade)&&"parent"!==d||!e||(d=c.updateParentCheckStatus(e,"boolean"===layui.type(t)?t:null),layui.each(d,function(e,t){var a=i.find('tr[lay-data-index="'+t[z]+'"] input[name="layTableCheckbox"]:not(:disabled)'),n=t[l];c.setRowCheckedClass(a.closest("tr"),n),a.prop({checked:n,indeterminate:t[g]})})),o=!(r=!0),0<(e=(e="all"===a.data.cascade?P.cache[n]:B.getData(n,!0)).filter(function(e){return!e[u.disabledName]})).length?layui.each(e,function(e,t){if((t[l]||t[g])&&(o=!0),t[l]||(r=!1),o&&!r)return!0}):r=!1,o=o&&!r,i.find('input[name="layTableCheckbox"][lay-filter="layTableAllChoose"]').prop({checked:r,indeterminate:o}),r)},a.prototype.updateParentCheckStatus=function(a,n){var i,e=this.getOptions(),t=e.tree,e=e.id,l=P.config.checkName,t=t.customName.children,d=[];return!(a[g]=!1)===n?a[t].length?layui.each(a[t],function(e,t){if(!t[l])return n=!1,a[g]=!0}):n=!1:!1===n?layui.each(a[t],function(e,t){if(t[l]||t[g])return a[g]=!0}):(n=!1,i=0,layui.each(a[t],function(e,t){t[l]&&i++}),n=a[t].length?a[t].length===i:a[l],a[g]=!n&&0li"],n.bodyElem=["."+C.CONST.BODY+":eq(0)",">."+C.CONST.ITEM],n.getContainer=function(){var e=n.documentElem||t.elem;return{header:{elem:e.find(n.headerElem[0]),items:e.find(n.headerElem.join(""))},body:{elem:e.find(n.bodyElem[0]),items:e.find(n.bodyElem.join(""))}}},"array"===layui.type(t.header)){if(0===t.header.length)return;"string"==typeof t.header[0]?(n.headerElem=t.header.concat(),n.documentElem=p(document)):(n.elemView=p('
'),t.className&&n.elemView.addClass(t.className),a=p('
    '),i=p('
    '),layui.each(t.header,function(e,t){t=n.renderHeaderItem(t);a.append(t)}),layui.each(t.body,function(e,t){t=n.renderBodyItem(t);i.append(t)}),n.elemView.append(a).append(i),t.elem.html(n.elemView))}else n.renderClose();"array"===layui.type(t.body)&&"string"==typeof t.body[0]&&(n.documentElem=p(document),n.bodyElem=t.body.concat());var e=n.data();"index"in t&&e.index!=t.index?n.change(n.findHeaderItem(t.index),!0):-1===e.index&&n.change(n.findHeaderItem(0),!0),n.roll("auto"),t.elem.hasClass(C.CONST.CLASS_HIDEV)&&t.elem.removeClass(C.CONST.CLASS_HIDEV),"function"==typeof t.afterRender&&t.afterRender(e),layui.event.call(t.elem[0],C.CONST.MOD_NAME,"afterRender("+t.id+")",e)},events:function(){var e,t=this,a=t.config,i=t.getContainer(),n=C.CONST.MOD_NAME,i=(t.documentElem?i.header:a).elem,a=a.trigger+(".lay_"+n+"_trigger"),n=t.documentElem?t.headerElem[1]:t.headerElem.join("");i.off(a).on(a,n,function(){t.change(p(this))}),r.onresize||(p(window).on("resize",function(){clearTimeout(e),e=setTimeout(function(){layui.each(C.cache.id,function(e){e=C.getThis(e);e&&e.roll("init")})},50)}),r.onresize=!0)}}),r={},t=C.Class;t.prototype.add=function(e){var t,a,i=this,n=(i.config,i.getContainer()),r=i.renderHeaderItem(e),o=i.renderBodyItem(e),d=(/(before|after)/.test(e.mode)?(a=i.data(),d=(t=e.hasOwnProperty("index"))?i.findHeaderItem(e.index):a.thisHeaderItem,t=t?i.findBodyItem(e.index):a.thisHeaderItem,d[e.mode](r),t[e.mode](o)):(a={prepend:"prepend",append:"append"}[e.mode||"append"]||"append",n.header.elem[a](r),n.body.elem[a](o)),i.change(r,!0),i.data());"function"==typeof e.done&&e.done(d)},t.prototype.close=function(e,t){if(e&&e[0]){var a=this,i=a.config,n=e.index();if(e[0]&&"false"!==e.attr("lay-closable")){var r=a.data();if(!t)if(!1===layui.event.call(e[0],C.CONST.MOD_NAME,"beforeClose("+i.id+")",p.extend(r,{index:e.index()})))return;e.hasClass(C.CONST.CLASS_THIS)&&(e.next()[0]?a.change(e.next(),!0):e.prev()[0]&&a.change(e.prev(),!0)),e.remove(),a.findBodyItem(n).remove(),a.roll("auto",n);r=a.data();layui.event.call(r.thisHeaderItem[0],C.CONST.MOD_NAME,"afterClose("+i.id+")",r)}}},t.prototype.closeMult=function(e,t){var a,i=this,n=i.config,r=i.getContainer(),o=i.data(),d=r.header.items,l=r.body.items,r='[lay-closable="false"]',s=":not("+r+")",r=(t=t===undefined?o.index:t,d.each(function(e){var t=p(this).attr("lay-closable");t&&l.eq(e).attr("lay-closable",t)}),"false"!==o.thisHeaderItem.attr("lay-closable")&&("all"!==e&&e?t!==o.index&&i.change(i.findHeaderItem(t),!0):(a=d.filter(":gt("+o.index+")"+r).eq(0),o=p(d.filter(":lt("+o.index+")"+r).get().reverse()).eq(0),a[0]?i.change(a,!0):o[0]&&i.change(o,!0))),("other"===e?(d.eq(t).siblings(s).remove(),l.eq(t).siblings(s)):"right"===e?(d.filter(":gt("+t+")"+s).remove(),l.filter(":gt("+t+")"+s)):(d.filter(s).remove(),l.filter(s))).remove(),i.roll("auto"),i.data());layui.event.call(r.thisHeaderItem[0],C.CONST.MOD_NAME,"afterClose("+n.id+")",r)},t.prototype.change=function(e,t){if(e&&e[0]){var a=this,i=a.config,n=e.index(),r=e.find("a"),r="string"==typeof r.attr("href")&&"_blank"===r.attr("target"),o="string"==typeof e.attr("lay-unselect");if(!r&&!o){r=a.data();if(!t)if(!1===layui.event.call(e[0],C.CONST.MOD_NAME,"beforeChange("+i.id+")",p.extend(r,{from:{index:r.index,headerItem:r.thisHeaderItem},to:{index:e.index(),headerItem:e}})))return;e.addClass(C.CONST.CLASS_THIS).siblings().removeClass(C.CONST.CLASS_THIS),a.findBodyItem(n).addClass(C.CONST.CLASS_SHOW).siblings().removeClass(C.CONST.CLASS_SHOW),a.roll("auto",n);r=a.data();layui.event.call(r.thisHeaderItem[0],C.CONST.MOD_NAME,"afterChange("+i.id+")",r)}}},t.prototype.renderHeaderItem=function(e){var t=this.config,a=p(e.headerItem||t.headerItem||"
  • ");return a.html(e.title||"New Tab"),layui.each(e,function(e,t){/^(title|content|mode|done)$/.test(e)||a.attr("lay-"+e,t)}),this.appendClose(a,e),a},t.prototype.renderBodyItem=function(e){var t=this.config,t=p(e.bodyItem||t.bodyItem||'
    ');return t.html(e.content||""),t},t.prototype.appendClose=function(e,t){var a=this;a.config.closable&&"false"!==(t=t||{}).closable&&"false"!==e.attr("lay-closable")&&!e.find("."+C.CONST.CLOSE)[0]&&((t=p('')).on("click",function(){return a.close(p(this).parent()),!1}),e.append(t))},t.prototype.renderClose=function(){var e=this,t=e.config,a=e.getContainer();t.closable?a.header.items.each(function(){e.appendClose(p(this))}):a.header.items.each(function(){p(this).find("."+C.CONST.CLOSE).remove()})},t.prototype.roll=function(e,i){var n=this,t=n.config,a=n.getContainer(),r=a.header.elem,o=a.header.items,a=r.prop("scrollWidth"),d=Math.ceil(r.outerWidth()),l=r.data("left")||0,s="scroll"===t.headerMode,c="layui-tabs-scroll",f="layui-tabs-bar",u=["layui-icon-prev","layui-icon-next"],h={elem:p('
    '),bar:p(['
    ','','',"
    "].join(""))};if("normal"!==t.headerMode){var m,y=r.parent("."+c);if(s||!s&&d=d-l)return r.css("left",-a).data("left",-a),!1}),l=r.data("left")||0,y.find("."+u[0])[l<0?"removeClass":"addClass"](C.CONST.CLASS_DISABLED),y.find("."+u[1])[0')),n=(e.tree(a),i.elem=p(i.elem));if(n[0]){if(e.key=i.id||e.index,e.elem=a,e.elemNone=p('
    '+i.text.none+"
    "),n.html(e.elem),0==e.elem.find(".layui-tree-set").length)return e.elem.append(e.elemNone);i.showCheckbox&&e.renderForm("checkbox"),e.elem.find(".layui-tree-set").each(function(){var e=p(this);e.parent(".layui-tree-pack")[0]||e.addClass("layui-tree-setHide"),!e.next()[0]&&e.parents(".layui-tree-pack").eq(1).hasClass("layui-tree-lineExtend")&&e.addClass(T),e.next()[0]||e.parents(".layui-tree-set").eq(0).next()[0]||e.addClass(T)}),e.events()}},l.prototype.renderForm=function(e){i.render(e,"LAY-tree-"+this.index)},l.prototype.tree=function(r,e){var d=this,s=d.config,o=s.customName,e=e||s.data;layui.each(e,function(e,i){var a,n,t=i[o.children]&&0"),c=p(['
    ','
    ','
    ',s.showLine?t?'':'':'',s.showCheckbox?'':"",s.isJump&&i.href?''+(i[o.title]||i.label||s.text.defaultNodeName)+"":''+(i[o.title]||i.label||s.text.defaultNodeName)+"","
    ",s.edit?(a={add:'',update:'',del:''},n=['
    '],!0===s.edit&&(s.edit=["update","del"]),"object"==typeof s.edit?(layui.each(s.edit,function(e,i){n.push(a[i]||"")}),n.join("")+"
    "):void 0):"","
    "].join(""));t&&(c.append(l),d.tree(l,i[o.children])),r.append(c),c.prev("."+k)[0]&&c.prev().children(".layui-tree-pack").addClass("layui-tree-showLine"),t||c.parent(".layui-tree-pack").addClass("layui-tree-lineExtend"),d.spread(c,i),s.showCheckbox&&(i.checked&&d.checkids.push(i[o.id]),d.checkClick(c,i)),s.edit&&d.operate(c,i)})},l.prototype.spread=function(n,t){var l=this,c=l.config,e=n.children("."+b),i=e.children("."+g),a=i.find('input[same="layuiTreeCheck"]'),r=e.find("."+C),e=e.find("."+w),d=c.onlyIconControl?r:i,s="";d.on("click",function(e){var i=n.children("."+N),a=(d.children(".layui-icon")[0]?d:d.find(".layui-tree-icon")).children(".layui-icon");i[0]?n.hasClass(F)?(n.removeClass(F),i.slideUp(200),a.removeClass(x).addClass(v),l.updateFieldValue(t,"spread",!1)):(n.addClass(F),i.slideDown(200),a.addClass(x).removeClass(v),l.updateFieldValue(t,"spread",!0),c.accordion&&((i=n.siblings("."+k)).removeClass(F),i.children("."+N).slideUp(200),i.find(".layui-tree-icon").children(".layui-icon").removeClass(x).addClass(v))):s="normal"}),e.on("click",function(){p(this).hasClass(u)||(s=n.hasClass(F)?c.onlyIconControl?"open":"close":c.onlyIconControl?"close":"open",a[0]&&l.updateFieldValue(t,"checked",a.prop("checked")),c.click&&c.click({elem:n,state:s,data:t}))})},l.prototype.updateFieldValue=function(e,i,a){i in e&&(e[i]=a)},l.prototype.setCheckbox=function(e,i,a){var t,n=this,l=n.config.customName,c=a.prop("checked");a.prop("disabled")||("object"!=typeof i[l.children]&&!e.find("."+N)[0]||e.find("."+N).find('input[same="layuiTreeCheck"]').each(function(e){this.disabled||((e=i[l.children][e])&&n.updateFieldValue(e,"checked",c),n.updateFieldValue(this,"checked",c))}),(t=function(e){var i,a,n;e.parents("."+k)[0]&&(a=(e=e.parent("."+N)).parent(),n=e.prev().find('input[same="layuiTreeCheck"]'),c?n.prop("checked",c):(e.find('input[same="layuiTreeCheck"]').each(function(){this.checked&&(i=!0)}),i||n.prop("checked",!1)),t(a))})(e),n.renderForm("checkbox"))},l.prototype.checkClick=function(a,n){var t=this,l=t.config;a.children("."+b).children("."+g).on("click",'input[same="layuiTreeCheck"]+',function(e){layui.stope(e);var e=p(this).prev(),i=e.prop("checked");e.prop("disabled")||(t.setCheckbox(a,n,e),t.updateFieldValue(n,"checked",i),l.oncheck&&l.oncheck({elem:a,checked:i,data:n}))})},l.prototype.operate=function(r,d){var s=this,o=s.config,u=o.customName,e=r.children("."+b),h=e.children("."+g);e.children(".layui-tree-btnGroup").on("click",".layui-icon",function(e){layui.stope(e);var i,e=p(this).data("type"),n=r.children("."+N),t={data:d,type:e,elem:r};if("add"==e){n[0]||(o.showLine?(h.find("."+C).addClass("layui-tree-icon"),h.find("."+C).children(".layui-icon").addClass(v).removeClass("layui-icon-file")):h.find(".layui-tree-iconArrow").removeClass(m),r.append('
    '));var a,l=o.operate&&o.operate(t),c={};if(c[u.title]=o.text.defaultNodeName,c[u.id]=l,s.tree(r.children("."+N),[c]),o.showLine&&(n[0]?(n.hasClass(S)||n.addClass(S),r.find("."+N).each(function(){p(this).children("."+k).last().addClass(T)}),(n.children("."+k).last().prev().hasClass(T)?n.children("."+k).last().prev():n.children("."+k).last()).removeClass(T),!r.parent("."+N)[0]&&r.next()[0]&&n.children("."+k).last().removeClass(T)):(l=r.siblings("."+k),a=1,c=r.parent("."+N),layui.each(l,function(e,i){p(i).children("."+N)[0]||(a=0)}),(1==a?(l.children("."+N).addClass(L),l.children("."+N).children("."+k).removeClass(T),r.children("."+N).addClass(L),c.removeClass(S),c.children("."+k).last().children("."+N).children("."+k).last()):r.children("."+N).children("."+k)).addClass(T))),!o.showCheckbox)return;h.find('input[same="layuiTreeCheck"]')[0].checked&&(r.children("."+N).children("."+k).last().find('input[same="layuiTreeCheck"]')[0].checked=!0),s.renderForm("checkbox")}else"update"==e?(l=h.children("."+w).html(),h.children("."+w).html(""),h.append(''),h.children(".layui-tree-editInput").val(f.unescape(l)).focus(),i=function(e){var i=f.escape(e.val().trim())||o.text.defaultNodeName;e.remove(),h.children("."+w).html(i),t.data[u.title]=i,o.operate&&o.operate(t)},h.children(".layui-tree-editInput").blur(function(){i(p(this))}),h.children(".layui-tree-editInput").on("keydown",function(e){13===e.keyCode&&(e.preventDefault(),i(p(this)))})):y.confirm('\u786e\u8ba4\u5220\u9664\u8be5\u8282\u70b9 "'+(d[u.title]||"")+'" \u5417\uff1f',function(e){var l,a,i;o.operate&&o.operate(t),t.status="remove",y.close(e),r.prev("."+k)[0]||r.next("."+k)[0]||r.parent("."+N)[0]?(r.siblings("."+k).children("."+b)[0]?(o.showCheckbox&&(l=function(e){var i,a,n,t;e.parents("."+k)[0]&&(i=e.siblings("."+k).children("."+b),a=(e=e.parent("."+N).prev()).find('input[same="layuiTreeCheck"]')[0],n=1,(t=0)==a.checked)&&(i.each(function(e,i){i=p(i).find('input[same="layuiTreeCheck"]')[0];0!=i.checked||i.disabled||(n=0),i.disabled||(t=1)}),1==n)&&1==t&&(a.checked=!0,s.renderForm("checkbox"),l(e.parent("."+k)))})(r),o.showLine&&(e=r.siblings("."+k),a=1,i=r.parent("."+N),layui.each(e,function(e,i){p(i).children("."+N)[0]||(a=0)}),1==a?(n[0]||(i.removeClass(S),e.children("."+N).addClass(L),e.children("."+N).children("."+k).removeClass(T)),(r.next()[0]?i.children("."+k).last():r.prev()).children("."+N).children("."+k).last().addClass(T),r.next()[0]||r.parents("."+k)[1]||r.parents("."+k).eq(0).next()[0]||r.prev("."+k).addClass(T)):!r.next()[0]&&r.hasClass(T)&&r.prev().addClass(T))):(e=r.parent("."+N).prev(),o.showLine?(e.find("."+C).removeClass("layui-tree-icon"),e.find("."+C).children(".layui-icon").removeClass(x).addClass("layui-icon-file"),(i=e.parents("."+N).eq(0)).addClass(S),i.children("."+k).each(function(){p(this).children("."+N).children("."+k).last().addClass(T)})):e.find(".layui-tree-iconArrow").addClass(m),r.parents("."+k).eq(0).removeClass(F),r.parent("."+N).remove()),r.remove()):(r.remove(),s.elem.append(s.elemNone))})})},l.prototype.events=function(){var i=this,t=i.config;i.elem.find(".layui-tree-checkedFirst");i.setChecked(i.checkids),i.elem.find(".layui-tree-search").on("keyup",function(){var e=p(this),a=e.val(),e=e.nextAll(),n=[];e.find("."+w).each(function(){var i,e=p(this).parents("."+b);-1!=p(this).html().indexOf(a)&&(n.push(p(this).parent()),(i=function(e){e.addClass("layui-tree-searchShow"),e.parent("."+N)[0]&&i(e.parent("."+N).parent("."+k))})(e.parent("."+k)))}),e.find("."+b).each(function(){var e=p(this).parent("."+k);e.hasClass("layui-tree-searchShow")||e.addClass(m)}),0==e.find(".layui-tree-searchShow").length&&i.elem.append(i.elemNone),t.onsearch&&t.onsearch({elem:n})}),i.elem.find(".layui-tree-search").on("keydown",function(){p(this).nextAll().find("."+b).each(function(){p(this).parent("."+k).removeClass("layui-tree-searchShow "+m)}),p(".layui-tree-emptyText")[0]&&p(".layui-tree-emptyText").remove()})},l.prototype.getChecked=function(){var t=this,e=t.config,l=e.customName,i=[],a=[],c=(t.elem.find(".layui-form-checked").each(function(){i.push(p(this).prev()[0].value)}),function(e,n){layui.each(e,function(e,a){layui.each(i,function(e,i){if(a[l.id]==i)return t.updateFieldValue(a,"checked",!0),delete(i=p.extend({},a))[l.children],n.push(i),a[l.children]&&(i[l.children]=[],c(a[l.children],i[l.children])),!0})})});return c(p.extend({},e.data),a),a},l.prototype.setChecked=function(l){this.config;this.elem.find("."+k).each(function(e,i){var a=p(this).data("id"),n=p(i).children("."+b).find('input[same="layuiTreeCheck"]'),t=n.next();if("number"==typeof l){if(a.toString()==l.toString())return n[0].checked||t.click(),!1}else"object"==typeof l&&layui.each(l,function(e,i){if(i.toString()==a.toString()&&!n[0].checked)return t.click(),!0})})},n.that={},n.config={},t.reload=function(e,i){e=n.that[e];return e.reload(i),n.call(e)},t.getChecked=function(e){return n.that[e].getChecked()},t.setChecked=function(e,i){return n.that[e].setChecked(i)},t.render=function(e){e=new l(e);return n.call(e)},e(a,t)});layui.define(["laytpl","form"],function(e){"use strict";var d=layui.$,n=layui.laytpl,t=layui.form,a="transfer",i={config:{},index:layui[a]?layui[a].index+1e4:0,set:function(e){var t=this;return t.config=d.extend({},t.config,e),t},on:function(e,t){return layui.onevent.call(this,a,e,t)}},l=function(){var t=this,e=t.config,a=e.id||t.index;return l.that[a]=t,{config:l.config[a]=e,reload:function(e){t.reload.call(t,e)},getData:function(){return t.getData.call(t)}}},s="layui-hide",u="layui-btn-disabled",c="layui-none",r="layui-transfer-box",h="layui-transfer-header",o="layui-transfer-search",f="layui-transfer-data",y=function(e){return['
    ','
    ','","
    ","{{# if(d.data.showSearch){ }}",'","{{# } }}",'
      ',"
      "].join("")},p=['
      ',y({index:0,checkAllName:"layTransferLeftCheckAll"}),'
      ','",'","
      ",y({index:1,checkAllName:"layTransferRightCheckAll"}),"
      "].join(""),v=function(e){var t=this;t.index=++i.index,t.config=d.extend({},t.config,i.config,e),t.render()};v.prototype.config={title:["\u5217\u8868\u4e00","\u5217\u8868\u4e8c"],width:200,height:360,data:[],value:[],showSearch:!1,id:"",text:{none:"\u65e0\u6570\u636e",searchNone:"\u65e0\u5339\u914d\u6570\u636e"}},v.prototype.reload=function(e){var t=this;t.config=d.extend({},t.config,e),t.render()},v.prototype.render=function(){var e=this,t=e.config,a=e.elem=d(n(p,{open:"{{",close:"}}"}).render({data:t,index:e.index})),i=t.elem=d(t.elem);i[0]&&(t.data=t.data||[],t.value=t.value||[],t.id="id"in t?t.id:elem.attr("id")||e.index,e.key=t.id,i.html(e.elem),e.layBox=e.elem.find("."+r),e.layHeader=e.elem.find("."+h),e.laySearch=e.elem.find("."+o),e.layData=a.find("."+f),e.layBtn=a.find(".layui-transfer-active .layui-btn"),e.layBox.css({width:t.width,height:t.height}),e.layData.css({height:(i=t.height-e.layHeader.outerHeight(),t.showSearch&&(i-=e.laySearch.outerHeight()),i-2)}),e.renderData(),e.events())},v.prototype.renderData=function(){var e=this,t=e.config,l=[{checkName:"layTransferLeftCheck",views:[]},{checkName:"layTransferRightCheck",views:[]}];e.parseData(function(a){var i=a.selected?1:0,n=["
    • ",'',"
    • "].join("");i?layui.each(t.value,function(e,t){t==a.value&&a.selected&&(l[i].views[e]=n)}):l[i].views.push(n),delete a.selected}),e.layData.eq(0).html(l[0].views.join("")),e.layData.eq(1).html(l[1].views.join("")),e.renderCheckBtn()},v.prototype.renderForm=function(e){t.render(e,"LAY-transfer-"+this.index)},v.prototype.renderCheckBtn=function(c){var r=this,o=r.config;c=c||{},r.layBox.each(function(e){var t=d(this),a=t.find("."+f),t=t.find("."+h).find('input[type="checkbox"]'),i=a.find('input[type="checkbox"]'),n=0,l=!1;i.each(function(){var e=d(this).data("hide");(this.checked||this.disabled||e)&&n++,this.checked&&!e&&(l=!0)}),t.prop("checked",l&&n===i.length),r.layBtn.eq(e)[l?"removeClass":"addClass"](u),c.stopNone||(i=a.children("li:not(."+s+")").length,r.noneView(a,i?"":o.text.none))}),r.renderForm("checkbox")},v.prototype.noneView=function(e,t){var a=d('

      '+(t||"")+"

      ");e.find("."+c)[0]&&e.find("."+c).remove(),t.replace(/\s/g,"")&&e.append(a)},v.prototype.setValue=function(){var e=this.config,t=[];return this.layBox.eq(1).find("."+f+' input[type="checkbox"]').each(function(){d(this).data("hide")||t.push(this.value)}),e.value=t,this},v.prototype.parseData=function(t){var i=this.config,n=[];return layui.each(i.data,function(e,a){a=("function"==typeof i.parseData?i.parseData(a):a)||a,n.push(a=d.extend({},a)),layui.each(i.value,function(e,t){t==a.value&&(a.selected=!0)}),t&&t(a)}),i.data=n,this},v.prototype.getData=function(e){var t=this.config,i=[];return this.setValue(),layui.each(e||t.value,function(e,a){layui.each(t.data,function(e,t){delete t.selected,a==t.value&&i.push(t)})}),i},v.prototype.transfer=function(e,t){var a,i=this,n=i.config,l=i.layBox.eq(e),c=[],t=(t?((a=(t=t).find('input[type="checkbox"]'))[0].checked=!1,l.siblings("."+r).find("."+f).append(t.clone()),t.remove(),c.push(a[0].value),i.setValue()):l.each(function(e){d(this).find("."+f).children("li").each(function(){var e=d(this),t=e.find('input[type="checkbox"]'),a=t.data("hide");t[0].checked&&!a&&(t[0].checked=!1,l.siblings("."+r).find("."+f).append(e.clone()),e.remove(),c.push(t[0].value)),i.setValue()})}),i.renderCheckBtn(),l.siblings("."+r).find("."+o+" input"));""!==t.val()&&t.trigger("keyup"),n.onchange&&n.onchange(i.getData(c),e)},v.prototype.events=function(){var n=this,l=n.config;n.elem.on("click",'input[lay-filter="layTransferCheckbox"]+',function(){var e=d(this).prev(),t=e[0].checked,a=e.parents("."+r).eq(0).find("."+f);e[0].disabled||("all"===e.attr("lay-type")&&a.find('input[type="checkbox"]').each(function(){this.disabled||(this.checked=t)}),setTimeout(function(){n.renderCheckBtn({stopNone:!0})},0))}),n.elem.on("dblclick","."+f+">li",function(e){var t=d(this),a=t.children('input[type="checkbox"]'),i=t.parent().parent().data("index");a[0].disabled||!1!==("function"==typeof l.dblclick?l.dblclick({elem:t,data:n.getData([a[0].value])[0],index:i}):null)&&n.transfer(i,t)}),n.layBtn.on("click",function(){var e=d(this),t=e.data("index");e.hasClass(u)||n.transfer(t)}),n.laySearch.find("input").on("keyup",function(){var i=this.value,e=d(this).parents("."+o).eq(0).siblings("."+f),t=e.children("li"),t=(t.each(function(){var e=d(this),t=e.find('input[type="checkbox"]'),a=t[0].title,a=("cs"!==l.showSearch&&(a=a.toLowerCase(),i=i.toLowerCase()),-1!==a.indexOf(i));e[a?"removeClass":"addClass"](s),t.data("hide",!a)}),n.renderCheckBtn(),t.length===e.children("li."+s).length);n.noneView(e,t?l.text.searchNone:"")})},l.that={},l.config={},i.reload=function(e,t){e=l.that[e];return e.reload(t),l.call(e)},i.getData=function(e){return l.that[e].getData()},i.render=function(e){e=new v(e);return l.call(e)},e(a,i)});layui.define(["jquery","lay"],function(e){"use strict";var o=layui.$,l=layui.lay,t=(layui.hint(),layui.device(),{config:{},set:function(e){var n=this;return n.config=o.extend({},n.config,e),n},on:function(e,n){return layui.onevent.call(this,r,e,n)}}),r="carousel",s="layui-this",u="layui-carousel-left",c="layui-carousel-right",m="layui-carousel-prev",h="layui-carousel-next",a="layui-carousel-arrow",d="layui-carousel-ind",n=function(e){var n=this;n.config=o.extend({},n.config,t.config,e),n.render()};n.prototype.config={width:"600px",height:"280px",full:!1,arrow:"hover",indicator:"inside",autoplay:!0,interval:3e3,anim:"",trigger:"click",index:0},n.prototype.render=function(){var e=this,n=e.config,i=o(n.elem);if(1*[carousel-item]>*"),n.index<0&&(n.index=0),n.index>=e.elemItem.length&&(n.index=e.elemItem.length-1),n.interval<800&&(n.interval=800),n.full?n.elem.css({position:"fixed",width:"100%",height:"100%",zIndex:9999}):n.elem.css({width:n.width,height:n.height}),n.elem.attr("lay-anim",n.anim),e.elemItem.eq(n.index).addClass(s),e.indicator(),e.arrow(),e.autoplay(),1=this.elemItem.length?0:e},n.prototype.addIndex=function(e){var n=this.config;n.index=n.index+(e=e||1),n.index>=this.elemItem.length&&(n.index=0)},n.prototype.subIndex=function(e){var n=this.config;n.index=n.index-(e=e||1),n.index<0&&(n.index=this.elemItem.length-1)},n.prototype.autoplay=function(){var e=this,n=e.config,i=e.elemItem.length;n.autoplay&&(clearInterval(e.timer),1',''].join(""));e.elem.attr("lay-arrow",e.arrow),e.elem.find("."+a)[0]&&e.elem.find("."+a).remove(),1i.index?n.slide("add",e-i.index):e
        ',(n=[],layui.each(e.elemItem,function(e){n.push("")}),n.join("")),"
      "].join(""));i.elem.attr("lay-indicator",i.indicator),i.elem.find("."+d)[0]&&i.elem.find("."+d).remove(),1t[a?"height":"width"]()/3)&&o.slide(0a.length&&(a.value=a.length),parseInt(a.value)===a.value||a.half||(a.value=Math.ceil(a.value)-a.value<.5?Math.ceil(a.value):Math.floor(a.value)),'
        "),n=1;n<=a.length;n++){var o='
      • ";a.half&&parseInt(a.value)!==a.value&&n==Math.ceil(a.value)?i=i+'
      • ":i+=o}i+="
      "+(a.text?''+a.value+"\u661f":"")+"";var l=a.elem,s=l.next(".layui-rate");s[0]&&s.remove(),e.elemTemp=u(i),a.span=e.elemTemp.next("span"),a.setText&&a.setText(a.value),l.html(e.elemTemp),l.addClass("layui-inline"),a.readonly||e.action()},a.prototype.setvalue=function(e){this.config.value=e,this.render()},a.prototype.action=function(){var n=this.config,t=this.elemTemp,i=t.find("i").width(),l=t.children("li");l.each(function(e){var a=e+1,l=u(this);l.on("click",function(e){n.value=a,n.half&&e.pageX-u(this).offset().left<=i/2&&(n.value=n.value-.5),n.text&&t.next("span").text(n.value+"\u661f"),n.choose&&n.choose(n.value),n.setText&&n.setText(n.value)}),l.on("mousemove",function(e){t.find("i").each(function(){u(this).addClass(h).removeClass(s)}),t.find("i:lt("+a+")").each(function(){u(this).addClass(f).removeClass(v)}),n.half&&e.pageX-u(this).offset().left<=i/2&&l.children("i").addClass(o).removeClass(f)}),l.on("mouseleave",function(){t.find("i").each(function(){u(this).addClass(h).removeClass(s)}),t.find("i:lt("+Math.floor(n.value)+")").each(function(){u(this).addClass(f).removeClass(v)}),n.half&&parseInt(n.value)!==n.value&&t.children("li:eq("+Math.floor(n.value)+")").children("i").addClass(o).removeClass("layui-icon-rate-solid layui-icon-rate")})}),r.touchSwipe(t,{onTouchMove:function(e,a){var i;Date.now()-a.timeStart<=200||(a=e.touches[0].pageX,e=t.width()/n.length,a=(a-t.offset().left)/e,(i=(i=(e=a%1)<=.5&&n.half?.5+(a-e):Math.ceil(a))>n.length?n.length:i)<0&&(i=0),l.each(function(e){var a=u(this).children("i"),l=Math.ceil(i)-e==1,t=Math.ceil(i)>e,e=i-e==.5;t?(a.addClass(f).removeClass(v),n.half&&e&&a.addClass(o).removeClass(f)):a.addClass(h).removeClass(s),a.toggleClass("layui-rate-hover",l)}),n.value=i,n.text&&t.next("span").text(n.value+"\u661f"),n.setText&&n.setText(n.value))},onTouchEnd:function(e,a){Date.now()-a.timeStart<=200||(t.find("i").removeClass("layui-rate-hover"),n.choose&&n.choose(n.value),n.setText&&n.setText(n.value))}})},a.prototype.events=function(){},c.render=function(e){e=new a(e);return function(){var a=this;return{setvalue:function(e){a.setvalue.call(a,e)},config:a.config}}.call(e)},e(l,c)});layui.define("jquery",function(o){"use strict";var w=layui.$,l=function(o){};l.prototype.load=function(o){var i,n,r,l,c,m,e,t,a,f,s,u,p,d,y,g=this,h=0,v=w((o=o||{}).elem);if(v[0])return c=w(o.scrollElem||document),m="mb"in o?o.mb:50,e=!("isAuto"in o)||o.isAuto,t=o.moreText||"\u52a0\u8f7d\u66f4\u591a",a=o.end||"\u6ca1\u6709\u66f4\u591a\u4e86",f="top"===(o.direction||"bottom"),g._cleanup(v,c),s=o.scrollElem&&o.scrollElem!==document,p=w('"),v.find(".layui-flow-more")[0]||v[f?"prepend":"append"](p),d=function(o,l){var e=s?c.prop("scrollHeight"):document.documentElement.scrollHeight,t=c.scrollTop();o=w(o),p[f?"after":"before"](o),(l=0==l||null)?p.html(a):p.find("a").html(u),n=l,i=null,r&&r(),f&&(o=s?c.prop("scrollHeight"):document.documentElement.scrollHeight,1===h?c.scrollTop(o):1'),"function"==typeof o.done&&o.done(++h,d)})(),p.find("a").on("click.flow",function(){w(this);n||i||y()}),o.isLazyimg&&(r=g.lazyimg({elem:o.elem+" img",scrollElem:o.scrollElem,direction:o.direction})),e&&c.on("scroll.flow",function(){var e=w(this),t=e.scrollTop();l&&clearTimeout(l),!n&&v.width()&&(l=setTimeout(function(){var o=(s?e:w(window)).height(),l=s?e.prop("scrollHeight"):document.documentElement.scrollHeight;(f?t<=m:l-t-o<=m)&&!i&&y()},100))}),g},l.prototype.lazyimg=function(o){var l,m=this,a=0,f=w((o=o||{}).scrollElem||document),s=o.elem||"img",n="top"===(o.direction||"bottom"),u=o.scrollElem&&o.scrollElem!==document,p=function(l,o){var e,t=f.scrollTop(),o=t+o,i=u?l.offset().top-f.offset().top+t:l.offset().top;(n?i+l.height():i)>=t&&i<=o&&l.attr("lay-src")&&(e=l.attr("lay-src"),layui.img(e,function(){var o=m.lazyimg.elem.eq(a);l.attr("src",e).removeAttr("lay-src"),o[0]&&r(o),a++},function(){m.lazyimg.elem.eq(a);l.removeAttr("lay-src")}))},r=function(o,l){var e=(u?l||f:w(window)).height(),t=f.scrollTop(),i=t+e;if(m.lazyimg.elem=w(s),o)p(o,e);else for(var n=0;n"),preview:"Preview"},wordWrap:!0,lang:"text",highlighter:!1,langMarker:!1},R=layui.code?layui.code.index+1e4:0,j=function(e){return String(e).replace(/\s+$/,"").replace(/^\n|\n$/,"")};e("code",function(l,e){var o,i,t,a,n,d,c,s,r,u,y,p,E,f,h,v,m,L,_,M,C,g={config:l=x.extend(!0,{},T,l),reload:function(e){layui.code(this.updateOptions(e))},updateOptions:function(e){return delete(e=e||{}).elem,x.extend(!0,l,e)},reloadCode:function(e){layui.code(this.updateOptions(e),"reloadCode")}},w=x(l.elem);return 1',l.ln?['
      ',D.digit(t+1)+".","
      "].join(""):"",'
      ',e||" ","
      ",""].join("")})}},a=l.code,n=function(e){return"function"==typeof l.codeParse?l.codeParse(e,l):e},"reloadCode"===e?o.children(".layui-code-wrap").html(w(n(a)).html):(d=layui.code.index=++R,o.attr("lay-code-index",d),(M=A.CDDE_DATA_CLASS in o.data())&&o.attr("class",o.data(A.CDDE_DATA_CLASS)||""),M||o.data(A.CDDE_DATA_CLASS,o.attr("class")),c={copy:{className:"file-b",title:["\u590d\u5236\u4ee3\u7801"],event:function(e){var t=D.unescape(n(l.code)),a="function"==typeof l.onCopy;lay.clipboard.writeText({text:t,done:function(){if(a&&!1===l.onCopy(t,!0))return;W.msg("\u5df2\u590d\u5236",{icon:1})},error:function(){if(a&&!1===l.onCopy(t,!1))return;W.msg("\u590d\u5236\u5931\u8d25",{icon:2})}})}}},function b(){var e=o.parent("."+A.ELEM_PREVIEW),t=e.children("."+A.ELEM_TAB),a=e.children("."+A.ELEM_ITEM+"-preview");return t.remove(),a.remove(),e[0]&&o.unwrap(),b}(),l.preview&&(M="LAY-CODE-DF-"+d,f=l.layout||["code","preview"],s="iframe"===l.preview,E=x('
      '),C=x('
      '),r=x('
      '),_=x('
      '),u=x('
      '),l.id&&E.attr("id",l.id),E.addClass(l.className),C.attr("lay-filter",M),layui.each(f,function(e,t){var a=x('
    • ');0===e&&a.addClass("layui-this"),a.html(l.text[t]),r.append(a)}),x.extend(c,{full:{className:"screen-full",title:["\u6700\u5927\u5316\u663e\u793a","\u8fd8\u539f\u663e\u793a"],event:function(e){var e=e.elem,t=e.closest("."+A.ELEM_PREVIEW),a="layui-icon-"+this.className,i="layui-icon-screen-restore",l=this.title,o=x("html,body"),n="layui-scrollbar-hide";e.hasClass(a)?(t.addClass(A.ELEM_FULL),e.removeClass(a).addClass(i),e.attr("title",l[1]),o.addClass(n)):(t.removeClass(A.ELEM_FULL),e.removeClass(i).addClass(a),e.attr("title",l[0]),o.removeClass(n))}},window:{className:"release",title:["\u5728\u65b0\u7a97\u53e3\u9884\u89c8"],event:function(e){D.openWin({content:n(l.code)})}}}),l.copy&&("array"===layui.type(l.tools)?-1===l.tools.indexOf("copy")&&l.tools.unshift("copy"):l.tools=["copy"]),u.on("click",">i",function(){var e=x(this),t=e.data("type"),e={elem:e,type:t,options:l,rawCode:l.code,finalCode:D.unescape(n(l.code))};c[t]&&"function"==typeof c[t].event&&c[t].event(e),"function"==typeof l.toolsEvent&&l.toolsEvent(e)}),l.addTools&&l.tools&&(l.tools=[].concat(l.tools,l.addTools)),layui.each(l.tools,function(e,t){var a="object"==typeof t,i=a?t:c[t]||{className:t,title:[t]},l=i.className||i.type,o=i.title||[""],a=a?i.type||l:t;a&&(c[a]||((t={})[a]=i,x.extend(c,t)),u.append(''))}),o.addClass(A.ELEM_ITEM).wrap(E),C.append(r),l.tools&&C.append(u),o.before(C),s&&_.html(''),y=function(e){var t=e.children("iframe")[0];s&&t?t.srcdoc=n(l.code):e.html(l.code),setTimeout(function(){"function"==typeof l.done&&l.done({container:e,options:l,render:function(){N.render(e.find(".layui-form")),S.render(),I.render({elem:["."+A.ELEM_PREVIEW,".layui-tabs"].join(" ")})}})},3)},"preview"===f[0]?(_.addClass(A.ELEM_SHOW),o.before(_),y(_)):o.addClass(A.ELEM_SHOW).after(_),l.previewStyle=[l.style,l.previewStyle].join(""),_.attr("style",l.previewStyle),S.on("tab("+M+")",function(e){var t=x(this),a=x(e.elem).closest("."+A.ELEM_PREVIEW).find("."+A.ELEM_ITEM),e=a.eq(e.index);a.removeClass(A.ELEM_SHOW),e.addClass(A.ELEM_SHOW),"preview"===t.attr("lay-id")&&y(e),L()})),p=x(''),o.addClass((E=["layui-code-view layui-border-box"],l.wordWrap||E.push("layui-code-nowrap"),E.join(" "))),(C=l.theme||l.skin)&&(o.removeClass("layui-code-theme-dark layui-code-theme-light"),o.addClass("layui-code-theme-"+C)),l.highlighter&&o.addClass([l.highlighter,"language-"+l.lang,"layui-code-hl"].join(" ")),f=w(l.encode?D.escape(n(a)):a),h=f.lines,o.html(p.html(f.html)),l.ln&&o.append('
      '),l.height&&p.css("max-height",l.height),l.codeStyle=[l.style,l.codeStyle].join(""),l.codeStyle&&p.attr("style",function(e,t){return(t||"")+l.codeStyle}),v=[{selector:">.layui-code-wrap>.layui-code-line{}",setValue:function(e,t){e.style["padding-left"]=t+"px"}},{selector:">.layui-code-wrap>.layui-code-line>.layui-code-line-number{}",setValue:function(e,t){e.style.width=t+"px"}},{selector:">.layui-code-ln-side{}",setValue:function(e,t){e.style.width=t+"px"}}],m=lay.style({target:o[0],id:"DF-code-"+d,text:x.map(x.map(v,function(e){return e.selector}),function(e,t){return['.layui-code-view[lay-code-index="'+d+'"]',e].join(" ")}).join("")}),L=function b(){var e,i;return l.ln&&(e=Math.floor(h.length/100),i=p.children("."+A.ELEM_LINE).last().children("."+A.ELEM_LINE_NUM).outerWidth(),o.addClass(A.ELEM_LN_MODE),e)&&A.LINE_RAW_WIDTH
    • ')).html(l.title||l.text.code),o.prepend(_)),M=x('
      '),l.copy&&!l.preview&&((C=x(['','',""].join(""))).on("click",function(){c.copy.event()}),M.append(C)),l.langMarker&&M.append(''+l.lang+""),l.about&&M.append(l.about),o.append(M),l.preview||setTimeout(function(){"function"==typeof l.done&&l.done({})},3),l.elem.length===1+d&&"function"==typeof l.allDone&&l.allDone())),g})}),layui["layui.all"]||layui.addcss("modules/code.css?v=6","skincodecss"); -//# sourceMappingURL=layui.js.map diff --git a/web/static/lib/less.js b/web/static/lib/less.js deleted file mode 100755 index aaf10dc..0000000 --- a/web/static/lib/less.js +++ /dev/null @@ -1,11360 +0,0 @@ -/** - * Less - Leaner CSS v4.1.3 - * http://lesscss.org - * - * Copyright (c) 2009-2022, Alexis Sellier - * Licensed under the Apache-2.0 License. - * - * @license Apache-2.0 - */ - - (function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : - typeof define === 'function' && define.amd ? define(factory) : - (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.less = factory()); -}(this, (function () { 'use strict'; - - // Export a new default each time - function defaultOptions () { - return { - /* Inline Javascript - @plugin still allowed */ - javascriptEnabled: false, - /* Outputs a makefile import dependency list to stdout. */ - depends: false, - /* (DEPRECATED) Compress using less built-in compression. - * This does an okay job but does not utilise all the tricks of - * dedicated css compression. */ - compress: false, - /* Runs the less parser and just reports errors without any output. */ - lint: false, - /* Sets available include paths. - * If the file in an @import rule does not exist at that exact location, - * less will look for it at the location(s) passed to this option. - * You might use this for instance to specify a path to a library which - * you want to be referenced simply and relatively in the less files. */ - paths: [], - /* color output in the terminal */ - color: true, - /* The strictImports controls whether the compiler will allow an @import inside of either - * @media blocks or (a later addition) other selector blocks. - * See: https://github.com/less/less.js/issues/656 */ - strictImports: false, - /* Allow Imports from Insecure HTTPS Hosts */ - insecure: false, - /* Allows you to add a path to every generated import and url in your css. - * This does not affect less import statements that are processed, just ones - * that are left in the output css. */ - rootpath: '', - /* By default URLs are kept as-is, so if you import a file in a sub-directory - * that references an image, exactly the same URL will be output in the css. - * This option allows you to re-write URL's in imported files so that the - * URL is always relative to the base imported file */ - rewriteUrls: false, - /* How to process math - * 0 always - eagerly try to solve all operations - * 1 parens-division - require parens for division "/" - * 2 parens | strict - require parens for all operations - * 3 strict-legacy - legacy strict behavior (super-strict) - */ - math: 1, - /* Without this option, less attempts to guess at the output unit when it does maths. */ - strictUnits: false, - /* Effectively the declaration is put at the top of your base Less file, - * meaning it can be used but it also can be overridden if this variable - * is defined in the file. */ - globalVars: null, - /* As opposed to the global variable option, this puts the declaration at the - * end of your base file, meaning it will override anything defined in your Less file. */ - modifyVars: null, - /* This option allows you to specify a argument to go on to every URL. */ - urlArgs: '' - }; - } - - function extractId(href) { - return href.replace(/^[a-z-]+:\/+?[^\/]+/, '') // Remove protocol & domain - .replace(/[\?\&]livereload=\w+/, '') // Remove LiveReload cachebuster - .replace(/^\//, '') // Remove root / - .replace(/\.[a-zA-Z]+$/, '') // Remove simple extension - .replace(/[^\.\w-]+/g, '-') // Replace illegal characters - .replace(/\./g, ':'); // Replace dots with colons(for valid id) - } - function addDataAttr(options, tag) { - if (!tag) { - return; - } // in case of tag is null or undefined - for (var opt in tag.dataset) { - if (tag.dataset.hasOwnProperty(opt)) { - if (opt === 'env' || opt === 'dumpLineNumbers' || opt === 'rootpath' || opt === 'errorReporting') { - options[opt] = tag.dataset[opt]; - } - else { - try { - options[opt] = JSON.parse(tag.dataset[opt]); - } - catch (_) { } - } - } - } - } - - var browser = { - createCSS: function (document, styles, sheet) { - // Strip the query-string - var href = sheet.href || ''; - // If there is no title set, use the filename, minus the extension - var id = "less:" + (sheet.title || extractId(href)); - // If this has already been inserted into the DOM, we may need to replace it - var oldStyleNode = document.getElementById(id); - var keepOldStyleNode = false; - // Create a new stylesheet node for insertion or (if necessary) replacement - var styleNode = document.createElement('style'); - styleNode.setAttribute('type', 'text/css'); - if (sheet.media) { - styleNode.setAttribute('media', sheet.media); - } - styleNode.id = id; - if (!styleNode.styleSheet) { - styleNode.appendChild(document.createTextNode(styles)); - // If new contents match contents of oldStyleNode, don't replace oldStyleNode - keepOldStyleNode = (oldStyleNode !== null && oldStyleNode.childNodes.length > 0 && styleNode.childNodes.length > 0 && - oldStyleNode.firstChild.nodeValue === styleNode.firstChild.nodeValue); - } - var head = document.getElementsByTagName('head')[0]; - // If there is no oldStyleNode, just append; otherwise, only append if we need - // to replace oldStyleNode with an updated stylesheet - if (oldStyleNode === null || keepOldStyleNode === false) { - var nextEl = sheet && sheet.nextSibling || null; - if (nextEl) { - nextEl.parentNode.insertBefore(styleNode, nextEl); - } - else { - head.appendChild(styleNode); - } - } - if (oldStyleNode && keepOldStyleNode === false) { - oldStyleNode.parentNode.removeChild(oldStyleNode); - } - // For IE. - // This needs to happen *after* the style element is added to the DOM, otherwise IE 7 and 8 may crash. - // See http://social.msdn.microsoft.com/Forums/en-US/7e081b65-878a-4c22-8e68-c10d39c2ed32/internet-explorer-crashes-appending-style-element-to-head - if (styleNode.styleSheet) { - try { - styleNode.styleSheet.cssText = styles; - } - catch (e) { - throw new Error('Couldn\'t reassign styleSheet.cssText.'); - } - } - }, - currentScript: function (window) { - var document = window.document; - return document.currentScript || (function () { - var scripts = document.getElementsByTagName('script'); - return scripts[scripts.length - 1]; - })(); - } - }; - - var addDefaultOptions = (function (window, options) { - // use options from the current script tag data attribues - addDataAttr(options, browser.currentScript(window)); - if (options.isFileProtocol === undefined) { - options.isFileProtocol = /^(file|(chrome|safari)(-extension)?|resource|qrc|app):/.test(window.location.protocol); - } - // Load styles asynchronously (default: false) - // - // This is set to `false` by default, so that the body - // doesn't start loading before the stylesheets are parsed. - // Setting this to `true` can result in flickering. - // - options.async = options.async || false; - options.fileAsync = options.fileAsync || false; - // Interval between watch polls - options.poll = options.poll || (options.isFileProtocol ? 1000 : 1500); - options.env = options.env || (window.location.hostname == '127.0.0.1' || - window.location.hostname == '0.0.0.0' || - window.location.hostname == 'localhost' || - (window.location.port && - window.location.port.length > 0) || - options.isFileProtocol ? 'development' - : 'production'); - var dumpLineNumbers = /!dumpLineNumbers:(comments|mediaquery|all)/.exec(window.location.hash); - if (dumpLineNumbers) { - options.dumpLineNumbers = dumpLineNumbers[1]; - } - if (options.useFileCache === undefined) { - options.useFileCache = true; - } - if (options.onReady === undefined) { - options.onReady = true; - } - if (options.relativeUrls) { - options.rewriteUrls = 'all'; - } - }); - - var logger$1 = { - error: function (msg) { - this._fireEvent('error', msg); - }, - warn: function (msg) { - this._fireEvent('warn', msg); - }, - info: function (msg) { - this._fireEvent('info', msg); - }, - debug: function (msg) { - this._fireEvent('debug', msg); - }, - addListener: function (listener) { - this._listeners.push(listener); - }, - removeListener: function (listener) { - for (var i = 0; i < this._listeners.length; i++) { - if (this._listeners[i] === listener) { - this._listeners.splice(i, 1); - return; - } - } - }, - _fireEvent: function (type, msg) { - for (var i = 0; i < this._listeners.length; i++) { - var logFunction = this._listeners[i][type]; - if (logFunction) { - logFunction(msg); - } - } - }, - _listeners: [] - }; - - /** - * @todo Document why this abstraction exists, and the relationship between - * environment, file managers, and plugin manager - */ - var Environment = /** @class */ (function () { - function Environment(externalEnvironment, fileManagers) { - this.fileManagers = fileManagers || []; - externalEnvironment = externalEnvironment || {}; - var optionalFunctions = ['encodeBase64', 'mimeLookup', 'charsetLookup', 'getSourceMapGenerator']; - var requiredFunctions = []; - var functions = requiredFunctions.concat(optionalFunctions); - for (var i = 0; i < functions.length; i++) { - var propName = functions[i]; - var environmentFunc = externalEnvironment[propName]; - if (environmentFunc) { - this[propName] = environmentFunc.bind(externalEnvironment); - } - else if (i < requiredFunctions.length) { - this.warn("missing required function in environment - " + propName); - } - } - } - Environment.prototype.getFileManager = function (filename, currentDirectory, options, environment, isSync) { - if (!filename) { - logger$1.warn('getFileManager called with no filename.. Please report this issue. continuing.'); - } - if (currentDirectory == null) { - logger$1.warn('getFileManager called with null directory.. Please report this issue. continuing.'); - } - var fileManagers = this.fileManagers; - if (options.pluginManager) { - fileManagers = [].concat(fileManagers).concat(options.pluginManager.getFileManagers()); - } - for (var i = fileManagers.length - 1; i >= 0; i--) { - var fileManager = fileManagers[i]; - if (fileManager[isSync ? 'supportsSync' : 'supports'](filename, currentDirectory, options, environment)) { - return fileManager; - } - } - return null; - }; - Environment.prototype.addFileManager = function (fileManager) { - this.fileManagers.push(fileManager); - }; - Environment.prototype.clearFileManagers = function () { - this.fileManagers = []; - }; - return Environment; - }()); - - var colors = { - 'aliceblue': '#f0f8ff', - 'antiquewhite': '#faebd7', - 'aqua': '#00ffff', - 'aquamarine': '#7fffd4', - 'azure': '#f0ffff', - 'beige': '#f5f5dc', - 'bisque': '#ffe4c4', - 'black': '#000000', - 'blanchedalmond': '#ffebcd', - 'blue': '#0000ff', - 'blueviolet': '#8a2be2', - 'brown': '#a52a2a', - 'burlywood': '#deb887', - 'cadetblue': '#5f9ea0', - 'chartreuse': '#7fff00', - 'chocolate': '#d2691e', - 'coral': '#ff7f50', - 'cornflowerblue': '#6495ed', - 'cornsilk': '#fff8dc', - 'crimson': '#dc143c', - 'cyan': '#00ffff', - 'darkblue': '#00008b', - 'darkcyan': '#008b8b', - 'darkgoldenrod': '#b8860b', - 'darkgray': '#a9a9a9', - 'darkgrey': '#a9a9a9', - 'darkgreen': '#006400', - 'darkkhaki': '#bdb76b', - 'darkmagenta': '#8b008b', - 'darkolivegreen': '#556b2f', - 'darkorange': '#ff8c00', - 'darkorchid': '#9932cc', - 'darkred': '#8b0000', - 'darksalmon': '#e9967a', - 'darkseagreen': '#8fbc8f', - 'darkslateblue': '#483d8b', - 'darkslategray': '#2f4f4f', - 'darkslategrey': '#2f4f4f', - 'darkturquoise': '#00ced1', - 'darkviolet': '#9400d3', - 'deeppink': '#ff1493', - 'deepskyblue': '#00bfff', - 'dimgray': '#696969', - 'dimgrey': '#696969', - 'dodgerblue': '#1e90ff', - 'firebrick': '#b22222', - 'floralwhite': '#fffaf0', - 'forestgreen': '#228b22', - 'fuchsia': '#ff00ff', - 'gainsboro': '#dcdcdc', - 'ghostwhite': '#f8f8ff', - 'gold': '#ffd700', - 'goldenrod': '#daa520', - 'gray': '#808080', - 'grey': '#808080', - 'green': '#008000', - 'greenyellow': '#adff2f', - 'honeydew': '#f0fff0', - 'hotpink': '#ff69b4', - 'indianred': '#cd5c5c', - 'indigo': '#4b0082', - 'ivory': '#fffff0', - 'khaki': '#f0e68c', - 'lavender': '#e6e6fa', - 'lavenderblush': '#fff0f5', - 'lawngreen': '#7cfc00', - 'lemonchiffon': '#fffacd', - 'lightblue': '#add8e6', - 'lightcoral': '#f08080', - 'lightcyan': '#e0ffff', - 'lightgoldenrodyellow': '#fafad2', - 'lightgray': '#d3d3d3', - 'lightgrey': '#d3d3d3', - 'lightgreen': '#90ee90', - 'lightpink': '#ffb6c1', - 'lightsalmon': '#ffa07a', - 'lightseagreen': '#20b2aa', - 'lightskyblue': '#87cefa', - 'lightslategray': '#778899', - 'lightslategrey': '#778899', - 'lightsteelblue': '#b0c4de', - 'lightyellow': '#ffffe0', - 'lime': '#00ff00', - 'limegreen': '#32cd32', - 'linen': '#faf0e6', - 'magenta': '#ff00ff', - 'maroon': '#800000', - 'mediumaquamarine': '#66cdaa', - 'mediumblue': '#0000cd', - 'mediumorchid': '#ba55d3', - 'mediumpurple': '#9370d8', - 'mediumseagreen': '#3cb371', - 'mediumslateblue': '#7b68ee', - 'mediumspringgreen': '#00fa9a', - 'mediumturquoise': '#48d1cc', - 'mediumvioletred': '#c71585', - 'midnightblue': '#191970', - 'mintcream': '#f5fffa', - 'mistyrose': '#ffe4e1', - 'moccasin': '#ffe4b5', - 'navajowhite': '#ffdead', - 'navy': '#000080', - 'oldlace': '#fdf5e6', - 'olive': '#808000', - 'olivedrab': '#6b8e23', - 'orange': '#ffa500', - 'orangered': '#ff4500', - 'orchid': '#da70d6', - 'palegoldenrod': '#eee8aa', - 'palegreen': '#98fb98', - 'paleturquoise': '#afeeee', - 'palevioletred': '#d87093', - 'papayawhip': '#ffefd5', - 'peachpuff': '#ffdab9', - 'peru': '#cd853f', - 'pink': '#ffc0cb', - 'plum': '#dda0dd', - 'powderblue': '#b0e0e6', - 'purple': '#800080', - 'rebeccapurple': '#663399', - 'red': '#ff0000', - 'rosybrown': '#bc8f8f', - 'royalblue': '#4169e1', - 'saddlebrown': '#8b4513', - 'salmon': '#fa8072', - 'sandybrown': '#f4a460', - 'seagreen': '#2e8b57', - 'seashell': '#fff5ee', - 'sienna': '#a0522d', - 'silver': '#c0c0c0', - 'skyblue': '#87ceeb', - 'slateblue': '#6a5acd', - 'slategray': '#708090', - 'slategrey': '#708090', - 'snow': '#fffafa', - 'springgreen': '#00ff7f', - 'steelblue': '#4682b4', - 'tan': '#d2b48c', - 'teal': '#008080', - 'thistle': '#d8bfd8', - 'tomato': '#ff6347', - 'turquoise': '#40e0d0', - 'violet': '#ee82ee', - 'wheat': '#f5deb3', - 'white': '#ffffff', - 'whitesmoke': '#f5f5f5', - 'yellow': '#ffff00', - 'yellowgreen': '#9acd32' - }; - - var unitConversions = { - length: { - 'm': 1, - 'cm': 0.01, - 'mm': 0.001, - 'in': 0.0254, - 'px': 0.0254 / 96, - 'pt': 0.0254 / 72, - 'pc': 0.0254 / 72 * 12 - }, - duration: { - 's': 1, - 'ms': 0.001 - }, - angle: { - 'rad': 1 / (2 * Math.PI), - 'deg': 1 / 360, - 'grad': 1 / 400, - 'turn': 1 - } - }; - - var data = { colors: colors, unitConversions: unitConversions }; - - /** - * The reason why Node is a class and other nodes simply do not extend - * from Node (since we're transpiling) is due to this issue: - * - * https://github.com/less/less.js/issues/3434 - */ - var Node = /** @class */ (function () { - function Node() { - this.parent = null; - this.visibilityBlocks = undefined; - this.nodeVisible = undefined; - this.rootNode = null; - this.parsed = null; - } - Object.defineProperty(Node.prototype, "currentFileInfo", { - get: function () { - return this.fileInfo(); - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(Node.prototype, "index", { - get: function () { - return this.getIndex(); - }, - enumerable: false, - configurable: true - }); - Node.prototype.setParent = function (nodes, parent) { - function set(node) { - if (node && node instanceof Node) { - node.parent = parent; - } - } - if (Array.isArray(nodes)) { - nodes.forEach(set); - } - else { - set(nodes); - } - }; - Node.prototype.getIndex = function () { - return this._index || (this.parent && this.parent.getIndex()) || 0; - }; - Node.prototype.fileInfo = function () { - return this._fileInfo || (this.parent && this.parent.fileInfo()) || {}; - }; - Node.prototype.isRulesetLike = function () { return false; }; - Node.prototype.toCSS = function (context) { - var strs = []; - this.genCSS(context, { - add: function (chunk, fileInfo, index) { - strs.push(chunk); - }, - isEmpty: function () { - return strs.length === 0; - } - }); - return strs.join(''); - }; - Node.prototype.genCSS = function (context, output) { - output.add(this.value); - }; - Node.prototype.accept = function (visitor) { - this.value = visitor.visit(this.value); - }; - Node.prototype.eval = function () { return this; }; - Node.prototype._operate = function (context, op, a, b) { - switch (op) { - case '+': return a + b; - case '-': return a - b; - case '*': return a * b; - case '/': return a / b; - } - }; - Node.prototype.fround = function (context, value) { - var precision = context && context.numPrecision; - // add "epsilon" to ensure numbers like 1.000000005 (represented as 1.000000004999...) are properly rounded: - return (precision) ? Number((value + 2e-16).toFixed(precision)) : value; - }; - Node.compare = function (a, b) { - /* returns: - -1: a < b - 0: a = b - 1: a > b - and *any* other value for a != b (e.g. undefined, NaN, -2 etc.) */ - if ((a.compare) && - // for "symmetric results" force toCSS-based comparison - // of Quoted or Anonymous if either value is one of those - !(b.type === 'Quoted' || b.type === 'Anonymous')) { - return a.compare(b); - } - else if (b.compare) { - return -b.compare(a); - } - else if (a.type !== b.type) { - return undefined; - } - a = a.value; - b = b.value; - if (!Array.isArray(a)) { - return a === b ? 0 : undefined; - } - if (a.length !== b.length) { - return undefined; - } - for (var i = 0; i < a.length; i++) { - if (Node.compare(a[i], b[i]) !== 0) { - return undefined; - } - } - return 0; - }; - Node.numericCompare = function (a, b) { - return a < b ? -1 - : a === b ? 0 - : a > b ? 1 : undefined; - }; - // Returns true if this node represents root of ast imported by reference - Node.prototype.blocksVisibility = function () { - if (this.visibilityBlocks == null) { - this.visibilityBlocks = 0; - } - return this.visibilityBlocks !== 0; - }; - Node.prototype.addVisibilityBlock = function () { - if (this.visibilityBlocks == null) { - this.visibilityBlocks = 0; - } - this.visibilityBlocks = this.visibilityBlocks + 1; - }; - Node.prototype.removeVisibilityBlock = function () { - if (this.visibilityBlocks == null) { - this.visibilityBlocks = 0; - } - this.visibilityBlocks = this.visibilityBlocks - 1; - }; - // Turns on node visibility - if called node will be shown in output regardless - // of whether it comes from import by reference or not - Node.prototype.ensureVisibility = function () { - this.nodeVisible = true; - }; - // Turns off node visibility - if called node will NOT be shown in output regardless - // of whether it comes from import by reference or not - Node.prototype.ensureInvisibility = function () { - this.nodeVisible = false; - }; - // return values: - // false - the node must not be visible - // true - the node must be visible - // undefined or null - the node has the same visibility as its parent - Node.prototype.isVisible = function () { - return this.nodeVisible; - }; - Node.prototype.visibilityInfo = function () { - return { - visibilityBlocks: this.visibilityBlocks, - nodeVisible: this.nodeVisible - }; - }; - Node.prototype.copyVisibilityInfo = function (info) { - if (!info) { - return; - } - this.visibilityBlocks = info.visibilityBlocks; - this.nodeVisible = info.nodeVisible; - }; - return Node; - }()); - - // - // RGB Colors - #ff0014, #eee - // - var Color = function (rgb, a, originalForm) { - var self = this; - // - // The end goal here, is to parse the arguments - // into an integer triplet, such as `128, 255, 0` - // - // This facilitates operations and conversions. - // - if (Array.isArray(rgb)) { - this.rgb = rgb; - } - else if (rgb.length >= 6) { - this.rgb = []; - rgb.match(/.{2}/g).map(function (c, i) { - if (i < 3) { - self.rgb.push(parseInt(c, 16)); - } - else { - self.alpha = (parseInt(c, 16)) / 255; - } - }); - } - else { - this.rgb = []; - rgb.split('').map(function (c, i) { - if (i < 3) { - self.rgb.push(parseInt(c + c, 16)); - } - else { - self.alpha = (parseInt(c + c, 16)) / 255; - } - }); - } - this.alpha = this.alpha || (typeof a === 'number' ? a : 1); - if (typeof originalForm !== 'undefined') { - this.value = originalForm; - } - }; - Color.prototype = Object.assign(new Node(), { - type: 'Color', - luma: function () { - var r = this.rgb[0] / 255, g = this.rgb[1] / 255, b = this.rgb[2] / 255; - r = (r <= 0.03928) ? r / 12.92 : Math.pow(((r + 0.055) / 1.055), 2.4); - g = (g <= 0.03928) ? g / 12.92 : Math.pow(((g + 0.055) / 1.055), 2.4); - b = (b <= 0.03928) ? b / 12.92 : Math.pow(((b + 0.055) / 1.055), 2.4); - return 0.2126 * r + 0.7152 * g + 0.0722 * b; - }, - genCSS: function (context, output) { - output.add(this.toCSS(context)); - }, - toCSS: function (context, doNotCompress) { - var compress = context && context.compress && !doNotCompress; - var color; - var alpha; - var colorFunction; - var args = []; - // `value` is set if this color was originally - // converted from a named color string so we need - // to respect this and try to output named color too. - alpha = this.fround(context, this.alpha); - if (this.value) { - if (this.value.indexOf('rgb') === 0) { - if (alpha < 1) { - colorFunction = 'rgba'; - } - } - else if (this.value.indexOf('hsl') === 0) { - if (alpha < 1) { - colorFunction = 'hsla'; - } - else { - colorFunction = 'hsl'; - } - } - else { - return this.value; - } - } - else { - if (alpha < 1) { - colorFunction = 'rgba'; - } - } - switch (colorFunction) { - case 'rgba': - args = this.rgb.map(function (c) { - return clamp$1(Math.round(c), 255); - }).concat(clamp$1(alpha, 1)); - break; - case 'hsla': - args.push(clamp$1(alpha, 1)); - case 'hsl': - color = this.toHSL(); - args = [ - this.fround(context, color.h), - this.fround(context, color.s * 100) + "%", - this.fround(context, color.l * 100) + "%" - ].concat(args); - } - if (colorFunction) { - // Values are capped between `0` and `255`, rounded and zero-padded. - return colorFunction + "(" + args.join("," + (compress ? '' : ' ')) + ")"; - } - color = this.toRGB(); - if (compress) { - var splitcolor = color.split(''); - // Convert color to short format - if (splitcolor[1] === splitcolor[2] && splitcolor[3] === splitcolor[4] && splitcolor[5] === splitcolor[6]) { - color = "#" + splitcolor[1] + splitcolor[3] + splitcolor[5]; - } - } - return color; - }, - // - // Operations have to be done per-channel, if not, - // channels will spill onto each other. Once we have - // our result, in the form of an integer triplet, - // we create a new Color node to hold the result. - // - operate: function (context, op, other) { - var rgb = new Array(3); - var alpha = this.alpha * (1 - other.alpha) + other.alpha; - for (var c = 0; c < 3; c++) { - rgb[c] = this._operate(context, op, this.rgb[c], other.rgb[c]); - } - return new Color(rgb, alpha); - }, - toRGB: function () { - return toHex(this.rgb); - }, - toHSL: function () { - var r = this.rgb[0] / 255, g = this.rgb[1] / 255, b = this.rgb[2] / 255, a = this.alpha; - var max = Math.max(r, g, b), min = Math.min(r, g, b); - var h; - var s; - var l = (max + min) / 2; - var d = max - min; - if (max === min) { - h = s = 0; - } - else { - s = l > 0.5 ? d / (2 - max - min) : d / (max + min); - switch (max) { - case r: - h = (g - b) / d + (g < b ? 6 : 0); - break; - case g: - h = (b - r) / d + 2; - break; - case b: - h = (r - g) / d + 4; - break; - } - h /= 6; - } - return { h: h * 360, s: s, l: l, a: a }; - }, - // Adapted from http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript - toHSV: function () { - var r = this.rgb[0] / 255, g = this.rgb[1] / 255, b = this.rgb[2] / 255, a = this.alpha; - var max = Math.max(r, g, b), min = Math.min(r, g, b); - var h; - var s; - var v = max; - var d = max - min; - if (max === 0) { - s = 0; - } - else { - s = d / max; - } - if (max === min) { - h = 0; - } - else { - switch (max) { - case r: - h = (g - b) / d + (g < b ? 6 : 0); - break; - case g: - h = (b - r) / d + 2; - break; - case b: - h = (r - g) / d + 4; - break; - } - h /= 6; - } - return { h: h * 360, s: s, v: v, a: a }; - }, - toARGB: function () { - return toHex([this.alpha * 255].concat(this.rgb)); - }, - compare: function (x) { - return (x.rgb && - x.rgb[0] === this.rgb[0] && - x.rgb[1] === this.rgb[1] && - x.rgb[2] === this.rgb[2] && - x.alpha === this.alpha) ? 0 : undefined; - } - }); - Color.fromKeyword = function (keyword) { - var c; - var key = keyword.toLowerCase(); - if (colors.hasOwnProperty(key)) { - c = new Color(colors[key].slice(1)); - } - else if (key === 'transparent') { - c = new Color([0, 0, 0], 0); - } - if (c) { - c.value = keyword; - return c; - } - }; - function clamp$1(v, max) { - return Math.min(Math.max(v, 0), max); - } - function toHex(v) { - return "#" + v.map(function (c) { - c = clamp$1(Math.round(c), 255); - return (c < 16 ? '0' : '') + c.toString(16); - }).join(''); - } - - var Paren = function (node) { - this.value = node; - }; - Paren.prototype = Object.assign(new Node(), { - type: 'Paren', - genCSS: function (context, output) { - output.add('('); - this.value.genCSS(context, output); - output.add(')'); - }, - eval: function (context) { - return new Paren(this.value.eval(context)); - } - }); - - var _noSpaceCombinators = { - '': true, - ' ': true, - '|': true - }; - var Combinator = function (value) { - if (value === ' ') { - this.value = ' '; - this.emptyOrWhitespace = true; - } - else { - this.value = value ? value.trim() : ''; - this.emptyOrWhitespace = this.value === ''; - } - }; - Combinator.prototype = Object.assign(new Node(), { - type: 'Combinator', - genCSS: function (context, output) { - var spaceOrEmpty = (context.compress || _noSpaceCombinators[this.value]) ? '' : ' '; - output.add(spaceOrEmpty + this.value + spaceOrEmpty); - } - }); - - var Element = function (combinator, value, isVariable, index, currentFileInfo, visibilityInfo) { - this.combinator = combinator instanceof Combinator ? - combinator : new Combinator(combinator); - if (typeof value === 'string') { - this.value = value.trim(); - } - else if (value) { - this.value = value; - } - else { - this.value = ''; - } - this.isVariable = isVariable; - this._index = index; - this._fileInfo = currentFileInfo; - this.copyVisibilityInfo(visibilityInfo); - this.setParent(this.combinator, this); - }; - Element.prototype = Object.assign(new Node(), { - type: 'Element', - accept: function (visitor) { - var value = this.value; - this.combinator = visitor.visit(this.combinator); - if (typeof value === 'object') { - this.value = visitor.visit(value); - } - }, - eval: function (context) { - return new Element(this.combinator, this.value.eval ? this.value.eval(context) : this.value, this.isVariable, this.getIndex(), this.fileInfo(), this.visibilityInfo()); - }, - clone: function () { - return new Element(this.combinator, this.value, this.isVariable, this.getIndex(), this.fileInfo(), this.visibilityInfo()); - }, - genCSS: function (context, output) { - output.add(this.toCSS(context), this.fileInfo(), this.getIndex()); - }, - toCSS: function (context) { - context = context || {}; - var value = this.value; - var firstSelector = context.firstSelector; - if (value instanceof Paren) { - // selector in parens should not be affected by outer selector - // flags (breaks only interpolated selectors - see #1973) - context.firstSelector = true; - } - value = value.toCSS ? value.toCSS(context) : value; - context.firstSelector = firstSelector; - if (value === '' && this.combinator.value.charAt(0) === '&') { - return ''; - } - else { - return this.combinator.toCSS(context) + value; - } - } - }); - - var Math$1 = { - ALWAYS: 0, - PARENS_DIVISION: 1, - PARENS: 2 - // removed - STRICT_LEGACY: 3 - }; - var RewriteUrls = { - OFF: 0, - LOCAL: 1, - ALL: 2 - }; - - /** - * Returns the object type of the given payload - * - * @param {*} payload - * @returns {string} - */ - function getType(payload) { - return Object.prototype.toString.call(payload).slice(8, -1); - } - /** - * Returns whether the payload is a plain JavaScript object (excluding special classes or objects with other prototypes) - * - * @param {*} payload - * @returns {payload is Record} - */ - function isPlainObject(payload) { - if (getType(payload) !== 'Object') - return false; - return payload.constructor === Object && Object.getPrototypeOf(payload) === Object.prototype; - } - /** - * Returns whether the payload is an array - * - * @param {any} payload - * @returns {payload is any[]} - */ - function isArray(payload) { - return getType(payload) === 'Array'; - } - - /*! ***************************************************************************** - Copyright (c) Microsoft Corporation. All rights reserved. - 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 - - THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED - WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, - MERCHANTABLITY OR NON-INFRINGEMENT. - - See the Apache Version 2.0 License for specific language governing permissions - and limitations under the License. - ***************************************************************************** */ - - function __spreadArrays() { - for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length; - for (var r = Array(s), k = 0, i = 0; i < il; i++) - for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) - r[k] = a[j]; - return r; - } - - function assignProp(carry, key, newVal, originalObject, includeNonenumerable) { - var propType = {}.propertyIsEnumerable.call(originalObject, key) - ? 'enumerable' - : 'nonenumerable'; - if (propType === 'enumerable') - carry[key] = newVal; - if (includeNonenumerable && propType === 'nonenumerable') { - Object.defineProperty(carry, key, { - value: newVal, - enumerable: false, - writable: true, - configurable: true, - }); - } - } - /** - * Copy (clone) an object and all its props recursively to get rid of any prop referenced of the original object. Arrays are also cloned, however objects inside arrays are still linked. - * - * @export - * @template T - * @param {T} target Target can be anything - * @param {Options} [options={}] Options can be `props` or `nonenumerable` - * @returns {T} the target with replaced values - * @export - */ - function copy(target, options) { - if (options === void 0) { options = {}; } - if (isArray(target)) - return target.map(function (i) { return copy(i, options); }); - if (!isPlainObject(target)) - return target; - var props = Object.getOwnPropertyNames(target); - var symbols = Object.getOwnPropertySymbols(target); - return __spreadArrays(props, symbols).reduce(function (carry, key) { - if (isArray(options.props) && !options.props.includes(key)) { - return carry; - } - var val = target[key]; - var newVal = copy(val, options); - assignProp(carry, key, newVal, target, options.nonenumerable); - return carry; - }, {}); - } - - /* jshint proto: true */ - function getLocation(index, inputStream) { - var n = index + 1; - var line = null; - var column = -1; - while (--n >= 0 && inputStream.charAt(n) !== '\n') { - column++; - } - if (typeof index === 'number') { - line = (inputStream.slice(0, index).match(/\n/g) || '').length; - } - return { - line: line, - column: column - }; - } - function copyArray(arr) { - var i; - var length = arr.length; - var copy = new Array(length); - for (i = 0; i < length; i++) { - copy[i] = arr[i]; - } - return copy; - } - function clone(obj) { - var cloned = {}; - for (var prop in obj) { - if (obj.hasOwnProperty(prop)) { - cloned[prop] = obj[prop]; - } - } - return cloned; - } - function defaults(obj1, obj2) { - var newObj = obj2 || {}; - if (!obj2._defaults) { - newObj = {}; - var defaults_1 = copy(obj1); - newObj._defaults = defaults_1; - var cloned = obj2 ? copy(obj2) : {}; - Object.assign(newObj, defaults_1, cloned); - } - return newObj; - } - function copyOptions(obj1, obj2) { - if (obj2 && obj2._defaults) { - return obj2; - } - var opts = defaults(obj1, obj2); - if (opts.strictMath) { - opts.math = Math$1.PARENS; - } - // Back compat with changed relativeUrls option - if (opts.relativeUrls) { - opts.rewriteUrls = RewriteUrls.ALL; - } - if (typeof opts.math === 'string') { - switch (opts.math.toLowerCase()) { - case 'always': - opts.math = Math$1.ALWAYS; - break; - case 'parens-division': - opts.math = Math$1.PARENS_DIVISION; - break; - case 'strict': - case 'parens': - opts.math = Math$1.PARENS; - break; - default: - opts.math = Math$1.PARENS; - } - } - if (typeof opts.rewriteUrls === 'string') { - switch (opts.rewriteUrls.toLowerCase()) { - case 'off': - opts.rewriteUrls = RewriteUrls.OFF; - break; - case 'local': - opts.rewriteUrls = RewriteUrls.LOCAL; - break; - case 'all': - opts.rewriteUrls = RewriteUrls.ALL; - break; - } - } - return opts; - } - function merge(obj1, obj2) { - for (var prop in obj2) { - if (obj2.hasOwnProperty(prop)) { - obj1[prop] = obj2[prop]; - } - } - return obj1; - } - function flattenArray(arr, result) { - if (result === void 0) { result = []; } - for (var i = 0, length_1 = arr.length; i < length_1; i++) { - var value = arr[i]; - if (Array.isArray(value)) { - flattenArray(value, result); - } - else { - if (value !== undefined) { - result.push(value); - } - } - } - return result; - } - - var utils = /*#__PURE__*/Object.freeze({ - __proto__: null, - getLocation: getLocation, - copyArray: copyArray, - clone: clone, - defaults: defaults, - copyOptions: copyOptions, - merge: merge, - flattenArray: flattenArray - }); - - var anonymousFunc = /(|Function):(\d+):(\d+)/; - /** - * This is a centralized class of any error that could be thrown internally (mostly by the parser). - * Besides standard .message it keeps some additional data like a path to the file where the error - * occurred along with line and column numbers. - * - * @class - * @extends Error - * @type {module.LessError} - * - * @prop {string} type - * @prop {string} filename - * @prop {number} index - * @prop {number} line - * @prop {number} column - * @prop {number} callLine - * @prop {number} callExtract - * @prop {string[]} extract - * - * @param {Object} e - An error object to wrap around or just a descriptive object - * @param {Object} fileContentMap - An object with file contents in 'contents' property (like importManager) @todo - move to fileManager? - * @param {string} [currentFilename] - */ - var LessError = function (e, fileContentMap, currentFilename) { - Error.call(this); - var filename = e.filename || currentFilename; - this.message = e.message; - this.stack = e.stack; - if (fileContentMap && filename) { - var input = fileContentMap.contents[filename]; - var loc = getLocation(e.index, input); - var line = loc.line; - var col = loc.column; - var callLine = e.call && getLocation(e.call, input).line; - var lines = input ? input.split('\n') : ''; - this.type = e.type || 'Syntax'; - this.filename = filename; - this.index = e.index; - this.line = typeof line === 'number' ? line + 1 : null; - this.column = col; - if (!this.line && this.stack) { - var found = this.stack.match(anonymousFunc); - /** - * We have to figure out how this environment stringifies anonymous functions - * so we can correctly map plugin errors. - * - * Note, in Node 8, the output of anonymous funcs varied based on parameters - * being present or not, so we inject dummy params. - */ - var func = new Function('a', 'throw new Error()'); - var lineAdjust = 0; - try { - func(); - } - catch (e) { - var match = e.stack.match(anonymousFunc); - var line = parseInt(match[2]); - lineAdjust = 1 - line; - } - if (found) { - if (found[2]) { - this.line = parseInt(found[2]) + lineAdjust; - } - if (found[3]) { - this.column = parseInt(found[3]); - } - } - } - this.callLine = callLine + 1; - this.callExtract = lines[callLine]; - this.extract = [ - lines[this.line - 2], - lines[this.line - 1], - lines[this.line] - ]; - } - }; - if (typeof Object.create === 'undefined') { - var F = function () { }; - F.prototype = Error.prototype; - LessError.prototype = new F(); - } - else { - LessError.prototype = Object.create(Error.prototype); - } - LessError.prototype.constructor = LessError; - /** - * An overridden version of the default Object.prototype.toString - * which uses additional information to create a helpful message. - * - * @param {Object} options - * @returns {string} - */ - LessError.prototype.toString = function (options) { - options = options || {}; - var message = ''; - var extract = this.extract || []; - var error = []; - var stylize = function (str) { return str; }; - if (options.stylize) { - var type = typeof options.stylize; - if (type !== 'function') { - throw Error("options.stylize should be a function, got a " + type + "!"); - } - stylize = options.stylize; - } - if (this.line !== null) { - if (typeof extract[0] === 'string') { - error.push(stylize(this.line - 1 + " " + extract[0], 'grey')); - } - if (typeof extract[1] === 'string') { - var errorTxt = this.line + " "; - if (extract[1]) { - errorTxt += extract[1].slice(0, this.column) + - stylize(stylize(stylize(extract[1].substr(this.column, 1), 'bold') + - extract[1].slice(this.column + 1), 'red'), 'inverse'); - } - error.push(errorTxt); - } - if (typeof extract[2] === 'string') { - error.push(stylize(this.line + 1 + " " + extract[2], 'grey')); - } - error = error.join('\n') + stylize('', 'reset') + "\n"; - } - message += stylize(this.type + "Error: " + this.message, 'red'); - if (this.filename) { - message += stylize(' in ', 'red') + this.filename; - } - if (this.line) { - message += stylize(" on line " + this.line + ", column " + (this.column + 1) + ":", 'grey'); - } - message += "\n" + error; - if (this.callLine) { - message += stylize('from ', 'red') + (this.filename || '') + "/n"; - message += stylize(this.callLine, 'grey') + " " + this.callExtract + "/n"; - } - return message; - }; - - var Selector = function (elements, extendList, condition, index, currentFileInfo, visibilityInfo) { - this.extendList = extendList; - this.condition = condition; - this.evaldCondition = !condition; - this._index = index; - this._fileInfo = currentFileInfo; - this.elements = this.getElements(elements); - this.mixinElements_ = undefined; - this.copyVisibilityInfo(visibilityInfo); - this.setParent(this.elements, this); - }; - Selector.prototype = Object.assign(new Node(), { - type: 'Selector', - accept: function (visitor) { - if (this.elements) { - this.elements = visitor.visitArray(this.elements); - } - if (this.extendList) { - this.extendList = visitor.visitArray(this.extendList); - } - if (this.condition) { - this.condition = visitor.visit(this.condition); - } - }, - createDerived: function (elements, extendList, evaldCondition) { - elements = this.getElements(elements); - var newSelector = new Selector(elements, extendList || this.extendList, null, this.getIndex(), this.fileInfo(), this.visibilityInfo()); - newSelector.evaldCondition = (evaldCondition != null) ? evaldCondition : this.evaldCondition; - newSelector.mediaEmpty = this.mediaEmpty; - return newSelector; - }, - getElements: function (els) { - if (!els) { - return [new Element('', '&', false, this._index, this._fileInfo)]; - } - if (typeof els === 'string') { - this.parse.parseNode(els, ['selector'], this._index, this._fileInfo, function (err, result) { - if (err) { - throw new LessError({ - index: err.index, - message: err.message - }, this.parse.imports, this._fileInfo.filename); - } - els = result[0].elements; - }); - } - return els; - }, - createEmptySelectors: function () { - var el = new Element('', '&', false, this._index, this._fileInfo), sels = [new Selector([el], null, null, this._index, this._fileInfo)]; - sels[0].mediaEmpty = true; - return sels; - }, - match: function (other) { - var elements = this.elements; - var len = elements.length; - var olen; - var i; - other = other.mixinElements(); - olen = other.length; - if (olen === 0 || len < olen) { - return 0; - } - else { - for (i = 0; i < olen; i++) { - if (elements[i].value !== other[i]) { - return 0; - } - } - } - return olen; // return number of matched elements - }, - mixinElements: function () { - if (this.mixinElements_) { - return this.mixinElements_; - } - var elements = this.elements.map(function (v) { - return v.combinator.value + (v.value.value || v.value); - }).join('').match(/[,&#\*\.\w-]([\w-]|(\\.))*/g); - if (elements) { - if (elements[0] === '&') { - elements.shift(); - } - } - else { - elements = []; - } - return (this.mixinElements_ = elements); - }, - isJustParentSelector: function () { - return !this.mediaEmpty && - this.elements.length === 1 && - this.elements[0].value === '&' && - (this.elements[0].combinator.value === ' ' || this.elements[0].combinator.value === ''); - }, - eval: function (context) { - var evaldCondition = this.condition && this.condition.eval(context); - var elements = this.elements; - var extendList = this.extendList; - elements = elements && elements.map(function (e) { return e.eval(context); }); - extendList = extendList && extendList.map(function (extend) { return extend.eval(context); }); - return this.createDerived(elements, extendList, evaldCondition); - }, - genCSS: function (context, output) { - var i, element; - if ((!context || !context.firstSelector) && this.elements[0].combinator.value === '') { - output.add(' ', this.fileInfo(), this.getIndex()); - } - for (i = 0; i < this.elements.length; i++) { - element = this.elements[i]; - element.genCSS(context, output); - } - }, - getIsOutput: function () { - return this.evaldCondition; - } - }); - - var Value = function (value) { - if (!value) { - throw new Error('Value requires an array argument'); - } - if (!Array.isArray(value)) { - this.value = [value]; - } - else { - this.value = value; - } - }; - Value.prototype = Object.assign(new Node(), { - type: 'Value', - accept: function (visitor) { - if (this.value) { - this.value = visitor.visitArray(this.value); - } - }, - eval: function (context) { - if (this.value.length === 1) { - return this.value[0].eval(context); - } - else { - return new Value(this.value.map(function (v) { - return v.eval(context); - })); - } - }, - genCSS: function (context, output) { - var i; - for (i = 0; i < this.value.length; i++) { - this.value[i].genCSS(context, output); - if (i + 1 < this.value.length) { - output.add((context && context.compress) ? ',' : ', '); - } - } - } - }); - - var Keyword = function (value) { - this.value = value; - }; - Keyword.prototype = Object.assign(new Node(), { - type: 'Keyword', - genCSS: function (context, output) { - if (this.value === '%') { - throw { type: 'Syntax', message: 'Invalid % without number' }; - } - output.add(this.value); - } - }); - Keyword.True = new Keyword('true'); - Keyword.False = new Keyword('false'); - - var Anonymous = function (value, index, currentFileInfo, mapLines, rulesetLike, visibilityInfo) { - this.value = value; - this._index = index; - this._fileInfo = currentFileInfo; - this.mapLines = mapLines; - this.rulesetLike = (typeof rulesetLike === 'undefined') ? false : rulesetLike; - this.allowRoot = true; - this.copyVisibilityInfo(visibilityInfo); - }; - Anonymous.prototype = Object.assign(new Node(), { - type: 'Anonymous', - eval: function () { - return new Anonymous(this.value, this._index, this._fileInfo, this.mapLines, this.rulesetLike, this.visibilityInfo()); - }, - compare: function (other) { - return other.toCSS && this.toCSS() === other.toCSS() ? 0 : undefined; - }, - isRulesetLike: function () { - return this.rulesetLike; - }, - genCSS: function (context, output) { - this.nodeVisible = Boolean(this.value); - if (this.nodeVisible) { - output.add(this.value, this._fileInfo, this._index, this.mapLines); - } - } - }); - - var MATH$1 = Math$1; - function evalName(context, name) { - var value = ''; - var i; - var n = name.length; - var output = { add: function (s) { value += s; } }; - for (i = 0; i < n; i++) { - name[i].eval(context).genCSS(context, output); - } - return value; - } - var Declaration = function (name, value, important, merge, index, currentFileInfo, inline, variable) { - this.name = name; - this.value = (value instanceof Node) ? value : new Value([value ? new Anonymous(value) : null]); - this.important = important ? " " + important.trim() : ''; - this.merge = merge; - this._index = index; - this._fileInfo = currentFileInfo; - this.inline = inline || false; - this.variable = (variable !== undefined) ? variable - : (name.charAt && (name.charAt(0) === '@')); - this.allowRoot = true; - this.setParent(this.value, this); - }; - Declaration.prototype = Object.assign(new Node(), { - type: 'Declaration', - genCSS: function (context, output) { - output.add(this.name + (context.compress ? ':' : ': '), this.fileInfo(), this.getIndex()); - try { - this.value.genCSS(context, output); - } - catch (e) { - e.index = this._index; - e.filename = this._fileInfo.filename; - throw e; - } - output.add(this.important + ((this.inline || (context.lastRule && context.compress)) ? '' : ';'), this._fileInfo, this._index); - }, - eval: function (context) { - var mathBypass = false, prevMath, name = this.name, evaldValue, variable = this.variable; - if (typeof name !== 'string') { - // expand 'primitive' name directly to get - // things faster (~10% for benchmark.less): - name = (name.length === 1) && (name[0] instanceof Keyword) ? - name[0].value : evalName(context, name); - variable = false; // never treat expanded interpolation as new variable name - } - // @todo remove when parens-division is default - if (name === 'font' && context.math === MATH$1.ALWAYS) { - mathBypass = true; - prevMath = context.math; - context.math = MATH$1.PARENS_DIVISION; - } - try { - context.importantScope.push({}); - evaldValue = this.value.eval(context); - if (!this.variable && evaldValue.type === 'DetachedRuleset') { - throw { message: 'Rulesets cannot be evaluated on a property.', - index: this.getIndex(), filename: this.fileInfo().filename }; - } - var important = this.important; - var importantResult = context.importantScope.pop(); - if (!important && importantResult.important) { - important = importantResult.important; - } - return new Declaration(name, evaldValue, important, this.merge, this.getIndex(), this.fileInfo(), this.inline, variable); - } - catch (e) { - if (typeof e.index !== 'number') { - e.index = this.getIndex(); - e.filename = this.fileInfo().filename; - } - throw e; - } - finally { - if (mathBypass) { - context.math = prevMath; - } - } - }, - makeImportant: function () { - return new Declaration(this.name, this.value, '!important', this.merge, this.getIndex(), this.fileInfo(), this.inline); - } - }); - - function asComment(ctx) { - return "/* line " + ctx.debugInfo.lineNumber + ", " + ctx.debugInfo.fileName + " */\n"; - } - function asMediaQuery(ctx) { - var filenameWithProtocol = ctx.debugInfo.fileName; - if (!/^[a-z]+:\/\//i.test(filenameWithProtocol)) { - filenameWithProtocol = "file://" + filenameWithProtocol; - } - return "@media -sass-debug-info{filename{font-family:" + filenameWithProtocol.replace(/([.:\/\\])/g, function (a) { - if (a == '\\') { - a = '\/'; - } - return "\\" + a; - }) + "}line{font-family:\\00003" + ctx.debugInfo.lineNumber + "}}\n"; - } - function debugInfo(context, ctx, lineSeparator) { - var result = ''; - if (context.dumpLineNumbers && !context.compress) { - switch (context.dumpLineNumbers) { - case 'comments': - result = asComment(ctx); - break; - case 'mediaquery': - result = asMediaQuery(ctx); - break; - case 'all': - result = asComment(ctx) + (lineSeparator || '') + asMediaQuery(ctx); - break; - } - } - return result; - } - - var Comment = function (value, isLineComment, index, currentFileInfo) { - this.value = value; - this.isLineComment = isLineComment; - this._index = index; - this._fileInfo = currentFileInfo; - this.allowRoot = true; - }; - Comment.prototype = Object.assign(new Node(), { - type: 'Comment', - genCSS: function (context, output) { - if (this.debugInfo) { - output.add(debugInfo(context, this), this.fileInfo(), this.getIndex()); - } - output.add(this.value); - }, - isSilent: function (context) { - var isCompressed = context.compress && this.value[2] !== '!'; - return this.isLineComment || isCompressed; - } - }); - - var contexts = {}; - var copyFromOriginal = function copyFromOriginal(original, destination, propertiesToCopy) { - if (!original) { - return; - } - for (var i = 0; i < propertiesToCopy.length; i++) { - if (original.hasOwnProperty(propertiesToCopy[i])) { - destination[propertiesToCopy[i]] = original[propertiesToCopy[i]]; - } - } - }; - /* - parse is used whilst parsing - */ - var parseCopyProperties = [ - // options - 'paths', - 'rewriteUrls', - 'rootpath', - 'strictImports', - 'insecure', - 'dumpLineNumbers', - 'compress', - 'syncImport', - 'chunkInput', - 'mime', - 'useFileCache', - // context - 'processImports', - // Used by the import manager to stop multiple import visitors being created. - 'pluginManager' // Used as the plugin manager for the session - ]; - contexts.Parse = function (options) { - copyFromOriginal(options, this, parseCopyProperties); - if (typeof this.paths === 'string') { - this.paths = [this.paths]; - } - }; - var evalCopyProperties = [ - 'paths', - 'compress', - 'math', - 'strictUnits', - 'sourceMap', - 'importMultiple', - 'urlArgs', - 'javascriptEnabled', - 'pluginManager', - 'importantScope', - 'rewriteUrls' // option - whether to adjust URL's to be relative - ]; - contexts.Eval = function (options, frames) { - copyFromOriginal(options, this, evalCopyProperties); - if (typeof this.paths === 'string') { - this.paths = [this.paths]; - } - this.frames = frames || []; - this.importantScope = this.importantScope || []; - }; - contexts.Eval.prototype.enterCalc = function () { - if (!this.calcStack) { - this.calcStack = []; - } - this.calcStack.push(true); - this.inCalc = true; - }; - contexts.Eval.prototype.exitCalc = function () { - this.calcStack.pop(); - if (!this.calcStack.length) { - this.inCalc = false; - } - }; - contexts.Eval.prototype.inParenthesis = function () { - if (!this.parensStack) { - this.parensStack = []; - } - this.parensStack.push(true); - }; - contexts.Eval.prototype.outOfParenthesis = function () { - this.parensStack.pop(); - }; - contexts.Eval.prototype.inCalc = false; - contexts.Eval.prototype.mathOn = true; - contexts.Eval.prototype.isMathOn = function (op) { - if (!this.mathOn) { - return false; - } - if (op === '/' && this.math !== Math$1.ALWAYS && (!this.parensStack || !this.parensStack.length)) { - return false; - } - if (this.math > Math$1.PARENS_DIVISION) { - return this.parensStack && this.parensStack.length; - } - return true; - }; - contexts.Eval.prototype.pathRequiresRewrite = function (path) { - var isRelative = this.rewriteUrls === RewriteUrls.LOCAL ? isPathLocalRelative : isPathRelative; - return isRelative(path); - }; - contexts.Eval.prototype.rewritePath = function (path, rootpath) { - var newPath; - rootpath = rootpath || ''; - newPath = this.normalizePath(rootpath + path); - // If a path was explicit relative and the rootpath was not an absolute path - // we must ensure that the new path is also explicit relative. - if (isPathLocalRelative(path) && - isPathRelative(rootpath) && - isPathLocalRelative(newPath) === false) { - newPath = "./" + newPath; - } - return newPath; - }; - contexts.Eval.prototype.normalizePath = function (path) { - var segments = path.split('/').reverse(); - var segment; - path = []; - while (segments.length !== 0) { - segment = segments.pop(); - switch (segment) { - case '.': - break; - case '..': - if ((path.length === 0) || (path[path.length - 1] === '..')) { - path.push(segment); - } - else { - path.pop(); - } - break; - default: - path.push(segment); - break; - } - } - return path.join('/'); - }; - function isPathRelative(path) { - return !/^(?:[a-z-]+:|\/|#)/i.test(path); - } - function isPathLocalRelative(path) { - return path.charAt(0) === '.'; - } - // todo - do the same for the toCSS ? - - function makeRegistry(base) { - return { - _data: {}, - add: function (name, func) { - // precautionary case conversion, as later querying of - // the registry by function-caller uses lower case as well. - name = name.toLowerCase(); - if (this._data.hasOwnProperty(name)) ; - this._data[name] = func; - }, - addMultiple: function (functions) { - var _this = this; - Object.keys(functions).forEach(function (name) { - _this.add(name, functions[name]); - }); - }, - get: function (name) { - return this._data[name] || (base && base.get(name)); - }, - getLocalFunctions: function () { - return this._data; - }, - inherit: function () { - return makeRegistry(this); - }, - create: function (base) { - return makeRegistry(base); - } - }; - } - var functionRegistry = makeRegistry(null); - - var defaultFunc = { - eval: function () { - var v = this.value_; - var e = this.error_; - if (e) { - throw e; - } - if (v != null) { - return v ? Keyword.True : Keyword.False; - } - }, - value: function (v) { - this.value_ = v; - }, - error: function (e) { - this.error_ = e; - }, - reset: function () { - this.value_ = this.error_ = null; - } - }; - - var Ruleset = function (selectors, rules, strictImports, visibilityInfo) { - this.selectors = selectors; - this.rules = rules; - this._lookups = {}; - this._variables = null; - this._properties = null; - this.strictImports = strictImports; - this.copyVisibilityInfo(visibilityInfo); - this.allowRoot = true; - this.setParent(this.selectors, this); - this.setParent(this.rules, this); - }; - Ruleset.prototype = Object.assign(new Node(), { - type: 'Ruleset', - isRuleset: true, - isRulesetLike: function () { return true; }, - accept: function (visitor) { - if (this.paths) { - this.paths = visitor.visitArray(this.paths, true); - } - else if (this.selectors) { - this.selectors = visitor.visitArray(this.selectors); - } - if (this.rules && this.rules.length) { - this.rules = visitor.visitArray(this.rules); - } - }, - eval: function (context) { - var selectors; - var selCnt; - var selector; - var i; - var hasVariable; - var hasOnePassingSelector = false; - if (this.selectors && (selCnt = this.selectors.length)) { - selectors = new Array(selCnt); - defaultFunc.error({ - type: 'Syntax', - message: 'it is currently only allowed in parametric mixin guards,' - }); - for (i = 0; i < selCnt; i++) { - selector = this.selectors[i].eval(context); - for (var j = 0; j < selector.elements.length; j++) { - if (selector.elements[j].isVariable) { - hasVariable = true; - break; - } - } - selectors[i] = selector; - if (selector.evaldCondition) { - hasOnePassingSelector = true; - } - } - if (hasVariable) { - var toParseSelectors = new Array(selCnt); - for (i = 0; i < selCnt; i++) { - selector = selectors[i]; - toParseSelectors[i] = selector.toCSS(context); - } - this.parse.parseNode(toParseSelectors.join(','), ["selectors"], selectors[0].getIndex(), selectors[0].fileInfo(), function (err, result) { - if (result) { - selectors = flattenArray(result); - } - }); - } - defaultFunc.reset(); - } - else { - hasOnePassingSelector = true; - } - var rules = this.rules ? copyArray(this.rules) : null; - var ruleset = new Ruleset(selectors, rules, this.strictImports, this.visibilityInfo()); - var rule; - var subRule; - ruleset.originalRuleset = this; - ruleset.root = this.root; - ruleset.firstRoot = this.firstRoot; - ruleset.allowImports = this.allowImports; - if (this.debugInfo) { - ruleset.debugInfo = this.debugInfo; - } - if (!hasOnePassingSelector) { - rules.length = 0; - } - // inherit a function registry from the frames stack when possible; - // otherwise from the global registry - ruleset.functionRegistry = (function (frames) { - var i = 0; - var n = frames.length; - var found; - for (; i !== n; ++i) { - found = frames[i].functionRegistry; - if (found) { - return found; - } - } - return functionRegistry; - }(context.frames)).inherit(); - // push the current ruleset to the frames stack - var ctxFrames = context.frames; - ctxFrames.unshift(ruleset); - // currrent selectors - var ctxSelectors = context.selectors; - if (!ctxSelectors) { - context.selectors = ctxSelectors = []; - } - ctxSelectors.unshift(this.selectors); - // Evaluate imports - if (ruleset.root || ruleset.allowImports || !ruleset.strictImports) { - ruleset.evalImports(context); - } - // Store the frames around mixin definitions, - // so they can be evaluated like closures when the time comes. - var rsRules = ruleset.rules; - for (i = 0; (rule = rsRules[i]); i++) { - if (rule.evalFirst) { - rsRules[i] = rule.eval(context); - } - } - var mediaBlockCount = (context.mediaBlocks && context.mediaBlocks.length) || 0; - // Evaluate mixin calls. - for (i = 0; (rule = rsRules[i]); i++) { - if (rule.type === 'MixinCall') { - /* jshint loopfunc:true */ - rules = rule.eval(context).filter(function (r) { - if ((r instanceof Declaration) && r.variable) { - // do not pollute the scope if the variable is - // already there. consider returning false here - // but we need a way to "return" variable from mixins - return !(ruleset.variable(r.name)); - } - return true; - }); - rsRules.splice.apply(rsRules, [i, 1].concat(rules)); - i += rules.length - 1; - ruleset.resetCache(); - } - else if (rule.type === 'VariableCall') { - /* jshint loopfunc:true */ - rules = rule.eval(context).rules.filter(function (r) { - if ((r instanceof Declaration) && r.variable) { - // do not pollute the scope at all - return false; - } - return true; - }); - rsRules.splice.apply(rsRules, [i, 1].concat(rules)); - i += rules.length - 1; - ruleset.resetCache(); - } - } - // Evaluate everything else - for (i = 0; (rule = rsRules[i]); i++) { - if (!rule.evalFirst) { - rsRules[i] = rule = rule.eval ? rule.eval(context) : rule; - } - } - // Evaluate everything else - for (i = 0; (rule = rsRules[i]); i++) { - // for rulesets, check if it is a css guard and can be removed - if (rule instanceof Ruleset && rule.selectors && rule.selectors.length === 1) { - // check if it can be folded in (e.g. & where) - if (rule.selectors[0] && rule.selectors[0].isJustParentSelector()) { - rsRules.splice(i--, 1); - for (var j = 0; (subRule = rule.rules[j]); j++) { - if (subRule instanceof Node) { - subRule.copyVisibilityInfo(rule.visibilityInfo()); - if (!(subRule instanceof Declaration) || !subRule.variable) { - rsRules.splice(++i, 0, subRule); - } - } - } - } - } - } - // Pop the stack - ctxFrames.shift(); - ctxSelectors.shift(); - if (context.mediaBlocks) { - for (i = mediaBlockCount; i < context.mediaBlocks.length; i++) { - context.mediaBlocks[i].bubbleSelectors(selectors); - } - } - return ruleset; - }, - evalImports: function (context) { - var rules = this.rules; - var i; - var importRules; - if (!rules) { - return; - } - for (i = 0; i < rules.length; i++) { - if (rules[i].type === 'Import') { - importRules = rules[i].eval(context); - if (importRules && (importRules.length || importRules.length === 0)) { - rules.splice.apply(rules, [i, 1].concat(importRules)); - i += importRules.length - 1; - } - else { - rules.splice(i, 1, importRules); - } - this.resetCache(); - } - } - }, - makeImportant: function () { - var result = new Ruleset(this.selectors, this.rules.map(function (r) { - if (r.makeImportant) { - return r.makeImportant(); - } - else { - return r; - } - }), this.strictImports, this.visibilityInfo()); - return result; - }, - matchArgs: function (args) { - return !args || args.length === 0; - }, - // lets you call a css selector with a guard - matchCondition: function (args, context) { - var lastSelector = this.selectors[this.selectors.length - 1]; - if (!lastSelector.evaldCondition) { - return false; - } - if (lastSelector.condition && - !lastSelector.condition.eval(new contexts.Eval(context, context.frames))) { - return false; - } - return true; - }, - resetCache: function () { - this._rulesets = null; - this._variables = null; - this._properties = null; - this._lookups = {}; - }, - variables: function () { - if (!this._variables) { - this._variables = !this.rules ? {} : this.rules.reduce(function (hash, r) { - if (r instanceof Declaration && r.variable === true) { - hash[r.name] = r; - } - // when evaluating variables in an import statement, imports have not been eval'd - // so we need to go inside import statements. - // guard against root being a string (in the case of inlined less) - if (r.type === 'Import' && r.root && r.root.variables) { - var vars = r.root.variables(); - for (var name_1 in vars) { - if (vars.hasOwnProperty(name_1)) { - hash[name_1] = r.root.variable(name_1); - } - } - } - return hash; - }, {}); - } - return this._variables; - }, - properties: function () { - if (!this._properties) { - this._properties = !this.rules ? {} : this.rules.reduce(function (hash, r) { - if (r instanceof Declaration && r.variable !== true) { - var name_2 = (r.name.length === 1) && (r.name[0] instanceof Keyword) ? - r.name[0].value : r.name; - // Properties don't overwrite as they can merge - if (!hash["$" + name_2]) { - hash["$" + name_2] = [r]; - } - else { - hash["$" + name_2].push(r); - } - } - return hash; - }, {}); - } - return this._properties; - }, - variable: function (name) { - var decl = this.variables()[name]; - if (decl) { - return this.parseValue(decl); - } - }, - property: function (name) { - var decl = this.properties()[name]; - if (decl) { - return this.parseValue(decl); - } - }, - lastDeclaration: function () { - for (var i = this.rules.length; i > 0; i--) { - var decl = this.rules[i - 1]; - if (decl instanceof Declaration) { - return this.parseValue(decl); - } - } - }, - parseValue: function (toParse) { - var self = this; - function transformDeclaration(decl) { - if (decl.value instanceof Anonymous && !decl.parsed) { - if (typeof decl.value.value === 'string') { - this.parse.parseNode(decl.value.value, ['value', 'important'], decl.value.getIndex(), decl.fileInfo(), function (err, result) { - if (err) { - decl.parsed = true; - } - if (result) { - decl.value = result[0]; - decl.important = result[1] || ''; - decl.parsed = true; - } - }); - } - else { - decl.parsed = true; - } - return decl; - } - else { - return decl; - } - } - if (!Array.isArray(toParse)) { - return transformDeclaration.call(self, toParse); - } - else { - var nodes_1 = []; - toParse.forEach(function (n) { - nodes_1.push(transformDeclaration.call(self, n)); - }); - return nodes_1; - } - }, - rulesets: function () { - if (!this.rules) { - return []; - } - var filtRules = []; - var rules = this.rules; - var i; - var rule; - for (i = 0; (rule = rules[i]); i++) { - if (rule.isRuleset) { - filtRules.push(rule); - } - } - return filtRules; - }, - prependRule: function (rule) { - var rules = this.rules; - if (rules) { - rules.unshift(rule); - } - else { - this.rules = [rule]; - } - this.setParent(rule, this); - }, - find: function (selector, self, filter) { - self = self || this; - var rules = []; - var match; - var foundMixins; - var key = selector.toCSS(); - if (key in this._lookups) { - return this._lookups[key]; - } - this.rulesets().forEach(function (rule) { - if (rule !== self) { - for (var j = 0; j < rule.selectors.length; j++) { - match = selector.match(rule.selectors[j]); - if (match) { - if (selector.elements.length > match) { - if (!filter || filter(rule)) { - foundMixins = rule.find(new Selector(selector.elements.slice(match)), self, filter); - for (var i = 0; i < foundMixins.length; ++i) { - foundMixins[i].path.push(rule); - } - Array.prototype.push.apply(rules, foundMixins); - } - } - else { - rules.push({ rule: rule, path: [] }); - } - break; - } - } - } - }); - this._lookups[key] = rules; - return rules; - }, - genCSS: function (context, output) { - var i; - var j; - var charsetRuleNodes = []; - var ruleNodes = []; - var // Line number debugging - debugInfo$1; - var rule; - var path; - context.tabLevel = (context.tabLevel || 0); - if (!this.root) { - context.tabLevel++; - } - var tabRuleStr = context.compress ? '' : Array(context.tabLevel + 1).join(' '); - var tabSetStr = context.compress ? '' : Array(context.tabLevel).join(' '); - var sep; - var charsetNodeIndex = 0; - var importNodeIndex = 0; - for (i = 0; (rule = this.rules[i]); i++) { - if (rule instanceof Comment) { - if (importNodeIndex === i) { - importNodeIndex++; - } - ruleNodes.push(rule); - } - else if (rule.isCharset && rule.isCharset()) { - ruleNodes.splice(charsetNodeIndex, 0, rule); - charsetNodeIndex++; - importNodeIndex++; - } - else if (rule.type === 'Import') { - ruleNodes.splice(importNodeIndex, 0, rule); - importNodeIndex++; - } - else { - ruleNodes.push(rule); - } - } - ruleNodes = charsetRuleNodes.concat(ruleNodes); - // If this is the root node, we don't render - // a selector, or {}. - if (!this.root) { - debugInfo$1 = debugInfo(context, this, tabSetStr); - if (debugInfo$1) { - output.add(debugInfo$1); - output.add(tabSetStr); - } - var paths = this.paths; - var pathCnt = paths.length; - var pathSubCnt = void 0; - sep = context.compress ? ',' : (",\n" + tabSetStr); - for (i = 0; i < pathCnt; i++) { - path = paths[i]; - if (!(pathSubCnt = path.length)) { - continue; - } - if (i > 0) { - output.add(sep); - } - context.firstSelector = true; - path[0].genCSS(context, output); - context.firstSelector = false; - for (j = 1; j < pathSubCnt; j++) { - path[j].genCSS(context, output); - } - } - output.add((context.compress ? '{' : ' {\n') + tabRuleStr); - } - // Compile rules and rulesets - for (i = 0; (rule = ruleNodes[i]); i++) { - if (i + 1 === ruleNodes.length) { - context.lastRule = true; - } - var currentLastRule = context.lastRule; - if (rule.isRulesetLike(rule)) { - context.lastRule = false; - } - if (rule.genCSS) { - rule.genCSS(context, output); - } - else if (rule.value) { - output.add(rule.value.toString()); - } - context.lastRule = currentLastRule; - if (!context.lastRule && rule.isVisible()) { - output.add(context.compress ? '' : ("\n" + tabRuleStr)); - } - else { - context.lastRule = false; - } - } - if (!this.root) { - output.add((context.compress ? '}' : "\n" + tabSetStr + "}")); - context.tabLevel--; - } - if (!output.isEmpty() && !context.compress && this.firstRoot) { - output.add('\n'); - } - }, - joinSelectors: function (paths, context, selectors) { - for (var s = 0; s < selectors.length; s++) { - this.joinSelector(paths, context, selectors[s]); - } - }, - joinSelector: function (paths, context, selector) { - function createParenthesis(elementsToPak, originalElement) { - var replacementParen, j; - if (elementsToPak.length === 0) { - replacementParen = new Paren(elementsToPak[0]); - } - else { - var insideParent = new Array(elementsToPak.length); - for (j = 0; j < elementsToPak.length; j++) { - insideParent[j] = new Element(null, elementsToPak[j], originalElement.isVariable, originalElement._index, originalElement._fileInfo); - } - replacementParen = new Paren(new Selector(insideParent)); - } - return replacementParen; - } - function createSelector(containedElement, originalElement) { - var element, selector; - element = new Element(null, containedElement, originalElement.isVariable, originalElement._index, originalElement._fileInfo); - selector = new Selector([element]); - return selector; - } - // joins selector path from `beginningPath` with selector path in `addPath` - // `replacedElement` contains element that is being replaced by `addPath` - // returns concatenated path - function addReplacementIntoPath(beginningPath, addPath, replacedElement, originalSelector) { - var newSelectorPath, lastSelector, newJoinedSelector; - // our new selector path - newSelectorPath = []; - // construct the joined selector - if & is the first thing this will be empty, - // if not newJoinedSelector will be the last set of elements in the selector - if (beginningPath.length > 0) { - newSelectorPath = copyArray(beginningPath); - lastSelector = newSelectorPath.pop(); - newJoinedSelector = originalSelector.createDerived(copyArray(lastSelector.elements)); - } - else { - newJoinedSelector = originalSelector.createDerived([]); - } - if (addPath.length > 0) { - // /deep/ is a CSS4 selector - (removed, so should deprecate) - // that is valid without anything in front of it - // so if the & does not have a combinator that is "" or " " then - // and there is a combinator on the parent, then grab that. - // this also allows + a { & .b { .a & { ... though not sure why you would want to do that - var combinator = replacedElement.combinator; - var parentEl = addPath[0].elements[0]; - if (combinator.emptyOrWhitespace && !parentEl.combinator.emptyOrWhitespace) { - combinator = parentEl.combinator; - } - // join the elements so far with the first part of the parent - newJoinedSelector.elements.push(new Element(combinator, parentEl.value, replacedElement.isVariable, replacedElement._index, replacedElement._fileInfo)); - newJoinedSelector.elements = newJoinedSelector.elements.concat(addPath[0].elements.slice(1)); - } - // now add the joined selector - but only if it is not empty - if (newJoinedSelector.elements.length !== 0) { - newSelectorPath.push(newJoinedSelector); - } - // put together the parent selectors after the join (e.g. the rest of the parent) - if (addPath.length > 1) { - var restOfPath = addPath.slice(1); - restOfPath = restOfPath.map(function (selector) { - return selector.createDerived(selector.elements, []); - }); - newSelectorPath = newSelectorPath.concat(restOfPath); - } - return newSelectorPath; - } - // joins selector path from `beginningPath` with every selector path in `addPaths` array - // `replacedElement` contains element that is being replaced by `addPath` - // returns array with all concatenated paths - function addAllReplacementsIntoPath(beginningPath, addPaths, replacedElement, originalSelector, result) { - var j; - for (j = 0; j < beginningPath.length; j++) { - var newSelectorPath = addReplacementIntoPath(beginningPath[j], addPaths, replacedElement, originalSelector); - result.push(newSelectorPath); - } - return result; - } - function mergeElementsOnToSelectors(elements, selectors) { - var i, sel; - if (elements.length === 0) { - return; - } - if (selectors.length === 0) { - selectors.push([new Selector(elements)]); - return; - } - for (i = 0; (sel = selectors[i]); i++) { - // if the previous thing in sel is a parent this needs to join on to it - if (sel.length > 0) { - sel[sel.length - 1] = sel[sel.length - 1].createDerived(sel[sel.length - 1].elements.concat(elements)); - } - else { - sel.push(new Selector(elements)); - } - } - } - // replace all parent selectors inside `inSelector` by content of `context` array - // resulting selectors are returned inside `paths` array - // returns true if `inSelector` contained at least one parent selector - function replaceParentSelector(paths, context, inSelector) { - // The paths are [[Selector]] - // The first list is a list of comma separated selectors - // The inner list is a list of inheritance separated selectors - // e.g. - // .a, .b { - // .c { - // } - // } - // == [[.a] [.c]] [[.b] [.c]] - // - var i, j, k, currentElements, newSelectors, selectorsMultiplied, sel, el, hadParentSelector = false, length, lastSelector; - function findNestedSelector(element) { - var maybeSelector; - if (!(element.value instanceof Paren)) { - return null; - } - maybeSelector = element.value.value; - if (!(maybeSelector instanceof Selector)) { - return null; - } - return maybeSelector; - } - // the elements from the current selector so far - currentElements = []; - // the current list of new selectors to add to the path. - // We will build it up. We initiate it with one empty selector as we "multiply" the new selectors - // by the parents - newSelectors = [ - [] - ]; - for (i = 0; (el = inSelector.elements[i]); i++) { - // non parent reference elements just get added - if (el.value !== '&') { - var nestedSelector = findNestedSelector(el); - if (nestedSelector != null) { - // merge the current list of non parent selector elements - // on to the current list of selectors to add - mergeElementsOnToSelectors(currentElements, newSelectors); - var nestedPaths = []; - var replaced = void 0; - var replacedNewSelectors = []; - replaced = replaceParentSelector(nestedPaths, context, nestedSelector); - hadParentSelector = hadParentSelector || replaced; - // the nestedPaths array should have only one member - replaceParentSelector does not multiply selectors - for (k = 0; k < nestedPaths.length; k++) { - var replacementSelector = createSelector(createParenthesis(nestedPaths[k], el), el); - addAllReplacementsIntoPath(newSelectors, [replacementSelector], el, inSelector, replacedNewSelectors); - } - newSelectors = replacedNewSelectors; - currentElements = []; - } - else { - currentElements.push(el); - } - } - else { - hadParentSelector = true; - // the new list of selectors to add - selectorsMultiplied = []; - // merge the current list of non parent selector elements - // on to the current list of selectors to add - mergeElementsOnToSelectors(currentElements, newSelectors); - // loop through our current selectors - for (j = 0; j < newSelectors.length; j++) { - sel = newSelectors[j]; - // if we don't have any parent paths, the & might be in a mixin so that it can be used - // whether there are parents or not - if (context.length === 0) { - // the combinator used on el should now be applied to the next element instead so that - // it is not lost - if (sel.length > 0) { - sel[0].elements.push(new Element(el.combinator, '', el.isVariable, el._index, el._fileInfo)); - } - selectorsMultiplied.push(sel); - } - else { - // and the parent selectors - for (k = 0; k < context.length; k++) { - // We need to put the current selectors - // then join the last selector's elements on to the parents selectors - var newSelectorPath = addReplacementIntoPath(sel, context[k], el, inSelector); - // add that to our new set of selectors - selectorsMultiplied.push(newSelectorPath); - } - } - } - // our new selectors has been multiplied, so reset the state - newSelectors = selectorsMultiplied; - currentElements = []; - } - } - // if we have any elements left over (e.g. .a& .b == .b) - // add them on to all the current selectors - mergeElementsOnToSelectors(currentElements, newSelectors); - for (i = 0; i < newSelectors.length; i++) { - length = newSelectors[i].length; - if (length > 0) { - paths.push(newSelectors[i]); - lastSelector = newSelectors[i][length - 1]; - newSelectors[i][length - 1] = lastSelector.createDerived(lastSelector.elements, inSelector.extendList); - } - } - return hadParentSelector; - } - function deriveSelector(visibilityInfo, deriveFrom) { - var newSelector = deriveFrom.createDerived(deriveFrom.elements, deriveFrom.extendList, deriveFrom.evaldCondition); - newSelector.copyVisibilityInfo(visibilityInfo); - return newSelector; - } - // joinSelector code follows - var i, newPaths, hadParentSelector; - newPaths = []; - hadParentSelector = replaceParentSelector(newPaths, context, selector); - if (!hadParentSelector) { - if (context.length > 0) { - newPaths = []; - for (i = 0; i < context.length; i++) { - var concatenated = context[i].map(deriveSelector.bind(this, selector.visibilityInfo())); - concatenated.push(selector); - newPaths.push(concatenated); - } - } - else { - newPaths = [[selector]]; - } - } - for (i = 0; i < newPaths.length; i++) { - paths.push(newPaths[i]); - } - } - }); - - var AtRule = function (name, value, rules, index, currentFileInfo, debugInfo, isRooted, visibilityInfo) { - var i; - this.name = name; - this.value = (value instanceof Node) ? value : (value ? new Anonymous(value) : value); - if (rules) { - if (Array.isArray(rules)) { - this.rules = rules; - } - else { - this.rules = [rules]; - this.rules[0].selectors = (new Selector([], null, null, index, currentFileInfo)).createEmptySelectors(); - } - for (i = 0; i < this.rules.length; i++) { - this.rules[i].allowImports = true; - } - this.setParent(this.rules, this); - } - this._index = index; - this._fileInfo = currentFileInfo; - this.debugInfo = debugInfo; - this.isRooted = isRooted || false; - this.copyVisibilityInfo(visibilityInfo); - this.allowRoot = true; - }; - AtRule.prototype = Object.assign(new Node(), { - type: 'AtRule', - accept: function (visitor) { - var value = this.value, rules = this.rules; - if (rules) { - this.rules = visitor.visitArray(rules); - } - if (value) { - this.value = visitor.visit(value); - } - }, - isRulesetLike: function () { - return this.rules || !this.isCharset(); - }, - isCharset: function () { - return '@charset' === this.name; - }, - genCSS: function (context, output) { - var value = this.value, rules = this.rules; - output.add(this.name, this.fileInfo(), this.getIndex()); - if (value) { - output.add(' '); - value.genCSS(context, output); - } - if (rules) { - this.outputRuleset(context, output, rules); - } - else { - output.add(';'); - } - }, - eval: function (context) { - var mediaPathBackup, mediaBlocksBackup, value = this.value, rules = this.rules; - // media stored inside other atrule should not bubble over it - // backpup media bubbling information - mediaPathBackup = context.mediaPath; - mediaBlocksBackup = context.mediaBlocks; - // deleted media bubbling information - context.mediaPath = []; - context.mediaBlocks = []; - if (value) { - value = value.eval(context); - } - if (rules) { - // assuming that there is only one rule at this point - that is how parser constructs the rule - rules = [rules[0].eval(context)]; - rules[0].root = true; - } - // restore media bubbling information - context.mediaPath = mediaPathBackup; - context.mediaBlocks = mediaBlocksBackup; - return new AtRule(this.name, value, rules, this.getIndex(), this.fileInfo(), this.debugInfo, this.isRooted, this.visibilityInfo()); - }, - variable: function (name) { - if (this.rules) { - // assuming that there is only one rule at this point - that is how parser constructs the rule - return Ruleset.prototype.variable.call(this.rules[0], name); - } - }, - find: function () { - if (this.rules) { - // assuming that there is only one rule at this point - that is how parser constructs the rule - return Ruleset.prototype.find.apply(this.rules[0], arguments); - } - }, - rulesets: function () { - if (this.rules) { - // assuming that there is only one rule at this point - that is how parser constructs the rule - return Ruleset.prototype.rulesets.apply(this.rules[0]); - } - }, - outputRuleset: function (context, output, rules) { - var ruleCnt = rules.length; - var i; - context.tabLevel = (context.tabLevel | 0) + 1; - // Compressed - if (context.compress) { - output.add('{'); - for (i = 0; i < ruleCnt; i++) { - rules[i].genCSS(context, output); - } - output.add('}'); - context.tabLevel--; - return; - } - // Non-compressed - var tabSetStr = "\n" + Array(context.tabLevel).join(' '), tabRuleStr = tabSetStr + " "; - if (!ruleCnt) { - output.add(" {" + tabSetStr + "}"); - } - else { - output.add(" {" + tabRuleStr); - rules[0].genCSS(context, output); - for (i = 1; i < ruleCnt; i++) { - output.add(tabRuleStr); - rules[i].genCSS(context, output); - } - output.add(tabSetStr + "}"); - } - context.tabLevel--; - } - }); - - var DetachedRuleset = function (ruleset, frames) { - this.ruleset = ruleset; - this.frames = frames; - this.setParent(this.ruleset, this); - }; - DetachedRuleset.prototype = Object.assign(new Node(), { - type: 'DetachedRuleset', - evalFirst: true, - accept: function (visitor) { - this.ruleset = visitor.visit(this.ruleset); - }, - eval: function (context) { - var frames = this.frames || copyArray(context.frames); - return new DetachedRuleset(this.ruleset, frames); - }, - callEval: function (context) { - return this.ruleset.eval(this.frames ? new contexts.Eval(context, this.frames.concat(context.frames)) : context); - } - }); - - var Unit = function (numerator, denominator, backupUnit) { - this.numerator = numerator ? copyArray(numerator).sort() : []; - this.denominator = denominator ? copyArray(denominator).sort() : []; - if (backupUnit) { - this.backupUnit = backupUnit; - } - else if (numerator && numerator.length) { - this.backupUnit = numerator[0]; - } - }; - Unit.prototype = Object.assign(new Node(), { - type: 'Unit', - clone: function () { - return new Unit(copyArray(this.numerator), copyArray(this.denominator), this.backupUnit); - }, - genCSS: function (context, output) { - // Dimension checks the unit is singular and throws an error if in strict math mode. - var strictUnits = context && context.strictUnits; - if (this.numerator.length === 1) { - output.add(this.numerator[0]); // the ideal situation - } - else if (!strictUnits && this.backupUnit) { - output.add(this.backupUnit); - } - else if (!strictUnits && this.denominator.length) { - output.add(this.denominator[0]); - } - }, - toString: function () { - var i, returnStr = this.numerator.join('*'); - for (i = 0; i < this.denominator.length; i++) { - returnStr += "/" + this.denominator[i]; - } - return returnStr; - }, - compare: function (other) { - return this.is(other.toString()) ? 0 : undefined; - }, - is: function (unitString) { - return this.toString().toUpperCase() === unitString.toUpperCase(); - }, - isLength: function () { - return RegExp('^(px|em|ex|ch|rem|in|cm|mm|pc|pt|ex|vw|vh|vmin|vmax)$', 'gi').test(this.toCSS()); - }, - isEmpty: function () { - return this.numerator.length === 0 && this.denominator.length === 0; - }, - isSingular: function () { - return this.numerator.length <= 1 && this.denominator.length === 0; - }, - map: function (callback) { - var i; - for (i = 0; i < this.numerator.length; i++) { - this.numerator[i] = callback(this.numerator[i], false); - } - for (i = 0; i < this.denominator.length; i++) { - this.denominator[i] = callback(this.denominator[i], true); - } - }, - usedUnits: function () { - var group; - var result = {}; - var mapUnit; - var groupName; - mapUnit = function (atomicUnit) { - /* jshint loopfunc:true */ - if (group.hasOwnProperty(atomicUnit) && !result[groupName]) { - result[groupName] = atomicUnit; - } - return atomicUnit; - }; - for (groupName in unitConversions) { - if (unitConversions.hasOwnProperty(groupName)) { - group = unitConversions[groupName]; - this.map(mapUnit); - } - } - return result; - }, - cancel: function () { - var counter = {}; - var atomicUnit; - var i; - for (i = 0; i < this.numerator.length; i++) { - atomicUnit = this.numerator[i]; - counter[atomicUnit] = (counter[atomicUnit] || 0) + 1; - } - for (i = 0; i < this.denominator.length; i++) { - atomicUnit = this.denominator[i]; - counter[atomicUnit] = (counter[atomicUnit] || 0) - 1; - } - this.numerator = []; - this.denominator = []; - for (atomicUnit in counter) { - if (counter.hasOwnProperty(atomicUnit)) { - var count = counter[atomicUnit]; - if (count > 0) { - for (i = 0; i < count; i++) { - this.numerator.push(atomicUnit); - } - } - else if (count < 0) { - for (i = 0; i < -count; i++) { - this.denominator.push(atomicUnit); - } - } - } - } - this.numerator.sort(); - this.denominator.sort(); - } - }); - - // - // A number with a unit - // - var Dimension = function (value, unit) { - this.value = parseFloat(value); - if (isNaN(this.value)) { - throw new Error('Dimension is not a number.'); - } - this.unit = (unit && unit instanceof Unit) ? unit : - new Unit(unit ? [unit] : undefined); - this.setParent(this.unit, this); - }; - Dimension.prototype = Object.assign(new Node(), { - type: 'Dimension', - accept: function (visitor) { - this.unit = visitor.visit(this.unit); - }, - eval: function (context) { - return this; - }, - toColor: function () { - return new Color([this.value, this.value, this.value]); - }, - genCSS: function (context, output) { - if ((context && context.strictUnits) && !this.unit.isSingular()) { - throw new Error("Multiple units in dimension. Correct the units or use the unit function. Bad unit: " + this.unit.toString()); - } - var value = this.fround(context, this.value); - var strValue = String(value); - if (value !== 0 && value < 0.000001 && value > -0.000001) { - // would be output 1e-6 etc. - strValue = value.toFixed(20).replace(/0+$/, ''); - } - if (context && context.compress) { - // Zero values doesn't need a unit - if (value === 0 && this.unit.isLength()) { - output.add(strValue); - return; - } - // Float values doesn't need a leading zero - if (value > 0 && value < 1) { - strValue = (strValue).substr(1); - } - } - output.add(strValue); - this.unit.genCSS(context, output); - }, - // In an operation between two Dimensions, - // we default to the first Dimension's unit, - // so `1px + 2` will yield `3px`. - operate: function (context, op, other) { - /* jshint noempty:false */ - var value = this._operate(context, op, this.value, other.value); - var unit = this.unit.clone(); - if (op === '+' || op === '-') { - if (unit.numerator.length === 0 && unit.denominator.length === 0) { - unit = other.unit.clone(); - if (this.unit.backupUnit) { - unit.backupUnit = this.unit.backupUnit; - } - } - else if (other.unit.numerator.length === 0 && unit.denominator.length === 0) ; - else { - other = other.convertTo(this.unit.usedUnits()); - if (context.strictUnits && other.unit.toString() !== unit.toString()) { - throw new Error("Incompatible units. Change the units or use the unit function. " - + ("Bad units: '" + unit.toString() + "' and '" + other.unit.toString() + "'.")); - } - value = this._operate(context, op, this.value, other.value); - } - } - else if (op === '*') { - unit.numerator = unit.numerator.concat(other.unit.numerator).sort(); - unit.denominator = unit.denominator.concat(other.unit.denominator).sort(); - unit.cancel(); - } - else if (op === '/') { - unit.numerator = unit.numerator.concat(other.unit.denominator).sort(); - unit.denominator = unit.denominator.concat(other.unit.numerator).sort(); - unit.cancel(); - } - return new Dimension(value, unit); - }, - compare: function (other) { - var a, b; - if (!(other instanceof Dimension)) { - return undefined; - } - if (this.unit.isEmpty() || other.unit.isEmpty()) { - a = this; - b = other; - } - else { - a = this.unify(); - b = other.unify(); - if (a.unit.compare(b.unit) !== 0) { - return undefined; - } - } - return Node.numericCompare(a.value, b.value); - }, - unify: function () { - return this.convertTo({ length: 'px', duration: 's', angle: 'rad' }); - }, - convertTo: function (conversions) { - var value = this.value; - var unit = this.unit.clone(); - var i; - var groupName; - var group; - var targetUnit; - var derivedConversions = {}; - var applyUnit; - if (typeof conversions === 'string') { - for (i in unitConversions) { - if (unitConversions[i].hasOwnProperty(conversions)) { - derivedConversions = {}; - derivedConversions[i] = conversions; - } - } - conversions = derivedConversions; - } - applyUnit = function (atomicUnit, denominator) { - /* jshint loopfunc:true */ - if (group.hasOwnProperty(atomicUnit)) { - if (denominator) { - value = value / (group[atomicUnit] / group[targetUnit]); - } - else { - value = value * (group[atomicUnit] / group[targetUnit]); - } - return targetUnit; - } - return atomicUnit; - }; - for (groupName in conversions) { - if (conversions.hasOwnProperty(groupName)) { - targetUnit = conversions[groupName]; - group = unitConversions[groupName]; - unit.map(applyUnit); - } - } - unit.cancel(); - return new Dimension(value, unit); - } - }); - - var MATH = Math$1; - var Operation = function (op, operands, isSpaced) { - this.op = op.trim(); - this.operands = operands; - this.isSpaced = isSpaced; - }; - Operation.prototype = Object.assign(new Node(), { - type: 'Operation', - accept: function (visitor) { - this.operands = visitor.visitArray(this.operands); - }, - eval: function (context) { - var a = this.operands[0].eval(context), b = this.operands[1].eval(context), op; - if (context.isMathOn(this.op)) { - op = this.op === './' ? '/' : this.op; - if (a instanceof Dimension && b instanceof Color) { - a = a.toColor(); - } - if (b instanceof Dimension && a instanceof Color) { - b = b.toColor(); - } - if (!a.operate || !b.operate) { - if ((a instanceof Operation || b instanceof Operation) - && a.op === '/' && context.math === MATH.PARENS_DIVISION) { - return new Operation(this.op, [a, b], this.isSpaced); - } - throw { type: 'Operation', - message: 'Operation on an invalid type' }; - } - return a.operate(context, op, b); - } - else { - return new Operation(this.op, [a, b], this.isSpaced); - } - }, - genCSS: function (context, output) { - this.operands[0].genCSS(context, output); - if (this.isSpaced) { - output.add(' '); - } - output.add(this.op); - if (this.isSpaced) { - output.add(' '); - } - this.operands[1].genCSS(context, output); - } - }); - - /*! ***************************************************************************** - Copyright (c) Microsoft Corporation. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - PERFORMANCE OF THIS SOFTWARE. - ***************************************************************************** */ - - function __spreadArray(to, from, pack) { - if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { - if (ar || !(i in from)) { - if (!ar) ar = Array.prototype.slice.call(from, 0, i); - ar[i] = from[i]; - } - } - return to.concat(ar || from); - } - - var Expression = function (value, noSpacing) { - this.value = value; - this.noSpacing = noSpacing; - if (!value) { - throw new Error('Expression requires an array parameter'); - } - }; - Expression.prototype = Object.assign(new Node(), { - type: 'Expression', - accept: function (visitor) { - this.value = visitor.visitArray(this.value); - }, - eval: function (context) { - var returnValue; - var mathOn = context.isMathOn(); - var inParenthesis = this.parens; - var doubleParen = false; - if (inParenthesis) { - context.inParenthesis(); - } - if (this.value.length > 1) { - returnValue = new Expression(this.value.map(function (e) { - if (!e.eval) { - return e; - } - return e.eval(context); - }), this.noSpacing); - } - else if (this.value.length === 1) { - if (this.value[0].parens && !this.value[0].parensInOp && !context.inCalc) { - doubleParen = true; - } - returnValue = this.value[0].eval(context); - } - else { - returnValue = this; - } - if (inParenthesis) { - context.outOfParenthesis(); - } - if (this.parens && this.parensInOp && !mathOn && !doubleParen - && (!(returnValue instanceof Dimension))) { - returnValue = new Paren(returnValue); - } - return returnValue; - }, - genCSS: function (context, output) { - for (var i = 0; i < this.value.length; i++) { - this.value[i].genCSS(context, output); - if (!this.noSpacing && i + 1 < this.value.length) { - output.add(' '); - } - } - }, - throwAwayComments: function () { - this.value = this.value.filter(function (v) { - return !(v instanceof Comment); - }); - } - }); - - var functionCaller = /** @class */ (function () { - function functionCaller(name, context, index, currentFileInfo) { - this.name = name.toLowerCase(); - this.index = index; - this.context = context; - this.currentFileInfo = currentFileInfo; - this.func = context.frames[0].functionRegistry.get(this.name); - } - functionCaller.prototype.isValid = function () { - return Boolean(this.func); - }; - functionCaller.prototype.call = function (args) { - var _this = this; - if (!(Array.isArray(args))) { - args = [args]; - } - var evalArgs = this.func.evalArgs; - if (evalArgs !== false) { - args = args.map(function (a) { return a.eval(_this.context); }); - } - var commentFilter = function (item) { return !(item.type === 'Comment'); }; - // This code is terrible and should be replaced as per this issue... - // https://github.com/less/less.js/issues/2477 - args = args - .filter(commentFilter) - .map(function (item) { - if (item.type === 'Expression') { - var subNodes = item.value.filter(commentFilter); - if (subNodes.length === 1) { - // https://github.com/less/less.js/issues/3616 - if (item.parens && subNodes[0].op === '/') { - return item; - } - return subNodes[0]; - } - else { - return new Expression(subNodes); - } - } - return item; - }); - if (evalArgs === false) { - return this.func.apply(this, __spreadArray([this.context], args)); - } - return this.func.apply(this, args); - }; - return functionCaller; - }()); - - // - // A function call node. - // - var Call = function (name, args, index, currentFileInfo) { - this.name = name; - this.args = args; - this.calc = name === 'calc'; - this._index = index; - this._fileInfo = currentFileInfo; - }; - Call.prototype = Object.assign(new Node(), { - type: 'Call', - accept: function (visitor) { - if (this.args) { - this.args = visitor.visitArray(this.args); - } - }, - // - // When evaluating a function call, - // we either find the function in the functionRegistry, - // in which case we call it, passing the evaluated arguments, - // if this returns null or we cannot find the function, we - // simply print it out as it appeared originally [2]. - // - // The reason why we evaluate the arguments, is in the case where - // we try to pass a variable to a function, like: `saturate(@color)`. - // The function should receive the value, not the variable. - // - eval: function (context) { - var _this = this; - /** - * Turn off math for calc(), and switch back on for evaluating nested functions - */ - var currentMathContext = context.mathOn; - context.mathOn = !this.calc; - if (this.calc || context.inCalc) { - context.enterCalc(); - } - var exitCalc = function () { - if (_this.calc || context.inCalc) { - context.exitCalc(); - } - context.mathOn = currentMathContext; - }; - var result; - var funcCaller = new functionCaller(this.name, context, this.getIndex(), this.fileInfo()); - if (funcCaller.isValid()) { - try { - result = funcCaller.call(this.args); - exitCalc(); - } - catch (e) { - if (e.hasOwnProperty('line') && e.hasOwnProperty('column')) { - throw e; - } - throw { - type: e.type || 'Runtime', - message: "Error evaluating function `" + this.name + "`" + (e.message ? ": " + e.message : ''), - index: this.getIndex(), - filename: this.fileInfo().filename, - line: e.lineNumber, - column: e.columnNumber - }; - } - } - if (result !== null && result !== undefined) { - // Results that that are not nodes are cast as Anonymous nodes - // Falsy values or booleans are returned as empty nodes - if (!(result instanceof Node)) { - if (!result || result === true) { - result = new Anonymous(null); - } - else { - result = new Anonymous(result.toString()); - } - } - result._index = this._index; - result._fileInfo = this._fileInfo; - return result; - } - var args = this.args.map(function (a) { return a.eval(context); }); - exitCalc(); - return new Call(this.name, args, this.getIndex(), this.fileInfo()); - }, - genCSS: function (context, output) { - output.add(this.name + "(", this.fileInfo(), this.getIndex()); - for (var i = 0; i < this.args.length; i++) { - this.args[i].genCSS(context, output); - if (i + 1 < this.args.length) { - output.add(', '); - } - } - output.add(')'); - } - }); - - var Variable = function (name, index, currentFileInfo) { - this.name = name; - this._index = index; - this._fileInfo = currentFileInfo; - }; - Variable.prototype = Object.assign(new Node(), { - type: 'Variable', - eval: function (context) { - var variable, name = this.name; - if (name.indexOf('@@') === 0) { - name = "@" + new Variable(name.slice(1), this.getIndex(), this.fileInfo()).eval(context).value; - } - if (this.evaluating) { - throw { type: 'Name', - message: "Recursive variable definition for " + name, - filename: this.fileInfo().filename, - index: this.getIndex() }; - } - this.evaluating = true; - variable = this.find(context.frames, function (frame) { - var v = frame.variable(name); - if (v) { - if (v.important) { - var importantScope = context.importantScope[context.importantScope.length - 1]; - importantScope.important = v.important; - } - // If in calc, wrap vars in a function call to cascade evaluate args first - if (context.inCalc) { - return (new Call('_SELF', [v.value])).eval(context); - } - else { - return v.value.eval(context); - } - } - }); - if (variable) { - this.evaluating = false; - return variable; - } - else { - throw { type: 'Name', - message: "variable " + name + " is undefined", - filename: this.fileInfo().filename, - index: this.getIndex() }; - } - }, - find: function (obj, fun) { - for (var i = 0, r = void 0; i < obj.length; i++) { - r = fun.call(obj, obj[i]); - if (r) { - return r; - } - } - return null; - } - }); - - var Property = function (name, index, currentFileInfo) { - this.name = name; - this._index = index; - this._fileInfo = currentFileInfo; - }; - Property.prototype = Object.assign(new Node(), { - type: 'Property', - eval: function (context) { - var property; - var name = this.name; - // TODO: shorten this reference - var mergeRules = context.pluginManager.less.visitors.ToCSSVisitor.prototype._mergeRules; - if (this.evaluating) { - throw { type: 'Name', - message: "Recursive property reference for " + name, - filename: this.fileInfo().filename, - index: this.getIndex() }; - } - this.evaluating = true; - property = this.find(context.frames, function (frame) { - var v; - var vArr = frame.property(name); - if (vArr) { - for (var i = 0; i < vArr.length; i++) { - v = vArr[i]; - vArr[i] = new Declaration(v.name, v.value, v.important, v.merge, v.index, v.currentFileInfo, v.inline, v.variable); - } - mergeRules(vArr); - v = vArr[vArr.length - 1]; - if (v.important) { - var importantScope = context.importantScope[context.importantScope.length - 1]; - importantScope.important = v.important; - } - v = v.value.eval(context); - return v; - } - }); - if (property) { - this.evaluating = false; - return property; - } - else { - throw { type: 'Name', - message: "Property '" + name + "' is undefined", - filename: this.currentFileInfo.filename, - index: this.index }; - } - }, - find: function (obj, fun) { - for (var i = 0, r = void 0; i < obj.length; i++) { - r = fun.call(obj, obj[i]); - if (r) { - return r; - } - } - return null; - } - }); - - var Attribute = function (key, op, value, cif) { - this.key = key; - this.op = op; - this.value = value; - this.cif = cif; - }; - Attribute.prototype = Object.assign(new Node(), { - type: 'Attribute', - eval: function (context) { - return new Attribute(this.key.eval ? this.key.eval(context) : this.key, this.op, (this.value && this.value.eval) ? this.value.eval(context) : this.value, this.cif); - }, - genCSS: function (context, output) { - output.add(this.toCSS(context)); - }, - toCSS: function (context) { - var value = this.key.toCSS ? this.key.toCSS(context) : this.key; - if (this.op) { - value += this.op; - value += (this.value.toCSS ? this.value.toCSS(context) : this.value); - } - if (this.cif) { - value = value + " " + this.cif; - } - return "[" + value + "]"; - } - }); - - var Quoted = function (str, content, escaped, index, currentFileInfo) { - this.escaped = (escaped == null) ? true : escaped; - this.value = content || ''; - this.quote = str.charAt(0); - this._index = index; - this._fileInfo = currentFileInfo; - this.variableRegex = /@\{([\w-]+)\}/g; - this.propRegex = /\$\{([\w-]+)\}/g; - this.allowRoot = escaped; - }; - Quoted.prototype = Object.assign(new Node(), { - type: 'Quoted', - genCSS: function (context, output) { - if (!this.escaped) { - output.add(this.quote, this.fileInfo(), this.getIndex()); - } - output.add(this.value); - if (!this.escaped) { - output.add(this.quote); - } - }, - containsVariables: function () { - return this.value.match(this.variableRegex); - }, - eval: function (context) { - var that = this; - var value = this.value; - var variableReplacement = function (_, name) { - var v = new Variable("@" + name, that.getIndex(), that.fileInfo()).eval(context, true); - return (v instanceof Quoted) ? v.value : v.toCSS(); - }; - var propertyReplacement = function (_, name) { - var v = new Property("$" + name, that.getIndex(), that.fileInfo()).eval(context, true); - return (v instanceof Quoted) ? v.value : v.toCSS(); - }; - function iterativeReplace(value, regexp, replacementFnc) { - var evaluatedValue = value; - do { - value = evaluatedValue.toString(); - evaluatedValue = value.replace(regexp, replacementFnc); - } while (value !== evaluatedValue); - return evaluatedValue; - } - value = iterativeReplace(value, this.variableRegex, variableReplacement); - value = iterativeReplace(value, this.propRegex, propertyReplacement); - return new Quoted(this.quote + value + this.quote, value, this.escaped, this.getIndex(), this.fileInfo()); - }, - compare: function (other) { - // when comparing quoted strings allow the quote to differ - if (other.type === 'Quoted' && !this.escaped && !other.escaped) { - return Node.numericCompare(this.value, other.value); - } - else { - return other.toCSS && this.toCSS() === other.toCSS() ? 0 : undefined; - } - } - }); - - function escapePath(path) { - return path.replace(/[\(\)'"\s]/g, function (match) { return "\\" + match; }); - } - var URL = function (val, index, currentFileInfo, isEvald) { - this.value = val; - this._index = index; - this._fileInfo = currentFileInfo; - this.isEvald = isEvald; - }; - URL.prototype = Object.assign(new Node(), { - type: 'Url', - accept: function (visitor) { - this.value = visitor.visit(this.value); - }, - genCSS: function (context, output) { - output.add('url('); - this.value.genCSS(context, output); - output.add(')'); - }, - eval: function (context) { - var val = this.value.eval(context); - var rootpath; - if (!this.isEvald) { - // Add the rootpath if the URL requires a rewrite - rootpath = this.fileInfo() && this.fileInfo().rootpath; - if (typeof rootpath === 'string' && - typeof val.value === 'string' && - context.pathRequiresRewrite(val.value)) { - if (!val.quote) { - rootpath = escapePath(rootpath); - } - val.value = context.rewritePath(val.value, rootpath); - } - else { - val.value = context.normalizePath(val.value); - } - // Add url args if enabled - if (context.urlArgs) { - if (!val.value.match(/^\s*data:/)) { - var delimiter = val.value.indexOf('?') === -1 ? '?' : '&'; - var urlArgs = delimiter + context.urlArgs; - if (val.value.indexOf('#') !== -1) { - val.value = val.value.replace('#', urlArgs + "#"); - } - else { - val.value += urlArgs; - } - } - } - } - return new URL(val, this.getIndex(), this.fileInfo(), true); - } - }); - - var Media = function (value, features, index, currentFileInfo, visibilityInfo) { - this._index = index; - this._fileInfo = currentFileInfo; - var selectors = (new Selector([], null, null, this._index, this._fileInfo)).createEmptySelectors(); - this.features = new Value(features); - this.rules = [new Ruleset(selectors, value)]; - this.rules[0].allowImports = true; - this.copyVisibilityInfo(visibilityInfo); - this.allowRoot = true; - this.setParent(selectors, this); - this.setParent(this.features, this); - this.setParent(this.rules, this); - }; - Media.prototype = Object.assign(new AtRule(), { - type: 'Media', - isRulesetLike: function () { - return true; - }, - accept: function (visitor) { - if (this.features) { - this.features = visitor.visit(this.features); - } - if (this.rules) { - this.rules = visitor.visitArray(this.rules); - } - }, - genCSS: function (context, output) { - output.add('@media ', this._fileInfo, this._index); - this.features.genCSS(context, output); - this.outputRuleset(context, output, this.rules); - }, - eval: function (context) { - if (!context.mediaBlocks) { - context.mediaBlocks = []; - context.mediaPath = []; - } - var media = new Media(null, [], this._index, this._fileInfo, this.visibilityInfo()); - if (this.debugInfo) { - this.rules[0].debugInfo = this.debugInfo; - media.debugInfo = this.debugInfo; - } - media.features = this.features.eval(context); - context.mediaPath.push(media); - context.mediaBlocks.push(media); - this.rules[0].functionRegistry = context.frames[0].functionRegistry.inherit(); - context.frames.unshift(this.rules[0]); - media.rules = [this.rules[0].eval(context)]; - context.frames.shift(); - context.mediaPath.pop(); - return context.mediaPath.length === 0 ? media.evalTop(context) : - media.evalNested(context); - }, - evalTop: function (context) { - var result = this; - // Render all dependent Media blocks. - if (context.mediaBlocks.length > 1) { - var selectors = (new Selector([], null, null, this.getIndex(), this.fileInfo())).createEmptySelectors(); - result = new Ruleset(selectors, context.mediaBlocks); - result.multiMedia = true; - result.copyVisibilityInfo(this.visibilityInfo()); - this.setParent(result, this); - } - delete context.mediaBlocks; - delete context.mediaPath; - return result; - }, - evalNested: function (context) { - var i; - var value; - var path = context.mediaPath.concat([this]); - // Extract the media-query conditions separated with `,` (OR). - for (i = 0; i < path.length; i++) { - value = path[i].features instanceof Value ? - path[i].features.value : path[i].features; - path[i] = Array.isArray(value) ? value : [value]; - } - // Trace all permutations to generate the resulting media-query. - // - // (a, b and c) with nested (d, e) -> - // a and d - // a and e - // b and c and d - // b and c and e - this.features = new Value(this.permute(path).map(function (path) { - path = path.map(function (fragment) { return fragment.toCSS ? fragment : new Anonymous(fragment); }); - for (i = path.length - 1; i > 0; i--) { - path.splice(i, 0, new Anonymous('and')); - } - return new Expression(path); - })); - this.setParent(this.features, this); - // Fake a tree-node that doesn't output anything. - return new Ruleset([], []); - }, - permute: function (arr) { - if (arr.length === 0) { - return []; - } - else if (arr.length === 1) { - return arr[0]; - } - else { - var result = []; - var rest = this.permute(arr.slice(1)); - for (var i = 0; i < rest.length; i++) { - for (var j = 0; j < arr[0].length; j++) { - result.push([arr[0][j]].concat(rest[i])); - } - } - return result; - } - }, - bubbleSelectors: function (selectors) { - if (!selectors) { - return; - } - this.rules = [new Ruleset(copyArray(selectors), [this.rules[0]])]; - this.setParent(this.rules, this); - } - }); - - // - // CSS @import node - // - // The general strategy here is that we don't want to wait - // for the parsing to be completed, before we start importing - // the file. That's because in the context of a browser, - // most of the time will be spent waiting for the server to respond. - // - // On creation, we push the import path to our import queue, though - // `import,push`, we also pass it a callback, which it'll call once - // the file has been fetched, and parsed. - // - var Import = function (path, features, options, index, currentFileInfo, visibilityInfo) { - this.options = options; - this._index = index; - this._fileInfo = currentFileInfo; - this.path = path; - this.features = features; - this.allowRoot = true; - if (this.options.less !== undefined || this.options.inline) { - this.css = !this.options.less || this.options.inline; - } - else { - var pathValue = this.getPath(); - if (pathValue && /[#\.\&\?]css([\?;].*)?$/.test(pathValue)) { - this.css = true; - } - } - this.copyVisibilityInfo(visibilityInfo); - this.setParent(this.features, this); - this.setParent(this.path, this); - }; - Import.prototype = Object.assign(new Node(), { - type: 'Import', - accept: function (visitor) { - if (this.features) { - this.features = visitor.visit(this.features); - } - this.path = visitor.visit(this.path); - if (!this.options.isPlugin && !this.options.inline && this.root) { - this.root = visitor.visit(this.root); - } - }, - genCSS: function (context, output) { - if (this.css && this.path._fileInfo.reference === undefined) { - output.add('@import ', this._fileInfo, this._index); - this.path.genCSS(context, output); - if (this.features) { - output.add(' '); - this.features.genCSS(context, output); - } - output.add(';'); - } - }, - getPath: function () { - return (this.path instanceof URL) ? - this.path.value.value : this.path.value; - }, - isVariableImport: function () { - var path = this.path; - if (path instanceof URL) { - path = path.value; - } - if (path instanceof Quoted) { - return path.containsVariables(); - } - return true; - }, - evalForImport: function (context) { - var path = this.path; - if (path instanceof URL) { - path = path.value; - } - return new Import(path.eval(context), this.features, this.options, this._index, this._fileInfo, this.visibilityInfo()); - }, - evalPath: function (context) { - var path = this.path.eval(context); - var fileInfo = this._fileInfo; - if (!(path instanceof URL)) { - // Add the rootpath if the URL requires a rewrite - var pathValue = path.value; - if (fileInfo && - pathValue && - context.pathRequiresRewrite(pathValue)) { - path.value = context.rewritePath(pathValue, fileInfo.rootpath); - } - else { - path.value = context.normalizePath(path.value); - } - } - return path; - }, - eval: function (context) { - var result = this.doEval(context); - if (this.options.reference || this.blocksVisibility()) { - if (result.length || result.length === 0) { - result.forEach(function (node) { - node.addVisibilityBlock(); - }); - } - else { - result.addVisibilityBlock(); - } - } - return result; - }, - doEval: function (context) { - var ruleset; - var registry; - var features = this.features && this.features.eval(context); - if (this.options.isPlugin) { - if (this.root && this.root.eval) { - try { - this.root.eval(context); - } - catch (e) { - e.message = 'Plugin error during evaluation'; - throw new LessError(e, this.root.imports, this.root.filename); - } - } - registry = context.frames[0] && context.frames[0].functionRegistry; - if (registry && this.root && this.root.functions) { - registry.addMultiple(this.root.functions); - } - return []; - } - if (this.skip) { - if (typeof this.skip === 'function') { - this.skip = this.skip(); - } - if (this.skip) { - return []; - } - } - if (this.options.inline) { - var contents = new Anonymous(this.root, 0, { - filename: this.importedFilename, - reference: this.path._fileInfo && this.path._fileInfo.reference - }, true, true); - return this.features ? new Media([contents], this.features.value) : [contents]; - } - else if (this.css) { - var newImport = new Import(this.evalPath(context), features, this.options, this._index); - if (!newImport.css && this.error) { - throw this.error; - } - return newImport; - } - else if (this.root) { - ruleset = new Ruleset(null, copyArray(this.root.rules)); - ruleset.evalImports(context); - return this.features ? new Media(ruleset.rules, this.features.value) : ruleset.rules; - } - else { - return []; - } - } - }); - - var JsEvalNode = function () { }; - JsEvalNode.prototype = Object.assign(new Node(), { - evaluateJavaScript: function (expression, context) { - var result; - var that = this; - var evalContext = {}; - if (!context.javascriptEnabled) { - throw { message: 'Inline JavaScript is not enabled. Is it set in your options?', - filename: this.fileInfo().filename, - index: this.getIndex() }; - } - expression = expression.replace(/@\{([\w-]+)\}/g, function (_, name) { - return that.jsify(new Variable("@" + name, that.getIndex(), that.fileInfo()).eval(context)); - }); - try { - expression = new Function("return (" + expression + ")"); - } - catch (e) { - throw { message: "JavaScript evaluation error: " + e.message + " from `" + expression + "`", - filename: this.fileInfo().filename, - index: this.getIndex() }; - } - var variables = context.frames[0].variables(); - for (var k in variables) { - if (variables.hasOwnProperty(k)) { - /* jshint loopfunc:true */ - evalContext[k.slice(1)] = { - value: variables[k].value, - toJS: function () { - return this.value.eval(context).toCSS(); - } - }; - } - } - try { - result = expression.call(evalContext); - } - catch (e) { - throw { message: "JavaScript evaluation error: '" + e.name + ": " + e.message.replace(/["]/g, '\'') + "'", - filename: this.fileInfo().filename, - index: this.getIndex() }; - } - return result; - }, - jsify: function (obj) { - if (Array.isArray(obj.value) && (obj.value.length > 1)) { - return "[" + obj.value.map(function (v) { return v.toCSS(); }).join(', ') + "]"; - } - else { - return obj.toCSS(); - } - } - }); - - var JavaScript = function (string, escaped, index, currentFileInfo) { - this.escaped = escaped; - this.expression = string; - this._index = index; - this._fileInfo = currentFileInfo; - }; - JavaScript.prototype = Object.assign(new JsEvalNode(), { - type: 'JavaScript', - eval: function (context) { - var result = this.evaluateJavaScript(this.expression, context); - var type = typeof result; - if (type === 'number' && !isNaN(result)) { - return new Dimension(result); - } - else if (type === 'string') { - return new Quoted("\"" + result + "\"", result, this.escaped, this._index); - } - else if (Array.isArray(result)) { - return new Anonymous(result.join(', ')); - } - else { - return new Anonymous(result); - } - } - }); - - var Assignment = function (key, val) { - this.key = key; - this.value = val; - }; - Assignment.prototype = Object.assign(new Node(), { - type: 'Assignment', - accept: function (visitor) { - this.value = visitor.visit(this.value); - }, - eval: function (context) { - if (this.value.eval) { - return new Assignment(this.key, this.value.eval(context)); - } - return this; - }, - genCSS: function (context, output) { - output.add(this.key + "="); - if (this.value.genCSS) { - this.value.genCSS(context, output); - } - else { - output.add(this.value); - } - } - }); - - var Condition = function (op, l, r, i, negate) { - this.op = op.trim(); - this.lvalue = l; - this.rvalue = r; - this._index = i; - this.negate = negate; - }; - Condition.prototype = Object.assign(new Node(), { - type: 'Condition', - accept: function (visitor) { - this.lvalue = visitor.visit(this.lvalue); - this.rvalue = visitor.visit(this.rvalue); - }, - eval: function (context) { - var result = (function (op, a, b) { - switch (op) { - case 'and': return a && b; - case 'or': return a || b; - default: - switch (Node.compare(a, b)) { - case -1: - return op === '<' || op === '=<' || op === '<='; - case 0: - return op === '=' || op === '>=' || op === '=<' || op === '<='; - case 1: - return op === '>' || op === '>='; - default: - return false; - } - } - })(this.op, this.lvalue.eval(context), this.rvalue.eval(context)); - return this.negate ? !result : result; - } - }); - - var UnicodeDescriptor = function (value) { - this.value = value; - }; - UnicodeDescriptor.prototype = Object.assign(new Node(), { - type: 'UnicodeDescriptor' - }); - - var Negative = function (node) { - this.value = node; - }; - Negative.prototype = Object.assign(new Node(), { - type: 'Negative', - genCSS: function (context, output) { - output.add('-'); - this.value.genCSS(context, output); - }, - eval: function (context) { - if (context.isMathOn()) { - return (new Operation('*', [new Dimension(-1), this.value])).eval(context); - } - return new Negative(this.value.eval(context)); - } - }); - - var Extend = function (selector, option, index, currentFileInfo, visibilityInfo) { - this.selector = selector; - this.option = option; - this.object_id = Extend.next_id++; - this.parent_ids = [this.object_id]; - this._index = index; - this._fileInfo = currentFileInfo; - this.copyVisibilityInfo(visibilityInfo); - this.allowRoot = true; - switch (option) { - case 'all': - this.allowBefore = true; - this.allowAfter = true; - break; - default: - this.allowBefore = false; - this.allowAfter = false; - break; - } - this.setParent(this.selector, this); - }; - Extend.prototype = Object.assign(new Node(), { - type: 'Extend', - accept: function (visitor) { - this.selector = visitor.visit(this.selector); - }, - eval: function (context) { - return new Extend(this.selector.eval(context), this.option, this.getIndex(), this.fileInfo(), this.visibilityInfo()); - }, - clone: function (context) { - return new Extend(this.selector, this.option, this.getIndex(), this.fileInfo(), this.visibilityInfo()); - }, - // it concatenates (joins) all selectors in selector array - findSelfSelectors: function (selectors) { - var selfElements = [], i, selectorElements; - for (i = 0; i < selectors.length; i++) { - selectorElements = selectors[i].elements; - // duplicate the logic in genCSS function inside the selector node. - // future TODO - move both logics into the selector joiner visitor - if (i > 0 && selectorElements.length && selectorElements[0].combinator.value === '') { - selectorElements[0].combinator.value = ' '; - } - selfElements = selfElements.concat(selectors[i].elements); - } - this.selfSelectors = [new Selector(selfElements)]; - this.selfSelectors[0].copyVisibilityInfo(this.visibilityInfo()); - } - }); - Extend.next_id = 0; - - var VariableCall = function (variable, index, currentFileInfo) { - this.variable = variable; - this._index = index; - this._fileInfo = currentFileInfo; - this.allowRoot = true; - }; - VariableCall.prototype = Object.assign(new Node(), { - type: 'VariableCall', - eval: function (context) { - var rules; - var detachedRuleset = new Variable(this.variable, this.getIndex(), this.fileInfo()).eval(context); - var error = new LessError({ message: "Could not evaluate variable call " + this.variable }); - if (!detachedRuleset.ruleset) { - if (detachedRuleset.rules) { - rules = detachedRuleset; - } - else if (Array.isArray(detachedRuleset)) { - rules = new Ruleset('', detachedRuleset); - } - else if (Array.isArray(detachedRuleset.value)) { - rules = new Ruleset('', detachedRuleset.value); - } - else { - throw error; - } - detachedRuleset = new DetachedRuleset(rules); - } - if (detachedRuleset.ruleset) { - return detachedRuleset.callEval(context); - } - throw error; - } - }); - - var NamespaceValue = function (ruleCall, lookups, index, fileInfo) { - this.value = ruleCall; - this.lookups = lookups; - this._index = index; - this._fileInfo = fileInfo; - }; - NamespaceValue.prototype = Object.assign(new Node(), { - type: 'NamespaceValue', - eval: function (context) { - var i, name, rules = this.value.eval(context); - for (i = 0; i < this.lookups.length; i++) { - name = this.lookups[i]; - /** - * Eval'd DRs return rulesets. - * Eval'd mixins return rules, so let's make a ruleset if we need it. - * We need to do this because of late parsing of values - */ - if (Array.isArray(rules)) { - rules = new Ruleset([new Selector()], rules); - } - if (name === '') { - rules = rules.lastDeclaration(); - } - else if (name.charAt(0) === '@') { - if (name.charAt(1) === '@') { - name = "@" + new Variable(name.substr(1)).eval(context).value; - } - if (rules.variables) { - rules = rules.variable(name); - } - if (!rules) { - throw { type: 'Name', - message: "variable " + name + " not found", - filename: this.fileInfo().filename, - index: this.getIndex() }; - } - } - else { - if (name.substring(0, 2) === '$@') { - name = "$" + new Variable(name.substr(1)).eval(context).value; - } - else { - name = name.charAt(0) === '$' ? name : "$" + name; - } - if (rules.properties) { - rules = rules.property(name); - } - if (!rules) { - throw { type: 'Name', - message: "property \"" + name.substr(1) + "\" not found", - filename: this.fileInfo().filename, - index: this.getIndex() }; - } - // Properties are an array of values, since a ruleset can have multiple props. - // We pick the last one (the "cascaded" value) - rules = rules[rules.length - 1]; - } - if (rules.value) { - rules = rules.eval(context).value; - } - if (rules.ruleset) { - rules = rules.ruleset.eval(context); - } - } - return rules; - } - }); - - var Definition = function (name, params, rules, condition, variadic, frames, visibilityInfo) { - this.name = name || 'anonymous mixin'; - this.selectors = [new Selector([new Element(null, name, false, this._index, this._fileInfo)])]; - this.params = params; - this.condition = condition; - this.variadic = variadic; - this.arity = params.length; - this.rules = rules; - this._lookups = {}; - var optionalParameters = []; - this.required = params.reduce(function (count, p) { - if (!p.name || (p.name && !p.value)) { - return count + 1; - } - else { - optionalParameters.push(p.name); - return count; - } - }, 0); - this.optionalParameters = optionalParameters; - this.frames = frames; - this.copyVisibilityInfo(visibilityInfo); - this.allowRoot = true; - }; - Definition.prototype = Object.assign(new Ruleset(), { - type: 'MixinDefinition', - evalFirst: true, - accept: function (visitor) { - if (this.params && this.params.length) { - this.params = visitor.visitArray(this.params); - } - this.rules = visitor.visitArray(this.rules); - if (this.condition) { - this.condition = visitor.visit(this.condition); - } - }, - evalParams: function (context, mixinEnv, args, evaldArguments) { - /* jshint boss:true */ - var frame = new Ruleset(null, null); - var varargs; - var arg; - var params = copyArray(this.params); - var i; - var j; - var val; - var name; - var isNamedFound; - var argIndex; - var argsLength = 0; - if (mixinEnv.frames && mixinEnv.frames[0] && mixinEnv.frames[0].functionRegistry) { - frame.functionRegistry = mixinEnv.frames[0].functionRegistry.inherit(); - } - mixinEnv = new contexts.Eval(mixinEnv, [frame].concat(mixinEnv.frames)); - if (args) { - args = copyArray(args); - argsLength = args.length; - for (i = 0; i < argsLength; i++) { - arg = args[i]; - if (name = (arg && arg.name)) { - isNamedFound = false; - for (j = 0; j < params.length; j++) { - if (!evaldArguments[j] && name === params[j].name) { - evaldArguments[j] = arg.value.eval(context); - frame.prependRule(new Declaration(name, arg.value.eval(context))); - isNamedFound = true; - break; - } - } - if (isNamedFound) { - args.splice(i, 1); - i--; - continue; - } - else { - throw { type: 'Runtime', message: "Named argument for " + this.name + " " + args[i].name + " not found" }; - } - } - } - } - argIndex = 0; - for (i = 0; i < params.length; i++) { - if (evaldArguments[i]) { - continue; - } - arg = args && args[argIndex]; - if (name = params[i].name) { - if (params[i].variadic) { - varargs = []; - for (j = argIndex; j < argsLength; j++) { - varargs.push(args[j].value.eval(context)); - } - frame.prependRule(new Declaration(name, new Expression(varargs).eval(context))); - } - else { - val = arg && arg.value; - if (val) { - // This was a mixin call, pass in a detached ruleset of it's eval'd rules - if (Array.isArray(val)) { - val = new DetachedRuleset(new Ruleset('', val)); - } - else { - val = val.eval(context); - } - } - else if (params[i].value) { - val = params[i].value.eval(mixinEnv); - frame.resetCache(); - } - else { - throw { type: 'Runtime', message: "wrong number of arguments for " + this.name + " (" + argsLength + " for " + this.arity + ")" }; - } - frame.prependRule(new Declaration(name, val)); - evaldArguments[i] = val; - } - } - if (params[i].variadic && args) { - for (j = argIndex; j < argsLength; j++) { - evaldArguments[j] = args[j].value.eval(context); - } - } - argIndex++; - } - return frame; - }, - makeImportant: function () { - var rules = !this.rules ? this.rules : this.rules.map(function (r) { - if (r.makeImportant) { - return r.makeImportant(true); - } - else { - return r; - } - }); - var result = new Definition(this.name, this.params, rules, this.condition, this.variadic, this.frames); - return result; - }, - eval: function (context) { - return new Definition(this.name, this.params, this.rules, this.condition, this.variadic, this.frames || copyArray(context.frames)); - }, - evalCall: function (context, args, important) { - var _arguments = []; - var mixinFrames = this.frames ? this.frames.concat(context.frames) : context.frames; - var frame = this.evalParams(context, new contexts.Eval(context, mixinFrames), args, _arguments); - var rules; - var ruleset; - frame.prependRule(new Declaration('@arguments', new Expression(_arguments).eval(context))); - rules = copyArray(this.rules); - ruleset = new Ruleset(null, rules); - ruleset.originalRuleset = this; - ruleset = ruleset.eval(new contexts.Eval(context, [this, frame].concat(mixinFrames))); - if (important) { - ruleset = ruleset.makeImportant(); - } - return ruleset; - }, - matchCondition: function (args, context) { - if (this.condition && !this.condition.eval(new contexts.Eval(context, [this.evalParams(context, /* the parameter variables */ new contexts.Eval(context, this.frames ? this.frames.concat(context.frames) : context.frames), args, [])] - .concat(this.frames || []) // the parent namespace/mixin frames - .concat(context.frames)))) { // the current environment frames - return false; - } - return true; - }, - matchArgs: function (args, context) { - var allArgsCnt = (args && args.length) || 0; - var len; - var optionalParameters = this.optionalParameters; - var requiredArgsCnt = !args ? 0 : args.reduce(function (count, p) { - if (optionalParameters.indexOf(p.name) < 0) { - return count + 1; - } - else { - return count; - } - }, 0); - if (!this.variadic) { - if (requiredArgsCnt < this.required) { - return false; - } - if (allArgsCnt > this.params.length) { - return false; - } - } - else { - if (requiredArgsCnt < (this.required - 1)) { - return false; - } - } - // check patterns - len = Math.min(requiredArgsCnt, this.arity); - for (var i = 0; i < len; i++) { - if (!this.params[i].name && !this.params[i].variadic) { - if (args[i].value.eval(context).toCSS() != this.params[i].value.eval(context).toCSS()) { - return false; - } - } - } - return true; - } - }); - - var MixinCall = function (elements, args, index, currentFileInfo, important) { - this.selector = new Selector(elements); - this.arguments = args || []; - this._index = index; - this._fileInfo = currentFileInfo; - this.important = important; - this.allowRoot = true; - this.setParent(this.selector, this); - }; - MixinCall.prototype = Object.assign(new Node(), { - type: 'MixinCall', - accept: function (visitor) { - if (this.selector) { - this.selector = visitor.visit(this.selector); - } - if (this.arguments.length) { - this.arguments = visitor.visitArray(this.arguments); - } - }, - eval: function (context) { - var mixins; - var mixin; - var mixinPath; - var args = []; - var arg; - var argValue; - var rules = []; - var match = false; - var i; - var m; - var f; - var isRecursive; - var isOneFound; - var candidates = []; - var candidate; - var conditionResult = []; - var defaultResult; - var defFalseEitherCase = -1; - var defNone = 0; - var defTrue = 1; - var defFalse = 2; - var count; - var originalRuleset; - var noArgumentsFilter; - this.selector = this.selector.eval(context); - function calcDefGroup(mixin, mixinPath) { - var f, p, namespace; - for (f = 0; f < 2; f++) { - conditionResult[f] = true; - defaultFunc.value(f); - for (p = 0; p < mixinPath.length && conditionResult[f]; p++) { - namespace = mixinPath[p]; - if (namespace.matchCondition) { - conditionResult[f] = conditionResult[f] && namespace.matchCondition(null, context); - } - } - if (mixin.matchCondition) { - conditionResult[f] = conditionResult[f] && mixin.matchCondition(args, context); - } - } - if (conditionResult[0] || conditionResult[1]) { - if (conditionResult[0] != conditionResult[1]) { - return conditionResult[1] ? - defTrue : defFalse; - } - return defNone; - } - return defFalseEitherCase; - } - for (i = 0; i < this.arguments.length; i++) { - arg = this.arguments[i]; - argValue = arg.value.eval(context); - if (arg.expand && Array.isArray(argValue.value)) { - argValue = argValue.value; - for (m = 0; m < argValue.length; m++) { - args.push({ value: argValue[m] }); - } - } - else { - args.push({ name: arg.name, value: argValue }); - } - } - noArgumentsFilter = function (rule) { return rule.matchArgs(null, context); }; - for (i = 0; i < context.frames.length; i++) { - if ((mixins = context.frames[i].find(this.selector, null, noArgumentsFilter)).length > 0) { - isOneFound = true; - // To make `default()` function independent of definition order we have two "subpasses" here. - // At first we evaluate each guard *twice* (with `default() == true` and `default() == false`), - // and build candidate list with corresponding flags. Then, when we know all possible matches, - // we make a final decision. - for (m = 0; m < mixins.length; m++) { - mixin = mixins[m].rule; - mixinPath = mixins[m].path; - isRecursive = false; - for (f = 0; f < context.frames.length; f++) { - if ((!(mixin instanceof Definition)) && mixin === (context.frames[f].originalRuleset || context.frames[f])) { - isRecursive = true; - break; - } - } - if (isRecursive) { - continue; - } - if (mixin.matchArgs(args, context)) { - candidate = { mixin: mixin, group: calcDefGroup(mixin, mixinPath) }; - if (candidate.group !== defFalseEitherCase) { - candidates.push(candidate); - } - match = true; - } - } - defaultFunc.reset(); - count = [0, 0, 0]; - for (m = 0; m < candidates.length; m++) { - count[candidates[m].group]++; - } - if (count[defNone] > 0) { - defaultResult = defFalse; - } - else { - defaultResult = defTrue; - if ((count[defTrue] + count[defFalse]) > 1) { - throw { type: 'Runtime', - message: "Ambiguous use of `default()` found when matching for `" + this.format(args) + "`", - index: this.getIndex(), filename: this.fileInfo().filename }; - } - } - for (m = 0; m < candidates.length; m++) { - candidate = candidates[m].group; - if ((candidate === defNone) || (candidate === defaultResult)) { - try { - mixin = candidates[m].mixin; - if (!(mixin instanceof Definition)) { - originalRuleset = mixin.originalRuleset || mixin; - mixin = new Definition('', [], mixin.rules, null, false, null, originalRuleset.visibilityInfo()); - mixin.originalRuleset = originalRuleset; - } - var newRules = mixin.evalCall(context, args, this.important).rules; - this._setVisibilityToReplacement(newRules); - Array.prototype.push.apply(rules, newRules); - } - catch (e) { - throw { message: e.message, index: this.getIndex(), filename: this.fileInfo().filename, stack: e.stack }; - } - } - } - if (match) { - return rules; - } - } - } - if (isOneFound) { - throw { type: 'Runtime', - message: "No matching definition was found for `" + this.format(args) + "`", - index: this.getIndex(), filename: this.fileInfo().filename }; - } - else { - throw { type: 'Name', - message: this.selector.toCSS().trim() + " is undefined", - index: this.getIndex(), filename: this.fileInfo().filename }; - } - }, - _setVisibilityToReplacement: function (replacement) { - var i, rule; - if (this.blocksVisibility()) { - for (i = 0; i < replacement.length; i++) { - rule = replacement[i]; - rule.addVisibilityBlock(); - } - } - }, - format: function (args) { - return this.selector.toCSS().trim() + "(" + (args ? args.map(function (a) { - var argValue = ''; - if (a.name) { - argValue += a.name + ":"; - } - if (a.value.toCSS) { - argValue += a.value.toCSS(); - } - else { - argValue += '???'; - } - return argValue; - }).join(', ') : '') + ")"; - } - }); - - var tree = { - Node: Node, - Color: Color, - AtRule: AtRule, - DetachedRuleset: DetachedRuleset, - Operation: Operation, - Dimension: Dimension, - Unit: Unit, - Keyword: Keyword, - Variable: Variable, - Property: Property, - Ruleset: Ruleset, - Element: Element, - Attribute: Attribute, - Combinator: Combinator, - Selector: Selector, - Quoted: Quoted, - Expression: Expression, - Declaration: Declaration, - Call: Call, - URL: URL, - Import: Import, - Comment: Comment, - Anonymous: Anonymous, - Value: Value, - JavaScript: JavaScript, - Assignment: Assignment, - Condition: Condition, - Paren: Paren, - Media: Media, - UnicodeDescriptor: UnicodeDescriptor, - Negative: Negative, - Extend: Extend, - VariableCall: VariableCall, - NamespaceValue: NamespaceValue, - mixin: { - Call: MixinCall, - Definition: Definition - } - }; - - var AbstractFileManager = /** @class */ (function () { - function AbstractFileManager() { - } - AbstractFileManager.prototype.getPath = function (filename) { - var j = filename.lastIndexOf('?'); - if (j > 0) { - filename = filename.slice(0, j); - } - j = filename.lastIndexOf('/'); - if (j < 0) { - j = filename.lastIndexOf('\\'); - } - if (j < 0) { - return ''; - } - return filename.slice(0, j + 1); - }; - AbstractFileManager.prototype.tryAppendExtension = function (path, ext) { - return /(\.[a-z]*$)|([\?;].*)$/.test(path) ? path : path + ext; - }; - AbstractFileManager.prototype.tryAppendLessExtension = function (path) { - return this.tryAppendExtension(path, '.less'); - }; - AbstractFileManager.prototype.supportsSync = function () { - return false; - }; - AbstractFileManager.prototype.alwaysMakePathsAbsolute = function () { - return false; - }; - AbstractFileManager.prototype.isPathAbsolute = function (filename) { - return (/^(?:[a-z-]+:|\/|\\|#)/i).test(filename); - }; - // TODO: pull out / replace? - AbstractFileManager.prototype.join = function (basePath, laterPath) { - if (!basePath) { - return laterPath; - } - return basePath + laterPath; - }; - AbstractFileManager.prototype.pathDiff = function (url, baseUrl) { - // diff between two paths to create a relative path - var urlParts = this.extractUrlParts(url); - var baseUrlParts = this.extractUrlParts(baseUrl); - var i; - var max; - var urlDirectories; - var baseUrlDirectories; - var diff = ''; - if (urlParts.hostPart !== baseUrlParts.hostPart) { - return ''; - } - max = Math.max(baseUrlParts.directories.length, urlParts.directories.length); - for (i = 0; i < max; i++) { - if (baseUrlParts.directories[i] !== urlParts.directories[i]) { - break; - } - } - baseUrlDirectories = baseUrlParts.directories.slice(i); - urlDirectories = urlParts.directories.slice(i); - for (i = 0; i < baseUrlDirectories.length - 1; i++) { - diff += '../'; - } - for (i = 0; i < urlDirectories.length - 1; i++) { - diff += urlDirectories[i] + "/"; - } - return diff; - }; - // helper function, not part of API - AbstractFileManager.prototype.extractUrlParts = function (url, baseUrl) { - // urlParts[1] = protocol://hostname/ OR / - // urlParts[2] = / if path relative to host base - // urlParts[3] = directories - // urlParts[4] = filename - // urlParts[5] = parameters - var urlPartsRegex = /^((?:[a-z-]+:)?\/{2}(?:[^\/\?#]*\/)|([\/\\]))?((?:[^\/\\\?#]*[\/\\])*)([^\/\\\?#]*)([#\?].*)?$/i; - var urlParts = url.match(urlPartsRegex); - var returner = {}; - var rawDirectories = []; - var directories = []; - var i; - var baseUrlParts; - if (!urlParts) { - throw new Error("Could not parse sheet href - '" + url + "'"); - } - // Stylesheets in IE don't always return the full path - if (baseUrl && (!urlParts[1] || urlParts[2])) { - baseUrlParts = baseUrl.match(urlPartsRegex); - if (!baseUrlParts) { - throw new Error("Could not parse page url - '" + baseUrl + "'"); - } - urlParts[1] = urlParts[1] || baseUrlParts[1] || ''; - if (!urlParts[2]) { - urlParts[3] = baseUrlParts[3] + urlParts[3]; - } - } - if (urlParts[3]) { - rawDirectories = urlParts[3].replace(/\\/g, '/').split('/'); - // collapse '..' and skip '.' - for (i = 0; i < rawDirectories.length; i++) { - if (rawDirectories[i] === '..') { - directories.pop(); - } - else if (rawDirectories[i] !== '.') { - directories.push(rawDirectories[i]); - } - } - } - returner.hostPart = urlParts[1]; - returner.directories = directories; - returner.rawPath = (urlParts[1] || '') + rawDirectories.join('/'); - returner.path = (urlParts[1] || '') + directories.join('/'); - returner.filename = urlParts[4]; - returner.fileUrl = returner.path + (urlParts[4] || ''); - returner.url = returner.fileUrl + (urlParts[5] || ''); - return returner; - }; - return AbstractFileManager; - }()); - - var AbstractPluginLoader = /** @class */ (function () { - function AbstractPluginLoader() { - // Implemented by Node.js plugin loader - this.require = function () { - return null; - }; - } - AbstractPluginLoader.prototype.evalPlugin = function (contents, context, imports, pluginOptions, fileInfo) { - var loader, registry, pluginObj, localModule, pluginManager, filename, result; - pluginManager = context.pluginManager; - if (fileInfo) { - if (typeof fileInfo === 'string') { - filename = fileInfo; - } - else { - filename = fileInfo.filename; - } - } - var shortname = (new this.less.FileManager()).extractUrlParts(filename).filename; - if (filename) { - pluginObj = pluginManager.get(filename); - if (pluginObj) { - result = this.trySetOptions(pluginObj, filename, shortname, pluginOptions); - if (result) { - return result; - } - try { - if (pluginObj.use) { - pluginObj.use.call(this.context, pluginObj); - } - } - catch (e) { - e.message = e.message || 'Error during @plugin call'; - return new LessError(e, imports, filename); - } - return pluginObj; - } - } - localModule = { - exports: {}, - pluginManager: pluginManager, - fileInfo: fileInfo - }; - registry = functionRegistry.create(); - var registerPlugin = function (obj) { - pluginObj = obj; - }; - try { - loader = new Function('module', 'require', 'registerPlugin', 'functions', 'tree', 'less', 'fileInfo', contents); - loader(localModule, this.require(filename), registerPlugin, registry, this.less.tree, this.less, fileInfo); - } - catch (e) { - return new LessError(e, imports, filename); - } - if (!pluginObj) { - pluginObj = localModule.exports; - } - pluginObj = this.validatePlugin(pluginObj, filename, shortname); - if (pluginObj instanceof LessError) { - return pluginObj; - } - if (pluginObj) { - pluginObj.imports = imports; - pluginObj.filename = filename; - // For < 3.x (or unspecified minVersion) - setOptions() before install() - if (!pluginObj.minVersion || this.compareVersion('3.0.0', pluginObj.minVersion) < 0) { - result = this.trySetOptions(pluginObj, filename, shortname, pluginOptions); - if (result) { - return result; - } - } - // Run on first load - pluginManager.addPlugin(pluginObj, fileInfo.filename, registry); - pluginObj.functions = registry.getLocalFunctions(); - // Need to call setOptions again because the pluginObj might have functions - result = this.trySetOptions(pluginObj, filename, shortname, pluginOptions); - if (result) { - return result; - } - // Run every @plugin call - try { - if (pluginObj.use) { - pluginObj.use.call(this.context, pluginObj); - } - } - catch (e) { - e.message = e.message || 'Error during @plugin call'; - return new LessError(e, imports, filename); - } - } - else { - return new LessError({ message: 'Not a valid plugin' }, imports, filename); - } - return pluginObj; - }; - AbstractPluginLoader.prototype.trySetOptions = function (plugin, filename, name, options) { - if (options && !plugin.setOptions) { - return new LessError({ - message: "Options have been provided but the plugin " + name + " does not support any options." - }); - } - try { - plugin.setOptions && plugin.setOptions(options); - } - catch (e) { - return new LessError(e); - } - }; - AbstractPluginLoader.prototype.validatePlugin = function (plugin, filename, name) { - if (plugin) { - // support plugins being a function - // so that the plugin can be more usable programmatically - if (typeof plugin === 'function') { - plugin = new plugin(); - } - if (plugin.minVersion) { - if (this.compareVersion(plugin.minVersion, this.less.version) < 0) { - return new LessError({ - message: "Plugin " + name + " requires version " + this.versionToString(plugin.minVersion) - }); - } - } - return plugin; - } - return null; - }; - AbstractPluginLoader.prototype.compareVersion = function (aVersion, bVersion) { - if (typeof aVersion === 'string') { - aVersion = aVersion.match(/^(\d+)\.?(\d+)?\.?(\d+)?/); - aVersion.shift(); - } - for (var i = 0; i < aVersion.length; i++) { - if (aVersion[i] !== bVersion[i]) { - return parseInt(aVersion[i]) > parseInt(bVersion[i]) ? -1 : 1; - } - } - return 0; - }; - AbstractPluginLoader.prototype.versionToString = function (version) { - var versionString = ''; - for (var i = 0; i < version.length; i++) { - versionString += (versionString ? '.' : '') + version[i]; - } - return versionString; - }; - AbstractPluginLoader.prototype.printUsage = function (plugins) { - for (var i = 0; i < plugins.length; i++) { - var plugin = plugins[i]; - if (plugin.printUsage) { - plugin.printUsage(); - } - } - }; - return AbstractPluginLoader; - }()); - - var _visitArgs = { visitDeeper: true }; - var _hasIndexed = false; - function _noop(node) { - return node; - } - function indexNodeTypes(parent, ticker) { - // add .typeIndex to tree node types for lookup table - var key, child; - for (key in parent) { - /* eslint guard-for-in: 0 */ - child = parent[key]; - switch (typeof child) { - case 'function': - // ignore bound functions directly on tree which do not have a prototype - // or aren't nodes - if (child.prototype && child.prototype.type) { - child.prototype.typeIndex = ticker++; - } - break; - case 'object': - ticker = indexNodeTypes(child, ticker); - break; - } - } - return ticker; - } - var Visitor = /** @class */ (function () { - function Visitor(implementation) { - this._implementation = implementation; - this._visitInCache = {}; - this._visitOutCache = {}; - if (!_hasIndexed) { - indexNodeTypes(tree, 1); - _hasIndexed = true; - } - } - Visitor.prototype.visit = function (node) { - if (!node) { - return node; - } - var nodeTypeIndex = node.typeIndex; - if (!nodeTypeIndex) { - // MixinCall args aren't a node type? - if (node.value && node.value.typeIndex) { - this.visit(node.value); - } - return node; - } - var impl = this._implementation; - var func = this._visitInCache[nodeTypeIndex]; - var funcOut = this._visitOutCache[nodeTypeIndex]; - var visitArgs = _visitArgs; - var fnName; - visitArgs.visitDeeper = true; - if (!func) { - fnName = "visit" + node.type; - func = impl[fnName] || _noop; - funcOut = impl[fnName + "Out"] || _noop; - this._visitInCache[nodeTypeIndex] = func; - this._visitOutCache[nodeTypeIndex] = funcOut; - } - if (func !== _noop) { - var newNode = func.call(impl, node, visitArgs); - if (node && impl.isReplacing) { - node = newNode; - } - } - if (visitArgs.visitDeeper && node) { - if (node.length) { - for (var i = 0, cnt = node.length; i < cnt; i++) { - if (node[i].accept) { - node[i].accept(this); - } - } - } - else if (node.accept) { - node.accept(this); - } - } - if (funcOut != _noop) { - funcOut.call(impl, node); - } - return node; - }; - Visitor.prototype.visitArray = function (nodes, nonReplacing) { - if (!nodes) { - return nodes; - } - var cnt = nodes.length; - var i; - // Non-replacing - if (nonReplacing || !this._implementation.isReplacing) { - for (i = 0; i < cnt; i++) { - this.visit(nodes[i]); - } - return nodes; - } - // Replacing - var out = []; - for (i = 0; i < cnt; i++) { - var evald = this.visit(nodes[i]); - if (evald === undefined) { - continue; - } - if (!evald.splice) { - out.push(evald); - } - else if (evald.length) { - this.flatten(evald, out); - } - } - return out; - }; - Visitor.prototype.flatten = function (arr, out) { - if (!out) { - out = []; - } - var cnt, i, item, nestedCnt, j, nestedItem; - for (i = 0, cnt = arr.length; i < cnt; i++) { - item = arr[i]; - if (item === undefined) { - continue; - } - if (!item.splice) { - out.push(item); - continue; - } - for (j = 0, nestedCnt = item.length; j < nestedCnt; j++) { - nestedItem = item[j]; - if (nestedItem === undefined) { - continue; - } - if (!nestedItem.splice) { - out.push(nestedItem); - } - else if (nestedItem.length) { - this.flatten(nestedItem, out); - } - } - } - return out; - }; - return Visitor; - }()); - - var ImportSequencer = /** @class */ (function () { - function ImportSequencer(onSequencerEmpty) { - this.imports = []; - this.variableImports = []; - this._onSequencerEmpty = onSequencerEmpty; - this._currentDepth = 0; - } - ImportSequencer.prototype.addImport = function (callback) { - var importSequencer = this, importItem = { - callback: callback, - args: null, - isReady: false - }; - this.imports.push(importItem); - return function () { - importItem.args = Array.prototype.slice.call(arguments, 0); - importItem.isReady = true; - importSequencer.tryRun(); - }; - }; - ImportSequencer.prototype.addVariableImport = function (callback) { - this.variableImports.push(callback); - }; - ImportSequencer.prototype.tryRun = function () { - this._currentDepth++; - try { - while (true) { - while (this.imports.length > 0) { - var importItem = this.imports[0]; - if (!importItem.isReady) { - return; - } - this.imports = this.imports.slice(1); - importItem.callback.apply(null, importItem.args); - } - if (this.variableImports.length === 0) { - break; - } - var variableImport = this.variableImports[0]; - this.variableImports = this.variableImports.slice(1); - variableImport(); - } - } - finally { - this._currentDepth--; - } - if (this._currentDepth === 0 && this._onSequencerEmpty) { - this._onSequencerEmpty(); - } - }; - return ImportSequencer; - }()); - - var ImportVisitor = function (importer, finish) { - this._visitor = new Visitor(this); - this._importer = importer; - this._finish = finish; - this.context = new contexts.Eval(); - this.importCount = 0; - this.onceFileDetectionMap = {}; - this.recursionDetector = {}; - this._sequencer = new ImportSequencer(this._onSequencerEmpty.bind(this)); - }; - ImportVisitor.prototype = { - isReplacing: false, - run: function (root) { - try { - // process the contents - this._visitor.visit(root); - } - catch (e) { - this.error = e; - } - this.isFinished = true; - this._sequencer.tryRun(); - }, - _onSequencerEmpty: function () { - if (!this.isFinished) { - return; - } - this._finish(this.error); - }, - visitImport: function (importNode, visitArgs) { - var inlineCSS = importNode.options.inline; - if (!importNode.css || inlineCSS) { - var context = new contexts.Eval(this.context, copyArray(this.context.frames)); - var importParent = context.frames[0]; - this.importCount++; - if (importNode.isVariableImport()) { - this._sequencer.addVariableImport(this.processImportNode.bind(this, importNode, context, importParent)); - } - else { - this.processImportNode(importNode, context, importParent); - } - } - visitArgs.visitDeeper = false; - }, - processImportNode: function (importNode, context, importParent) { - var evaldImportNode; - var inlineCSS = importNode.options.inline; - try { - evaldImportNode = importNode.evalForImport(context); - } - catch (e) { - if (!e.filename) { - e.index = importNode.getIndex(); - e.filename = importNode.fileInfo().filename; - } - // attempt to eval properly and treat as css - importNode.css = true; - // if that fails, this error will be thrown - importNode.error = e; - } - if (evaldImportNode && (!evaldImportNode.css || inlineCSS)) { - if (evaldImportNode.options.multiple) { - context.importMultiple = true; - } - // try appending if we haven't determined if it is css or not - var tryAppendLessExtension = evaldImportNode.css === undefined; - for (var i = 0; i < importParent.rules.length; i++) { - if (importParent.rules[i] === importNode) { - importParent.rules[i] = evaldImportNode; - break; - } - } - var onImported = this.onImported.bind(this, evaldImportNode, context), sequencedOnImported = this._sequencer.addImport(onImported); - this._importer.push(evaldImportNode.getPath(), tryAppendLessExtension, evaldImportNode.fileInfo(), evaldImportNode.options, sequencedOnImported); - } - else { - this.importCount--; - if (this.isFinished) { - this._sequencer.tryRun(); - } - } - }, - onImported: function (importNode, context, e, root, importedAtRoot, fullPath) { - if (e) { - if (!e.filename) { - e.index = importNode.getIndex(); - e.filename = importNode.fileInfo().filename; - } - this.error = e; - } - var importVisitor = this, inlineCSS = importNode.options.inline, isPlugin = importNode.options.isPlugin, isOptional = importNode.options.optional, duplicateImport = importedAtRoot || fullPath in importVisitor.recursionDetector; - if (!context.importMultiple) { - if (duplicateImport) { - importNode.skip = true; - } - else { - importNode.skip = function () { - if (fullPath in importVisitor.onceFileDetectionMap) { - return true; - } - importVisitor.onceFileDetectionMap[fullPath] = true; - return false; - }; - } - } - if (!fullPath && isOptional) { - importNode.skip = true; - } - if (root) { - importNode.root = root; - importNode.importedFilename = fullPath; - if (!inlineCSS && !isPlugin && (context.importMultiple || !duplicateImport)) { - importVisitor.recursionDetector[fullPath] = true; - var oldContext = this.context; - this.context = context; - try { - this._visitor.visit(root); - } - catch (e) { - this.error = e; - } - this.context = oldContext; - } - } - importVisitor.importCount--; - if (importVisitor.isFinished) { - importVisitor._sequencer.tryRun(); - } - }, - visitDeclaration: function (declNode, visitArgs) { - if (declNode.value.type === 'DetachedRuleset') { - this.context.frames.unshift(declNode); - } - else { - visitArgs.visitDeeper = false; - } - }, - visitDeclarationOut: function (declNode) { - if (declNode.value.type === 'DetachedRuleset') { - this.context.frames.shift(); - } - }, - visitAtRule: function (atRuleNode, visitArgs) { - this.context.frames.unshift(atRuleNode); - }, - visitAtRuleOut: function (atRuleNode) { - this.context.frames.shift(); - }, - visitMixinDefinition: function (mixinDefinitionNode, visitArgs) { - this.context.frames.unshift(mixinDefinitionNode); - }, - visitMixinDefinitionOut: function (mixinDefinitionNode) { - this.context.frames.shift(); - }, - visitRuleset: function (rulesetNode, visitArgs) { - this.context.frames.unshift(rulesetNode); - }, - visitRulesetOut: function (rulesetNode) { - this.context.frames.shift(); - }, - visitMedia: function (mediaNode, visitArgs) { - this.context.frames.unshift(mediaNode.rules[0]); - }, - visitMediaOut: function (mediaNode) { - this.context.frames.shift(); - } - }; - - var SetTreeVisibilityVisitor = /** @class */ (function () { - function SetTreeVisibilityVisitor(visible) { - this.visible = visible; - } - SetTreeVisibilityVisitor.prototype.run = function (root) { - this.visit(root); - }; - SetTreeVisibilityVisitor.prototype.visitArray = function (nodes) { - if (!nodes) { - return nodes; - } - var cnt = nodes.length; - var i; - for (i = 0; i < cnt; i++) { - this.visit(nodes[i]); - } - return nodes; - }; - SetTreeVisibilityVisitor.prototype.visit = function (node) { - if (!node) { - return node; - } - if (node.constructor === Array) { - return this.visitArray(node); - } - if (!node.blocksVisibility || node.blocksVisibility()) { - return node; - } - if (this.visible) { - node.ensureVisibility(); - } - else { - node.ensureInvisibility(); - } - node.accept(this); - return node; - }; - return SetTreeVisibilityVisitor; - }()); - - /* jshint loopfunc:true */ - var ExtendFinderVisitor = /** @class */ (function () { - function ExtendFinderVisitor() { - this._visitor = new Visitor(this); - this.contexts = []; - this.allExtendsStack = [[]]; - } - ExtendFinderVisitor.prototype.run = function (root) { - root = this._visitor.visit(root); - root.allExtends = this.allExtendsStack[0]; - return root; - }; - ExtendFinderVisitor.prototype.visitDeclaration = function (declNode, visitArgs) { - visitArgs.visitDeeper = false; - }; - ExtendFinderVisitor.prototype.visitMixinDefinition = function (mixinDefinitionNode, visitArgs) { - visitArgs.visitDeeper = false; - }; - ExtendFinderVisitor.prototype.visitRuleset = function (rulesetNode, visitArgs) { - if (rulesetNode.root) { - return; - } - var i; - var j; - var extend; - var allSelectorsExtendList = []; - var extendList; - // get &:extend(.a); rules which apply to all selectors in this ruleset - var rules = rulesetNode.rules, ruleCnt = rules ? rules.length : 0; - for (i = 0; i < ruleCnt; i++) { - if (rulesetNode.rules[i] instanceof tree.Extend) { - allSelectorsExtendList.push(rules[i]); - rulesetNode.extendOnEveryPath = true; - } - } - // now find every selector and apply the extends that apply to all extends - // and the ones which apply to an individual extend - var paths = rulesetNode.paths; - for (i = 0; i < paths.length; i++) { - var selectorPath = paths[i], selector = selectorPath[selectorPath.length - 1], selExtendList = selector.extendList; - extendList = selExtendList ? copyArray(selExtendList).concat(allSelectorsExtendList) - : allSelectorsExtendList; - if (extendList) { - extendList = extendList.map(function (allSelectorsExtend) { - return allSelectorsExtend.clone(); - }); - } - for (j = 0; j < extendList.length; j++) { - this.foundExtends = true; - extend = extendList[j]; - extend.findSelfSelectors(selectorPath); - extend.ruleset = rulesetNode; - if (j === 0) { - extend.firstExtendOnThisSelectorPath = true; - } - this.allExtendsStack[this.allExtendsStack.length - 1].push(extend); - } - } - this.contexts.push(rulesetNode.selectors); - }; - ExtendFinderVisitor.prototype.visitRulesetOut = function (rulesetNode) { - if (!rulesetNode.root) { - this.contexts.length = this.contexts.length - 1; - } - }; - ExtendFinderVisitor.prototype.visitMedia = function (mediaNode, visitArgs) { - mediaNode.allExtends = []; - this.allExtendsStack.push(mediaNode.allExtends); - }; - ExtendFinderVisitor.prototype.visitMediaOut = function (mediaNode) { - this.allExtendsStack.length = this.allExtendsStack.length - 1; - }; - ExtendFinderVisitor.prototype.visitAtRule = function (atRuleNode, visitArgs) { - atRuleNode.allExtends = []; - this.allExtendsStack.push(atRuleNode.allExtends); - }; - ExtendFinderVisitor.prototype.visitAtRuleOut = function (atRuleNode) { - this.allExtendsStack.length = this.allExtendsStack.length - 1; - }; - return ExtendFinderVisitor; - }()); - var ProcessExtendsVisitor = /** @class */ (function () { - function ProcessExtendsVisitor() { - this._visitor = new Visitor(this); - } - ProcessExtendsVisitor.prototype.run = function (root) { - var extendFinder = new ExtendFinderVisitor(); - this.extendIndices = {}; - extendFinder.run(root); - if (!extendFinder.foundExtends) { - return root; - } - root.allExtends = root.allExtends.concat(this.doExtendChaining(root.allExtends, root.allExtends)); - this.allExtendsStack = [root.allExtends]; - var newRoot = this._visitor.visit(root); - this.checkExtendsForNonMatched(root.allExtends); - return newRoot; - }; - ProcessExtendsVisitor.prototype.checkExtendsForNonMatched = function (extendList) { - var indices = this.extendIndices; - extendList.filter(function (extend) { - return !extend.hasFoundMatches && extend.parent_ids.length == 1; - }).forEach(function (extend) { - var selector = '_unknown_'; - try { - selector = extend.selector.toCSS({}); - } - catch (_) { } - if (!indices[extend.index + " " + selector]) { - indices[extend.index + " " + selector] = true; - logger$1.warn("extend '" + selector + "' has no matches"); - } - }); - }; - ProcessExtendsVisitor.prototype.doExtendChaining = function (extendsList, extendsListTarget, iterationCount) { - // - // chaining is different from normal extension.. if we extend an extend then we are not just copying, altering - // and pasting the selector we would do normally, but we are also adding an extend with the same target selector - // this means this new extend can then go and alter other extends - // - // this method deals with all the chaining work - without it, extend is flat and doesn't work on other extend selectors - // this is also the most expensive.. and a match on one selector can cause an extension of a selector we had already - // processed if we look at each selector at a time, as is done in visitRuleset - var extendIndex; - var targetExtendIndex; - var matches; - var extendsToAdd = []; - var newSelector; - var extendVisitor = this; - var selectorPath; - var extend; - var targetExtend; - var newExtend; - iterationCount = iterationCount || 0; - // loop through comparing every extend with every target extend. - // a target extend is the one on the ruleset we are looking at copy/edit/pasting in place - // e.g. .a:extend(.b) {} and .b:extend(.c) {} then the first extend extends the second one - // and the second is the target. - // the separation into two lists allows us to process a subset of chains with a bigger set, as is the - // case when processing media queries - for (extendIndex = 0; extendIndex < extendsList.length; extendIndex++) { - for (targetExtendIndex = 0; targetExtendIndex < extendsListTarget.length; targetExtendIndex++) { - extend = extendsList[extendIndex]; - targetExtend = extendsListTarget[targetExtendIndex]; - // look for circular references - if (extend.parent_ids.indexOf(targetExtend.object_id) >= 0) { - continue; - } - // find a match in the target extends self selector (the bit before :extend) - selectorPath = [targetExtend.selfSelectors[0]]; - matches = extendVisitor.findMatch(extend, selectorPath); - if (matches.length) { - extend.hasFoundMatches = true; - // we found a match, so for each self selector.. - extend.selfSelectors.forEach(function (selfSelector) { - var info = targetExtend.visibilityInfo(); - // process the extend as usual - newSelector = extendVisitor.extendSelector(matches, selectorPath, selfSelector, extend.isVisible()); - // but now we create a new extend from it - newExtend = new (tree.Extend)(targetExtend.selector, targetExtend.option, 0, targetExtend.fileInfo(), info); - newExtend.selfSelectors = newSelector; - // add the extend onto the list of extends for that selector - newSelector[newSelector.length - 1].extendList = [newExtend]; - // record that we need to add it. - extendsToAdd.push(newExtend); - newExtend.ruleset = targetExtend.ruleset; - // remember its parents for circular references - newExtend.parent_ids = newExtend.parent_ids.concat(targetExtend.parent_ids, extend.parent_ids); - // only process the selector once.. if we have :extend(.a,.b) then multiple - // extends will look at the same selector path, so when extending - // we know that any others will be duplicates in terms of what is added to the css - if (targetExtend.firstExtendOnThisSelectorPath) { - newExtend.firstExtendOnThisSelectorPath = true; - targetExtend.ruleset.paths.push(newSelector); - } - }); - } - } - } - if (extendsToAdd.length) { - // try to detect circular references to stop a stack overflow. - // may no longer be needed. - this.extendChainCount++; - if (iterationCount > 100) { - var selectorOne = '{unable to calculate}'; - var selectorTwo = '{unable to calculate}'; - try { - selectorOne = extendsToAdd[0].selfSelectors[0].toCSS(); - selectorTwo = extendsToAdd[0].selector.toCSS(); - } - catch (e) { } - throw { message: "extend circular reference detected. One of the circular extends is currently:" + selectorOne + ":extend(" + selectorTwo + ")" }; - } - // now process the new extends on the existing rules so that we can handle a extending b extending c extending - // d extending e... - return extendsToAdd.concat(extendVisitor.doExtendChaining(extendsToAdd, extendsListTarget, iterationCount + 1)); - } - else { - return extendsToAdd; - } - }; - ProcessExtendsVisitor.prototype.visitDeclaration = function (ruleNode, visitArgs) { - visitArgs.visitDeeper = false; - }; - ProcessExtendsVisitor.prototype.visitMixinDefinition = function (mixinDefinitionNode, visitArgs) { - visitArgs.visitDeeper = false; - }; - ProcessExtendsVisitor.prototype.visitSelector = function (selectorNode, visitArgs) { - visitArgs.visitDeeper = false; - }; - ProcessExtendsVisitor.prototype.visitRuleset = function (rulesetNode, visitArgs) { - if (rulesetNode.root) { - return; - } - var matches; - var pathIndex; - var extendIndex; - var allExtends = this.allExtendsStack[this.allExtendsStack.length - 1]; - var selectorsToAdd = []; - var extendVisitor = this; - var selectorPath; - // look at each selector path in the ruleset, find any extend matches and then copy, find and replace - for (extendIndex = 0; extendIndex < allExtends.length; extendIndex++) { - for (pathIndex = 0; pathIndex < rulesetNode.paths.length; pathIndex++) { - selectorPath = rulesetNode.paths[pathIndex]; - // extending extends happens initially, before the main pass - if (rulesetNode.extendOnEveryPath) { - continue; - } - var extendList = selectorPath[selectorPath.length - 1].extendList; - if (extendList && extendList.length) { - continue; - } - matches = this.findMatch(allExtends[extendIndex], selectorPath); - if (matches.length) { - allExtends[extendIndex].hasFoundMatches = true; - allExtends[extendIndex].selfSelectors.forEach(function (selfSelector) { - var extendedSelectors; - extendedSelectors = extendVisitor.extendSelector(matches, selectorPath, selfSelector, allExtends[extendIndex].isVisible()); - selectorsToAdd.push(extendedSelectors); - }); - } - } - } - rulesetNode.paths = rulesetNode.paths.concat(selectorsToAdd); - }; - ProcessExtendsVisitor.prototype.findMatch = function (extend, haystackSelectorPath) { - // - // look through the haystack selector path to try and find the needle - extend.selector - // returns an array of selector matches that can then be replaced - // - var haystackSelectorIndex; - var hackstackSelector; - var hackstackElementIndex; - var haystackElement; - var targetCombinator; - var i; - var extendVisitor = this; - var needleElements = extend.selector.elements; - var potentialMatches = []; - var potentialMatch; - var matches = []; - // loop through the haystack elements - for (haystackSelectorIndex = 0; haystackSelectorIndex < haystackSelectorPath.length; haystackSelectorIndex++) { - hackstackSelector = haystackSelectorPath[haystackSelectorIndex]; - for (hackstackElementIndex = 0; hackstackElementIndex < hackstackSelector.elements.length; hackstackElementIndex++) { - haystackElement = hackstackSelector.elements[hackstackElementIndex]; - // if we allow elements before our match we can add a potential match every time. otherwise only at the first element. - if (extend.allowBefore || (haystackSelectorIndex === 0 && hackstackElementIndex === 0)) { - potentialMatches.push({ pathIndex: haystackSelectorIndex, index: hackstackElementIndex, matched: 0, - initialCombinator: haystackElement.combinator }); - } - for (i = 0; i < potentialMatches.length; i++) { - potentialMatch = potentialMatches[i]; - // selectors add " " onto the first element. When we use & it joins the selectors together, but if we don't - // then each selector in haystackSelectorPath has a space before it added in the toCSS phase. so we need to - // work out what the resulting combinator will be - targetCombinator = haystackElement.combinator.value; - if (targetCombinator === '' && hackstackElementIndex === 0) { - targetCombinator = ' '; - } - // if we don't match, null our match to indicate failure - if (!extendVisitor.isElementValuesEqual(needleElements[potentialMatch.matched].value, haystackElement.value) || - (potentialMatch.matched > 0 && needleElements[potentialMatch.matched].combinator.value !== targetCombinator)) { - potentialMatch = null; - } - else { - potentialMatch.matched++; - } - // if we are still valid and have finished, test whether we have elements after and whether these are allowed - if (potentialMatch) { - potentialMatch.finished = potentialMatch.matched === needleElements.length; - if (potentialMatch.finished && - (!extend.allowAfter && - (hackstackElementIndex + 1 < hackstackSelector.elements.length || haystackSelectorIndex + 1 < haystackSelectorPath.length))) { - potentialMatch = null; - } - } - // if null we remove, if not, we are still valid, so either push as a valid match or continue - if (potentialMatch) { - if (potentialMatch.finished) { - potentialMatch.length = needleElements.length; - potentialMatch.endPathIndex = haystackSelectorIndex; - potentialMatch.endPathElementIndex = hackstackElementIndex + 1; // index after end of match - potentialMatches.length = 0; // we don't allow matches to overlap, so start matching again - matches.push(potentialMatch); - } - } - else { - potentialMatches.splice(i, 1); - i--; - } - } - } - } - return matches; - }; - ProcessExtendsVisitor.prototype.isElementValuesEqual = function (elementValue1, elementValue2) { - if (typeof elementValue1 === 'string' || typeof elementValue2 === 'string') { - return elementValue1 === elementValue2; - } - if (elementValue1 instanceof tree.Attribute) { - if (elementValue1.op !== elementValue2.op || elementValue1.key !== elementValue2.key) { - return false; - } - if (!elementValue1.value || !elementValue2.value) { - if (elementValue1.value || elementValue2.value) { - return false; - } - return true; - } - elementValue1 = elementValue1.value.value || elementValue1.value; - elementValue2 = elementValue2.value.value || elementValue2.value; - return elementValue1 === elementValue2; - } - elementValue1 = elementValue1.value; - elementValue2 = elementValue2.value; - if (elementValue1 instanceof tree.Selector) { - if (!(elementValue2 instanceof tree.Selector) || elementValue1.elements.length !== elementValue2.elements.length) { - return false; - } - for (var i = 0; i < elementValue1.elements.length; i++) { - if (elementValue1.elements[i].combinator.value !== elementValue2.elements[i].combinator.value) { - if (i !== 0 || (elementValue1.elements[i].combinator.value || ' ') !== (elementValue2.elements[i].combinator.value || ' ')) { - return false; - } - } - if (!this.isElementValuesEqual(elementValue1.elements[i].value, elementValue2.elements[i].value)) { - return false; - } - } - return true; - } - return false; - }; - ProcessExtendsVisitor.prototype.extendSelector = function (matches, selectorPath, replacementSelector, isVisible) { - // for a set of matches, replace each match with the replacement selector - var currentSelectorPathIndex = 0, currentSelectorPathElementIndex = 0, path = [], matchIndex, selector, firstElement, match, newElements; - for (matchIndex = 0; matchIndex < matches.length; matchIndex++) { - match = matches[matchIndex]; - selector = selectorPath[match.pathIndex]; - firstElement = new tree.Element(match.initialCombinator, replacementSelector.elements[0].value, replacementSelector.elements[0].isVariable, replacementSelector.elements[0].getIndex(), replacementSelector.elements[0].fileInfo()); - if (match.pathIndex > currentSelectorPathIndex && currentSelectorPathElementIndex > 0) { - path[path.length - 1].elements = path[path.length - 1] - .elements.concat(selectorPath[currentSelectorPathIndex].elements.slice(currentSelectorPathElementIndex)); - currentSelectorPathElementIndex = 0; - currentSelectorPathIndex++; - } - newElements = selector.elements - .slice(currentSelectorPathElementIndex, match.index) - .concat([firstElement]) - .concat(replacementSelector.elements.slice(1)); - if (currentSelectorPathIndex === match.pathIndex && matchIndex > 0) { - path[path.length - 1].elements = - path[path.length - 1].elements.concat(newElements); - } - else { - path = path.concat(selectorPath.slice(currentSelectorPathIndex, match.pathIndex)); - path.push(new tree.Selector(newElements)); - } - currentSelectorPathIndex = match.endPathIndex; - currentSelectorPathElementIndex = match.endPathElementIndex; - if (currentSelectorPathElementIndex >= selectorPath[currentSelectorPathIndex].elements.length) { - currentSelectorPathElementIndex = 0; - currentSelectorPathIndex++; - } - } - if (currentSelectorPathIndex < selectorPath.length && currentSelectorPathElementIndex > 0) { - path[path.length - 1].elements = path[path.length - 1] - .elements.concat(selectorPath[currentSelectorPathIndex].elements.slice(currentSelectorPathElementIndex)); - currentSelectorPathIndex++; - } - path = path.concat(selectorPath.slice(currentSelectorPathIndex, selectorPath.length)); - path = path.map(function (currentValue) { - // we can re-use elements here, because the visibility property matters only for selectors - var derived = currentValue.createDerived(currentValue.elements); - if (isVisible) { - derived.ensureVisibility(); - } - else { - derived.ensureInvisibility(); - } - return derived; - }); - return path; - }; - ProcessExtendsVisitor.prototype.visitMedia = function (mediaNode, visitArgs) { - var newAllExtends = mediaNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length - 1]); - newAllExtends = newAllExtends.concat(this.doExtendChaining(newAllExtends, mediaNode.allExtends)); - this.allExtendsStack.push(newAllExtends); - }; - ProcessExtendsVisitor.prototype.visitMediaOut = function (mediaNode) { - var lastIndex = this.allExtendsStack.length - 1; - this.allExtendsStack.length = lastIndex; - }; - ProcessExtendsVisitor.prototype.visitAtRule = function (atRuleNode, visitArgs) { - var newAllExtends = atRuleNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length - 1]); - newAllExtends = newAllExtends.concat(this.doExtendChaining(newAllExtends, atRuleNode.allExtends)); - this.allExtendsStack.push(newAllExtends); - }; - ProcessExtendsVisitor.prototype.visitAtRuleOut = function (atRuleNode) { - var lastIndex = this.allExtendsStack.length - 1; - this.allExtendsStack.length = lastIndex; - }; - return ProcessExtendsVisitor; - }()); - - var JoinSelectorVisitor = /** @class */ (function () { - function JoinSelectorVisitor() { - this.contexts = [[]]; - this._visitor = new Visitor(this); - } - JoinSelectorVisitor.prototype.run = function (root) { - return this._visitor.visit(root); - }; - JoinSelectorVisitor.prototype.visitDeclaration = function (declNode, visitArgs) { - visitArgs.visitDeeper = false; - }; - JoinSelectorVisitor.prototype.visitMixinDefinition = function (mixinDefinitionNode, visitArgs) { - visitArgs.visitDeeper = false; - }; - JoinSelectorVisitor.prototype.visitRuleset = function (rulesetNode, visitArgs) { - var context = this.contexts[this.contexts.length - 1]; - var paths = []; - var selectors; - this.contexts.push(paths); - if (!rulesetNode.root) { - selectors = rulesetNode.selectors; - if (selectors) { - selectors = selectors.filter(function (selector) { return selector.getIsOutput(); }); - rulesetNode.selectors = selectors.length ? selectors : (selectors = null); - if (selectors) { - rulesetNode.joinSelectors(paths, context, selectors); - } - } - if (!selectors) { - rulesetNode.rules = null; - } - rulesetNode.paths = paths; - } - }; - JoinSelectorVisitor.prototype.visitRulesetOut = function (rulesetNode) { - this.contexts.length = this.contexts.length - 1; - }; - JoinSelectorVisitor.prototype.visitMedia = function (mediaNode, visitArgs) { - var context = this.contexts[this.contexts.length - 1]; - mediaNode.rules[0].root = (context.length === 0 || context[0].multiMedia); - }; - JoinSelectorVisitor.prototype.visitAtRule = function (atRuleNode, visitArgs) { - var context = this.contexts[this.contexts.length - 1]; - if (atRuleNode.rules && atRuleNode.rules.length) { - atRuleNode.rules[0].root = (atRuleNode.isRooted || context.length === 0 || null); - } - }; - return JoinSelectorVisitor; - }()); - - var CSSVisitorUtils = /** @class */ (function () { - function CSSVisitorUtils(context) { - this._visitor = new Visitor(this); - this._context = context; - } - CSSVisitorUtils.prototype.containsSilentNonBlockedChild = function (bodyRules) { - var rule; - if (!bodyRules) { - return false; - } - for (var r = 0; r < bodyRules.length; r++) { - rule = bodyRules[r]; - if (rule.isSilent && rule.isSilent(this._context) && !rule.blocksVisibility()) { - // the atrule contains something that was referenced (likely by extend) - // therefore it needs to be shown in output too - return true; - } - } - return false; - }; - CSSVisitorUtils.prototype.keepOnlyVisibleChilds = function (owner) { - if (owner && owner.rules) { - owner.rules = owner.rules.filter(function (thing) { return thing.isVisible(); }); - } - }; - CSSVisitorUtils.prototype.isEmpty = function (owner) { - return (owner && owner.rules) - ? (owner.rules.length === 0) : true; - }; - CSSVisitorUtils.prototype.hasVisibleSelector = function (rulesetNode) { - return (rulesetNode && rulesetNode.paths) - ? (rulesetNode.paths.length > 0) : false; - }; - CSSVisitorUtils.prototype.resolveVisibility = function (node, originalRules) { - if (!node.blocksVisibility()) { - if (this.isEmpty(node) && !this.containsSilentNonBlockedChild(originalRules)) { - return; - } - return node; - } - var compiledRulesBody = node.rules[0]; - this.keepOnlyVisibleChilds(compiledRulesBody); - if (this.isEmpty(compiledRulesBody)) { - return; - } - node.ensureVisibility(); - node.removeVisibilityBlock(); - return node; - }; - CSSVisitorUtils.prototype.isVisibleRuleset = function (rulesetNode) { - if (rulesetNode.firstRoot) { - return true; - } - if (this.isEmpty(rulesetNode)) { - return false; - } - if (!rulesetNode.root && !this.hasVisibleSelector(rulesetNode)) { - return false; - } - return true; - }; - return CSSVisitorUtils; - }()); - var ToCSSVisitor = function (context) { - this._visitor = new Visitor(this); - this._context = context; - this.utils = new CSSVisitorUtils(context); - }; - ToCSSVisitor.prototype = { - isReplacing: true, - run: function (root) { - return this._visitor.visit(root); - }, - visitDeclaration: function (declNode, visitArgs) { - if (declNode.blocksVisibility() || declNode.variable) { - return; - } - return declNode; - }, - visitMixinDefinition: function (mixinNode, visitArgs) { - // mixin definitions do not get eval'd - this means they keep state - // so we have to clear that state here so it isn't used if toCSS is called twice - mixinNode.frames = []; - }, - visitExtend: function (extendNode, visitArgs) { - }, - visitComment: function (commentNode, visitArgs) { - if (commentNode.blocksVisibility() || commentNode.isSilent(this._context)) { - return; - } - return commentNode; - }, - visitMedia: function (mediaNode, visitArgs) { - var originalRules = mediaNode.rules[0].rules; - mediaNode.accept(this._visitor); - visitArgs.visitDeeper = false; - return this.utils.resolveVisibility(mediaNode, originalRules); - }, - visitImport: function (importNode, visitArgs) { - if (importNode.blocksVisibility()) { - return; - } - return importNode; - }, - visitAtRule: function (atRuleNode, visitArgs) { - if (atRuleNode.rules && atRuleNode.rules.length) { - return this.visitAtRuleWithBody(atRuleNode, visitArgs); - } - else { - return this.visitAtRuleWithoutBody(atRuleNode, visitArgs); - } - }, - visitAnonymous: function (anonymousNode, visitArgs) { - if (!anonymousNode.blocksVisibility()) { - anonymousNode.accept(this._visitor); - return anonymousNode; - } - }, - visitAtRuleWithBody: function (atRuleNode, visitArgs) { - // if there is only one nested ruleset and that one has no path, then it is - // just fake ruleset - function hasFakeRuleset(atRuleNode) { - var bodyRules = atRuleNode.rules; - return bodyRules.length === 1 && (!bodyRules[0].paths || bodyRules[0].paths.length === 0); - } - function getBodyRules(atRuleNode) { - var nodeRules = atRuleNode.rules; - if (hasFakeRuleset(atRuleNode)) { - return nodeRules[0].rules; - } - return nodeRules; - } - // it is still true that it is only one ruleset in array - // this is last such moment - // process childs - var originalRules = getBodyRules(atRuleNode); - atRuleNode.accept(this._visitor); - visitArgs.visitDeeper = false; - if (!this.utils.isEmpty(atRuleNode)) { - this._mergeRules(atRuleNode.rules[0].rules); - } - return this.utils.resolveVisibility(atRuleNode, originalRules); - }, - visitAtRuleWithoutBody: function (atRuleNode, visitArgs) { - if (atRuleNode.blocksVisibility()) { - return; - } - if (atRuleNode.name === '@charset') { - // Only output the debug info together with subsequent @charset definitions - // a comment (or @media statement) before the actual @charset atrule would - // be considered illegal css as it has to be on the first line - if (this.charset) { - if (atRuleNode.debugInfo) { - var comment = new tree.Comment("/* " + atRuleNode.toCSS(this._context).replace(/\n/g, '') + " */\n"); - comment.debugInfo = atRuleNode.debugInfo; - return this._visitor.visit(comment); - } - return; - } - this.charset = true; - } - return atRuleNode; - }, - checkValidNodes: function (rules, isRoot) { - if (!rules) { - return; - } - for (var i = 0; i < rules.length; i++) { - var ruleNode = rules[i]; - if (isRoot && ruleNode instanceof tree.Declaration && !ruleNode.variable) { - throw { message: 'Properties must be inside selector blocks. They cannot be in the root', - index: ruleNode.getIndex(), filename: ruleNode.fileInfo() && ruleNode.fileInfo().filename }; - } - if (ruleNode instanceof tree.Call) { - throw { message: "Function '" + ruleNode.name + "' did not return a root node", - index: ruleNode.getIndex(), filename: ruleNode.fileInfo() && ruleNode.fileInfo().filename }; - } - if (ruleNode.type && !ruleNode.allowRoot) { - throw { message: ruleNode.type + " node returned by a function is not valid here", - index: ruleNode.getIndex(), filename: ruleNode.fileInfo() && ruleNode.fileInfo().filename }; - } - } - }, - visitRuleset: function (rulesetNode, visitArgs) { - // at this point rulesets are nested into each other - var rule; - var rulesets = []; - this.checkValidNodes(rulesetNode.rules, rulesetNode.firstRoot); - if (!rulesetNode.root) { - // remove invisible paths - this._compileRulesetPaths(rulesetNode); - // remove rulesets from this ruleset body and compile them separately - var nodeRules = rulesetNode.rules; - var nodeRuleCnt = nodeRules ? nodeRules.length : 0; - for (var i = 0; i < nodeRuleCnt;) { - rule = nodeRules[i]; - if (rule && rule.rules) { - // visit because we are moving them out from being a child - rulesets.push(this._visitor.visit(rule)); - nodeRules.splice(i, 1); - nodeRuleCnt--; - continue; - } - i++; - } - // accept the visitor to remove rules and refactor itself - // then we can decide nogw whether we want it or not - // compile body - if (nodeRuleCnt > 0) { - rulesetNode.accept(this._visitor); - } - else { - rulesetNode.rules = null; - } - visitArgs.visitDeeper = false; - } - else { // if (! rulesetNode.root) { - rulesetNode.accept(this._visitor); - visitArgs.visitDeeper = false; - } - if (rulesetNode.rules) { - this._mergeRules(rulesetNode.rules); - this._removeDuplicateRules(rulesetNode.rules); - } - // now decide whether we keep the ruleset - if (this.utils.isVisibleRuleset(rulesetNode)) { - rulesetNode.ensureVisibility(); - rulesets.splice(0, 0, rulesetNode); - } - if (rulesets.length === 1) { - return rulesets[0]; - } - return rulesets; - }, - _compileRulesetPaths: function (rulesetNode) { - if (rulesetNode.paths) { - rulesetNode.paths = rulesetNode.paths - .filter(function (p) { - var i; - if (p[0].elements[0].combinator.value === ' ') { - p[0].elements[0].combinator = new (tree.Combinator)(''); - } - for (i = 0; i < p.length; i++) { - if (p[i].isVisible() && p[i].getIsOutput()) { - return true; - } - } - return false; - }); - } - }, - _removeDuplicateRules: function (rules) { - if (!rules) { - return; - } - // remove duplicates - var ruleCache = {}; - var ruleList; - var rule; - var i; - for (i = rules.length - 1; i >= 0; i--) { - rule = rules[i]; - if (rule instanceof tree.Declaration) { - if (!ruleCache[rule.name]) { - ruleCache[rule.name] = rule; - } - else { - ruleList = ruleCache[rule.name]; - if (ruleList instanceof tree.Declaration) { - ruleList = ruleCache[rule.name] = [ruleCache[rule.name].toCSS(this._context)]; - } - var ruleCSS = rule.toCSS(this._context); - if (ruleList.indexOf(ruleCSS) !== -1) { - rules.splice(i, 1); - } - else { - ruleList.push(ruleCSS); - } - } - } - } - }, - _mergeRules: function (rules) { - if (!rules) { - return; - } - var groups = {}; - var groupsArr = []; - for (var i = 0; i < rules.length; i++) { - var rule = rules[i]; - if (rule.merge) { - var key = rule.name; - groups[key] ? rules.splice(i--, 1) : - groupsArr.push(groups[key] = []); - groups[key].push(rule); - } - } - groupsArr.forEach(function (group) { - if (group.length > 0) { - var result_1 = group[0]; - var space_1 = []; - var comma_1 = [new tree.Expression(space_1)]; - group.forEach(function (rule) { - if ((rule.merge === '+') && (space_1.length > 0)) { - comma_1.push(new tree.Expression(space_1 = [])); - } - space_1.push(rule.value); - result_1.important = result_1.important || rule.important; - }); - result_1.value = new tree.Value(comma_1); - } - }); - } - }; - - var visitors = { - Visitor: Visitor, - ImportVisitor: ImportVisitor, - MarkVisibleSelectorsVisitor: SetTreeVisibilityVisitor, - ExtendVisitor: ProcessExtendsVisitor, - JoinSelectorVisitor: JoinSelectorVisitor, - ToCSSVisitor: ToCSSVisitor - }; - - // Split the input into chunks. - function chunker (input, fail) { - var len = input.length; - var level = 0; - var parenLevel = 0; - var lastOpening; - var lastOpeningParen; - var lastMultiComment; - var lastMultiCommentEndBrace; - var chunks = []; - var emitFrom = 0; - var chunkerCurrentIndex; - var currentChunkStartIndex; - var cc; - var cc2; - var matched; - function emitChunk(force) { - var len = chunkerCurrentIndex - emitFrom; - if (((len < 512) && !force) || !len) { - return; - } - chunks.push(input.slice(emitFrom, chunkerCurrentIndex + 1)); - emitFrom = chunkerCurrentIndex + 1; - } - for (chunkerCurrentIndex = 0; chunkerCurrentIndex < len; chunkerCurrentIndex++) { - cc = input.charCodeAt(chunkerCurrentIndex); - if (((cc >= 97) && (cc <= 122)) || (cc < 34)) { - // a-z or whitespace - continue; - } - switch (cc) { - case 40: // ( - parenLevel++; - lastOpeningParen = chunkerCurrentIndex; - continue; - case 41: // ) - if (--parenLevel < 0) { - return fail('missing opening `(`', chunkerCurrentIndex); - } - continue; - case 59: // ; - if (!parenLevel) { - emitChunk(); - } - continue; - case 123: // { - level++; - lastOpening = chunkerCurrentIndex; - continue; - case 125: // } - if (--level < 0) { - return fail('missing opening `{`', chunkerCurrentIndex); - } - if (!level && !parenLevel) { - emitChunk(); - } - continue; - case 92: // \ - if (chunkerCurrentIndex < len - 1) { - chunkerCurrentIndex++; - continue; - } - return fail('unescaped `\\`', chunkerCurrentIndex); - case 34: - case 39: - case 96: // ", ' and ` - matched = 0; - currentChunkStartIndex = chunkerCurrentIndex; - for (chunkerCurrentIndex = chunkerCurrentIndex + 1; chunkerCurrentIndex < len; chunkerCurrentIndex++) { - cc2 = input.charCodeAt(chunkerCurrentIndex); - if (cc2 > 96) { - continue; - } - if (cc2 == cc) { - matched = 1; - break; - } - if (cc2 == 92) { // \ - if (chunkerCurrentIndex == len - 1) { - return fail('unescaped `\\`', chunkerCurrentIndex); - } - chunkerCurrentIndex++; - } - } - if (matched) { - continue; - } - return fail("unmatched `" + String.fromCharCode(cc) + "`", currentChunkStartIndex); - case 47: // /, check for comment - if (parenLevel || (chunkerCurrentIndex == len - 1)) { - continue; - } - cc2 = input.charCodeAt(chunkerCurrentIndex + 1); - if (cc2 == 47) { - // //, find lnfeed - for (chunkerCurrentIndex = chunkerCurrentIndex + 2; chunkerCurrentIndex < len; chunkerCurrentIndex++) { - cc2 = input.charCodeAt(chunkerCurrentIndex); - if ((cc2 <= 13) && ((cc2 == 10) || (cc2 == 13))) { - break; - } - } - } - else if (cc2 == 42) { - // /*, find */ - lastMultiComment = currentChunkStartIndex = chunkerCurrentIndex; - for (chunkerCurrentIndex = chunkerCurrentIndex + 2; chunkerCurrentIndex < len - 1; chunkerCurrentIndex++) { - cc2 = input.charCodeAt(chunkerCurrentIndex); - if (cc2 == 125) { - lastMultiCommentEndBrace = chunkerCurrentIndex; - } - if (cc2 != 42) { - continue; - } - if (input.charCodeAt(chunkerCurrentIndex + 1) == 47) { - break; - } - } - if (chunkerCurrentIndex == len - 1) { - return fail('missing closing `*/`', currentChunkStartIndex); - } - chunkerCurrentIndex++; - } - continue; - case 42: // *, check for unmatched */ - if ((chunkerCurrentIndex < len - 1) && (input.charCodeAt(chunkerCurrentIndex + 1) == 47)) { - return fail('unmatched `/*`', chunkerCurrentIndex); - } - continue; - } - } - if (level !== 0) { - if ((lastMultiComment > lastOpening) && (lastMultiCommentEndBrace > lastMultiComment)) { - return fail('missing closing `}` or `*/`', lastOpening); - } - else { - return fail('missing closing `}`', lastOpening); - } - } - else if (parenLevel !== 0) { - return fail('missing closing `)`', lastOpeningParen); - } - emitChunk(true); - return chunks; - } - - var getParserInput = (function () { - var // Less input string - input; - var // current chunk - j; - var // holds state for backtracking - saveStack = []; - var // furthest index the parser has gone to - furthest; - var // if this is furthest we got to, this is the probably cause - furthestPossibleErrorMessage; - var // chunkified input - chunks; - var // current chunk - current; - var // index of current chunk, in `input` - currentPos; - var parserInput = {}; - var CHARCODE_SPACE = 32; - var CHARCODE_TAB = 9; - var CHARCODE_LF = 10; - var CHARCODE_CR = 13; - var CHARCODE_PLUS = 43; - var CHARCODE_COMMA = 44; - var CHARCODE_FORWARD_SLASH = 47; - var CHARCODE_9 = 57; - function skipWhitespace(length) { - var oldi = parserInput.i; - var oldj = j; - var curr = parserInput.i - currentPos; - var endIndex = parserInput.i + current.length - curr; - var mem = (parserInput.i += length); - var inp = input; - var c; - var nextChar; - var comment; - for (; parserInput.i < endIndex; parserInput.i++) { - c = inp.charCodeAt(parserInput.i); - if (parserInput.autoCommentAbsorb && c === CHARCODE_FORWARD_SLASH) { - nextChar = inp.charAt(parserInput.i + 1); - if (nextChar === '/') { - comment = { index: parserInput.i, isLineComment: true }; - var nextNewLine = inp.indexOf('\n', parserInput.i + 2); - if (nextNewLine < 0) { - nextNewLine = endIndex; - } - parserInput.i = nextNewLine; - comment.text = inp.substr(comment.index, parserInput.i - comment.index); - parserInput.commentStore.push(comment); - continue; - } - else if (nextChar === '*') { - var nextStarSlash = inp.indexOf('*/', parserInput.i + 2); - if (nextStarSlash >= 0) { - comment = { - index: parserInput.i, - text: inp.substr(parserInput.i, nextStarSlash + 2 - parserInput.i), - isLineComment: false - }; - parserInput.i += comment.text.length - 1; - parserInput.commentStore.push(comment); - continue; - } - } - break; - } - if ((c !== CHARCODE_SPACE) && (c !== CHARCODE_LF) && (c !== CHARCODE_TAB) && (c !== CHARCODE_CR)) { - break; - } - } - current = current.slice(length + parserInput.i - mem + curr); - currentPos = parserInput.i; - if (!current.length) { - if (j < chunks.length - 1) { - current = chunks[++j]; - skipWhitespace(0); // skip space at the beginning of a chunk - return true; // things changed - } - parserInput.finished = true; - } - return oldi !== parserInput.i || oldj !== j; - } - parserInput.save = function () { - currentPos = parserInput.i; - saveStack.push({ current: current, i: parserInput.i, j: j }); - }; - parserInput.restore = function (possibleErrorMessage) { - if (parserInput.i > furthest || (parserInput.i === furthest && possibleErrorMessage && !furthestPossibleErrorMessage)) { - furthest = parserInput.i; - furthestPossibleErrorMessage = possibleErrorMessage; - } - var state = saveStack.pop(); - current = state.current; - currentPos = parserInput.i = state.i; - j = state.j; - }; - parserInput.forget = function () { - saveStack.pop(); - }; - parserInput.isWhitespace = function (offset) { - var pos = parserInput.i + (offset || 0); - var code = input.charCodeAt(pos); - return (code === CHARCODE_SPACE || code === CHARCODE_CR || code === CHARCODE_TAB || code === CHARCODE_LF); - }; - // Specialization of $(tok) - parserInput.$re = function (tok) { - if (parserInput.i > currentPos) { - current = current.slice(parserInput.i - currentPos); - currentPos = parserInput.i; - } - var m = tok.exec(current); - if (!m) { - return null; - } - skipWhitespace(m[0].length); - if (typeof m === 'string') { - return m; - } - return m.length === 1 ? m[0] : m; - }; - parserInput.$char = function (tok) { - if (input.charAt(parserInput.i) !== tok) { - return null; - } - skipWhitespace(1); - return tok; - }; - parserInput.$str = function (tok) { - var tokLength = tok.length; - // https://jsperf.com/string-startswith/21 - for (var i = 0; i < tokLength; i++) { - if (input.charAt(parserInput.i + i) !== tok.charAt(i)) { - return null; - } - } - skipWhitespace(tokLength); - return tok; - }; - parserInput.$quoted = function (loc) { - var pos = loc || parserInput.i; - var startChar = input.charAt(pos); - if (startChar !== '\'' && startChar !== '"') { - return; - } - var length = input.length; - var currentPosition = pos; - for (var i = 1; i + currentPosition < length; i++) { - var nextChar = input.charAt(i + currentPosition); - switch (nextChar) { - case '\\': - i++; - continue; - case '\r': - case '\n': - break; - case startChar: - var str = input.substr(currentPosition, i + 1); - if (!loc && loc !== 0) { - skipWhitespace(i + 1); - return str; - } - return [startChar, str]; - } - } - return null; - }; - /** - * Permissive parsing. Ignores everything except matching {} [] () and quotes - * until matching token (outside of blocks) - */ - parserInput.$parseUntil = function (tok) { - var quote = ''; - var returnVal = null; - var inComment = false; - var blockDepth = 0; - var blockStack = []; - var parseGroups = []; - var length = input.length; - var startPos = parserInput.i; - var lastPos = parserInput.i; - var i = parserInput.i; - var loop = true; - var testChar; - if (typeof tok === 'string') { - testChar = function (char) { return char === tok; }; - } - else { - testChar = function (char) { return tok.test(char); }; - } - do { - var nextChar = input.charAt(i); - if (blockDepth === 0 && testChar(nextChar)) { - returnVal = input.substr(lastPos, i - lastPos); - if (returnVal) { - parseGroups.push(returnVal); - } - else { - parseGroups.push(' '); - } - returnVal = parseGroups; - skipWhitespace(i - startPos); - loop = false; - } - else { - if (inComment) { - if (nextChar === '*' && - input.charAt(i + 1) === '/') { - i++; - blockDepth--; - inComment = false; - } - i++; - continue; - } - switch (nextChar) { - case '\\': - i++; - nextChar = input.charAt(i); - parseGroups.push(input.substr(lastPos, i - lastPos + 1)); - lastPos = i + 1; - break; - case '/': - if (input.charAt(i + 1) === '*') { - i++; - inComment = true; - blockDepth++; - } - break; - case '\'': - case '"': - quote = parserInput.$quoted(i); - if (quote) { - parseGroups.push(input.substr(lastPos, i - lastPos), quote); - i += quote[1].length - 1; - lastPos = i + 1; - } - else { - skipWhitespace(i - startPos); - returnVal = nextChar; - loop = false; - } - break; - case '{': - blockStack.push('}'); - blockDepth++; - break; - case '(': - blockStack.push(')'); - blockDepth++; - break; - case '[': - blockStack.push(']'); - blockDepth++; - break; - case '}': - case ')': - case ']': - var expected = blockStack.pop(); - if (nextChar === expected) { - blockDepth--; - } - else { - // move the parser to the error and return expected - skipWhitespace(i - startPos); - returnVal = expected; - loop = false; - } - } - i++; - if (i > length) { - loop = false; - } - } - } while (loop); - return returnVal ? returnVal : null; - }; - parserInput.autoCommentAbsorb = true; - parserInput.commentStore = []; - parserInput.finished = false; - // Same as $(), but don't change the state of the parser, - // just return the match. - parserInput.peek = function (tok) { - if (typeof tok === 'string') { - // https://jsperf.com/string-startswith/21 - for (var i = 0; i < tok.length; i++) { - if (input.charAt(parserInput.i + i) !== tok.charAt(i)) { - return false; - } - } - return true; - } - else { - return tok.test(current); - } - }; - // Specialization of peek() - // TODO remove or change some currentChar calls to peekChar - parserInput.peekChar = function (tok) { return input.charAt(parserInput.i) === tok; }; - parserInput.currentChar = function () { return input.charAt(parserInput.i); }; - parserInput.prevChar = function () { return input.charAt(parserInput.i - 1); }; - parserInput.getInput = function () { return input; }; - parserInput.peekNotNumeric = function () { - var c = input.charCodeAt(parserInput.i); - // Is the first char of the dimension 0-9, '.', '+' or '-' - return (c > CHARCODE_9 || c < CHARCODE_PLUS) || c === CHARCODE_FORWARD_SLASH || c === CHARCODE_COMMA; - }; - parserInput.start = function (str, chunkInput, failFunction) { - input = str; - parserInput.i = j = currentPos = furthest = 0; - // chunking apparently makes things quicker (but my tests indicate - // it might actually make things slower in node at least) - // and it is a non-perfect parse - it can't recognise - // unquoted urls, meaning it can't distinguish comments - // meaning comments with quotes or {}() in them get 'counted' - // and then lead to parse errors. - // In addition if the chunking chunks in the wrong place we might - // not be able to parse a parser statement in one go - // this is officially deprecated but can be switched on via an option - // in the case it causes too much performance issues. - if (chunkInput) { - chunks = chunker(str, failFunction); - } - else { - chunks = [str]; - } - current = chunks[0]; - skipWhitespace(0); - }; - parserInput.end = function () { - var message; - var isFinished = parserInput.i >= input.length; - if (parserInput.i < furthest) { - message = furthestPossibleErrorMessage; - parserInput.i = furthest; - } - return { - isFinished: isFinished, - furthest: parserInput.i, - furthestPossibleErrorMessage: message, - furthestReachedEnd: parserInput.i >= input.length - 1, - furthestChar: input[parserInput.i] - }; - }; - return parserInput; - }); - - // - // less.js - parser - // - // A relatively straight-forward predictive parser. - // There is no tokenization/lexing stage, the input is parsed - // in one sweep. - // - // To make the parser fast enough to run in the browser, several - // optimization had to be made: - // - // - Matching and slicing on a huge input is often cause of slowdowns. - // The solution is to chunkify the input into smaller strings. - // The chunks are stored in the `chunks` var, - // `j` holds the current chunk index, and `currentPos` holds - // the index of the current chunk in relation to `input`. - // This gives us an almost 4x speed-up. - // - // - In many cases, we don't need to match individual tokens; - // for example, if a value doesn't hold any variables, operations - // or dynamic references, the parser can effectively 'skip' it, - // treating it as a literal. - // An example would be '1px solid #000' - which evaluates to itself, - // we don't need to know what the individual components are. - // The drawback, of course is that you don't get the benefits of - // syntax-checking on the CSS. This gives us a 50% speed-up in the parser, - // and a smaller speed-up in the code-gen. - // - // - // Token matching is done with the `$` function, which either takes - // a terminal string or regexp, or a non-terminal function to call. - // It also takes care of moving all the indices forwards. - // - var Parser = function Parser(context, imports, fileInfo) { - var parsers; - var parserInput = getParserInput(); - function error(msg, type) { - throw new LessError({ - index: parserInput.i, - filename: fileInfo.filename, - type: type || 'Syntax', - message: msg - }, imports); - } - function expect(arg, msg) { - // some older browsers return typeof 'function' for RegExp - var result = (arg instanceof Function) ? arg.call(parsers) : parserInput.$re(arg); - if (result) { - return result; - } - error(msg || (typeof arg === 'string' - ? "expected '" + arg + "' got '" + parserInput.currentChar() + "'" - : 'unexpected token')); - } - // Specialization of expect() - function expectChar(arg, msg) { - if (parserInput.$char(arg)) { - return arg; - } - error(msg || "expected '" + arg + "' got '" + parserInput.currentChar() + "'"); - } - function getDebugInfo(index) { - var filename = fileInfo.filename; - return { - lineNumber: getLocation(index, parserInput.getInput()).line + 1, - fileName: filename - }; - } - /** - * Used after initial parsing to create nodes on the fly - * - * @param {String} str - string to parse - * @param {Array} parseList - array of parsers to run input through e.g. ["value", "important"] - * @param {Number} currentIndex - start number to begin indexing - * @param {Object} fileInfo - fileInfo to attach to created nodes - */ - function parseNode(str, parseList, currentIndex, fileInfo, callback) { - var result; - var returnNodes = []; - var parser = parserInput; - try { - parser.start(str, false, function fail(msg, index) { - callback({ - message: msg, - index: index + currentIndex - }); - }); - for (var x = 0, p = void 0, i = void 0; (p = parseList[x]); x++) { - i = parser.i; - result = parsers[p](); - if (result) { - try { - result._index = i + currentIndex; - result._fileInfo = fileInfo; - } - catch (e) { } - returnNodes.push(result); - } - else { - returnNodes.push(null); - } - } - var endInfo = parser.end(); - if (endInfo.isFinished) { - callback(null, returnNodes); - } - else { - callback(true, null); - } - } - catch (e) { - throw new LessError({ - index: e.index + currentIndex, - message: e.message - }, imports, fileInfo.filename); - } - } - // - // The Parser - // - return { - parserInput: parserInput, - imports: imports, - fileInfo: fileInfo, - parseNode: parseNode, - // - // Parse an input string into an abstract syntax tree, - // @param str A string containing 'less' markup - // @param callback call `callback` when done. - // @param [additionalData] An optional map which can contains vars - a map (key, value) of variables to apply - // - parse: function (str, callback, additionalData) { - var root; - var err = null; - var globalVars; - var modifyVars; - var ignored; - var preText = ''; - // Optionally disable @plugin parsing - if (additionalData && additionalData.disablePluginRule) { - parsers.plugin = function () { - var dir = parserInput.$re(/^@plugin?\s+/); - if (dir) { - error('@plugin statements are not allowed when disablePluginRule is set to true'); - } - }; - } - globalVars = (additionalData && additionalData.globalVars) ? Parser.serializeVars(additionalData.globalVars) + "\n" : ''; - modifyVars = (additionalData && additionalData.modifyVars) ? "\n" + Parser.serializeVars(additionalData.modifyVars) : ''; - if (context.pluginManager) { - var preProcessors = context.pluginManager.getPreProcessors(); - for (var i = 0; i < preProcessors.length; i++) { - str = preProcessors[i].process(str, { context: context, imports: imports, fileInfo: fileInfo }); - } - } - if (globalVars || (additionalData && additionalData.banner)) { - preText = ((additionalData && additionalData.banner) ? additionalData.banner : '') + globalVars; - ignored = imports.contentsIgnoredChars; - ignored[fileInfo.filename] = ignored[fileInfo.filename] || 0; - ignored[fileInfo.filename] += preText.length; - } - str = str.replace(/\r\n?/g, '\n'); - // Remove potential UTF Byte Order Mark - str = preText + str.replace(/^\uFEFF/, '') + modifyVars; - imports.contents[fileInfo.filename] = str; - // Start with the primary rule. - // The whole syntax tree is held under a Ruleset node, - // with the `root` property set to true, so no `{}` are - // output. The callback is called when the input is parsed. - try { - parserInput.start(str, context.chunkInput, function fail(msg, index) { - throw new LessError({ - index: index, - type: 'Parse', - message: msg, - filename: fileInfo.filename - }, imports); - }); - tree.Node.prototype.parse = this; - root = new tree.Ruleset(null, this.parsers.primary()); - tree.Node.prototype.rootNode = root; - root.root = true; - root.firstRoot = true; - root.functionRegistry = functionRegistry.inherit(); - } - catch (e) { - return callback(new LessError(e, imports, fileInfo.filename)); - } - // If `i` is smaller than the `input.length - 1`, - // it means the parser wasn't able to parse the whole - // string, so we've got a parsing error. - // - // We try to extract a \n delimited string, - // showing the line where the parse error occurred. - // We split it up into two parts (the part which parsed, - // and the part which didn't), so we can color them differently. - var endInfo = parserInput.end(); - if (!endInfo.isFinished) { - var message = endInfo.furthestPossibleErrorMessage; - if (!message) { - message = 'Unrecognised input'; - if (endInfo.furthestChar === '}') { - message += '. Possibly missing opening \'{\''; - } - else if (endInfo.furthestChar === ')') { - message += '. Possibly missing opening \'(\''; - } - else if (endInfo.furthestReachedEnd) { - message += '. Possibly missing something'; - } - } - err = new LessError({ - type: 'Parse', - message: message, - index: endInfo.furthest, - filename: fileInfo.filename - }, imports); - } - var finish = function (e) { - e = err || e || imports.error; - if (e) { - if (!(e instanceof LessError)) { - e = new LessError(e, imports, fileInfo.filename); - } - return callback(e); - } - else { - return callback(null, root); - } - }; - if (context.processImports !== false) { - new visitors.ImportVisitor(imports, finish) - .run(root); - } - else { - return finish(); - } - }, - // - // Here in, the parsing rules/functions - // - // The basic structure of the syntax tree generated is as follows: - // - // Ruleset -> Declaration -> Value -> Expression -> Entity - // - // Here's some Less code: - // - // .class { - // color: #fff; - // border: 1px solid #000; - // width: @w + 4px; - // > .child {...} - // } - // - // And here's what the parse tree might look like: - // - // Ruleset (Selector '.class', [ - // Declaration ("color", Value ([Expression [Color #fff]])) - // Declaration ("border", Value ([Expression [Dimension 1px][Keyword "solid"][Color #000]])) - // Declaration ("width", Value ([Expression [Operation " + " [Variable "@w"][Dimension 4px]]])) - // Ruleset (Selector [Element '>', '.child'], [...]) - // ]) - // - // In general, most rules will try to parse a token with the `$re()` function, and if the return - // value is truly, will return a new node, of the relevant type. Sometimes, we need to check - // first, before parsing, that's when we use `peek()`. - // - parsers: parsers = { - // - // The `primary` rule is the *entry* and *exit* point of the parser. - // The rules here can appear at any level of the parse tree. - // - // The recursive nature of the grammar is an interplay between the `block` - // rule, which represents `{ ... }`, the `ruleset` rule, and this `primary` rule, - // as represented by this simplified grammar: - // - // primary → (ruleset | declaration)+ - // ruleset → selector+ block - // block → '{' primary '}' - // - // Only at one point is the primary rule not called from the - // block rule: at the root level. - // - primary: function () { - var mixin = this.mixin; - var root = []; - var node; - while (true) { - while (true) { - node = this.comment(); - if (!node) { - break; - } - root.push(node); - } - // always process comments before deciding if finished - if (parserInput.finished) { - break; - } - if (parserInput.peek('}')) { - break; - } - node = this.extendRule(); - if (node) { - root = root.concat(node); - continue; - } - node = mixin.definition() || this.declaration() || mixin.call(false, false) || - this.ruleset() || this.variableCall() || this.entities.call() || this.atrule(); - if (node) { - root.push(node); - } - else { - var foundSemiColon = false; - while (parserInput.$char(';')) { - foundSemiColon = true; - } - if (!foundSemiColon) { - break; - } - } - } - return root; - }, - // comments are collected by the main parsing mechanism and then assigned to nodes - // where the current structure allows it - comment: function () { - if (parserInput.commentStore.length) { - var comment = parserInput.commentStore.shift(); - return new (tree.Comment)(comment.text, comment.isLineComment, comment.index, fileInfo); - } - }, - // - // Entities are tokens which can be found inside an Expression - // - entities: { - mixinLookup: function () { - return parsers.mixin.call(true, true); - }, - // - // A string, which supports escaping " and ' - // - // "milky way" 'he\'s the one!' - // - quoted: function (forceEscaped) { - var str; - var index = parserInput.i; - var isEscaped = false; - parserInput.save(); - if (parserInput.$char('~')) { - isEscaped = true; - } - else if (forceEscaped) { - parserInput.restore(); - return; - } - str = parserInput.$quoted(); - if (!str) { - parserInput.restore(); - return; - } - parserInput.forget(); - return new (tree.Quoted)(str.charAt(0), str.substr(1, str.length - 2), isEscaped, index, fileInfo); - }, - // - // A catch-all word, such as: - // - // black border-collapse - // - keyword: function () { - var k = parserInput.$char('%') || parserInput.$re(/^\[?(?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+\]?/); - if (k) { - return tree.Color.fromKeyword(k) || new (tree.Keyword)(k); - } - }, - // - // A function call - // - // rgb(255, 0, 255) - // - // The arguments are parsed with the `entities.arguments` parser. - // - call: function () { - var name; - var args; - var func; - var index = parserInput.i; - // http://jsperf.com/case-insensitive-regex-vs-strtolower-then-regex/18 - if (parserInput.peek(/^url\(/i)) { - return; - } - parserInput.save(); - name = parserInput.$re(/^([\w-]+|%|~|progid:[\w\.]+)\(/); - if (!name) { - parserInput.forget(); - return; - } - name = name[1]; - func = this.customFuncCall(name); - if (func) { - args = func.parse(); - if (args && func.stop) { - parserInput.forget(); - return args; - } - } - args = this.arguments(args); - if (!parserInput.$char(')')) { - parserInput.restore('Could not parse call arguments or missing \')\''); - return; - } - parserInput.forget(); - return new (tree.Call)(name, args, index, fileInfo); - }, - // - // Parsing rules for functions with non-standard args, e.g.: - // - // boolean(not(2 > 1)) - // - // This is a quick prototype, to be modified/improved when - // more custom-parsed funcs come (e.g. `selector(...)`) - // - customFuncCall: function (name) { - /* Ideally the table is to be moved out of here for faster perf., - but it's quite tricky since it relies on all these `parsers` - and `expect` available only here */ - return { - alpha: f(parsers.ieAlpha, true), - boolean: f(condition), - 'if': f(condition) - }[name.toLowerCase()]; - function f(parse, stop) { - return { - parse: parse, - stop: stop // when true - stop after parse() and return its result, - // otherwise continue for plain args - }; - } - function condition() { - return [expect(parsers.condition, 'expected condition')]; - } - }, - arguments: function (prevArgs) { - var argsComma = prevArgs || []; - var argsSemiColon = []; - var isSemiColonSeparated; - var value; - parserInput.save(); - while (true) { - if (prevArgs) { - prevArgs = false; - } - else { - value = parsers.detachedRuleset() || this.assignment() || parsers.expression(); - if (!value) { - break; - } - if (value.value && value.value.length == 1) { - value = value.value[0]; - } - argsComma.push(value); - } - if (parserInput.$char(',')) { - continue; - } - if (parserInput.$char(';') || isSemiColonSeparated) { - isSemiColonSeparated = true; - value = (argsComma.length < 1) ? argsComma[0] - : new tree.Value(argsComma); - argsSemiColon.push(value); - argsComma = []; - } - } - parserInput.forget(); - return isSemiColonSeparated ? argsSemiColon : argsComma; - }, - literal: function () { - return this.dimension() || - this.color() || - this.quoted() || - this.unicodeDescriptor(); - }, - // Assignments are argument entities for calls. - // They are present in ie filter properties as shown below. - // - // filter: progid:DXImageTransform.Microsoft.Alpha( *opacity=50* ) - // - assignment: function () { - var key; - var value; - parserInput.save(); - key = parserInput.$re(/^\w+(?=\s?=)/i); - if (!key) { - parserInput.restore(); - return; - } - if (!parserInput.$char('=')) { - parserInput.restore(); - return; - } - value = parsers.entity(); - if (value) { - parserInput.forget(); - return new (tree.Assignment)(key, value); - } - else { - parserInput.restore(); - } - }, - // - // Parse url() tokens - // - // We use a specific rule for urls, because they don't really behave like - // standard function calls. The difference is that the argument doesn't have - // to be enclosed within a string, so it can't be parsed as an Expression. - // - url: function () { - var value; - var index = parserInput.i; - parserInput.autoCommentAbsorb = false; - if (!parserInput.$str('url(')) { - parserInput.autoCommentAbsorb = true; - return; - } - value = this.quoted() || this.variable() || this.property() || - parserInput.$re(/^(?:(?:\\[\(\)'"])|[^\(\)'"])+/) || ''; - parserInput.autoCommentAbsorb = true; - expectChar(')'); - return new (tree.URL)((value.value != null || - value instanceof tree.Variable || - value instanceof tree.Property) ? - value : new (tree.Anonymous)(value, index), index, fileInfo); - }, - // - // A Variable entity, such as `@fink`, in - // - // width: @fink + 2px - // - // We use a different parser for variable definitions, - // see `parsers.variable`. - // - variable: function () { - var ch; - var name; - var index = parserInput.i; - parserInput.save(); - if (parserInput.currentChar() === '@' && (name = parserInput.$re(/^@@?[\w-]+/))) { - ch = parserInput.currentChar(); - if (ch === '(' || ch === '[' && !parserInput.prevChar().match(/^\s/)) { - // this may be a VariableCall lookup - var result = parsers.variableCall(name); - if (result) { - parserInput.forget(); - return result; - } - } - parserInput.forget(); - return new (tree.Variable)(name, index, fileInfo); - } - parserInput.restore(); - }, - // A variable entity using the protective {} e.g. @{var} - variableCurly: function () { - var curly; - var index = parserInput.i; - if (parserInput.currentChar() === '@' && (curly = parserInput.$re(/^@\{([\w-]+)\}/))) { - return new (tree.Variable)("@" + curly[1], index, fileInfo); - } - }, - // - // A Property accessor, such as `$color`, in - // - // background-color: $color - // - property: function () { - var name; - var index = parserInput.i; - if (parserInput.currentChar() === '$' && (name = parserInput.$re(/^\$[\w-]+/))) { - return new (tree.Property)(name, index, fileInfo); - } - }, - // A property entity useing the protective {} e.g. ${prop} - propertyCurly: function () { - var curly; - var index = parserInput.i; - if (parserInput.currentChar() === '$' && (curly = parserInput.$re(/^\$\{([\w-]+)\}/))) { - return new (tree.Property)("$" + curly[1], index, fileInfo); - } - }, - // - // A Hexadecimal color - // - // #4F3C2F - // - // `rgb` and `hsl` colors are parsed through the `entities.call` parser. - // - color: function () { - var rgb; - parserInput.save(); - if (parserInput.currentChar() === '#' && (rgb = parserInput.$re(/^#([A-Fa-f0-9]{8}|[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3,4})([\w.#\[])?/))) { - if (!rgb[2]) { - parserInput.forget(); - return new (tree.Color)(rgb[1], undefined, rgb[0]); - } - } - parserInput.restore(); - }, - colorKeyword: function () { - parserInput.save(); - var autoCommentAbsorb = parserInput.autoCommentAbsorb; - parserInput.autoCommentAbsorb = false; - var k = parserInput.$re(/^[_A-Za-z-][_A-Za-z0-9-]+/); - parserInput.autoCommentAbsorb = autoCommentAbsorb; - if (!k) { - parserInput.forget(); - return; - } - parserInput.restore(); - var color = tree.Color.fromKeyword(k); - if (color) { - parserInput.$str(k); - return color; - } - }, - // - // A Dimension, that is, a number and a unit - // - // 0.5em 95% - // - dimension: function () { - if (parserInput.peekNotNumeric()) { - return; - } - var value = parserInput.$re(/^([+-]?\d*\.?\d+)(%|[a-z_]+)?/i); - if (value) { - return new (tree.Dimension)(value[1], value[2]); - } - }, - // - // A unicode descriptor, as is used in unicode-range - // - // U+0?? or U+00A1-00A9 - // - unicodeDescriptor: function () { - var ud; - ud = parserInput.$re(/^U\+[0-9a-fA-F?]+(\-[0-9a-fA-F?]+)?/); - if (ud) { - return new (tree.UnicodeDescriptor)(ud[0]); - } - }, - // - // JavaScript code to be evaluated - // - // `window.location.href` - // - javascript: function () { - var js; - var index = parserInput.i; - parserInput.save(); - var escape = parserInput.$char('~'); - var jsQuote = parserInput.$char('`'); - if (!jsQuote) { - parserInput.restore(); - return; - } - js = parserInput.$re(/^[^`]*`/); - if (js) { - parserInput.forget(); - return new (tree.JavaScript)(js.substr(0, js.length - 1), Boolean(escape), index, fileInfo); - } - parserInput.restore('invalid javascript definition'); - } - }, - // - // The variable part of a variable definition. Used in the `rule` parser - // - // @fink: - // - variable: function () { - var name; - if (parserInput.currentChar() === '@' && (name = parserInput.$re(/^(@[\w-]+)\s*:/))) { - return name[1]; - } - }, - // - // Call a variable value to retrieve a detached ruleset - // or a value from a detached ruleset's rules. - // - // @fink(); - // @fink; - // color: @fink[@color]; - // - variableCall: function (parsedName) { - var lookups; - var i = parserInput.i; - var inValue = !!parsedName; - var name = parsedName; - parserInput.save(); - if (name || (parserInput.currentChar() === '@' - && (name = parserInput.$re(/^(@[\w-]+)(\(\s*\))?/)))) { - lookups = this.mixin.ruleLookups(); - if (!lookups && ((inValue && parserInput.$str('()') !== '()') || (name[2] !== '()'))) { - parserInput.restore('Missing \'[...]\' lookup in variable call'); - return; - } - if (!inValue) { - name = name[1]; - } - var call = new tree.VariableCall(name, i, fileInfo); - if (!inValue && parsers.end()) { - parserInput.forget(); - return call; - } - else { - parserInput.forget(); - return new tree.NamespaceValue(call, lookups, i, fileInfo); - } - } - parserInput.restore(); - }, - // - // extend syntax - used to extend selectors - // - extend: function (isRule) { - var elements; - var e; - var index = parserInput.i; - var option; - var extendList; - var extend; - if (!parserInput.$str(isRule ? '&:extend(' : ':extend(')) { - return; - } - do { - option = null; - elements = null; - while (!(option = parserInput.$re(/^(all)(?=\s*(\)|,))/))) { - e = this.element(); - if (!e) { - break; - } - if (elements) { - elements.push(e); - } - else { - elements = [e]; - } - } - option = option && option[1]; - if (!elements) { - error('Missing target selector for :extend().'); - } - extend = new (tree.Extend)(new (tree.Selector)(elements), option, index, fileInfo); - if (extendList) { - extendList.push(extend); - } - else { - extendList = [extend]; - } - } while (parserInput.$char(',')); - expect(/^\)/); - if (isRule) { - expect(/^;/); - } - return extendList; - }, - // - // extendRule - used in a rule to extend all the parent selectors - // - extendRule: function () { - return this.extend(true); - }, - // - // Mixins - // - mixin: { - // - // A Mixin call, with an optional argument list - // - // #mixins > .square(#fff); - // #mixins.square(#fff); - // .rounded(4px, black); - // .button; - // - // We can lookup / return a value using the lookup syntax: - // - // color: #mixin.square(#fff)[@color]; - // - // The `while` loop is there because mixins can be - // namespaced, but we only support the child and descendant - // selector for now. - // - call: function (inValue, getLookup) { - var s = parserInput.currentChar(); - var important = false; - var lookups; - var index = parserInput.i; - var elements; - var args; - var hasParens; - if (s !== '.' && s !== '#') { - return; - } - parserInput.save(); // stop us absorbing part of an invalid selector - elements = this.elements(); - if (elements) { - if (parserInput.$char('(')) { - args = this.args(true).args; - expectChar(')'); - hasParens = true; - } - if (getLookup !== false) { - lookups = this.ruleLookups(); - } - if (getLookup === true && !lookups) { - parserInput.restore(); - return; - } - if (inValue && !lookups && !hasParens) { - // This isn't a valid in-value mixin call - parserInput.restore(); - return; - } - if (!inValue && parsers.important()) { - important = true; - } - if (inValue || parsers.end()) { - parserInput.forget(); - var mixin = new (tree.mixin.Call)(elements, args, index, fileInfo, !lookups && important); - if (lookups) { - return new tree.NamespaceValue(mixin, lookups); - } - else { - return mixin; - } - } - } - parserInput.restore(); - }, - /** - * Matching elements for mixins - * (Start with . or # and can have > ) - */ - elements: function () { - var elements; - var e; - var c; - var elem; - var elemIndex; - var re = /^[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/; - while (true) { - elemIndex = parserInput.i; - e = parserInput.$re(re); - if (!e) { - break; - } - elem = new (tree.Element)(c, e, false, elemIndex, fileInfo); - if (elements) { - elements.push(elem); - } - else { - elements = [elem]; - } - c = parserInput.$char('>'); - } - return elements; - }, - args: function (isCall) { - var entities = parsers.entities; - var returner = { args: null, variadic: false }; - var expressions = []; - var argsSemiColon = []; - var argsComma = []; - var isSemiColonSeparated; - var expressionContainsNamed; - var name; - var nameLoop; - var value; - var arg; - var expand; - var hasSep = true; - parserInput.save(); - while (true) { - if (isCall) { - arg = parsers.detachedRuleset() || parsers.expression(); - } - else { - parserInput.commentStore.length = 0; - if (parserInput.$str('...')) { - returner.variadic = true; - if (parserInput.$char(';') && !isSemiColonSeparated) { - isSemiColonSeparated = true; - } - (isSemiColonSeparated ? argsSemiColon : argsComma) - .push({ variadic: true }); - break; - } - arg = entities.variable() || entities.property() || entities.literal() || entities.keyword() || this.call(true); - } - if (!arg || !hasSep) { - break; - } - nameLoop = null; - if (arg.throwAwayComments) { - arg.throwAwayComments(); - } - value = arg; - var val = null; - if (isCall) { - // Variable - if (arg.value && arg.value.length == 1) { - val = arg.value[0]; - } - } - else { - val = arg; - } - if (val && (val instanceof tree.Variable || val instanceof tree.Property)) { - if (parserInput.$char(':')) { - if (expressions.length > 0) { - if (isSemiColonSeparated) { - error('Cannot mix ; and , as delimiter types'); - } - expressionContainsNamed = true; - } - value = parsers.detachedRuleset() || parsers.expression(); - if (!value) { - if (isCall) { - error('could not understand value for named argument'); - } - else { - parserInput.restore(); - returner.args = []; - return returner; - } - } - nameLoop = (name = val.name); - } - else if (parserInput.$str('...')) { - if (!isCall) { - returner.variadic = true; - if (parserInput.$char(';') && !isSemiColonSeparated) { - isSemiColonSeparated = true; - } - (isSemiColonSeparated ? argsSemiColon : argsComma) - .push({ name: arg.name, variadic: true }); - break; - } - else { - expand = true; - } - } - else if (!isCall) { - name = nameLoop = val.name; - value = null; - } - } - if (value) { - expressions.push(value); - } - argsComma.push({ name: nameLoop, value: value, expand: expand }); - if (parserInput.$char(',')) { - hasSep = true; - continue; - } - hasSep = parserInput.$char(';') === ';'; - if (hasSep || isSemiColonSeparated) { - if (expressionContainsNamed) { - error('Cannot mix ; and , as delimiter types'); - } - isSemiColonSeparated = true; - if (expressions.length > 1) { - value = new (tree.Value)(expressions); - } - argsSemiColon.push({ name: name, value: value, expand: expand }); - name = null; - expressions = []; - expressionContainsNamed = false; - } - } - parserInput.forget(); - returner.args = isSemiColonSeparated ? argsSemiColon : argsComma; - return returner; - }, - // - // A Mixin definition, with a list of parameters - // - // .rounded (@radius: 2px, @color) { - // ... - // } - // - // Until we have a finer grained state-machine, we have to - // do a look-ahead, to make sure we don't have a mixin call. - // See the `rule` function for more information. - // - // We start by matching `.rounded (`, and then proceed on to - // the argument list, which has optional default values. - // We store the parameters in `params`, with a `value` key, - // if there is a value, such as in the case of `@radius`. - // - // Once we've got our params list, and a closing `)`, we parse - // the `{...}` block. - // - definition: function () { - var name; - var params = []; - var match; - var ruleset; - var cond; - var variadic = false; - if ((parserInput.currentChar() !== '.' && parserInput.currentChar() !== '#') || - parserInput.peek(/^[^{]*\}/)) { - return; - } - parserInput.save(); - match = parserInput.$re(/^([#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(/); - if (match) { - name = match[1]; - var argInfo = this.args(false); - params = argInfo.args; - variadic = argInfo.variadic; - // .mixincall("@{a}"); - // looks a bit like a mixin definition.. - // also - // .mixincall(@a: {rule: set;}); - // so we have to be nice and restore - if (!parserInput.$char(')')) { - parserInput.restore('Missing closing \')\''); - return; - } - parserInput.commentStore.length = 0; - if (parserInput.$str('when')) { // Guard - cond = expect(parsers.conditions, 'expected condition'); - } - ruleset = parsers.block(); - if (ruleset) { - parserInput.forget(); - return new (tree.mixin.Definition)(name, params, ruleset, cond, variadic); - } - else { - parserInput.restore(); - } - } - else { - parserInput.restore(); - } - }, - ruleLookups: function () { - var rule; - var lookups = []; - if (parserInput.currentChar() !== '[') { - return; - } - while (true) { - parserInput.save(); - rule = this.lookupValue(); - if (!rule && rule !== '') { - parserInput.restore(); - break; - } - lookups.push(rule); - parserInput.forget(); - } - if (lookups.length > 0) { - return lookups; - } - }, - lookupValue: function () { - parserInput.save(); - if (!parserInput.$char('[')) { - parserInput.restore(); - return; - } - var name = parserInput.$re(/^(?:[@$]{0,2})[_a-zA-Z0-9-]*/); - if (!parserInput.$char(']')) { - parserInput.restore(); - return; - } - if (name || name === '') { - parserInput.forget(); - return name; - } - parserInput.restore(); - } - }, - // - // Entities are the smallest recognized token, - // and can be found inside a rule's value. - // - entity: function () { - var entities = this.entities; - return this.comment() || entities.literal() || entities.variable() || entities.url() || - entities.property() || entities.call() || entities.keyword() || this.mixin.call(true) || - entities.javascript(); - }, - // - // A Declaration terminator. Note that we use `peek()` to check for '}', - // because the `block` rule will be expecting it, but we still need to make sure - // it's there, if ';' was omitted. - // - end: function () { - return parserInput.$char(';') || parserInput.peek('}'); - }, - // - // IE's alpha function - // - // alpha(opacity=88) - // - ieAlpha: function () { - var value; - // http://jsperf.com/case-insensitive-regex-vs-strtolower-then-regex/18 - if (!parserInput.$re(/^opacity=/i)) { - return; - } - value = parserInput.$re(/^\d+/); - if (!value) { - value = expect(parsers.entities.variable, 'Could not parse alpha'); - value = "@{" + value.name.slice(1) + "}"; - } - expectChar(')'); - return new tree.Quoted('', "alpha(opacity=" + value + ")"); - }, - // - // A Selector Element - // - // div - // + h1 - // #socks - // input[type="text"] - // - // Elements are the building blocks for Selectors, - // they are made out of a `Combinator` (see combinator rule), - // and an element name, such as a tag a class, or `*`. - // - element: function () { - var e; - var c; - var v; - var index = parserInput.i; - c = this.combinator(); - e = parserInput.$re(/^(?:\d+\.\d+|\d+)%/) || - parserInput.$re(/^(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/) || - parserInput.$char('*') || parserInput.$char('&') || this.attribute() || - parserInput.$re(/^\([^&()@]+\)/) || parserInput.$re(/^[\.#:](?=@)/) || - this.entities.variableCurly(); - if (!e) { - parserInput.save(); - if (parserInput.$char('(')) { - if ((v = this.selector(false)) && parserInput.$char(')')) { - e = new (tree.Paren)(v); - parserInput.forget(); - } - else { - parserInput.restore('Missing closing \')\''); - } - } - else { - parserInput.forget(); - } - } - if (e) { - return new (tree.Element)(c, e, e instanceof tree.Variable, index, fileInfo); - } - }, - // - // Combinators combine elements together, in a Selector. - // - // Because our parser isn't white-space sensitive, special care - // has to be taken, when parsing the descendant combinator, ` `, - // as it's an empty space. We have to check the previous character - // in the input, to see if it's a ` ` character. More info on how - // we deal with this in *combinator.js*. - // - combinator: function () { - var c = parserInput.currentChar(); - if (c === '/') { - parserInput.save(); - var slashedCombinator = parserInput.$re(/^\/[a-z]+\//i); - if (slashedCombinator) { - parserInput.forget(); - return new (tree.Combinator)(slashedCombinator); - } - parserInput.restore(); - } - if (c === '>' || c === '+' || c === '~' || c === '|' || c === '^') { - parserInput.i++; - if (c === '^' && parserInput.currentChar() === '^') { - c = '^^'; - parserInput.i++; - } - while (parserInput.isWhitespace()) { - parserInput.i++; - } - return new (tree.Combinator)(c); - } - else if (parserInput.isWhitespace(-1)) { - return new (tree.Combinator)(' '); - } - else { - return new (tree.Combinator)(null); - } - }, - // - // A CSS Selector - // with less extensions e.g. the ability to extend and guard - // - // .class > div + h1 - // li a:hover - // - // Selectors are made out of one or more Elements, see above. - // - selector: function (isLess) { - var index = parserInput.i; - var elements; - var extendList; - var c; - var e; - var allExtends; - var when; - var condition; - isLess = isLess !== false; - while ((isLess && (extendList = this.extend())) || (isLess && (when = parserInput.$str('when'))) || (e = this.element())) { - if (when) { - condition = expect(this.conditions, 'expected condition'); - } - else if (condition) { - error('CSS guard can only be used at the end of selector'); - } - else if (extendList) { - if (allExtends) { - allExtends = allExtends.concat(extendList); - } - else { - allExtends = extendList; - } - } - else { - if (allExtends) { - error('Extend can only be used at the end of selector'); - } - c = parserInput.currentChar(); - if (elements) { - elements.push(e); - } - else { - elements = [e]; - } - e = null; - } - if (c === '{' || c === '}' || c === ';' || c === ',' || c === ')') { - break; - } - } - if (elements) { - return new (tree.Selector)(elements, allExtends, condition, index, fileInfo); - } - if (allExtends) { - error('Extend must be used to extend a selector, it cannot be used on its own'); - } - }, - selectors: function () { - var s; - var selectors; - while (true) { - s = this.selector(); - if (!s) { - break; - } - if (selectors) { - selectors.push(s); - } - else { - selectors = [s]; - } - parserInput.commentStore.length = 0; - if (s.condition && selectors.length > 1) { - error("Guards are only currently allowed on a single selector."); - } - if (!parserInput.$char(',')) { - break; - } - if (s.condition) { - error("Guards are only currently allowed on a single selector."); - } - parserInput.commentStore.length = 0; - } - return selectors; - }, - attribute: function () { - if (!parserInput.$char('[')) { - return; - } - var entities = this.entities; - var key; - var val; - var op; - // - // case-insensitive flag - // e.g. [attr operator value i] - // - var cif; - if (!(key = entities.variableCurly())) { - key = expect(/^(?:[_A-Za-z0-9-\*]*\|)?(?:[_A-Za-z0-9-]|\\.)+/); - } - op = parserInput.$re(/^[|~*$^]?=/); - if (op) { - val = entities.quoted() || parserInput.$re(/^[0-9]+%/) || parserInput.$re(/^[\w-]+/) || entities.variableCurly(); - if (val) { - cif = parserInput.$re(/^[iIsS]/); - } - } - expectChar(']'); - return new (tree.Attribute)(key, op, val, cif); - }, - // - // The `block` rule is used by `ruleset` and `mixin.definition`. - // It's a wrapper around the `primary` rule, with added `{}`. - // - block: function () { - var content; - if (parserInput.$char('{') && (content = this.primary()) && parserInput.$char('}')) { - return content; - } - }, - blockRuleset: function () { - var block = this.block(); - if (block) { - block = new tree.Ruleset(null, block); - } - return block; - }, - detachedRuleset: function () { - var argInfo; - var params; - var variadic; - parserInput.save(); - if (parserInput.$re(/^[.#]\(/)) { - /** - * DR args currently only implemented for each() function, and not - * yet settable as `@dr: #(@arg) {}` - * This should be done when DRs are merged with mixins. - * See: https://github.com/less/less-meta/issues/16 - */ - argInfo = this.mixin.args(false); - params = argInfo.args; - variadic = argInfo.variadic; - if (!parserInput.$char(')')) { - parserInput.restore(); - return; - } - } - var blockRuleset = this.blockRuleset(); - if (blockRuleset) { - parserInput.forget(); - if (params) { - return new tree.mixin.Definition(null, params, blockRuleset, null, variadic); - } - return new tree.DetachedRuleset(blockRuleset); - } - parserInput.restore(); - }, - // - // div, .class, body > p {...} - // - ruleset: function () { - var selectors; - var rules; - var debugInfo; - parserInput.save(); - if (context.dumpLineNumbers) { - debugInfo = getDebugInfo(parserInput.i); - } - selectors = this.selectors(); - if (selectors && (rules = this.block())) { - parserInput.forget(); - var ruleset = new (tree.Ruleset)(selectors, rules, context.strictImports); - if (context.dumpLineNumbers) { - ruleset.debugInfo = debugInfo; - } - return ruleset; - } - else { - parserInput.restore(); - } - }, - declaration: function () { - var name; - var value; - var index = parserInput.i; - var hasDR; - var c = parserInput.currentChar(); - var important; - var merge; - var isVariable; - if (c === '.' || c === '#' || c === '&' || c === ':') { - return; - } - parserInput.save(); - name = this.variable() || this.ruleProperty(); - if (name) { - isVariable = typeof name === 'string'; - if (isVariable) { - value = this.detachedRuleset(); - if (value) { - hasDR = true; - } - } - parserInput.commentStore.length = 0; - if (!value) { - // a name returned by this.ruleProperty() is always an array of the form: - // [string-1, ..., string-n, ""] or [string-1, ..., string-n, "+"] - // where each item is a tree.Keyword or tree.Variable - merge = !isVariable && name.length > 1 && name.pop().value; - // Custom property values get permissive parsing - if (name[0].value && name[0].value.slice(0, 2) === '--') { - value = this.permissiveValue(); - } - // Try to store values as anonymous - // If we need the value later we'll re-parse it in ruleset.parseValue - else { - value = this.anonymousValue(); - } - if (value) { - parserInput.forget(); - // anonymous values absorb the end ';' which is required for them to work - return new (tree.Declaration)(name, value, false, merge, index, fileInfo); - } - if (!value) { - value = this.value(); - } - if (value) { - important = this.important(); - } - else if (isVariable) { - // As a last resort, try permissiveValue - value = this.permissiveValue(); - } - } - if (value && (this.end() || hasDR)) { - parserInput.forget(); - return new (tree.Declaration)(name, value, important, merge, index, fileInfo); - } - else { - parserInput.restore(); - } - } - else { - parserInput.restore(); - } - }, - anonymousValue: function () { - var index = parserInput.i; - var match = parserInput.$re(/^([^.#@\$+\/'"*`(;{}-]*);/); - if (match) { - return new (tree.Anonymous)(match[1], index); - } - }, - /** - * Used for custom properties, at-rules, and variables (as fallback) - * Parses almost anything inside of {} [] () "" blocks - * until it reaches outer-most tokens. - * - * First, it will try to parse comments and entities to reach - * the end. This is mostly like the Expression parser except no - * math is allowed. - */ - permissiveValue: function (untilTokens) { - var i; - var e; - var done; - var value; - var tok = untilTokens || ';'; - var index = parserInput.i; - var result = []; - function testCurrentChar() { - var char = parserInput.currentChar(); - if (typeof tok === 'string') { - return char === tok; - } - else { - return tok.test(char); - } - } - if (testCurrentChar()) { - return; - } - value = []; - do { - e = this.comment(); - if (e) { - value.push(e); - continue; - } - e = this.entity(); - if (e) { - value.push(e); - } - } while (e); - done = testCurrentChar(); - if (value.length > 0) { - value = new (tree.Expression)(value); - if (done) { - return value; - } - else { - result.push(value); - } - // Preserve space before $parseUntil as it will not - if (parserInput.prevChar() === ' ') { - result.push(new tree.Anonymous(' ', index)); - } - } - parserInput.save(); - value = parserInput.$parseUntil(tok); - if (value) { - if (typeof value === 'string') { - error("Expected '" + value + "'", 'Parse'); - } - if (value.length === 1 && value[0] === ' ') { - parserInput.forget(); - return new tree.Anonymous('', index); - } - var item = void 0; - for (i = 0; i < value.length; i++) { - item = value[i]; - if (Array.isArray(item)) { - // Treat actual quotes as normal quoted values - result.push(new tree.Quoted(item[0], item[1], true, index, fileInfo)); - } - else { - if (i === value.length - 1) { - item = item.trim(); - } - // Treat like quoted values, but replace vars like unquoted expressions - var quote = new tree.Quoted('\'', item, true, index, fileInfo); - quote.variableRegex = /@([\w-]+)/g; - quote.propRegex = /\$([\w-]+)/g; - result.push(quote); - } - } - parserInput.forget(); - return new tree.Expression(result, true); - } - parserInput.restore(); - }, - // - // An @import atrule - // - // @import "lib"; - // - // Depending on our environment, importing is done differently: - // In the browser, it's an XHR request, in Node, it would be a - // file-system operation. The function used for importing is - // stored in `import`, which we pass to the Import constructor. - // - 'import': function () { - var path; - var features; - var index = parserInput.i; - var dir = parserInput.$re(/^@import\s+/); - if (dir) { - var options = (dir ? this.importOptions() : null) || {}; - if ((path = this.entities.quoted() || this.entities.url())) { - features = this.mediaFeatures(); - if (!parserInput.$char(';')) { - parserInput.i = index; - error('missing semi-colon or unrecognised media features on import'); - } - features = features && new (tree.Value)(features); - return new (tree.Import)(path, features, options, index, fileInfo); - } - else { - parserInput.i = index; - error('malformed import statement'); - } - } - }, - importOptions: function () { - var o; - var options = {}; - var optionName; - var value; - // list of options, surrounded by parens - if (!parserInput.$char('(')) { - return null; - } - do { - o = this.importOption(); - if (o) { - optionName = o; - value = true; - switch (optionName) { - case 'css': - optionName = 'less'; - value = false; - break; - case 'once': - optionName = 'multiple'; - value = false; - break; - } - options[optionName] = value; - if (!parserInput.$char(',')) { - break; - } - } - } while (o); - expectChar(')'); - return options; - }, - importOption: function () { - var opt = parserInput.$re(/^(less|css|multiple|once|inline|reference|optional)/); - if (opt) { - return opt[1]; - } - }, - mediaFeature: function () { - var entities = this.entities; - var nodes = []; - var e; - var p; - parserInput.save(); - do { - e = entities.keyword() || entities.variable() || entities.mixinLookup(); - if (e) { - nodes.push(e); - } - else if (parserInput.$char('(')) { - p = this.property(); - e = this.value(); - if (parserInput.$char(')')) { - if (p && e) { - nodes.push(new (tree.Paren)(new (tree.Declaration)(p, e, null, null, parserInput.i, fileInfo, true))); - } - else if (e) { - nodes.push(new (tree.Paren)(e)); - } - else { - error('badly formed media feature definition'); - } - } - else { - error('Missing closing \')\'', 'Parse'); - } - } - } while (e); - parserInput.forget(); - if (nodes.length > 0) { - return new (tree.Expression)(nodes); - } - }, - mediaFeatures: function () { - var entities = this.entities; - var features = []; - var e; - do { - e = this.mediaFeature(); - if (e) { - features.push(e); - if (!parserInput.$char(',')) { - break; - } - } - else { - e = entities.variable() || entities.mixinLookup(); - if (e) { - features.push(e); - if (!parserInput.$char(',')) { - break; - } - } - } - } while (e); - return features.length > 0 ? features : null; - }, - media: function () { - var features; - var rules; - var media; - var debugInfo; - var index = parserInput.i; - if (context.dumpLineNumbers) { - debugInfo = getDebugInfo(index); - } - parserInput.save(); - if (parserInput.$str('@media')) { - features = this.mediaFeatures(); - rules = this.block(); - if (!rules) { - error('media definitions require block statements after any features'); - } - parserInput.forget(); - media = new (tree.Media)(rules, features, index, fileInfo); - if (context.dumpLineNumbers) { - media.debugInfo = debugInfo; - } - return media; - } - parserInput.restore(); - }, - // - // A @plugin directive, used to import plugins dynamically. - // - // @plugin (args) "lib"; - // - plugin: function () { - var path; - var args; - var options; - var index = parserInput.i; - var dir = parserInput.$re(/^@plugin\s+/); - if (dir) { - args = this.pluginArgs(); - if (args) { - options = { - pluginArgs: args, - isPlugin: true - }; - } - else { - options = { isPlugin: true }; - } - if ((path = this.entities.quoted() || this.entities.url())) { - if (!parserInput.$char(';')) { - parserInput.i = index; - error('missing semi-colon on @plugin'); - } - return new (tree.Import)(path, null, options, index, fileInfo); - } - else { - parserInput.i = index; - error('malformed @plugin statement'); - } - } - }, - pluginArgs: function () { - // list of options, surrounded by parens - parserInput.save(); - if (!parserInput.$char('(')) { - parserInput.restore(); - return null; - } - var args = parserInput.$re(/^\s*([^\);]+)\)\s*/); - if (args[1]) { - parserInput.forget(); - return args[1].trim(); - } - else { - parserInput.restore(); - return null; - } - }, - // - // A CSS AtRule - // - // @charset "utf-8"; - // - atrule: function () { - var index = parserInput.i; - var name; - var value; - var rules; - var nonVendorSpecificName; - var hasIdentifier; - var hasExpression; - var hasUnknown; - var hasBlock = true; - var isRooted = true; - if (parserInput.currentChar() !== '@') { - return; - } - value = this['import']() || this.plugin() || this.media(); - if (value) { - return value; - } - parserInput.save(); - name = parserInput.$re(/^@[a-z-]+/); - if (!name) { - return; - } - nonVendorSpecificName = name; - if (name.charAt(1) == '-' && name.indexOf('-', 2) > 0) { - nonVendorSpecificName = "@" + name.slice(name.indexOf('-', 2) + 1); - } - switch (nonVendorSpecificName) { - case '@charset': - hasIdentifier = true; - hasBlock = false; - break; - case '@namespace': - hasExpression = true; - hasBlock = false; - break; - case '@keyframes': - case '@counter-style': - hasIdentifier = true; - break; - case '@document': - case '@supports': - hasUnknown = true; - isRooted = false; - break; - default: - hasUnknown = true; - break; - } - parserInput.commentStore.length = 0; - if (hasIdentifier) { - value = this.entity(); - if (!value) { - error("expected " + name + " identifier"); - } - } - else if (hasExpression) { - value = this.expression(); - if (!value) { - error("expected " + name + " expression"); - } - } - else if (hasUnknown) { - value = this.permissiveValue(/^[{;]/); - hasBlock = (parserInput.currentChar() === '{'); - if (!value) { - if (!hasBlock && parserInput.currentChar() !== ';') { - error(name + " rule is missing block or ending semi-colon"); - } - } - else if (!value.value) { - value = null; - } - } - if (hasBlock) { - rules = this.blockRuleset(); - } - if (rules || (!hasBlock && value && parserInput.$char(';'))) { - parserInput.forget(); - return new (tree.AtRule)(name, value, rules, index, fileInfo, context.dumpLineNumbers ? getDebugInfo(index) : null, isRooted); - } - parserInput.restore('at-rule options not recognised'); - }, - // - // A Value is a comma-delimited list of Expressions - // - // font-family: Baskerville, Georgia, serif; - // - // In a Rule, a Value represents everything after the `:`, - // and before the `;`. - // - value: function () { - var e; - var expressions = []; - var index = parserInput.i; - do { - e = this.expression(); - if (e) { - expressions.push(e); - if (!parserInput.$char(',')) { - break; - } - } - } while (e); - if (expressions.length > 0) { - return new (tree.Value)(expressions, index); - } - }, - important: function () { - if (parserInput.currentChar() === '!') { - return parserInput.$re(/^! *important/); - } - }, - sub: function () { - var a; - var e; - parserInput.save(); - if (parserInput.$char('(')) { - a = this.addition(); - if (a && parserInput.$char(')')) { - parserInput.forget(); - e = new (tree.Expression)([a]); - e.parens = true; - return e; - } - parserInput.restore('Expected \')\''); - return; - } - parserInput.restore(); - }, - multiplication: function () { - var m; - var a; - var op; - var operation; - var isSpaced; - m = this.operand(); - if (m) { - isSpaced = parserInput.isWhitespace(-1); - while (true) { - if (parserInput.peek(/^\/[*\/]/)) { - break; - } - parserInput.save(); - op = parserInput.$char('/') || parserInput.$char('*') || parserInput.$str('./'); - if (!op) { - parserInput.forget(); - break; - } - a = this.operand(); - if (!a) { - parserInput.restore(); - break; - } - parserInput.forget(); - m.parensInOp = true; - a.parensInOp = true; - operation = new (tree.Operation)(op, [operation || m, a], isSpaced); - isSpaced = parserInput.isWhitespace(-1); - } - return operation || m; - } - }, - addition: function () { - var m; - var a; - var op; - var operation; - var isSpaced; - m = this.multiplication(); - if (m) { - isSpaced = parserInput.isWhitespace(-1); - while (true) { - op = parserInput.$re(/^[-+]\s+/) || (!isSpaced && (parserInput.$char('+') || parserInput.$char('-'))); - if (!op) { - break; - } - a = this.multiplication(); - if (!a) { - break; - } - m.parensInOp = true; - a.parensInOp = true; - operation = new (tree.Operation)(op, [operation || m, a], isSpaced); - isSpaced = parserInput.isWhitespace(-1); - } - return operation || m; - } - }, - conditions: function () { - var a; - var b; - var index = parserInput.i; - var condition; - a = this.condition(true); - if (a) { - while (true) { - if (!parserInput.peek(/^,\s*(not\s*)?\(/) || !parserInput.$char(',')) { - break; - } - b = this.condition(true); - if (!b) { - break; - } - condition = new (tree.Condition)('or', condition || a, b, index); - } - return condition || a; - } - }, - condition: function (needsParens) { - var result; - var logical; - var next; - function or() { - return parserInput.$str('or'); - } - result = this.conditionAnd(needsParens); - if (!result) { - return; - } - logical = or(); - if (logical) { - next = this.condition(needsParens); - if (next) { - result = new (tree.Condition)(logical, result, next); - } - else { - return; - } - } - return result; - }, - conditionAnd: function (needsParens) { - var result; - var logical; - var next; - var self = this; - function insideCondition() { - var cond = self.negatedCondition(needsParens) || self.parenthesisCondition(needsParens); - if (!cond && !needsParens) { - return self.atomicCondition(needsParens); - } - return cond; - } - function and() { - return parserInput.$str('and'); - } - result = insideCondition(); - if (!result) { - return; - } - logical = and(); - if (logical) { - next = this.conditionAnd(needsParens); - if (next) { - result = new (tree.Condition)(logical, result, next); - } - else { - return; - } - } - return result; - }, - negatedCondition: function (needsParens) { - if (parserInput.$str('not')) { - var result = this.parenthesisCondition(needsParens); - if (result) { - result.negate = !result.negate; - } - return result; - } - }, - parenthesisCondition: function (needsParens) { - function tryConditionFollowedByParenthesis(me) { - var body; - parserInput.save(); - body = me.condition(needsParens); - if (!body) { - parserInput.restore(); - return; - } - if (!parserInput.$char(')')) { - parserInput.restore(); - return; - } - parserInput.forget(); - return body; - } - var body; - parserInput.save(); - if (!parserInput.$str('(')) { - parserInput.restore(); - return; - } - body = tryConditionFollowedByParenthesis(this); - if (body) { - parserInput.forget(); - return body; - } - body = this.atomicCondition(needsParens); - if (!body) { - parserInput.restore(); - return; - } - if (!parserInput.$char(')')) { - parserInput.restore("expected ')' got '" + parserInput.currentChar() + "'"); - return; - } - parserInput.forget(); - return body; - }, - atomicCondition: function (needsParens) { - var entities = this.entities; - var index = parserInput.i; - var a; - var b; - var c; - var op; - function cond() { - return this.addition() || entities.keyword() || entities.quoted() || entities.mixinLookup(); - } - cond = cond.bind(this); - a = cond(); - if (a) { - if (parserInput.$char('>')) { - if (parserInput.$char('=')) { - op = '>='; - } - else { - op = '>'; - } - } - else if (parserInput.$char('<')) { - if (parserInput.$char('=')) { - op = '<='; - } - else { - op = '<'; - } - } - else if (parserInput.$char('=')) { - if (parserInput.$char('>')) { - op = '=>'; - } - else if (parserInput.$char('<')) { - op = '=<'; - } - else { - op = '='; - } - } - if (op) { - b = cond(); - if (b) { - c = new (tree.Condition)(op, a, b, index, false); - } - else { - error('expected expression'); - } - } - else { - c = new (tree.Condition)('=', a, new (tree.Keyword)('true'), index, false); - } - return c; - } - }, - // - // An operand is anything that can be part of an operation, - // such as a Color, or a Variable - // - operand: function () { - var entities = this.entities; - var negate; - if (parserInput.peek(/^-[@\$\(]/)) { - negate = parserInput.$char('-'); - } - var o = this.sub() || entities.dimension() || - entities.color() || entities.variable() || - entities.property() || entities.call() || - entities.quoted(true) || entities.colorKeyword() || - entities.mixinLookup(); - if (negate) { - o.parensInOp = true; - o = new (tree.Negative)(o); - } - return o; - }, - // - // Expressions either represent mathematical operations, - // or white-space delimited Entities. - // - // 1px solid black - // @var * 2 - // - expression: function () { - var entities = []; - var e; - var delim; - var index = parserInput.i; - do { - e = this.comment(); - if (e) { - entities.push(e); - continue; - } - e = this.addition() || this.entity(); - if (e instanceof tree.Comment) { - e = null; - } - if (e) { - entities.push(e); - // operations do not allow keyword "/" dimension (e.g. small/20px) so we support that here - if (!parserInput.peek(/^\/[\/*]/)) { - delim = parserInput.$char('/'); - if (delim) { - entities.push(new (tree.Anonymous)(delim, index)); - } - } - } - } while (e); - if (entities.length > 0) { - return new (tree.Expression)(entities); - } - }, - property: function () { - var name = parserInput.$re(/^(\*?-?[_a-zA-Z0-9-]+)\s*:/); - if (name) { - return name[1]; - } - }, - ruleProperty: function () { - var name = []; - var index = []; - var s; - var k; - parserInput.save(); - var simpleProperty = parserInput.$re(/^([_a-zA-Z0-9-]+)\s*:/); - if (simpleProperty) { - name = [new (tree.Keyword)(simpleProperty[1])]; - parserInput.forget(); - return name; - } - function match(re) { - var i = parserInput.i; - var chunk = parserInput.$re(re); - if (chunk) { - index.push(i); - return name.push(chunk[1]); - } - } - match(/^(\*?)/); - while (true) { - if (!match(/^((?:[\w-]+)|(?:[@\$]\{[\w-]+\}))/)) { - break; - } - } - if ((name.length > 1) && match(/^((?:\+_|\+)?)\s*:/)) { - parserInput.forget(); - // at last, we have the complete match now. move forward, - // convert name particles to tree objects and return: - if (name[0] === '') { - name.shift(); - index.shift(); - } - for (k = 0; k < name.length; k++) { - s = name[k]; - name[k] = (s.charAt(0) !== '@' && s.charAt(0) !== '$') ? - new (tree.Keyword)(s) : - (s.charAt(0) === '@' ? - new (tree.Variable)("@" + s.slice(2, -1), index[k], fileInfo) : - new (tree.Property)("$" + s.slice(2, -1), index[k], fileInfo)); - } - return name; - } - parserInput.restore(); - } - } - }; - }; - Parser.serializeVars = function (vars) { - var s = ''; - for (var name_1 in vars) { - if (Object.hasOwnProperty.call(vars, name_1)) { - var value = vars[name_1]; - s += ((name_1[0] === '@') ? '' : '@') + name_1 + ": " + value + ((String(value).slice(-1) === ';') ? '' : ';'); - } - } - return s; - }; - - function boolean(condition) { - return condition ? Keyword.True : Keyword.False; - } - /** - * Functions with evalArgs set to false are sent context - * as the first argument. - */ - function If(context, condition, trueValue, falseValue) { - return condition.eval(context) ? trueValue.eval(context) - : (falseValue ? falseValue.eval(context) : new Anonymous); - } - If.evalArgs = false; - function isdefined(context, variable) { - try { - variable.eval(context); - return Keyword.True; - } - catch (e) { - return Keyword.False; - } - } - isdefined.evalArgs = false; - var boolean$1 = { isdefined: isdefined, boolean: boolean, 'if': If }; - - var colorFunctions; - function clamp(val) { - return Math.min(1, Math.max(0, val)); - } - function hsla(origColor, hsl) { - var color = colorFunctions.hsla(hsl.h, hsl.s, hsl.l, hsl.a); - if (color) { - if (origColor.value && - /^(rgb|hsl)/.test(origColor.value)) { - color.value = origColor.value; - } - else { - color.value = 'rgb'; - } - return color; - } - } - function toHSL(color) { - if (color.toHSL) { - return color.toHSL(); - } - else { - throw new Error('Argument cannot be evaluated to a color'); - } - } - function toHSV(color) { - if (color.toHSV) { - return color.toHSV(); - } - else { - throw new Error('Argument cannot be evaluated to a color'); - } - } - function number$1(n) { - if (n instanceof Dimension) { - return parseFloat(n.unit.is('%') ? n.value / 100 : n.value); - } - else if (typeof n === 'number') { - return n; - } - else { - throw { - type: 'Argument', - message: 'color functions take numbers as parameters' - }; - } - } - function scaled(n, size) { - if (n instanceof Dimension && n.unit.is('%')) { - return parseFloat(n.value * size / 100); - } - else { - return number$1(n); - } - } - colorFunctions = { - rgb: function (r, g, b) { - var a = 1; - /** - * Comma-less syntax - * e.g. rgb(0 128 255 / 50%) - */ - if (r instanceof Expression) { - var val = r.value; - r = val[0]; - g = val[1]; - b = val[2]; - /** - * @todo - should this be normalized in - * function caller? Or parsed differently? - */ - if (b instanceof Operation) { - var op = b; - b = op.operands[0]; - a = op.operands[1]; - } - } - var color = colorFunctions.rgba(r, g, b, a); - if (color) { - color.value = 'rgb'; - return color; - } - }, - rgba: function (r, g, b, a) { - try { - if (r instanceof Color) { - if (g) { - a = number$1(g); - } - else { - a = r.alpha; - } - return new Color(r.rgb, a, 'rgba'); - } - var rgb = [r, g, b].map(function (c) { return scaled(c, 255); }); - a = number$1(a); - return new Color(rgb, a, 'rgba'); - } - catch (e) { } - }, - hsl: function (h, s, l) { - var a = 1; - if (h instanceof Expression) { - var val = h.value; - h = val[0]; - s = val[1]; - l = val[2]; - if (l instanceof Operation) { - var op = l; - l = op.operands[0]; - a = op.operands[1]; - } - } - var color = colorFunctions.hsla(h, s, l, a); - if (color) { - color.value = 'hsl'; - return color; - } - }, - hsla: function (h, s, l, a) { - try { - if (h instanceof Color) { - if (s) { - a = number$1(s); - } - else { - a = h.alpha; - } - return new Color(h.rgb, a, 'hsla'); - } - var m1_1; - var m2_1; - function hue(h) { - h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h); - if (h * 6 < 1) { - return m1_1 + (m2_1 - m1_1) * h * 6; - } - else if (h * 2 < 1) { - return m2_1; - } - else if (h * 3 < 2) { - return m1_1 + (m2_1 - m1_1) * (2 / 3 - h) * 6; - } - else { - return m1_1; - } - } - h = (number$1(h) % 360) / 360; - s = clamp(number$1(s)); - l = clamp(number$1(l)); - a = clamp(number$1(a)); - m2_1 = l <= 0.5 ? l * (s + 1) : l + s - l * s; - m1_1 = l * 2 - m2_1; - var rgb = [ - hue(h + 1 / 3) * 255, - hue(h) * 255, - hue(h - 1 / 3) * 255 - ]; - a = number$1(a); - return new Color(rgb, a, 'hsla'); - } - catch (e) { } - }, - hsv: function (h, s, v) { - return colorFunctions.hsva(h, s, v, 1.0); - }, - hsva: function (h, s, v, a) { - h = ((number$1(h) % 360) / 360) * 360; - s = number$1(s); - v = number$1(v); - a = number$1(a); - var i; - var f; - i = Math.floor((h / 60) % 6); - f = (h / 60) - i; - var vs = [v, - v * (1 - s), - v * (1 - f * s), - v * (1 - (1 - f) * s)]; - var perm = [[0, 3, 1], - [2, 0, 1], - [1, 0, 3], - [1, 2, 0], - [3, 1, 0], - [0, 1, 2]]; - return colorFunctions.rgba(vs[perm[i][0]] * 255, vs[perm[i][1]] * 255, vs[perm[i][2]] * 255, a); - }, - hue: function (color) { - return new Dimension(toHSL(color).h); - }, - saturation: function (color) { - return new Dimension(toHSL(color).s * 100, '%'); - }, - lightness: function (color) { - return new Dimension(toHSL(color).l * 100, '%'); - }, - hsvhue: function (color) { - return new Dimension(toHSV(color).h); - }, - hsvsaturation: function (color) { - return new Dimension(toHSV(color).s * 100, '%'); - }, - hsvvalue: function (color) { - return new Dimension(toHSV(color).v * 100, '%'); - }, - red: function (color) { - return new Dimension(color.rgb[0]); - }, - green: function (color) { - return new Dimension(color.rgb[1]); - }, - blue: function (color) { - return new Dimension(color.rgb[2]); - }, - alpha: function (color) { - return new Dimension(toHSL(color).a); - }, - luma: function (color) { - return new Dimension(color.luma() * color.alpha * 100, '%'); - }, - luminance: function (color) { - var luminance = (0.2126 * color.rgb[0] / 255) + - (0.7152 * color.rgb[1] / 255) + - (0.0722 * color.rgb[2] / 255); - return new Dimension(luminance * color.alpha * 100, '%'); - }, - saturate: function (color, amount, method) { - // filter: saturate(3.2); - // should be kept as is, so check for color - if (!color.rgb) { - return null; - } - var hsl = toHSL(color); - if (typeof method !== 'undefined' && method.value === 'relative') { - hsl.s += hsl.s * amount.value / 100; - } - else { - hsl.s += amount.value / 100; - } - hsl.s = clamp(hsl.s); - return hsla(color, hsl); - }, - desaturate: function (color, amount, method) { - var hsl = toHSL(color); - if (typeof method !== 'undefined' && method.value === 'relative') { - hsl.s -= hsl.s * amount.value / 100; - } - else { - hsl.s -= amount.value / 100; - } - hsl.s = clamp(hsl.s); - return hsla(color, hsl); - }, - lighten: function (color, amount, method) { - var hsl = toHSL(color); - if (typeof method !== 'undefined' && method.value === 'relative') { - hsl.l += hsl.l * amount.value / 100; - } - else { - hsl.l += amount.value / 100; - } - hsl.l = clamp(hsl.l); - return hsla(color, hsl); - }, - darken: function (color, amount, method) { - var hsl = toHSL(color); - if (typeof method !== 'undefined' && method.value === 'relative') { - hsl.l -= hsl.l * amount.value / 100; - } - else { - hsl.l -= amount.value / 100; - } - hsl.l = clamp(hsl.l); - return hsla(color, hsl); - }, - fadein: function (color, amount, method) { - var hsl = toHSL(color); - if (typeof method !== 'undefined' && method.value === 'relative') { - hsl.a += hsl.a * amount.value / 100; - } - else { - hsl.a += amount.value / 100; - } - hsl.a = clamp(hsl.a); - return hsla(color, hsl); - }, - fadeout: function (color, amount, method) { - var hsl = toHSL(color); - if (typeof method !== 'undefined' && method.value === 'relative') { - hsl.a -= hsl.a * amount.value / 100; - } - else { - hsl.a -= amount.value / 100; - } - hsl.a = clamp(hsl.a); - return hsla(color, hsl); - }, - fade: function (color, amount) { - var hsl = toHSL(color); - hsl.a = amount.value / 100; - hsl.a = clamp(hsl.a); - return hsla(color, hsl); - }, - spin: function (color, amount) { - var hsl = toHSL(color); - var hue = (hsl.h + amount.value) % 360; - hsl.h = hue < 0 ? 360 + hue : hue; - return hsla(color, hsl); - }, - // - // Copyright (c) 2006-2009 Hampton Catlin, Natalie Weizenbaum, and Chris Eppstein - // http://sass-lang.com - // - mix: function (color1, color2, weight) { - if (!weight) { - weight = new Dimension(50); - } - var p = weight.value / 100.0; - var w = p * 2 - 1; - var a = toHSL(color1).a - toHSL(color2).a; - var w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0; - var w2 = 1 - w1; - var rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2, - color1.rgb[1] * w1 + color2.rgb[1] * w2, - color1.rgb[2] * w1 + color2.rgb[2] * w2]; - var alpha = color1.alpha * p + color2.alpha * (1 - p); - return new Color(rgb, alpha); - }, - greyscale: function (color) { - return colorFunctions.desaturate(color, new Dimension(100)); - }, - contrast: function (color, dark, light, threshold) { - // filter: contrast(3.2); - // should be kept as is, so check for color - if (!color.rgb) { - return null; - } - if (typeof light === 'undefined') { - light = colorFunctions.rgba(255, 255, 255, 1.0); - } - if (typeof dark === 'undefined') { - dark = colorFunctions.rgba(0, 0, 0, 1.0); - } - // Figure out which is actually light and dark: - if (dark.luma() > light.luma()) { - var t = light; - light = dark; - dark = t; - } - if (typeof threshold === 'undefined') { - threshold = 0.43; - } - else { - threshold = number$1(threshold); - } - if (color.luma() < threshold) { - return light; - } - else { - return dark; - } - }, - // Changes made in 2.7.0 - Reverted in 3.0.0 - // contrast: function (color, color1, color2, threshold) { - // // Return which of `color1` and `color2` has the greatest contrast with `color` - // // according to the standard WCAG contrast ratio calculation. - // // http://www.w3.org/TR/WCAG20/#contrast-ratiodef - // // The threshold param is no longer used, in line with SASS. - // // filter: contrast(3.2); - // // should be kept as is, so check for color - // if (!color.rgb) { - // return null; - // } - // if (typeof color1 === 'undefined') { - // color1 = colorFunctions.rgba(0, 0, 0, 1.0); - // } - // if (typeof color2 === 'undefined') { - // color2 = colorFunctions.rgba(255, 255, 255, 1.0); - // } - // var contrast1, contrast2; - // var luma = color.luma(); - // var luma1 = color1.luma(); - // var luma2 = color2.luma(); - // // Calculate contrast ratios for each color - // if (luma > luma1) { - // contrast1 = (luma + 0.05) / (luma1 + 0.05); - // } else { - // contrast1 = (luma1 + 0.05) / (luma + 0.05); - // } - // if (luma > luma2) { - // contrast2 = (luma + 0.05) / (luma2 + 0.05); - // } else { - // contrast2 = (luma2 + 0.05) / (luma + 0.05); - // } - // if (contrast1 > contrast2) { - // return color1; - // } else { - // return color2; - // } - // }, - argb: function (color) { - return new Anonymous(color.toARGB()); - }, - color: function (c) { - if ((c instanceof Quoted) && - (/^#([A-Fa-f0-9]{8}|[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3,4})$/i.test(c.value))) { - var val = c.value.slice(1); - return new Color(val, undefined, "#" + val); - } - if ((c instanceof Color) || (c = Color.fromKeyword(c.value))) { - c.value = undefined; - return c; - } - throw { - type: 'Argument', - message: 'argument must be a color keyword or 3|4|6|8 digit hex e.g. #FFF' - }; - }, - tint: function (color, amount) { - return colorFunctions.mix(colorFunctions.rgb(255, 255, 255), color, amount); - }, - shade: function (color, amount) { - return colorFunctions.mix(colorFunctions.rgb(0, 0, 0), color, amount); - } - }; - var color = colorFunctions; - - // Color Blending - // ref: http://www.w3.org/TR/compositing-1 - function colorBlend(mode, color1, color2) { - var ab = color1.alpha; // result - var // backdrop - cb; - var as = color2.alpha; - var // source - cs; - var ar; - var cr; - var r = []; - ar = as + ab * (1 - as); - for (var i = 0; i < 3; i++) { - cb = color1.rgb[i] / 255; - cs = color2.rgb[i] / 255; - cr = mode(cb, cs); - if (ar) { - cr = (as * cs + ab * (cb - - as * (cb + cs - cr))) / ar; - } - r[i] = cr * 255; - } - return new Color(r, ar); - } - var colorBlendModeFunctions = { - multiply: function (cb, cs) { - return cb * cs; - }, - screen: function (cb, cs) { - return cb + cs - cb * cs; - }, - overlay: function (cb, cs) { - cb *= 2; - return (cb <= 1) ? - colorBlendModeFunctions.multiply(cb, cs) : - colorBlendModeFunctions.screen(cb - 1, cs); - }, - softlight: function (cb, cs) { - var d = 1; - var e = cb; - if (cs > 0.5) { - e = 1; - d = (cb > 0.25) ? Math.sqrt(cb) - : ((16 * cb - 12) * cb + 4) * cb; - } - return cb - (1 - 2 * cs) * e * (d - cb); - }, - hardlight: function (cb, cs) { - return colorBlendModeFunctions.overlay(cs, cb); - }, - difference: function (cb, cs) { - return Math.abs(cb - cs); - }, - exclusion: function (cb, cs) { - return cb + cs - 2 * cb * cs; - }, - // non-w3c functions: - average: function (cb, cs) { - return (cb + cs) / 2; - }, - negation: function (cb, cs) { - return 1 - Math.abs(cb + cs - 1); - } - }; - for (var f$1 in colorBlendModeFunctions) { - if (colorBlendModeFunctions.hasOwnProperty(f$1)) { - colorBlend[f$1] = colorBlend.bind(null, colorBlendModeFunctions[f$1]); - } - } - - var dataUri = (function (environment) { - var fallback = function (functionThis, node) { return new URL(node, functionThis.index, functionThis.currentFileInfo).eval(functionThis.context); }; - return { 'data-uri': function (mimetypeNode, filePathNode) { - if (!filePathNode) { - filePathNode = mimetypeNode; - mimetypeNode = null; - } - var mimetype = mimetypeNode && mimetypeNode.value; - var filePath = filePathNode.value; - var currentFileInfo = this.currentFileInfo; - var currentDirectory = currentFileInfo.rewriteUrls ? - currentFileInfo.currentDirectory : currentFileInfo.entryPath; - var fragmentStart = filePath.indexOf('#'); - var fragment = ''; - if (fragmentStart !== -1) { - fragment = filePath.slice(fragmentStart); - filePath = filePath.slice(0, fragmentStart); - } - var context = clone(this.context); - context.rawBuffer = true; - var fileManager = environment.getFileManager(filePath, currentDirectory, context, environment, true); - if (!fileManager) { - return fallback(this, filePathNode); - } - var useBase64 = false; - // detect the mimetype if not given - if (!mimetypeNode) { - mimetype = environment.mimeLookup(filePath); - if (mimetype === 'image/svg+xml') { - useBase64 = false; - } - else { - // use base 64 unless it's an ASCII or UTF-8 format - var charset = environment.charsetLookup(mimetype); - useBase64 = ['US-ASCII', 'UTF-8'].indexOf(charset) < 0; - } - if (useBase64) { - mimetype += ';base64'; - } - } - else { - useBase64 = /;base64$/.test(mimetype); - } - var fileSync = fileManager.loadFileSync(filePath, currentDirectory, context, environment); - if (!fileSync.contents) { - logger$1.warn("Skipped data-uri embedding of " + filePath + " because file not found"); - return fallback(this, filePathNode || mimetypeNode); - } - var buf = fileSync.contents; - if (useBase64 && !environment.encodeBase64) { - return fallback(this, filePathNode); - } - buf = useBase64 ? environment.encodeBase64(buf) : encodeURIComponent(buf); - var uri = "data:" + mimetype + "," + buf + fragment; - return new URL(new Quoted("\"" + uri + "\"", uri, false, this.index, this.currentFileInfo), this.index, this.currentFileInfo); - } }; - }); - - var getItemsFromNode = function (node) { - // handle non-array values as an array of length 1 - // return 'undefined' if index is invalid - var items = Array.isArray(node.value) ? - node.value : Array(node); - return items; - }; - var list = { - _SELF: function (n) { - return n; - }, - '~': function () { - var expr = []; - for (var _i = 0; _i < arguments.length; _i++) { - expr[_i] = arguments[_i]; - } - if (expr.length === 1) { - return expr[0]; - } - return new Value(expr); - }, - extract: function (values, index) { - // (1-based index) - index = index.value - 1; - return getItemsFromNode(values)[index]; - }, - length: function (values) { - return new Dimension(getItemsFromNode(values).length); - }, - /** - * Creates a Less list of incremental values. - * Modeled after Lodash's range function, also exists natively in PHP - * - * @param {Dimension} [start=1] - * @param {Dimension} end - e.g. 10 or 10px - unit is added to output - * @param {Dimension} [step=1] - */ - range: function (start, end, step) { - var from; - var to; - var stepValue = 1; - var list = []; - if (end) { - to = end; - from = start.value; - if (step) { - stepValue = step.value; - } - } - else { - from = 1; - to = start; - } - for (var i = from; i <= to.value; i += stepValue) { - list.push(new Dimension(i, to.unit)); - } - return new Expression(list); - }, - each: function (list, rs) { - var _this = this; - var rules = []; - var newRules; - var iterator; - var tryEval = function (val) { - if (val instanceof Node) { - return val.eval(_this.context); - } - return val; - }; - if (list.value && !(list instanceof Quoted)) { - if (Array.isArray(list.value)) { - iterator = list.value.map(tryEval); - } - else { - iterator = [tryEval(list.value)]; - } - } - else if (list.ruleset) { - iterator = tryEval(list.ruleset).rules; - } - else if (list.rules) { - iterator = list.rules.map(tryEval); - } - else if (Array.isArray(list)) { - iterator = list.map(tryEval); - } - else { - iterator = [tryEval(list)]; - } - var valueName = '@value'; - var keyName = '@key'; - var indexName = '@index'; - if (rs.params) { - valueName = rs.params[0] && rs.params[0].name; - keyName = rs.params[1] && rs.params[1].name; - indexName = rs.params[2] && rs.params[2].name; - rs = rs.rules; - } - else { - rs = rs.ruleset; - } - for (var i = 0; i < iterator.length; i++) { - var key = void 0; - var value = void 0; - var item = iterator[i]; - if (item instanceof Declaration) { - key = typeof item.name === 'string' ? item.name : item.name[0].value; - value = item.value; - } - else { - key = new Dimension(i + 1); - value = item; - } - if (item instanceof Comment) { - continue; - } - newRules = rs.rules.slice(0); - if (valueName) { - newRules.push(new Declaration(valueName, value, false, false, this.index, this.currentFileInfo)); - } - if (indexName) { - newRules.push(new Declaration(indexName, new Dimension(i + 1), false, false, this.index, this.currentFileInfo)); - } - if (keyName) { - newRules.push(new Declaration(keyName, key, false, false, this.index, this.currentFileInfo)); - } - rules.push(new Ruleset([new (Selector)([new Element("", '&')])], newRules, rs.strictImports, rs.visibilityInfo())); - } - return new Ruleset([new (Selector)([new Element("", '&')])], rules, rs.strictImports, rs.visibilityInfo()).eval(this.context); - } - }; - - var MathHelper = function (fn, unit, n) { - if (!(n instanceof Dimension)) { - throw { type: 'Argument', message: 'argument must be a number' }; - } - if (unit == null) { - unit = n.unit; - } - else { - n = n.unify(); - } - return new Dimension(fn(parseFloat(n.value)), unit); - }; - - var mathFunctions = { - // name, unit - ceil: null, - floor: null, - sqrt: null, - abs: null, - tan: '', - sin: '', - cos: '', - atan: 'rad', - asin: 'rad', - acos: 'rad' - }; - for (var f in mathFunctions) { - if (mathFunctions.hasOwnProperty(f)) { - mathFunctions[f] = MathHelper.bind(null, Math[f], mathFunctions[f]); - } - } - mathFunctions.round = function (n, f) { - var fraction = typeof f === 'undefined' ? 0 : f.value; - return MathHelper(function (num) { return num.toFixed(fraction); }, null, n); - }; - - var minMax = function (isMin, args) { - args = Array.prototype.slice.call(args); - switch (args.length) { - case 0: throw { type: 'Argument', message: 'one or more arguments required' }; - } - var i; // key is the unit.toString() for unified Dimension values, - var j; - var current; - var currentUnified; - var referenceUnified; - var unit; - var unitStatic; - var unitClone; - var // elems only contains original argument values. - order = []; - var values = {}; - // value is the index into the order array. - for (i = 0; i < args.length; i++) { - current = args[i]; - if (!(current instanceof Dimension)) { - if (Array.isArray(args[i].value)) { - Array.prototype.push.apply(args, Array.prototype.slice.call(args[i].value)); - } - continue; - } - currentUnified = current.unit.toString() === '' && unitClone !== undefined ? new Dimension(current.value, unitClone).unify() : current.unify(); - unit = currentUnified.unit.toString() === '' && unitStatic !== undefined ? unitStatic : currentUnified.unit.toString(); - unitStatic = unit !== '' && unitStatic === undefined || unit !== '' && order[0].unify().unit.toString() === '' ? unit : unitStatic; - unitClone = unit !== '' && unitClone === undefined ? current.unit.toString() : unitClone; - j = values[''] !== undefined && unit !== '' && unit === unitStatic ? values[''] : values[unit]; - if (j === undefined) { - if (unitStatic !== undefined && unit !== unitStatic) { - throw { type: 'Argument', message: 'incompatible types' }; - } - values[unit] = order.length; - order.push(current); - continue; - } - referenceUnified = order[j].unit.toString() === '' && unitClone !== undefined ? new Dimension(order[j].value, unitClone).unify() : order[j].unify(); - if (isMin && currentUnified.value < referenceUnified.value || - !isMin && currentUnified.value > referenceUnified.value) { - order[j] = current; - } - } - if (order.length == 1) { - return order[0]; - } - args = order.map(function (a) { return a.toCSS(this.context); }).join(this.context.compress ? ',' : ', '); - return new Anonymous((isMin ? 'min' : 'max') + "(" + args + ")"); - }; - var number = { - min: function () { - var args = []; - for (var _i = 0; _i < arguments.length; _i++) { - args[_i] = arguments[_i]; - } - try { - return minMax(true, args); - } - catch (e) { } - }, - max: function () { - var args = []; - for (var _i = 0; _i < arguments.length; _i++) { - args[_i] = arguments[_i]; - } - try { - return minMax(false, args); - } - catch (e) { } - }, - convert: function (val, unit) { - return val.convertTo(unit.value); - }, - pi: function () { - return new Dimension(Math.PI); - }, - mod: function (a, b) { - return new Dimension(a.value % b.value, a.unit); - }, - pow: function (x, y) { - if (typeof x === 'number' && typeof y === 'number') { - x = new Dimension(x); - y = new Dimension(y); - } - else if (!(x instanceof Dimension) || !(y instanceof Dimension)) { - throw { type: 'Argument', message: 'arguments must be numbers' }; - } - return new Dimension(Math.pow(x.value, y.value), x.unit); - }, - percentage: function (n) { - var result = MathHelper(function (num) { return num * 100; }, '%', n); - return result; - } - }; - - var string = { - e: function (str) { - return new Quoted('"', str instanceof JavaScript ? str.evaluated : str.value, true); - }, - escape: function (str) { - return new Anonymous(encodeURI(str.value).replace(/=/g, '%3D').replace(/:/g, '%3A').replace(/#/g, '%23').replace(/;/g, '%3B') - .replace(/\(/g, '%28').replace(/\)/g, '%29')); - }, - replace: function (string, pattern, replacement, flags) { - var result = string.value; - replacement = (replacement.type === 'Quoted') ? - replacement.value : replacement.toCSS(); - result = result.replace(new RegExp(pattern.value, flags ? flags.value : ''), replacement); - return new Quoted(string.quote || '', result, string.escaped); - }, - '%': function (string /* arg, arg, ... */) { - var args = Array.prototype.slice.call(arguments, 1); - var result = string.value; - var _loop_1 = function (i) { - /* jshint loopfunc:true */ - result = result.replace(/%[sda]/i, function (token) { - var value = ((args[i].type === 'Quoted') && - token.match(/s/i)) ? args[i].value : args[i].toCSS(); - return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value; - }); - }; - for (var i = 0; i < args.length; i++) { - _loop_1(i); - } - result = result.replace(/%%/g, '%'); - return new Quoted(string.quote || '', result, string.escaped); - } - }; - - var svg = (function (environment) { - return { 'svg-gradient': function (direction) { - var stops; - var gradientDirectionSvg; - var gradientType = 'linear'; - var rectangleDimension = 'x="0" y="0" width="1" height="1"'; - var renderEnv = { compress: false }; - var returner; - var directionValue = direction.toCSS(renderEnv); - var i; - var color; - var position; - var positionValue; - var alpha; - function throwArgumentDescriptor() { - throw { type: 'Argument', - message: 'svg-gradient expects direction, start_color [start_position], [color position,]...,' + - ' end_color [end_position] or direction, color list' }; - } - if (arguments.length == 2) { - if (arguments[1].value.length < 2) { - throwArgumentDescriptor(); - } - stops = arguments[1].value; - } - else if (arguments.length < 3) { - throwArgumentDescriptor(); - } - else { - stops = Array.prototype.slice.call(arguments, 1); - } - switch (directionValue) { - case 'to bottom': - gradientDirectionSvg = 'x1="0%" y1="0%" x2="0%" y2="100%"'; - break; - case 'to right': - gradientDirectionSvg = 'x1="0%" y1="0%" x2="100%" y2="0%"'; - break; - case 'to bottom right': - gradientDirectionSvg = 'x1="0%" y1="0%" x2="100%" y2="100%"'; - break; - case 'to top right': - gradientDirectionSvg = 'x1="0%" y1="100%" x2="100%" y2="0%"'; - break; - case 'ellipse': - case 'ellipse at center': - gradientType = 'radial'; - gradientDirectionSvg = 'cx="50%" cy="50%" r="75%"'; - rectangleDimension = 'x="-50" y="-50" width="101" height="101"'; - break; - default: - throw { type: 'Argument', message: 'svg-gradient direction must be \'to bottom\', \'to right\',' + - ' \'to bottom right\', \'to top right\' or \'ellipse at center\'' }; - } - returner = "<" + gradientType + "Gradient id=\"g\" " + gradientDirectionSvg + ">"; - for (i = 0; i < stops.length; i += 1) { - if (stops[i] instanceof Expression) { - color = stops[i].value[0]; - position = stops[i].value[1]; - } - else { - color = stops[i]; - position = undefined; - } - if (!(color instanceof Color) || (!((i === 0 || i + 1 === stops.length) && position === undefined) && !(position instanceof Dimension))) { - throwArgumentDescriptor(); - } - positionValue = position ? position.toCSS(renderEnv) : i === 0 ? '0%' : '100%'; - alpha = color.alpha; - returner += ""; - } - returner += ""; - returner = encodeURIComponent(returner); - returner = "data:image/svg+xml," + returner; - return new URL(new Quoted("'" + returner + "'", returner, false, this.index, this.currentFileInfo), this.index, this.currentFileInfo); - } }; - }); - - var isa = function (n, Type) { return (n instanceof Type) ? Keyword.True : Keyword.False; }; - var isunit = function (n, unit) { - if (unit === undefined) { - throw { type: 'Argument', message: 'missing the required second argument to isunit.' }; - } - unit = typeof unit.value === 'string' ? unit.value : unit; - if (typeof unit !== 'string') { - throw { type: 'Argument', message: 'Second argument to isunit should be a unit or a string.' }; - } - return (n instanceof Dimension) && n.unit.is(unit) ? Keyword.True : Keyword.False; - }; - var types = { - isruleset: function (n) { - return isa(n, DetachedRuleset); - }, - iscolor: function (n) { - return isa(n, Color); - }, - isnumber: function (n) { - return isa(n, Dimension); - }, - isstring: function (n) { - return isa(n, Quoted); - }, - iskeyword: function (n) { - return isa(n, Keyword); - }, - isurl: function (n) { - return isa(n, URL); - }, - ispixel: function (n) { - return isunit(n, 'px'); - }, - ispercentage: function (n) { - return isunit(n, '%'); - }, - isem: function (n) { - return isunit(n, 'em'); - }, - isunit: isunit, - unit: function (val, unit) { - if (!(val instanceof Dimension)) { - throw { type: 'Argument', - message: "the first argument to unit must be a number" + (val instanceof Operation ? '. Have you forgotten parenthesis?' : '') }; - } - if (unit) { - if (unit instanceof Keyword) { - unit = unit.value; - } - else { - unit = unit.toCSS(); - } - } - else { - unit = ''; - } - return new Dimension(val.value, unit); - }, - 'get-unit': function (n) { - return new Anonymous(n.unit); - } - }; - - var functions = (function (environment) { - var functions = { functionRegistry: functionRegistry, functionCaller: functionCaller }; - // register functions - functionRegistry.addMultiple(boolean$1); - functionRegistry.add('default', defaultFunc.eval.bind(defaultFunc)); - functionRegistry.addMultiple(color); - functionRegistry.addMultiple(colorBlend); - functionRegistry.addMultiple(dataUri(environment)); - functionRegistry.addMultiple(list); - functionRegistry.addMultiple(mathFunctions); - functionRegistry.addMultiple(number); - functionRegistry.addMultiple(string); - functionRegistry.addMultiple(svg()); - functionRegistry.addMultiple(types); - return functions; - }); - - function transformTree (root, options) { - options = options || {}; - var evaldRoot; - var variables = options.variables; - var evalEnv = new contexts.Eval(options); - // - // Allows setting variables with a hash, so: - // - // `{ color: new tree.Color('#f01') }` will become: - // - // new tree.Declaration('@color', - // new tree.Value([ - // new tree.Expression([ - // new tree.Color('#f01') - // ]) - // ]) - // ) - // - if (typeof variables === 'object' && !Array.isArray(variables)) { - variables = Object.keys(variables).map(function (k) { - var value = variables[k]; - if (!(value instanceof tree.Value)) { - if (!(value instanceof tree.Expression)) { - value = new tree.Expression([value]); - } - value = new tree.Value([value]); - } - return new tree.Declaration("@" + k, value, false, null, 0); - }); - evalEnv.frames = [new tree.Ruleset(null, variables)]; - } - var visitors$1 = [ - new visitors.JoinSelectorVisitor(), - new visitors.MarkVisibleSelectorsVisitor(true), - new visitors.ExtendVisitor(), - new visitors.ToCSSVisitor({ compress: Boolean(options.compress) }) - ]; - var preEvalVisitors = []; - var v; - var visitorIterator; - /** - * first() / get() allows visitors to be added while visiting - * - * @todo Add scoping for visitors just like functions for @plugin; right now they're global - */ - if (options.pluginManager) { - visitorIterator = options.pluginManager.visitor(); - for (var i = 0; i < 2; i++) { - visitorIterator.first(); - while ((v = visitorIterator.get())) { - if (v.isPreEvalVisitor) { - if (i === 0 || preEvalVisitors.indexOf(v) === -1) { - preEvalVisitors.push(v); - v.run(root); - } - } - else { - if (i === 0 || visitors$1.indexOf(v) === -1) { - if (v.isPreVisitor) { - visitors$1.unshift(v); - } - else { - visitors$1.push(v); - } - } - } - } - } - } - evaldRoot = root.eval(evalEnv); - for (var i = 0; i < visitors$1.length; i++) { - visitors$1[i].run(evaldRoot); - } - // Run any remaining visitors added after eval pass - if (options.pluginManager) { - visitorIterator.first(); - while ((v = visitorIterator.get())) { - if (visitors$1.indexOf(v) === -1 && preEvalVisitors.indexOf(v) === -1) { - v.run(evaldRoot); - } - } - } - return evaldRoot; - } - - /** - * Plugin Manager - */ - var PluginManager = /** @class */ (function () { - function PluginManager(less) { - this.less = less; - this.visitors = []; - this.preProcessors = []; - this.postProcessors = []; - this.installedPlugins = []; - this.fileManagers = []; - this.iterator = -1; - this.pluginCache = {}; - this.Loader = new less.PluginLoader(less); - } - /** - * Adds all the plugins in the array - * @param {Array} plugins - */ - PluginManager.prototype.addPlugins = function (plugins) { - if (plugins) { - for (var i = 0; i < plugins.length; i++) { - this.addPlugin(plugins[i]); - } - } - }; - /** - * - * @param plugin - * @param {String} filename - */ - PluginManager.prototype.addPlugin = function (plugin, filename, functionRegistry) { - this.installedPlugins.push(plugin); - if (filename) { - this.pluginCache[filename] = plugin; - } - if (plugin.install) { - plugin.install(this.less, this, functionRegistry || this.less.functions.functionRegistry); - } - }; - /** - * - * @param filename - */ - PluginManager.prototype.get = function (filename) { - return this.pluginCache[filename]; - }; - /** - * Adds a visitor. The visitor object has options on itself to determine - * when it should run. - * @param visitor - */ - PluginManager.prototype.addVisitor = function (visitor) { - this.visitors.push(visitor); - }; - /** - * Adds a pre processor object - * @param {object} preProcessor - * @param {number} priority - guidelines 1 = before import, 1000 = import, 2000 = after import - */ - PluginManager.prototype.addPreProcessor = function (preProcessor, priority) { - var indexToInsertAt; - for (indexToInsertAt = 0; indexToInsertAt < this.preProcessors.length; indexToInsertAt++) { - if (this.preProcessors[indexToInsertAt].priority >= priority) { - break; - } - } - this.preProcessors.splice(indexToInsertAt, 0, { preProcessor: preProcessor, priority: priority }); - }; - /** - * Adds a post processor object - * @param {object} postProcessor - * @param {number} priority - guidelines 1 = before compression, 1000 = compression, 2000 = after compression - */ - PluginManager.prototype.addPostProcessor = function (postProcessor, priority) { - var indexToInsertAt; - for (indexToInsertAt = 0; indexToInsertAt < this.postProcessors.length; indexToInsertAt++) { - if (this.postProcessors[indexToInsertAt].priority >= priority) { - break; - } - } - this.postProcessors.splice(indexToInsertAt, 0, { postProcessor: postProcessor, priority: priority }); - }; - /** - * - * @param manager - */ - PluginManager.prototype.addFileManager = function (manager) { - this.fileManagers.push(manager); - }; - /** - * - * @returns {Array} - * @private - */ - PluginManager.prototype.getPreProcessors = function () { - var preProcessors = []; - for (var i = 0; i < this.preProcessors.length; i++) { - preProcessors.push(this.preProcessors[i].preProcessor); - } - return preProcessors; - }; - /** - * - * @returns {Array} - * @private - */ - PluginManager.prototype.getPostProcessors = function () { - var postProcessors = []; - for (var i = 0; i < this.postProcessors.length; i++) { - postProcessors.push(this.postProcessors[i].postProcessor); - } - return postProcessors; - }; - /** - * - * @returns {Array} - * @private - */ - PluginManager.prototype.getVisitors = function () { - return this.visitors; - }; - PluginManager.prototype.visitor = function () { - var self = this; - return { - first: function () { - self.iterator = -1; - return self.visitors[self.iterator]; - }, - get: function () { - self.iterator += 1; - return self.visitors[self.iterator]; - } - }; - }; - /** - * - * @returns {Array} - * @private - */ - PluginManager.prototype.getFileManagers = function () { - return this.fileManagers; - }; - return PluginManager; - }()); - var pm; - var PluginManagerFactory = function (less, newFactory) { - if (newFactory || !pm) { - pm = new PluginManager(less); - } - return pm; - }; - - function SourceMapOutput (environment) { - var SourceMapOutput = /** @class */ (function () { - function SourceMapOutput(options) { - this._css = []; - this._rootNode = options.rootNode; - this._contentsMap = options.contentsMap; - this._contentsIgnoredCharsMap = options.contentsIgnoredCharsMap; - if (options.sourceMapFilename) { - this._sourceMapFilename = options.sourceMapFilename.replace(/\\/g, '/'); - } - this._outputFilename = options.outputFilename; - this.sourceMapURL = options.sourceMapURL; - if (options.sourceMapBasepath) { - this._sourceMapBasepath = options.sourceMapBasepath.replace(/\\/g, '/'); - } - if (options.sourceMapRootpath) { - this._sourceMapRootpath = options.sourceMapRootpath.replace(/\\/g, '/'); - if (this._sourceMapRootpath.charAt(this._sourceMapRootpath.length - 1) !== '/') { - this._sourceMapRootpath += '/'; - } - } - else { - this._sourceMapRootpath = ''; - } - this._outputSourceFiles = options.outputSourceFiles; - this._sourceMapGeneratorConstructor = environment.getSourceMapGenerator(); - this._lineNumber = 0; - this._column = 0; - } - SourceMapOutput.prototype.removeBasepath = function (path) { - if (this._sourceMapBasepath && path.indexOf(this._sourceMapBasepath) === 0) { - path = path.substring(this._sourceMapBasepath.length); - if (path.charAt(0) === '\\' || path.charAt(0) === '/') { - path = path.substring(1); - } - } - return path; - }; - SourceMapOutput.prototype.normalizeFilename = function (filename) { - filename = filename.replace(/\\/g, '/'); - filename = this.removeBasepath(filename); - return (this._sourceMapRootpath || '') + filename; - }; - SourceMapOutput.prototype.add = function (chunk, fileInfo, index, mapLines) { - // ignore adding empty strings - if (!chunk) { - return; - } - var lines, sourceLines, columns, sourceColumns, i; - if (fileInfo && fileInfo.filename) { - var inputSource = this._contentsMap[fileInfo.filename]; - // remove vars/banner added to the top of the file - if (this._contentsIgnoredCharsMap[fileInfo.filename]) { - // adjust the index - index -= this._contentsIgnoredCharsMap[fileInfo.filename]; - if (index < 0) { - index = 0; - } - // adjust the source - inputSource = inputSource.slice(this._contentsIgnoredCharsMap[fileInfo.filename]); - } - /** - * ignore empty content, or failsafe - * if contents map is incorrect - */ - if (inputSource === undefined) { - this._css.push(chunk); - return; - } - inputSource = inputSource.substring(0, index); - sourceLines = inputSource.split('\n'); - sourceColumns = sourceLines[sourceLines.length - 1]; - } - lines = chunk.split('\n'); - columns = lines[lines.length - 1]; - if (fileInfo && fileInfo.filename) { - if (!mapLines) { - this._sourceMapGenerator.addMapping({ generated: { line: this._lineNumber + 1, column: this._column }, - original: { line: sourceLines.length, column: sourceColumns.length }, - source: this.normalizeFilename(fileInfo.filename) }); - } - else { - for (i = 0; i < lines.length; i++) { - this._sourceMapGenerator.addMapping({ generated: { line: this._lineNumber + i + 1, column: i === 0 ? this._column : 0 }, - original: { line: sourceLines.length + i, column: i === 0 ? sourceColumns.length : 0 }, - source: this.normalizeFilename(fileInfo.filename) }); - } - } - } - if (lines.length === 1) { - this._column += columns.length; - } - else { - this._lineNumber += lines.length - 1; - this._column = columns.length; - } - this._css.push(chunk); - }; - SourceMapOutput.prototype.isEmpty = function () { - return this._css.length === 0; - }; - SourceMapOutput.prototype.toCSS = function (context) { - this._sourceMapGenerator = new this._sourceMapGeneratorConstructor({ file: this._outputFilename, sourceRoot: null }); - if (this._outputSourceFiles) { - for (var filename in this._contentsMap) { - if (this._contentsMap.hasOwnProperty(filename)) { - var source = this._contentsMap[filename]; - if (this._contentsIgnoredCharsMap[filename]) { - source = source.slice(this._contentsIgnoredCharsMap[filename]); - } - this._sourceMapGenerator.setSourceContent(this.normalizeFilename(filename), source); - } - } - } - this._rootNode.genCSS(context, this); - if (this._css.length > 0) { - var sourceMapURL = void 0; - var sourceMapContent = JSON.stringify(this._sourceMapGenerator.toJSON()); - if (this.sourceMapURL) { - sourceMapURL = this.sourceMapURL; - } - else if (this._sourceMapFilename) { - sourceMapURL = this._sourceMapFilename; - } - this.sourceMapURL = sourceMapURL; - this.sourceMap = sourceMapContent; - } - return this._css.join(''); - }; - return SourceMapOutput; - }()); - return SourceMapOutput; - } - - function SourceMapBuilder (SourceMapOutput, environment) { - var SourceMapBuilder = /** @class */ (function () { - function SourceMapBuilder(options) { - this.options = options; - } - SourceMapBuilder.prototype.toCSS = function (rootNode, options, imports) { - var sourceMapOutput = new SourceMapOutput({ - contentsIgnoredCharsMap: imports.contentsIgnoredChars, - rootNode: rootNode, - contentsMap: imports.contents, - sourceMapFilename: this.options.sourceMapFilename, - sourceMapURL: this.options.sourceMapURL, - outputFilename: this.options.sourceMapOutputFilename, - sourceMapBasepath: this.options.sourceMapBasepath, - sourceMapRootpath: this.options.sourceMapRootpath, - outputSourceFiles: this.options.outputSourceFiles, - sourceMapGenerator: this.options.sourceMapGenerator, - sourceMapFileInline: this.options.sourceMapFileInline, - disableSourcemapAnnotation: this.options.disableSourcemapAnnotation - }); - var css = sourceMapOutput.toCSS(options); - this.sourceMap = sourceMapOutput.sourceMap; - this.sourceMapURL = sourceMapOutput.sourceMapURL; - if (this.options.sourceMapInputFilename) { - this.sourceMapInputFilename = sourceMapOutput.normalizeFilename(this.options.sourceMapInputFilename); - } - if (this.options.sourceMapBasepath !== undefined && this.sourceMapURL !== undefined) { - this.sourceMapURL = sourceMapOutput.removeBasepath(this.sourceMapURL); - } - return css + this.getCSSAppendage(); - }; - SourceMapBuilder.prototype.getCSSAppendage = function () { - var sourceMapURL = this.sourceMapURL; - if (this.options.sourceMapFileInline) { - if (this.sourceMap === undefined) { - return ''; - } - sourceMapURL = "data:application/json;base64," + environment.encodeBase64(this.sourceMap); - } - if (this.options.disableSourcemapAnnotation) { - return ''; - } - if (sourceMapURL) { - return "/*# sourceMappingURL=" + sourceMapURL + " */"; - } - return ''; - }; - SourceMapBuilder.prototype.getExternalSourceMap = function () { - return this.sourceMap; - }; - SourceMapBuilder.prototype.setExternalSourceMap = function (sourceMap) { - this.sourceMap = sourceMap; - }; - SourceMapBuilder.prototype.isInline = function () { - return this.options.sourceMapFileInline; - }; - SourceMapBuilder.prototype.getSourceMapURL = function () { - return this.sourceMapURL; - }; - SourceMapBuilder.prototype.getOutputFilename = function () { - return this.options.sourceMapOutputFilename; - }; - SourceMapBuilder.prototype.getInputFilename = function () { - return this.sourceMapInputFilename; - }; - return SourceMapBuilder; - }()); - return SourceMapBuilder; - } - - function ParseTree (SourceMapBuilder) { - var ParseTree = /** @class */ (function () { - function ParseTree(root, imports) { - this.root = root; - this.imports = imports; - } - ParseTree.prototype.toCSS = function (options) { - var evaldRoot; - var result = {}; - var sourceMapBuilder; - try { - evaldRoot = transformTree(this.root, options); - } - catch (e) { - throw new LessError(e, this.imports); - } - try { - var compress = Boolean(options.compress); - if (compress) { - logger$1.warn('The compress option has been deprecated. ' + - 'We recommend you use a dedicated css minifier, for instance see less-plugin-clean-css.'); - } - var toCSSOptions = { - compress: compress, - dumpLineNumbers: options.dumpLineNumbers, - strictUnits: Boolean(options.strictUnits), - numPrecision: 8 - }; - if (options.sourceMap) { - sourceMapBuilder = new SourceMapBuilder(options.sourceMap); - result.css = sourceMapBuilder.toCSS(evaldRoot, toCSSOptions, this.imports); - } - else { - result.css = evaldRoot.toCSS(toCSSOptions); - } - } - catch (e) { - throw new LessError(e, this.imports); - } - if (options.pluginManager) { - var postProcessors = options.pluginManager.getPostProcessors(); - for (var i = 0; i < postProcessors.length; i++) { - result.css = postProcessors[i].process(result.css, { sourceMap: sourceMapBuilder, options: options, imports: this.imports }); - } - } - if (options.sourceMap) { - result.map = sourceMapBuilder.getExternalSourceMap(); - } - result.imports = []; - for (var file in this.imports.files) { - if (this.imports.files.hasOwnProperty(file) && file !== this.imports.rootFilename) { - result.imports.push(file); - } - } - return result; - }; - return ParseTree; - }()); - return ParseTree; - } - - function ImportManager (environment) { - // FileInfo = { - // 'rewriteUrls' - option - whether to adjust URL's to be relative - // 'filename' - full resolved filename of current file - // 'rootpath' - path to append to normal URLs for this node - // 'currentDirectory' - path to the current file, absolute - // 'rootFilename' - filename of the base file - // 'entryPath' - absolute path to the entry file - // 'reference' - whether the file should not be output and only output parts that are referenced - var ImportManager = /** @class */ (function () { - function ImportManager(less, context, rootFileInfo) { - this.less = less; - this.rootFilename = rootFileInfo.filename; - this.paths = context.paths || []; // Search paths, when importing - this.contents = {}; // map - filename to contents of all the files - this.contentsIgnoredChars = {}; // map - filename to lines at the beginning of each file to ignore - this.mime = context.mime; - this.error = null; - this.context = context; - // Deprecated? Unused outside of here, could be useful. - this.queue = []; // Files which haven't been imported yet - this.files = {}; // Holds the imported parse trees. - } - /** - * Add an import to be imported - * @param path - the raw path - * @param tryAppendExtension - whether to try appending a file extension (.less or .js if the path has no extension) - * @param currentFileInfo - the current file info (used for instance to work out relative paths) - * @param importOptions - import options - * @param callback - callback for when it is imported - */ - ImportManager.prototype.push = function (path, tryAppendExtension, currentFileInfo, importOptions, callback) { - var importManager = this, pluginLoader = this.context.pluginManager.Loader; - this.queue.push(path); - var fileParsedFunc = function (e, root, fullPath) { - importManager.queue.splice(importManager.queue.indexOf(path), 1); // Remove the path from the queue - var importedEqualsRoot = fullPath === importManager.rootFilename; - if (importOptions.optional && e) { - callback(null, { rules: [] }, false, null); - logger$1.info("The file " + fullPath + " was skipped because it was not found and the import was marked optional."); - } - else { - // Inline imports aren't cached here. - // If we start to cache them, please make sure they won't conflict with non-inline imports of the - // same name as they used to do before this comment and the condition below have been added. - if (!importManager.files[fullPath] && !importOptions.inline) { - importManager.files[fullPath] = { root: root, options: importOptions }; - } - if (e && !importManager.error) { - importManager.error = e; - } - callback(e, root, importedEqualsRoot, fullPath); - } - }; - var newFileInfo = { - rewriteUrls: this.context.rewriteUrls, - entryPath: currentFileInfo.entryPath, - rootpath: currentFileInfo.rootpath, - rootFilename: currentFileInfo.rootFilename - }; - var fileManager = environment.getFileManager(path, currentFileInfo.currentDirectory, this.context, environment); - if (!fileManager) { - fileParsedFunc({ message: "Could not find a file-manager for " + path }); - return; - } - var loadFileCallback = function (loadedFile) { - var plugin; - var resolvedFilename = loadedFile.filename; - var contents = loadedFile.contents.replace(/^\uFEFF/, ''); - // Pass on an updated rootpath if path of imported file is relative and file - // is in a (sub|sup) directory - // - // Examples: - // - If path of imported file is 'module/nav/nav.less' and rootpath is 'less/', - // then rootpath should become 'less/module/nav/' - // - If path of imported file is '../mixins.less' and rootpath is 'less/', - // then rootpath should become 'less/../' - newFileInfo.currentDirectory = fileManager.getPath(resolvedFilename); - if (newFileInfo.rewriteUrls) { - newFileInfo.rootpath = fileManager.join((importManager.context.rootpath || ''), fileManager.pathDiff(newFileInfo.currentDirectory, newFileInfo.entryPath)); - if (!fileManager.isPathAbsolute(newFileInfo.rootpath) && fileManager.alwaysMakePathsAbsolute()) { - newFileInfo.rootpath = fileManager.join(newFileInfo.entryPath, newFileInfo.rootpath); - } - } - newFileInfo.filename = resolvedFilename; - var newEnv = new contexts.Parse(importManager.context); - newEnv.processImports = false; - importManager.contents[resolvedFilename] = contents; - if (currentFileInfo.reference || importOptions.reference) { - newFileInfo.reference = true; - } - if (importOptions.isPlugin) { - plugin = pluginLoader.evalPlugin(contents, newEnv, importManager, importOptions.pluginArgs, newFileInfo); - if (plugin instanceof LessError) { - fileParsedFunc(plugin, null, resolvedFilename); - } - else { - fileParsedFunc(null, plugin, resolvedFilename); - } - } - else if (importOptions.inline) { - fileParsedFunc(null, contents, resolvedFilename); - } - else { - // import (multiple) parse trees apparently get altered and can't be cached. - // TODO: investigate why this is - if (importManager.files[resolvedFilename] - && !importManager.files[resolvedFilename].options.multiple - && !importOptions.multiple) { - fileParsedFunc(null, importManager.files[resolvedFilename].root, resolvedFilename); - } - else { - new Parser(newEnv, importManager, newFileInfo).parse(contents, function (e, root) { - fileParsedFunc(e, root, resolvedFilename); - }); - } - } - }; - var loadedFile; - var promise; - var context = clone(this.context); - if (tryAppendExtension) { - context.ext = importOptions.isPlugin ? '.js' : '.less'; - } - if (importOptions.isPlugin) { - context.mime = 'application/javascript'; - if (context.syncImport) { - loadedFile = pluginLoader.loadPluginSync(path, currentFileInfo.currentDirectory, context, environment, fileManager); - } - else { - promise = pluginLoader.loadPlugin(path, currentFileInfo.currentDirectory, context, environment, fileManager); - } - } - else { - if (context.syncImport) { - loadedFile = fileManager.loadFileSync(path, currentFileInfo.currentDirectory, context, environment); - } - else { - promise = fileManager.loadFile(path, currentFileInfo.currentDirectory, context, environment, function (err, loadedFile) { - if (err) { - fileParsedFunc(err); - } - else { - loadFileCallback(loadedFile); - } - }); - } - } - if (loadedFile) { - if (!loadedFile.filename) { - fileParsedFunc(loadedFile); - } - else { - loadFileCallback(loadedFile); - } - } - else if (promise) { - promise.then(loadFileCallback, fileParsedFunc); - } - }; - return ImportManager; - }()); - return ImportManager; - } - - function Parse (environment, ParseTree, ImportManager) { - var parse = function (input, options, callback) { - if (typeof options === 'function') { - callback = options; - options = copyOptions(this.options, {}); - } - else { - options = copyOptions(this.options, options || {}); - } - if (!callback) { - var self_1 = this; - return new Promise(function (resolve, reject) { - parse.call(self_1, input, options, function (err, output) { - if (err) { - reject(err); - } - else { - resolve(output); - } - }); - }); - } - else { - var context_1; - var rootFileInfo = void 0; - var pluginManager_1 = new PluginManagerFactory(this, !options.reUsePluginManager); - options.pluginManager = pluginManager_1; - context_1 = new contexts.Parse(options); - if (options.rootFileInfo) { - rootFileInfo = options.rootFileInfo; - } - else { - var filename = options.filename || 'input'; - var entryPath = filename.replace(/[^\/\\]*$/, ''); - rootFileInfo = { - filename: filename, - rewriteUrls: context_1.rewriteUrls, - rootpath: context_1.rootpath || '', - currentDirectory: entryPath, - entryPath: entryPath, - rootFilename: filename - }; - // add in a missing trailing slash - if (rootFileInfo.rootpath && rootFileInfo.rootpath.slice(-1) !== '/') { - rootFileInfo.rootpath += '/'; - } - } - var imports_1 = new ImportManager(this, context_1, rootFileInfo); - this.importManager = imports_1; - // TODO: allow the plugins to be just a list of paths or names - // Do an async plugin queue like lessc - if (options.plugins) { - options.plugins.forEach(function (plugin) { - var evalResult, contents; - if (plugin.fileContent) { - contents = plugin.fileContent.replace(/^\uFEFF/, ''); - evalResult = pluginManager_1.Loader.evalPlugin(contents, context_1, imports_1, plugin.options, plugin.filename); - if (evalResult instanceof LessError) { - return callback(evalResult); - } - } - else { - pluginManager_1.addPlugin(plugin); - } - }); - } - new Parser(context_1, imports_1, rootFileInfo) - .parse(input, function (e, root) { - if (e) { - return callback(e); - } - callback(null, root, imports_1, options); - }, options); - } - }; - return parse; - } - - function Render (environment, ParseTree, ImportManager) { - var render = function (input, options, callback) { - if (typeof options === 'function') { - callback = options; - options = copyOptions(this.options, {}); - } - else { - options = copyOptions(this.options, options || {}); - } - if (!callback) { - var self_1 = this; - return new Promise(function (resolve, reject) { - render.call(self_1, input, options, function (err, output) { - if (err) { - reject(err); - } - else { - resolve(output); - } - }); - }); - } - else { - this.parse(input, options, function (err, root, imports, options) { - if (err) { - return callback(err); - } - var result; - try { - var parseTree = new ParseTree(root, imports); - result = parseTree.toCSS(options); - } - catch (err) { - return callback(err); - } - callback(null, result); - }); - } - }; - return render; - } - - var version = "4.1.3"; - - function parseNodeVersion(version) { - var match = version.match(/^v(\d{1,2})\.(\d{1,2})\.(\d{1,2})(?:-([0-9A-Za-z-.]+))?(?:\+([0-9A-Za-z-.]+))?$/); // eslint-disable-line max-len - if (!match) { - throw new Error('Unable to parse: ' + version); - } - - var res = { - major: parseInt(match[1], 10), - minor: parseInt(match[2], 10), - patch: parseInt(match[3], 10), - pre: match[4] || '', - build: match[5] || '', - }; - - return res; - } - - var parseNodeVersion_1 = parseNodeVersion; - - function lessRoot (environment, fileManagers) { - var sourceMapOutput, sourceMapBuilder, parseTree, importManager; - environment = new Environment(environment, fileManagers); - sourceMapOutput = SourceMapOutput(environment); - sourceMapBuilder = SourceMapBuilder(sourceMapOutput, environment); - parseTree = ParseTree(sourceMapBuilder); - importManager = ImportManager(environment); - var render = Render(environment, parseTree); - var parse = Parse(environment, parseTree, importManager); - var v = parseNodeVersion_1("v" + version); - var initial = { - version: [v.major, v.minor, v.patch], - data: data, - tree: tree, - Environment: Environment, - AbstractFileManager: AbstractFileManager, - AbstractPluginLoader: AbstractPluginLoader, - environment: environment, - visitors: visitors, - Parser: Parser, - functions: functions(environment), - contexts: contexts, - SourceMapOutput: sourceMapOutput, - SourceMapBuilder: sourceMapBuilder, - ParseTree: parseTree, - ImportManager: importManager, - render: render, - parse: parse, - LessError: LessError, - transformTree: transformTree, - utils: utils, - PluginManager: PluginManagerFactory, - logger: logger$1 - }; - // Create a public API - var ctor = function (t) { - return function () { - var obj = Object.create(t.prototype); - t.apply(obj, Array.prototype.slice.call(arguments, 0)); - return obj; - }; - }; - var t; - var api = Object.create(initial); - for (var n in initial.tree) { - /* eslint guard-for-in: 0 */ - t = initial.tree[n]; - if (typeof t === 'function') { - api[n.toLowerCase()] = ctor(t); - } - else { - api[n] = Object.create(null); - for (var o in t) { - /* eslint guard-for-in: 0 */ - api[n][o.toLowerCase()] = ctor(t[o]); - } - } - } - /** - * Some of the functions assume a `this` context of the API object, - * which causes it to fail when wrapped for ES6 imports. - * - * An assumed `this` should be removed in the future. - */ - initial.parse = initial.parse.bind(api); - initial.render = initial.render.bind(api); - return api; - } - - /* global window, XMLHttpRequest */ - var options$1; - var logger; - var fileCache = {}; - // TODOS - move log somewhere. pathDiff and doing something similar in node. use pathDiff in the other browser file for the initial load - var FileManager = function () { }; - FileManager.prototype = Object.assign(new AbstractFileManager(), { - alwaysMakePathsAbsolute: function () { - return true; - }, - join: function (basePath, laterPath) { - if (!basePath) { - return laterPath; - } - return this.extractUrlParts(laterPath, basePath).path; - }, - doXHR: function (url, type, callback, errback) { - var xhr = new XMLHttpRequest(); - var async = options$1.isFileProtocol ? options$1.fileAsync : true; - if (typeof xhr.overrideMimeType === 'function') { - xhr.overrideMimeType('text/css'); - } - logger.debug("XHR: Getting '" + url + "'"); - xhr.open('GET', url, async); - xhr.setRequestHeader('Accept', type || 'text/x-less, text/css; q=0.9, */*; q=0.5'); - xhr.send(null); - function handleResponse(xhr, callback, errback) { - if (xhr.status >= 200 && xhr.status < 300) { - callback(xhr.responseText, xhr.getResponseHeader('Last-Modified')); - } - else if (typeof errback === 'function') { - errback(xhr.status, url); - } - } - if (options$1.isFileProtocol && !options$1.fileAsync) { - if (xhr.status === 0 || (xhr.status >= 200 && xhr.status < 300)) { - callback(xhr.responseText); - } - else { - errback(xhr.status, url); - } - } - else if (async) { - xhr.onreadystatechange = function () { - if (xhr.readyState == 4) { - handleResponse(xhr, callback, errback); - } - }; - } - else { - handleResponse(xhr, callback, errback); - } - }, - supports: function () { - return true; - }, - clearFileCache: function () { - fileCache = {}; - }, - loadFile: function (filename, currentDirectory, options, environment) { - // TODO: Add prefix support like less-node? - // What about multiple paths? - if (currentDirectory && !this.isPathAbsolute(filename)) { - filename = currentDirectory + filename; - } - filename = options.ext ? this.tryAppendExtension(filename, options.ext) : filename; - options = options || {}; - // sheet may be set to the stylesheet for the initial load or a collection of properties including - // some context variables for imports - var hrefParts = this.extractUrlParts(filename, window.location.href); - var href = hrefParts.url; - var self = this; - return new Promise(function (resolve, reject) { - if (options.useFileCache && fileCache[href]) { - try { - var lessText = fileCache[href]; - return resolve({ contents: lessText, filename: href, webInfo: { lastModified: new Date() } }); - } - catch (e) { - return reject({ filename: href, message: "Error loading file " + href + " error was " + e.message }); - } - } - self.doXHR(href, options.mime, function doXHRCallback(data, lastModified) { - // per file cache - fileCache[href] = data; - // Use remote copy (re-parse) - resolve({ contents: data, filename: href, webInfo: { lastModified: lastModified } }); - }, function doXHRError(status, url) { - reject({ type: 'File', message: "'" + url + "' wasn't found (" + status + ")", href: href }); - }); - }); - } - }); - var FM = (function (opts, log) { - options$1 = opts; - logger = log; - return FileManager; - }); - - // TODO: Add tests for browser @plugin - /** - * Browser Plugin Loader - */ - var PluginLoader = function (less) { - this.less = less; - // Should we shim this.require for browser? Probably not? - }; - PluginLoader.prototype = Object.assign(new AbstractPluginLoader(), { - loadPlugin: function (filename, basePath, context, environment, fileManager) { - return new Promise(function (fulfill, reject) { - fileManager.loadFile(filename, basePath, context, environment) - .then(fulfill).catch(reject); - }); - } - }); - - var LogListener = (function (less, options) { - var logLevel_debug = 4; - var logLevel_info = 3; - var logLevel_warn = 2; - var logLevel_error = 1; - // The amount of logging in the javascript console. - // 3 - Debug, information and errors - // 2 - Information and errors - // 1 - Errors - // 0 - None - // Defaults to 2 - options.logLevel = typeof options.logLevel !== 'undefined' ? options.logLevel : (options.env === 'development' ? logLevel_info : logLevel_error); - if (!options.loggers) { - options.loggers = [{ - debug: function (msg) { - if (options.logLevel >= logLevel_debug) { - console.log(msg); - } - }, - info: function (msg) { - if (options.logLevel >= logLevel_info) { - console.log(msg); - } - }, - warn: function (msg) { - if (options.logLevel >= logLevel_warn) { - console.warn(msg); - } - }, - error: function (msg) { - if (options.logLevel >= logLevel_error) { - console.error(msg); - } - } - }]; - } - for (var i = 0; i < options.loggers.length; i++) { - less.logger.addListener(options.loggers[i]); - } - }); - - var ErrorReporting = (function (window, less, options) { - function errorHTML(e, rootHref) { - var id = "less-error-message:" + extractId(rootHref || ''); - var template = '
    • {content}
    • '; - var elem = window.document.createElement('div'); - var timer; - var content; - var errors = []; - var filename = e.filename || rootHref; - var filenameNoPath = filename.match(/([^\/]+(\?.*)?)$/)[1]; - elem.id = id; - elem.className = 'less-error-message'; - content = "

      " + (e.type || 'Syntax') + "Error: " + (e.message || 'There is an error in your .less file') + - ("

      in " + filenameNoPath + " "); - var errorline = function (e, i, classname) { - if (e.extract[i] !== undefined) { - errors.push(template.replace(/\{line\}/, (parseInt(e.line, 10) || 0) + (i - 1)) - .replace(/\{class\}/, classname) - .replace(/\{content\}/, e.extract[i])); - } - }; - if (e.line) { - errorline(e, 0, ''); - errorline(e, 1, 'line'); - errorline(e, 2, ''); - content += "on line " + e.line + ", column " + (e.column + 1) + ":

        " + errors.join('') + "
      "; - } - if (e.stack && (e.extract || options.logLevel >= 4)) { - content += "
      Stack Trace
      " + e.stack.split('\n').slice(1).join('
      '); - } - elem.innerHTML = content; - // CSS for error messages - browser.createCSS(window.document, [ - '.less-error-message ul, .less-error-message li {', - 'list-style-type: none;', - 'margin-right: 15px;', - 'padding: 4px 0;', - 'margin: 0;', - '}', - '.less-error-message label {', - 'font-size: 12px;', - 'margin-right: 15px;', - 'padding: 4px 0;', - 'color: #cc7777;', - '}', - '.less-error-message pre {', - 'color: #dd6666;', - 'padding: 4px 0;', - 'margin: 0;', - 'display: inline-block;', - '}', - '.less-error-message pre.line {', - 'color: #ff0000;', - '}', - '.less-error-message h3 {', - 'font-size: 20px;', - 'font-weight: bold;', - 'padding: 15px 0 5px 0;', - 'margin: 0;', - '}', - '.less-error-message a {', - 'color: #10a', - '}', - '.less-error-message .error {', - 'color: red;', - 'font-weight: bold;', - 'padding-bottom: 2px;', - 'border-bottom: 1px dashed red;', - '}' - ].join('\n'), { title: 'error-message' }); - elem.style.cssText = [ - 'font-family: Arial, sans-serif', - 'border: 1px solid #e00', - 'background-color: #eee', - 'border-radius: 5px', - '-webkit-border-radius: 5px', - '-moz-border-radius: 5px', - 'color: #e00', - 'padding: 15px', - 'margin-bottom: 15px' - ].join(';'); - if (options.env === 'development') { - timer = setInterval(function () { - var document = window.document; - var body = document.body; - if (body) { - if (document.getElementById(id)) { - body.replaceChild(elem, document.getElementById(id)); - } - else { - body.insertBefore(elem, body.firstChild); - } - clearInterval(timer); - } - }, 10); - } - } - function removeErrorHTML(path) { - var node = window.document.getElementById("less-error-message:" + extractId(path)); - if (node) { - node.parentNode.removeChild(node); - } - } - function removeError(path) { - if (!options.errorReporting || options.errorReporting === 'html') { - removeErrorHTML(path); - } - else if (options.errorReporting === 'console') ; - else if (typeof options.errorReporting === 'function') { - options.errorReporting('remove', path); - } - } - function errorConsole(e, rootHref) { - var template = '{line} {content}'; - var filename = e.filename || rootHref; - var errors = []; - var content = (e.type || 'Syntax') + "Error: " + (e.message || 'There is an error in your .less file') + " in " + filename; - var errorline = function (e, i, classname) { - if (e.extract[i] !== undefined) { - errors.push(template.replace(/\{line\}/, (parseInt(e.line, 10) || 0) + (i - 1)) - .replace(/\{class\}/, classname) - .replace(/\{content\}/, e.extract[i])); - } - }; - if (e.line) { - errorline(e, 0, ''); - errorline(e, 1, 'line'); - errorline(e, 2, ''); - content += " on line " + e.line + ", column " + (e.column + 1) + ":\n" + errors.join('\n'); - } - if (e.stack && (e.extract || options.logLevel >= 4)) { - content += "\nStack Trace\n" + e.stack; - } - less.logger.error(content); - } - function error(e, rootHref) { - if (!options.errorReporting || options.errorReporting === 'html') { - errorHTML(e, rootHref); - } - else if (options.errorReporting === 'console') { - errorConsole(e, rootHref); - } - else if (typeof options.errorReporting === 'function') { - options.errorReporting('add', e, rootHref); - } - } - return { - add: error, - remove: removeError - }; - }); - - // Cache system is a bit outdated and could do with work - var Cache = (function (window, options, logger) { - var cache = null; - if (options.env !== 'development') { - try { - cache = (typeof window.localStorage === 'undefined') ? null : window.localStorage; - } - catch (_) { } - } - return { - setCSS: function (path, lastModified, modifyVars, styles) { - if (cache) { - logger.info("saving " + path + " to cache."); - try { - cache.setItem(path, styles); - cache.setItem(path + ":timestamp", lastModified); - if (modifyVars) { - cache.setItem(path + ":vars", JSON.stringify(modifyVars)); - } - } - catch (e) { - // TODO - could do with adding more robust error handling - logger.error("failed to save \"" + path + "\" to local storage for caching."); - } - } - }, - getCSS: function (path, webInfo, modifyVars) { - var css = cache && cache.getItem(path); - var timestamp = cache && cache.getItem(path + ":timestamp"); - var vars = cache && cache.getItem(path + ":vars"); - modifyVars = modifyVars || {}; - vars = vars || "{}"; // if not set, treat as the JSON representation of an empty object - if (timestamp && webInfo.lastModified && - (new Date(webInfo.lastModified).valueOf() === - new Date(timestamp).valueOf()) && - JSON.stringify(modifyVars) === vars) { - // Use local copy - return css; - } - } - }; - }); - - var ImageSize = (function () { - function imageSize() { - throw { - type: 'Runtime', - message: 'Image size functions are not supported in browser version of less' - }; - } - var imageFunctions = { - 'image-size': function (filePathNode) { - imageSize(); - return -1; - }, - 'image-width': function (filePathNode) { - imageSize(); - return -1; - }, - 'image-height': function (filePathNode) { - imageSize(); - return -1; - } - }; - functionRegistry.addMultiple(imageFunctions); - }); - - // - var root = (function (window, options) { - var document = window.document; - var less = lessRoot(); - less.options = options; - var environment = less.environment; - var FileManager = FM(options, less.logger); - var fileManager = new FileManager(); - environment.addFileManager(fileManager); - less.FileManager = FileManager; - less.PluginLoader = PluginLoader; - LogListener(less, options); - var errors = ErrorReporting(window, less, options); - var cache = less.cache = options.cache || Cache(window, options, less.logger); - ImageSize(less.environment); - // Setup user functions - Deprecate? - if (options.functions) { - less.functions.functionRegistry.addMultiple(options.functions); - } - var typePattern = /^text\/(x-)?less$/; - function clone(obj) { - var cloned = {}; - for (var prop in obj) { - if (obj.hasOwnProperty(prop)) { - cloned[prop] = obj[prop]; - } - } - return cloned; - } - // only really needed for phantom - function bind(func, thisArg) { - var curryArgs = Array.prototype.slice.call(arguments, 2); - return function () { - var args = curryArgs.concat(Array.prototype.slice.call(arguments, 0)); - return func.apply(thisArg, args); - }; - } - function loadStyles(modifyVars) { - var styles = document.getElementsByTagName('style'); - var style; - for (var i = 0; i < styles.length; i++) { - style = styles[i]; - if (style.type.match(typePattern)) { - var instanceOptions = clone(options); - instanceOptions.modifyVars = modifyVars; - var lessText = style.innerHTML || ''; - instanceOptions.filename = document.location.href.replace(/#.*$/, ''); - /* jshint loopfunc:true */ - // use closure to store current style - less.render(lessText, instanceOptions, bind(function (style, e, result) { - if (e) { - errors.add(e, 'inline'); - } - else { - style.type = 'text/css'; - if (style.styleSheet) { - style.styleSheet.cssText = result.css; - } - else { - style.innerHTML = result.css; - } - } - }, null, style)); - } - } - } - function loadStyleSheet(sheet, callback, reload, remaining, modifyVars) { - var instanceOptions = clone(options); - addDataAttr(instanceOptions, sheet); - instanceOptions.mime = sheet.type; - if (modifyVars) { - instanceOptions.modifyVars = modifyVars; - } - function loadInitialFileCallback(loadedFile) { - var data = loadedFile.contents; - var path = loadedFile.filename; - var webInfo = loadedFile.webInfo; - var newFileInfo = { - currentDirectory: fileManager.getPath(path), - filename: path, - rootFilename: path, - rewriteUrls: instanceOptions.rewriteUrls - }; - newFileInfo.entryPath = newFileInfo.currentDirectory; - newFileInfo.rootpath = instanceOptions.rootpath || newFileInfo.currentDirectory; - if (webInfo) { - webInfo.remaining = remaining; - var css = cache.getCSS(path, webInfo, instanceOptions.modifyVars); - if (!reload && css) { - webInfo.local = true; - callback(null, css, data, sheet, webInfo, path); - return; - } - } - // TODO add tests around how this behaves when reloading - errors.remove(path); - instanceOptions.rootFileInfo = newFileInfo; - less.render(data, instanceOptions, function (e, result) { - if (e) { - e.href = path; - callback(e); - } - else { - cache.setCSS(sheet.href, webInfo.lastModified, instanceOptions.modifyVars, result.css); - callback(null, result.css, data, sheet, webInfo, path); - } - }); - } - fileManager.loadFile(sheet.href, null, instanceOptions, environment) - .then(function (loadedFile) { - loadInitialFileCallback(loadedFile); - }).catch(function (err) { - console.log(err); - callback(err); - }); - } - function loadStyleSheets(callback, reload, modifyVars) { - for (var i = 0; i < less.sheets.length; i++) { - loadStyleSheet(less.sheets[i], callback, reload, less.sheets.length - (i + 1), modifyVars); - } - } - function initRunningMode() { - if (less.env === 'development') { - less.watchTimer = setInterval(function () { - if (less.watchMode) { - fileManager.clearFileCache(); - loadStyleSheets(function (e, css, _, sheet, webInfo) { - if (e) { - errors.add(e, e.href || sheet.href); - } - else if (css) { - browser.createCSS(window.document, css, sheet); - } - }); - } - }, options.poll); - } - } - // - // Watch mode - // - less.watch = function () { - if (!less.watchMode) { - less.env = 'development'; - initRunningMode(); - } - this.watchMode = true; - return true; - }; - less.unwatch = function () { clearInterval(less.watchTimer); this.watchMode = false; return false; }; - // - // Synchronously get all tags with the 'rel' attribute set to - // "stylesheet/less". - // - less.registerStylesheetsImmediately = function () { - var links = document.getElementsByTagName('link'); - less.sheets = []; - for (var i = 0; i < links.length; i++) { - if (links[i].rel === 'stylesheet/less' || (links[i].rel.match(/stylesheet/) && - (links[i].type.match(typePattern)))) { - less.sheets.push(links[i]); - } - } - }; - // - // Asynchronously get all tags with the 'rel' attribute set to - // "stylesheet/less", returning a Promise. - // - less.registerStylesheets = function () { return new Promise(function (resolve, reject) { - less.registerStylesheetsImmediately(); - resolve(); - }); }; - // - // With this function, it's possible to alter variables and re-render - // CSS without reloading less-files - // - less.modifyVars = function (record) { return less.refresh(true, record, false); }; - less.refresh = function (reload, modifyVars, clearFileCache) { - if ((reload || clearFileCache) && clearFileCache !== false) { - fileManager.clearFileCache(); - } - return new Promise(function (resolve, reject) { - var startTime; - var endTime; - var totalMilliseconds; - var remainingSheets; - startTime = endTime = new Date(); - // Set counter for remaining unprocessed sheets - remainingSheets = less.sheets.length; - if (remainingSheets === 0) { - endTime = new Date(); - totalMilliseconds = endTime - startTime; - less.logger.info('Less has finished and no sheets were loaded.'); - resolve({ - startTime: startTime, - endTime: endTime, - totalMilliseconds: totalMilliseconds, - sheets: less.sheets.length - }); - } - else { - // Relies on less.sheets array, callback seems to be guaranteed to be called for every element of the array - loadStyleSheets(function (e, css, _, sheet, webInfo) { - if (e) { - errors.add(e, e.href || sheet.href); - reject(e); - return; - } - if (webInfo.local) { - less.logger.info("Loading " + sheet.href + " from cache."); - } - else { - less.logger.info("Rendered " + sheet.href + " successfully."); - } - browser.createCSS(window.document, css, sheet); - less.logger.info("CSS for " + sheet.href + " generated in " + (new Date() - endTime) + "ms"); - // Count completed sheet - remainingSheets--; - // Check if the last remaining sheet was processed and then call the promise - if (remainingSheets === 0) { - totalMilliseconds = new Date() - startTime; - less.logger.info("Less has finished. CSS generated in " + totalMilliseconds + "ms"); - resolve({ - startTime: startTime, - endTime: endTime, - totalMilliseconds: totalMilliseconds, - sheets: less.sheets.length - }); - } - endTime = new Date(); - }, reload, modifyVars); - } - loadStyles(modifyVars); - }); - }; - less.refreshStyles = loadStyles; - return less; - }); - - /** - * Kicks off less and compiles any stylesheets - * used in the browser distributed version of less - * to kick-start less using the browser api - */ - var options = defaultOptions(); - if (window.less) { - for (var key in window.less) { - if (window.less.hasOwnProperty(key)) { - options[key] = window.less[key]; - } - } - } - addDefaultOptions(window, options); - options.plugins = options.plugins || []; - if (window.LESS_PLUGINS) { - options.plugins = options.plugins.concat(window.LESS_PLUGINS); - } - var less = root(window, options); - window.less = less; - var css; - var head; - var style; - // Always restore page visibility - function resolveOrReject(data) { - if (data.filename) { - console.warn(data); - } - if (!options.async) { - head.removeChild(style); - } - } - if (options.onReady) { - if (/!watch/.test(window.location.hash)) { - less.watch(); - } - // Simulate synchronous stylesheet loading by hiding page rendering - if (!options.async) { - css = 'body { display: none !important }'; - head = document.head || document.getElementsByTagName('head')[0]; - style = document.createElement('style'); - style.type = 'text/css'; - if (style.styleSheet) { - style.styleSheet.cssText = css; - } - else { - style.appendChild(document.createTextNode(css)); - } - head.appendChild(style); - } - less.registerStylesheetsImmediately(); - less.pageLoadFinished = less.refresh(less.env === 'development').then(resolveOrReject, resolveOrReject); - } - - return less; - -}))); diff --git a/web/static/src/css-variables.css b/web/static/src/css-variables.css deleted file mode 100644 index 887dc9d..0000000 --- a/web/static/src/css-variables.css +++ /dev/null @@ -1,202 +0,0 @@ -:root{ - /* =====色板===== */ - /*常量,不随明暗主题变化*/ - --color-white: #FFFFFF; - --color-black: #000000; - - --lay-color-white: #FAFAFA; - --lay-color-black: #333333; - - --lay-color-red-1: #FFF1E8; - --lay-color-red-2: #FFD7C0; - --lay-color-red-3: #FFBB99; - --lay-color-red-4: #FF9C71; - --lay-color-red-5: #FF7A4A; - --lay-color-red-6: #FF5722; - --lay-color-red-7: #D23B15; - --lay-color-red-8: #A6250B; - --lay-color-red-9: #791404; - --lay-color-red-10: #4D0800; - - --lay-color-blue-1: #E8F9FF; - --lay-color-blue-2: #C0ECFF; - --lay-color-blue-3: #97DCFF; - --lay-color-blue-4: #6FCAFF; - --lay-color-blue-5: #46B5FF; - --lay-color-blue-6: #1E9FFF; - --lay-color-blue-7: #1379D2; - --lay-color-blue-8: #0A58A6; - --lay-color-blue-9: #043A79; - --lay-color-blue-10: #00214D; - - --lay-color-lightblue-1: #E8FDFF; - --lay-color-lightblue-2: #C1F4FB; - --lay-color-lightblue-3: #9CEAF7; - --lay-color-lightblue-4: #77DDF4; - --lay-color-lightblue-5: #53CEF0; - --lay-color-lightblue-6: #31BDEC; - --lay-color-lightblue-7: #1F95C4; - --lay-color-lightblue-8: #10709C; - --lay-color-lightblue-9: #064E74; - --lay-color-lightblue-10: #002F4D; - - --lay-color-layuigreen-1: #E8FFF9; - --lay-color-layuigreen-2: #B5F1E3; - --lay-color-layuigreen-3: #87E3D1; - --lay-color-layuigreen-4: #5DD6C1; - --lay-color-layuigreen-5: #37C8B5; - --lay-color-layuigreen-6: #16BAAA; - --lay-color-layuigreen-7: #0E9F95; - --lay-color-layuigreen-8: #08837F; - --lay-color-layuigreen-9: #036868; - --lay-color-layuigreen-10: #004A4D; - - --lay-color-green-1: #E8FFF2; - --lay-color-green-2: #B5F1D1; - --lay-color-green-3: #86E2B4; - --lay-color-green-4: #5CD49C; - --lay-color-green-5: #37C588; - --lay-color-green-6: #16B777; - --lay-color-green-7: #0E9C68; - --lay-color-green-8: #088259; - --lay-color-green-9: #036749; - --lay-color-green-10: #004D38; - - --lay-color-orange-1: #FFFCE8; - --lay-color-orange-2: #FFF5BA; - --lay-color-orange-3: #FFEA8B; - --lay-color-orange-4: #FFDC5D; - --lay-color-orange-5: #FFCB2E; - --lay-color-orange-6: #FFB800; - --lay-color-orange-7: #D29000; - --lay-color-orange-8: #A66C00; - --lay-color-orange-9: #794B00; - --lay-color-orange-10: #4D2D00; - - --lay-color-cyan-1: #E8F6FF; - --lay-color-cyan-2: #B9CEDD; - --lay-color-cyan-3: #8FA7BB; - --lay-color-cyan-4: #6A829A; - --lay-color-cyan-5: #4A5F78; - --lay-color-cyan-6: #2F4056; - --lay-color-cyan-7: #223654; - --lay-color-cyan-8: #162C51; - --lay-color-cyan-9: #0B214F; - --lay-color-cyan-10: #00174D; - - --lay-color-purple-1: #FDE8FF; - --lay-color-purple-2: #EDBEF4; - --lay-color-purple-3: #DC97E8; - --lay-color-purple-4: #C972DD; - --lay-color-purple-5: #B651D1; - --lay-color-purple-6: #A233C6; - --lay-color-purple-7: #8120A8; - --lay-color-purple-8: #631289; - --lay-color-purple-9: #48076B; - --lay-color-purple-10: #2F004D; - - --lay-color-black-1: #E8F8FF; - --lay-color-black-2: #BFD0D8; - --lay-color-black-3: #98A8B1; - --lay-color-black-4: #73818A; - --lay-color-black-5: #505B63; - --lay-color-black-6: #2F363C; - --lay-color-black-7: #23303C; - --lay-color-black-8: #18293C; - --lay-color-black-9: #0C213C; - --lay-color-black-10: #00183C; - - --lay-color-gray-1: #FAFAFA; - --lay-color-gray-2: #F6F6F6; - --lay-color-gray-3: #EEEEEE; - --lay-color-gray-4: #E2E2E2; - --lay-color-gray-5: #DDDDDD; - --lay-color-gray-6: #D2D2D2; - --lay-color-gray-7: #CCCCCC; - --lay-color-gray-8: #C2C2C2; - --lay-color-gray-9: #AAAAAA; - --lay-color-gray-10: #939393; - - --lay-color-gray-11: #858585; - --lay-color-gray-12: #7b7b7b; - --lay-color-gray-13: #686868; - - /* =====语义===== */ - /* 主色 */ - --lay-color-primary: var(--lay-color-layuigreen-6); - --lay-color-primary-hover: var(--lay-color-layuigreen-5); - --lay-color-primary-active: var(--lay-color-layuigreen-7); - --lay-color-primary-disabled: var(--lay-color-layuigreen-3); - --lay-color-primary-light: var(--lay-color-layuigreen-4); - - /* 次色 */ - --lay-color-secondary: var(--lay-color-green-6); - --lay-color-secondary-hover: var(--lay-color-green-5); - --lay-color-secondary-active: var(--lay-color-green-7); - --lay-color-secondary-disabled: var(--lay-color-green-3); - --lay-color-secondary-light: var(--lay-color-green-4); - - /* 引导 */ - --lay-color-info: var(--lay-color-lightblue-6); - --lay-color-info-hover: var(--lay-color-lightblue-5); - --lay-color-info-active: var(--lay-color-lightblue-7); - --lay-color-info-disabled: var(--lay-color-lightblue-3); - --lay-color-info-light: var(--lay-color-lightblue-4); - - /* 百搭 */ - --lay-color-normal: var(--lay-color-blue-6); - --lay-color-normal-hover: var(--lay-color-blue-5); - --lay-color-normal-active: var(--lay-color-blue-7); - --lay-color-normal-disabled: var(--lay-color-blue-3); - --lay-color-normal-light: var(--lay-color-blue-4); - - /* 警示 */ - --lay-color-warning: var(--lay-color-orange-6); - --lay-color-warning-hover: var(--lay-color-orange-5); - --lay-color-warning-active: var(--lay-color-orange-7); - --lay-color-warning-disabled: var(--lay-color-orange-3); - --lay-color-warning-light: var(--lay-color-orange-4); - - /* 成功 */ - --lay-color-success: var(--lay-color-green-6); - --lay-color-success-hover: var(--lay-color-green-5); - --lay-color-success-active: var(--lay-color-green-7); - --lay-color-success-disabled: var(--lay-color-green-3); - --lay-color-success-light: var(--lay-color-green-4); - - /* 错误 */ - --lay-color-danger: var(--lay-color-red-6); - --lay-color-danger-hover: var(--lay-color-red-5); - --lay-color-danger-active: var(--lay-color-red-7); - --lay-color-danger-disabled: var(--lay-color-red-3); - --lay-color-danger-light: var(--lay-color-red-4); - - --lay-color-bg-1: #17171A; /*整体背景*/ - --lay-color-bg-2: #232324; /*一级容器背景,卡片,面板*/ - --lay-color-bg-3: #2a2a2b; /*二级容器背景*/ - --lay-color-bg-4: #313132; /*三级容器背景*/ - --lay-color-bg-5: #373739; /*下拉弹出框、Tooltip 背景颜色*/ - --lay-color-bg-white: #f6f6f6; /*白色背景*/ - - --lay-color-text-1: rgba(255,255,255,.9); /*强调/正文标题*/ - --lay-color-text-2: rgba(255,255,255,.7); /*次强调/语句*/ - --lay-color-text-3: rgba(255,255,255,.5); /*次要信息*/ - --lay-color-text-4: rgba(255,255,255,.3);/*禁用状态文字 */ - - --lay-color-border-1: #2e2e30; - --lay-color-border-2: #484849; - --lay-color-border-3: #5f5f60; - --lay-color-border-4: #929293; - - --lay-color-fill-1: rgba(255,255,255,.04);/*浅/禁用*/ - --lay-color-fill-2: rgba(255,255,255,.08);/*常规/白底悬浮*/ - --lay-color-fill-3: rgba(255,255,255,.12); /*深/灰底悬浮*/ - --lay-color-fill-4: rgba(255,255,255,.16);/*重/特殊场景*/ - - --lay-color-hover: var(--lay-color-fill-3); /*bg*/ - --lay-color-active: var(--lay-color-fill-3); /*bg*/ - - --lay-shadow-1: 0 4px 6px rgba(0, 0, 0, 6%), 0 1px 10px rgba(0, 0, 0, 8%), 0 2px 4px rgba(0, 0, 0, 12%);/*基础/下层投影 卡片面板*/ - --lay-shadow-2: 0 8px 10px rgba(0, 0, 0, 12%), 0 3px 14px rgba(0, 0, 0, 10%), 0 5px 5px rgba(0, 0, 0, 16%);/*中层投影 下拉菜单,选择器*/ - --lay-shadow-3: 0 16px 24px rgba(0, 0, 0, 14%), 0 6px 30px rgba(0, 0, 0, 12%), 0 8px 10px rgba(0, 0, 0, 20%);/*上层投影 弹窗*/ -} diff --git a/web/static/src/layui-theme-dark-selector.css b/web/static/src/layui-theme-dark-selector.css deleted file mode 100644 index 070de96..0000000 --- a/web/static/src/layui-theme-dark-selector.css +++ /dev/null @@ -1,1899 +0,0 @@ -:root.dark { - --color-white: #FFFFFF; - --color-black: #000000; - --lay-color-white: #FAFAFA; - --lay-color-black: #333333; - --lay-color-red-1: #FFF1E8; - --lay-color-red-2: #FFD7C0; - --lay-color-red-3: #FFBB99; - --lay-color-red-4: #FF9C71; - --lay-color-red-5: #FF7A4A; - --lay-color-red-6: #FF5722; - --lay-color-red-7: #D23B15; - --lay-color-red-8: #A6250B; - --lay-color-red-9: #791404; - --lay-color-red-10: #4D0800; - --lay-color-blue-1: #E8F9FF; - --lay-color-blue-2: #C0ECFF; - --lay-color-blue-3: #97DCFF; - --lay-color-blue-4: #6FCAFF; - --lay-color-blue-5: #46B5FF; - --lay-color-blue-6: #1E9FFF; - --lay-color-blue-7: #1379D2; - --lay-color-blue-8: #0A58A6; - --lay-color-blue-9: #043A79; - --lay-color-blue-10: #00214D; - --lay-color-lightblue-1: #E8FDFF; - --lay-color-lightblue-2: #C1F4FB; - --lay-color-lightblue-3: #9CEAF7; - --lay-color-lightblue-4: #77DDF4; - --lay-color-lightblue-5: #53CEF0; - --lay-color-lightblue-6: #31BDEC; - --lay-color-lightblue-7: #1F95C4; - --lay-color-lightblue-8: #10709C; - --lay-color-lightblue-9: #064E74; - --lay-color-lightblue-10: #002F4D; - --lay-color-layuigreen-1: #E8FFF9; - --lay-color-layuigreen-2: #B5F1E3; - --lay-color-layuigreen-3: #87E3D1; - --lay-color-layuigreen-4: #5DD6C1; - --lay-color-layuigreen-5: #37C8B5; - --lay-color-layuigreen-6: #16BAAA; - --lay-color-layuigreen-7: #0E9F95; - --lay-color-layuigreen-8: #08837F; - --lay-color-layuigreen-9: #036868; - --lay-color-layuigreen-10: #004A4D; - --lay-color-green-1: #E8FFF2; - --lay-color-green-2: #B5F1D1; - --lay-color-green-3: #86E2B4; - --lay-color-green-4: #5CD49C; - --lay-color-green-5: #37C588; - --lay-color-green-6: #16B777; - --lay-color-green-7: #0E9C68; - --lay-color-green-8: #088259; - --lay-color-green-9: #036749; - --lay-color-green-10: #004D38; - --lay-color-orange-1: #FFFCE8; - --lay-color-orange-2: #FFF5BA; - --lay-color-orange-3: #FFEA8B; - --lay-color-orange-4: #FFDC5D; - --lay-color-orange-5: #FFCB2E; - --lay-color-orange-6: #FFB800; - --lay-color-orange-7: #D29000; - --lay-color-orange-8: #A66C00; - --lay-color-orange-9: #794B00; - --lay-color-orange-10: #4D2D00; - --lay-color-cyan-1: #E8F6FF; - --lay-color-cyan-2: #B9CEDD; - --lay-color-cyan-3: #8FA7BB; - --lay-color-cyan-4: #6A829A; - --lay-color-cyan-5: #4A5F78; - --lay-color-cyan-6: #2F4056; - --lay-color-cyan-7: #223654; - --lay-color-cyan-8: #162C51; - --lay-color-cyan-9: #0B214F; - --lay-color-cyan-10: #00174D; - --lay-color-purple-1: #FDE8FF; - --lay-color-purple-2: #EDBEF4; - --lay-color-purple-3: #DC97E8; - --lay-color-purple-4: #C972DD; - --lay-color-purple-5: #B651D1; - --lay-color-purple-6: #A233C6; - --lay-color-purple-7: #8120A8; - --lay-color-purple-8: #631289; - --lay-color-purple-9: #48076B; - --lay-color-purple-10: #2F004D; - --lay-color-black-1: #E8F8FF; - --lay-color-black-2: #BFD0D8; - --lay-color-black-3: #98A8B1; - --lay-color-black-4: #73818A; - --lay-color-black-5: #505B63; - --lay-color-black-6: #2F363C; - --lay-color-black-7: #23303C; - --lay-color-black-8: #18293C; - --lay-color-black-9: #0C213C; - --lay-color-black-10: #00183C; - --lay-color-gray-1: #FAFAFA; - --lay-color-gray-2: #F6F6F6; - --lay-color-gray-3: #EEEEEE; - --lay-color-gray-4: #E2E2E2; - --lay-color-gray-5: #DDDDDD; - --lay-color-gray-6: #D2D2D2; - --lay-color-gray-7: #CCCCCC; - --lay-color-gray-8: #C2C2C2; - --lay-color-gray-9: #AAAAAA; - --lay-color-gray-10: #939393; - --lay-color-gray-11: #858585; - --lay-color-gray-12: #7b7b7b; - --lay-color-gray-13: #686868; - --lay-color-primary: var(--lay-color-layuigreen-6); - --lay-color-primary-hover: var(--lay-color-layuigreen-5); - --lay-color-primary-active: var(--lay-color-layuigreen-7); - --lay-color-primary-disabled: var(--lay-color-layuigreen-3); - --lay-color-primary-light: var(--lay-color-layuigreen-4); - --lay-color-secondary: var(--lay-color-green-6); - --lay-color-secondary-hover: var(--lay-color-green-5); - --lay-color-secondary-active: var(--lay-color-green-7); - --lay-color-secondary-disabled: var(--lay-color-green-3); - --lay-color-secondary-light: var(--lay-color-green-4); - --lay-color-info: var(--lay-color-lightblue-6); - --lay-color-info-hover: var(--lay-color-lightblue-5); - --lay-color-info-active: var(--lay-color-lightblue-7); - --lay-color-info-disabled: var(--lay-color-lightblue-3); - --lay-color-info-light: var(--lay-color-lightblue-4); - --lay-color-normal: var(--lay-color-blue-6); - --lay-color-normal-hover: var(--lay-color-blue-5); - --lay-color-normal-active: var(--lay-color-blue-7); - --lay-color-normal-disabled: var(--lay-color-blue-3); - --lay-color-normal-light: var(--lay-color-blue-4); - --lay-color-warning: var(--lay-color-orange-6); - --lay-color-warning-hover: var(--lay-color-orange-5); - --lay-color-warning-active: var(--lay-color-orange-7); - --lay-color-warning-disabled: var(--lay-color-orange-3); - --lay-color-warning-light: var(--lay-color-orange-4); - --lay-color-success: var(--lay-color-green-6); - --lay-color-success-hover: var(--lay-color-green-5); - --lay-color-success-active: var(--lay-color-green-7); - --lay-color-success-disabled: var(--lay-color-green-3); - --lay-color-success-light: var(--lay-color-green-4); - --lay-color-danger: var(--lay-color-red-6); - --lay-color-danger-hover: var(--lay-color-red-5); - --lay-color-danger-active: var(--lay-color-red-7); - --lay-color-danger-disabled: var(--lay-color-red-3); - --lay-color-danger-light: var(--lay-color-red-4); - --lay-color-bg-1: #17171A; - --lay-color-bg-2: #232324; - --lay-color-bg-3: #2a2a2b; - --lay-color-bg-4: #313132; - --lay-color-bg-5: #373739; - --lay-color-bg-white: #f6f6f6; - --lay-color-text-1: rgba(255, 255, 255, 0.9); - --lay-color-text-2: rgba(255, 255, 255, 0.7); - --lay-color-text-3: rgba(255, 255, 255, 0.5); - --lay-color-text-4: rgba(255, 255, 255, 0.3); - --lay-color-border-1: #2e2e30; - --lay-color-border-2: #484849; - --lay-color-border-3: #5f5f60; - --lay-color-border-4: #929293; - --lay-color-fill-1: rgba(255, 255, 255, 0.04); - --lay-color-fill-2: rgba(255, 255, 255, 0.08); - --lay-color-fill-3: rgba(255, 255, 255, 0.12); - --lay-color-fill-4: rgba(255, 255, 255, 0.16); - --lay-color-hover: var(--lay-color-fill-3); - --lay-color-active: var(--lay-color-fill-3); - --lay-shadow-1: 0 4px 6px rgba(0, 0, 0, 0.06), 0 1px 10px rgba(0, 0, 0, 0.08), 0 2px 4px rgba(0, 0, 0, 0.12); - --lay-shadow-2: 0 8px 10px rgba(0, 0, 0, 0.12), 0 3px 14px rgba(0, 0, 0, 0.1), 0 5px 5px rgba(0, 0, 0, 0.16); - --lay-shadow-3: 0 16px 24px rgba(0, 0, 0, 0.14), 0 6px 30px rgba(0, 0, 0, 0.12), 0 8px 10px rgba(0, 0, 0, 0.2); -} -.dark blockquote, -.dark body, -.dark button, -.dark dd, -.dark div, -.dark dl, -.dark dt, -.dark form, -.dark h1, -.dark h2, -.dark h3, -.dark h4, -.dark h5, -.dark h6, -.dark input, -.dark li, -.dark ol, -.dark p, -.dark pre, -.dark td, -.dark textarea, -.dark th, -.dark ul { - -webkit-tap-highlight-color: rgba(0, 0, 0, 0); -} -.dark body { - color: var(--lay-color-text-2); - background-color: var(--lay-color-bg-1); - color-scheme: dark; -} -.dark hr { - border-bottom: 1px solid var(--lay-color-border-2) !important; -} -.dark a { - color: var(--lay-color-text-1); -} -.dark a:hover { - color: var(--lay-color-text-3); -} -.dark .layui-edge { - border-color: transparent; -} -.dark .layui-edge-top { - border-bottom-color: var(--lay-color-border-4); -} -.dark .layui-edge-right { - border-left-color: var(--lay-color-border-4); -} -.dark .layui-edge-bottom { - border-top-color: var(--lay-color-border-4); -} -.dark .layui-edge-left { - border-right-color: var(--lay-color-border-4); -} -.dark .layui-disabled, -.dark .layui-disabled:hover { - color: var(--lay-color-text-4) !important; -} -.dark .layui-icon { - -moz-osx-font-smoothing: grayscale; -} -.dark .layui-layout-admin .layui-header { - background-color: var(--lay-color-bg-2); -} -.dark .layui-layout-admin .layui-footer { - box-shadow: -1px 0 4px rgba(0, 0, 0, 0.12); - background-color: var(--lay-color-bg-2); -} -.dark .layui-layout-admin .layui-logo { - color: var(--lay-color-primary); - box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.15); -} -.dark .layui-elem-quote { - border-left: 5px solid var(--lay-color-secondary); - background-color: var(--lay-color-fill-1); -} -.dark .layui-quote-nm { - border-color: var(--lay-color-fill-1); -} -.dark .layui-progress { - background-color: var(--lay-color-bg-3); -} -.dark .layui-progress-bar { - background-color: var(--lay-color-secondary); -} -.dark .layui-progress-text { - color: var(--lay-color-text-2); -} -.dark .layui-progress-big .layui-progress-text { - color: var(--lay-color-text-1); -} -.dark .layui-colla-title { - color: var(--lay-color-text-1); - background-color: var(--lay-color-bg-2); -} -.dark .layui-colla-content { - color: var(--lay-color-text-2); -} -.dark .layui-card { - background-color: var(--lay-color-bg-2); - box-shadow: var(--lay-shadow-1); -} -.dark .layui-card-header { - border-bottom: 1px solid var(--lay-color-border-2); - color: var(--lay-color-text-1); -} -.dark .layui-panel { - box-shadow: var(--lay-shadow-1); - background-color: var(--lay-color-bg-2); - color: var(--lay-color-text-1); -} -.dark .layui-menu-body-panel { - box-shadow: var(--lay-shadow-2); -} -.dark .layui-panel-window { - border-top: 5px solid var(--lay-color-border-2); - background-color: var(--lay-color-bg-2); -} -.dark .layui-bg-red { - background-color: var(--lay-color-red-6) !important; - color: var(--lay-color-white) !important; -} -.dark .layui-bg-orange { - background-color: var(--lay-color-orange-6) !important; - color: var(--lay-color-white) !important; -} -.dark .layui-bg-green { - background-color: var(--lay-color-layuigreen-6) !important; - color: var(--lay-color-white) !important; -} -.dark .layui-bg-cyan { - background-color: var(--lay-color-cyan-6) !important; - color: var(--lay-color-white) !important; -} -.dark .layui-bg-blue { - background-color: var(--lay-color-blue-6) !important; - color: var(--lay-color-white) !important; -} -.dark .layui-bg-black { - background-color: var(--lay-color-black-6) !important; - color: var(--lay-color-white) !important; -} -.dark .layui-bg-purple { - background-color: var(--lay-color-purple-6) !important; - color: var(--lay-color-white) !important; -} -.dark .layui-bg-gray { - background-color: var(--lay-color-gray-1) !important; - color: var(--lay-color-black-6) !important; -} -.dark .layui-badge-rim, -.dark .layui-border, -.dark .layui-colla-content, -.dark .layui-colla-item, -.dark .layui-collapse, -.dark .layui-elem-field, -.dark .layui-form-pane .layui-form-item[pane], -.dark .layui-form-pane .layui-form-label, -.dark .layui-input, -.dark .layui-input-split, -.dark .layui-panel, -.dark .layui-select, -.dark .layui-tab-bar, -.dark .layui-tab-card, -.dark .layui-tab-title, -.dark .layui-tab-title .layui-this:after, -.dark .layui-textarea { - border-color: var(--lay-color-border-1); -} -.dark .layui-border { - color: var(--lay-color-text-1) !important; -} -.dark .layui-border-red { - border-color: var(--lay-color-red-6) !important; - color: var(--lay-color-red-6) !important; -} -.dark .layui-border-orange { - border-color: var(--lay-color-orange-6) !important; - color: var(--lay-color-orange-6) !important; -} -.dark .layui-border-green { - border-color: var(--lay-color-layuigreen-6) !important; - color: var(--lay-color-layuigreen-6) !important; -} -.dark .layui-border-cyan { - border-color: var(--lay-color-cyan-6) !important; - color: var(--lay-color-cyan-6) !important; -} -.dark .layui-border-blue { - border-color: var(--lay-color-blue-6) !important; - color: var(--lay-color-blue-6) !important; -} -.dark .layui-border-purple { - border-color: var(--lay-color-purple-6) !important; - color: var(--lay-color-purple-6) !important; -} -.dark .layui-border-black { - border-color: var(--lay-color-black-6) !important; - color: var(--lay-color-text-1) !important; -} -.dark .layui-text { - color: var(--lay-color-text-2); -} -.dark .layui-text-em, -.dark .layui-word-aux { - color: var(--lay-color-text-3) !important; -} -.dark .layui-text a:not(.layui-btn) { - color: var(--lay-color-lightblue-6); -} -.dark .layui-text blockquote:not(.layui-elem-quote) { - border-left: 5px solid var(--lay-color-border-4); -} -.dark .layui-font-red { - color: var(--lay-color-red-6) !important; -} -.dark .layui-font-orange { - color: var(--lay-color-orange-6) !important; -} -.dark .layui-font-green { - color: var(--lay-color-layuigreen-6) !important; -} -.dark .layui-font-cyan { - color: var(--lay-color-cyan-6) !important; -} -.dark .layui-font-blue { - color: var(--lay-color-lightblue-6) !important; -} -.dark .layui-font-black { - color: var(--lay-color-black) !important; -} -.dark .layui-font-purple { - color: var(--lay-color-purple-6) !important; -} -.dark .layui-font-gray { - color: var(--lay-color-gray-7) !important; -} -.dark .layui-btn { - border: 1px solid transparent; - background-color: var(--lay-color-primary); - color: var(--lay-color-text-1); -} -.dark .layui-btn:hover { - color: var(--lay-color-text-2); -} -.dark .layui-btn-primary { - border-color: var(--lay-color-border-2); - color: var(--lay-color-text-1); - background-color: var(--lay-color-bg-4); -} -.dark .layui-btn-primary:hover { - border-color: transparent; - color: var(--lay-color-text-2); -} -.dark .layui-btn-normal { - background-color: var(--lay-color-normal); -} -.dark .layui-btn-warm { - background-color: var(--lay-color-warning); -} -.dark .layui-btn-danger { - background-color: var(--lay-color-danger); -} -.dark .layui-btn-checked { - background-color: var(--lay-color-success); -} -.dark .layui-btn-disabled, -.dark .layui-btn-disabled:active, -.dark .layui-btn-disabled:hover { - border-color: var(--lay-color-border-2) !important; - background-color: var(--lay-color-bg-2) !important; - color: var(--lay-color-text-4) !important; -} -.dark .layui-btn-group .layui-btn { - border-left: 1px solid var(--lay-color-border-2); -} -.dark .layui-btn-group .layui-btn-primary:hover { - border-color: var(--lay-color-border-2); - color: var(--lay-color-primary); -} -.dark .layui-btn-group .layui-btn-primary:first-child { - border-left: 1px solid var(--lay-color-gray-5); -} -.dark .layui-input, -.dark .layui-select, -.dark .layui-textarea { - background-color: var(--lay-color-fill-2); - color: var(--lay-color-text-2); -} -.dark .layui-input:hover, -.dark .layui-textarea:hover { - border-color: var(--lay-color-border-2) !important; -} -.dark .layui-input:focus, -.dark .layui-textarea:focus { - border-color: var(--lay-color-secondary-hover) !important; - background-color: var(--lay-color-bg-2); - box-shadow: 0 0 0 3px rgba(22, 183, 119, 0.08); -} -.dark .layui-input[disabled], -.dark .layui-select[disabled], -.dark .layui-textarea[disabled], -.dark .layui-input.layui-disabled, -.dark .layui-textarea.layui-disabled { - background-color: var(--lay-color-fill-1); - color: var(--lay-color-text-4); - border-color: var(--lay-color-border-1) !important; - box-shadow: 0 0 0 0; -} -.dark .layui-form-danger + .layui-form-select .layui-input, -.dark .layui-form-danger:focus { - border-color: var(--lay-color-danger) !important; - box-shadow: 0 0 0 3px rgba(255, 87, 34, 0.08); -} -.dark .layui-input-prefix .layui-icon, -.dark .layui-input-split .layui-icon, -.dark .layui-input-suffix .layui-icon { - color: var(--lay-color-gray-8); -} -.dark .layui-input-wrap .layui-input:hover + .layui-input-split { - border-color: var(--lay-color-border-2); -} -.dark .layui-input-wrap .layui-input[disabled]:hover + .layui-input-split { - border-color: var(--lay-color-border-1); -} -.dark .layui-input-wrap .layui-input:focus + .layui-input-split { - border-color: var(--lay-color-secondary-hover); -} -.dark .layui-input-wrap .layui-input.layui-form-danger:focus + .layui-input-split { - border-color: var(--lay-color-danger); -} -.dark .layui-input-affix .layui-icon { - color: var(--lay-color-text-2); -} -.dark .layui-input-affix .layui-icon-clear { - color: var(--lay-color-text-2); -} -.dark .layui-input-affix .layui-icon:hover { - color: var(--lay-color-text-3); -} -.dark .layui-input-wrap .layui-input-number .layui-icon-up { - border-bottom-color: var(--lay-color-border-1); -} -.dark .layui-input-wrap .layui-input[type="number"].layui-input-number-out-of-range { - color: var(--lay-color-danger); -} -.dark .layui-form-select { - color: var(--lay-color-text-2); -} -.dark .layui-form-select .layui-edge { - border-top-color: var(--lay-color-gray-8); -} -.dark .layui-form-select dl { - border: 1px solid var(--lay-color-border-2); - background-color: var(--lay-color-bg-5); - box-shadow: var(--lay-shadow-2); -} -.dark .layui-form-select dl dt { - color: var(--lay-color-gray-8); -} -.dark .layui-form-select dl dd:hover { - background-color: var(--lay-color-active); -} -.dark .layui-form-select dl dd.layui-select-tips { - color: var(--lay-color-text-2); -} -.dark .layui-form-select dl dd.layui-this { - background-color: var(--lay-color-active); - color: var(--lay-color-text-1); -} -.dark .layui-form-select dl dd.layui-disabled, -.dark .layui-form-select dl dd:hover.layui-disabled { - background-color: var(--lay-color-bg-5); -} -.dark .layui-select-none { - color: var(--lay-color-black-8); -} -.dark .layui-select-disabled .layui-disabled { - border-color: var(--lay-color-border-1) !important; -} -.dark .layui-select-disabled .layui-edge { - border-top-color: var(--lay-color-gray-6); -} -.dark .layui-form-checkbox { - background-color: var(--lay-color-fill-2); -} -.dark .layui-form-checkbox > div { - background-color: var(--lay-color-fill-3); - color: var(--lay-color-text-2); -} -.dark .layui-form-checkbox:hover > div { - background-color: var(--lay-color-active); -} -.dark .layui-form-checkbox > i { - background-color: var(--lay-color-fill-1); - border-top-color: var(--lay-color-border-1); - border-right-color: var(--lay-color-border-1); - border-bottom-color: var(--lay-color-border-1); - border-left-color: initial; - color: var(--lay-color-text-1); -} -.dark .layui-form-checkbox:hover > i { - border-color: var(--lay-color-border-2); - color: var(--lay-color-text-4); -} -.dark .layui-form-checked, -.dark .layui-form-checked:hover { - border-color: var(--lay-color-secondary-active); -} -.dark .layui-form-checked > div, -.dark .layui-form-checked:hover > div { - background-color: var(--lay-color-secondary); -} -.dark .layui-form-checked > i, -.dark .layui-form-checked:hover > i { - color: var(--lay-color-secondary-hover); -} -.dark .layui-form-checkbox.layui-checkbox-disabled > div { - background-color: var(--lay-color-fill-3) !important; -} -.dark .layui-form-checkbox[lay-skin=primary] { - background-image: none; - background-color: initial; - border-color: initial !important; -} -.dark .layui-form-checkbox[lay-skin=primary] > div { - background-image: none; - background-color: initial; - color: var(--lay-color-text-2); -} -.dark .layui-form-checkbox[lay-skin=primary] > i { - border-color: var(--lay-color-border-1); - background-color: var(--lay-color-fill-2); -} -.dark .layui-form-checkbox[lay-skin=primary]:hover > i { - border-color: var(--lay-color-secondary-hover); - color: var(--lay-color-text-1); -} -.dark .layui-form-checked[lay-skin=primary] > i { - background-color: var(--lay-color-secondary); - color: var(--lay-color-text-1); - border-color: var(--lay-color-secondary-active) !important; -} -.dark .layui-checkbox-disabled[lay-skin=primary] > div { - background: none!important; - color: var(--lay-color-text-4) !important; -} -.dark .layui-form-checked.layui-checkbox-disabled[lay-skin=primary] > i { - background-color: var(--lay-color-fill-1) !important; - border-color: var(--lay-color-border-2) !important; -} -.dark .layui-checkbox-disabled[lay-skin=primary]:hover > i { - border-color: var(--lay-color-border-1); -} -.dark .layui-form-checkbox[lay-skin="primary"] > .layui-icon-indeterminate:before { - background-color: var(--lay-color-secondary-hover); - opacity: 1; -} -.dark .layui-form-checkbox[lay-skin="primary"]:hover > .layui-icon-indeterminate:before { - opacity: 1; -} -.dark .layui-form-checkbox[lay-skin="primary"] > .layui-icon-indeterminate { - border-color: var(--lay-color-secondary-hover); -} -.dark .layui-form-switch { - border-color: var(--lay-color-border-2); - background-color: var(--lay-color-fill-2); -} -.dark .layui-form-switch > i { - background-color: var(--lay-color-gray-4); -} -.dark .layui-form-switch.layui-checkbox-disabled > i { - background-color: var(--lay-color-gray-7); -} -.dark .layui-form-switch > div { - color: var(--lay-color-gray-8) !important; -} -.dark .layui-form-onswitch { - border-color: var(--lay-color-secondary-active); - background-color: var(--lay-color-secondary); -} -.dark .layui-form-onswitch > i { - background-color: var(--lay-color-gray-4); -} -.dark .layui-form-onswitch > div { - color: var(--lay-color-text-1) !important; -} -.dark .layui-checkbox-disabled { - border-color: var(--lay-color-border-2) !important; -} -.dark .layui-checkbox-disabled > div { - background-color: var(--lay-color-fill-3) !important; - color: var(--lay-color-text-4) !important; -} -.dark .layui-checkbox-disabled > i { - border-color: var(--lay-color-border-2) !important; -} -.dark .layui-checkbox-disabled:hover > i { - color: var(--lay-color-text-1) !important; -} -.dark .layui-form-switch.layui-checkbox-disabled > div { - background-color: initial!important; - color: var(--lay-color-text-3) !important; -} -.dark .layui-form-checkbox > i:before { - opacity: 0; - filter: alpha(opacity=0); -} -.dark .layui-form-checkbox:hover > i:before { - opacity: 1; - filter: alpha(opacity=100); -} -.dark .layui-form-checked.layui-checkbox-disabled:hover > i:before, -.dark .layui-form-checked:hover > i:before, -.dark .layui-form-checked > i:before { - opacity: 1; - filter: alpha(opacity=100); -} -.dark .layui-form-checkbox[lay-skin=primary]:hover > i:before { - opacity: 0; - filter: alpha(opacity=0); -} -.dark .layui-form-checked[lay-skin=primary]:hover > i:before { - opacity: 1; - filter: alpha(opacity=100); -} -.dark .layui-checkbox-disabled:hover > i:before { - opacity: 0; - filter: alpha(opacity=0); -} -.dark .layui-form-radio > i { - color: var(--lay-color-gray-8); -} -.dark .layui-form-radio:hover > *, -.dark .layui-form-radioed, -.dark .layui-form-radioed > i { - color: var(--lay-color-secondary); -} -.dark .layui-radio-disabled > i { - color: var(--lay-color-text-4) !important; -} -.dark .layui-radio-disabled > * { - color: var(--lay-color-text-4) !important; -} -.dark .layui-form-pane .layui-form-label { - background-color: var(--lay-color-bg-2); -} -.dark .layui-laypage a, -.dark .layui-laypage button, -.dark .layui-laypage input, -.dark .layui-laypage select, -.dark .layui-laypage span { - border: 1px solid var(--lay-color-border-2); -} -.dark .layui-laypage a, -.dark .layui-laypage span { - background-color: var(--lay-color-bg-2); - color: var(--lay-color-text-2); -} -.dark .layui-laypage a[data-page] { - color: var(--lay-color-text-2); -} -.dark .layui-laypage a:hover { - color: var(--lay-color-primary); -} -.dark .layui-laypage .layui-laypage-spr { - color: var(--lay-color-text-3); -} -.dark .layui-laypage .layui-laypage-curr em { - color: var(--lay-color-white); -} -.dark .layui-laypage .layui-laypage-curr .layui-laypage-em { - background-color: var(--lay-color-primary); -} -.dark .layui-laypage .layui-laypage-skip { - color: var(--lay-color-text-3); -} -.dark .layui-laypage button, -.dark .layui-laypage input { - background-color: var(--lay-color-bg-2); -} -.dark .layui-laypage input:focus, -.dark .layui-laypage select:focus { - border-color: var(--lay-color-primary) !important; -} -.dark .layui-flow-more { - color: var(--lay-color-text-1); -} -.dark .layui-flow-more a cite { - background-color: var(--lay-color-bg-4); - color: var(--lay-color-text-1); -} -.dark .layui-flow-more a i { - color: var(--lay-color-text-2); -} -.dark .layui-table { - background-color: var(--lay-color-bg-2); - color: var(--lay-color-text-2); -} -.dark .layui-table-mend { - background-color: var(--lay-color-bg-2); -} -.dark .layui-table-click, -.dark .layui-table-hover, -.dark .layui-table[lay-even] tbody tr:nth-child(even) { - background-color: var(--lay-color-fill-3); -} -.dark .layui-table-checked { - background-color: var(--lay-color-fill-2); - color: var(--lay-color-text-1); -} -.dark .layui-table-checked.layui-table-hover, -.dark .layui-table-checked.layui-table-click { - background-color: var(--lay-color-fill-3); -} -.dark .layui-table td, -.dark .layui-table th, -.dark .layui-table-col-set, -.dark .layui-table-fixed-r, -.dark .layui-table-grid-down, -.dark .layui-table-header, -.dark .layui-table-mend, -.dark .layui-table-page, -.dark .layui-table-tips-main, -.dark .layui-table-tool, -.dark .layui-table-total, -.dark .layui-table-view, -.dark .layui-table[lay-skin=line], -.dark .layui-table[lay-skin=row] { - border-color: var(--lay-color-border-2); -} -.dark .layui-table-view:after { - background-color: var(--lay-color-border-2); -} -.dark .layui-table-view .layui-table td[data-edit]:hover:after { - border: 1px solid var(--lay-color-primary-active); -} -.dark .layui-table-loading-icon .layui-icon { - color: var(--lay-color-gray-8); -} -/* .dark .layui-table-page { - background-color: var(--lay-color-bg-2); -} */ -.dark .layui-table-page .layui-laypage a, -.dark .layui-table-page .layui-laypage span { - border: none; -} -.dark .layui-table-tool { - background-color: var(--lay-color-bg-2); -} -.dark .layui-table-tool .layui-inline[lay-event] { - color: var(--lay-color-text-3); - border: 1px solid var(--lay-color-border-2); -} -.dark .layui-table-tool .layui-inline[lay-event]:hover { - border: 1px solid var(--lay-color-border-3); -} -.dark .layui-table-tool-panel { - color: var(--lay-color-text-1); - border: 1px solid var(--lay-color-border-2); - background-color: var(--lay-color-bg-5); - box-shadow: var(--lay-shadow-2); -} -.dark .layui-table-tool-panel li:hover { - background-color: var(--lay-color-active); -} -.dark .layui-table-col-set { - background-color: var(--lay-color-white); -} -.dark .layui-table-sort .layui-table-sort-asc { - border-bottom-color: var(--lay-color-gray-8); -} -.dark .layui-table-sort .layui-table-sort-asc:hover { - border-bottom-color: var(--lay-color-gray-11); -} -.dark .layui-table-sort .layui-table-sort-desc { - border-top-color: var(--lay-color-gray-8); -} -.dark .layui-table-sort .layui-table-sort-desc:hover { - border-top-color: var(--lay-color-gray-11); -} -.dark .layui-table-sort[lay-sort=asc] .layui-table-sort-asc { - border-bottom-color: var(--lay-color-gray-13); -} -.dark .layui-table-sort[lay-sort=desc] .layui-table-sort-desc { - border-top-color: var(--lay-color-gray-13); -} -.dark .layui-table-cell .layui-table-link { - color: var(--lay-color-lightblue-5); -} -.dark .layui-table-body .layui-none { - color: var(--lay-color-gray-8); -} -.dark .layui-table-fixed-l { - box-shadow: 1px 0 8px #000000; -} -.dark .layui-table-fixed-r { - box-shadow: -1px 0 8px #000000; -} -.dark .layui-table-edit { - box-shadow: var(--lay-shadow-1); - background-color: var(--lay-color-bg-2); -} -.dark .layui-table-edit:focus { - border-color: var(--lay-color-secondary) !important; -} -.dark select.layui-table-edit { - border-color: var(--lay-color-border-2); -} -.dark .layui-table-grid-down { - background-color: var(--lay-color-bg-5); - color: var(--lay-color-gray-8); -} -.dark .layui-table-grid-down:hover { - background-color: var(--lay-color-bg-5); -} -.dark .layui-table-cell-c { - background-color: var(--lay-color-gray-13); - color: var(--lay-color-text-1); - border-color: var(--lay-color-border-3); -} -.dark .layui-table-cell-c:hover { - border-color: var(--lay-color-secondary-hover); -} -.dark body .layui-table-tips .layui-layer-content { - box-shadow: var(--lay-shadow-3); -} -.dark .layui-table-tips-main { - background-color: var(--lay-color-bg-5); - color: var(--lay-color-text-3); -} -.dark .layui-table-tips-c { - background-color: var(--lay-color-gray-13); - color: var(--lay-color-text-1); -} -.dark .layui-table-tips-c:hover { - background-color: var(--lay-color-gray-10); -} -.dark .layui-upload-choose { - color: var(--lay-color-gray-8); -} -.dark .layui-upload-drag { - border: 1px dashed var(--lay-color-border-2); - background-color: var(--lay-color-bg-4); - color: var(--lay-color-text-2); -} -.dark .layui-upload-drag .layui-icon { - color: var(--lay-color-primary); -} -.dark .layui-upload-drag[lay-over] { - border-color: var(--lay-color-primary); -} -.dark .layui-menu { - background-color: var(--lay-color-bg-2); -} -.dark .layui-menu li { - color: var(--lay-color-text-1); -} -.dark .layui-menu li:hover { - background-color: var(--lay-color-bg-5); -} -.dark .layui-menu li.layui-disabled, -.dark .layui-menu li.layui-disabled * { - color: var(--lay-color-text-4) !important; -} -.dark .layui-menu .layui-menu-item-group > .layui-menu-body-title { - color: var(--lay-color-text-3); -} -.dark .layui-menu .layui-menu-item-none { - color: var(--lay-color-text-3); -} -.dark .layui-menu .layui-menu-item-divider { - border-bottom: 1px solid var(--lay-color-border-2); -} -.dark .layui-menu .layui-menu-item-group:hover, -.dark .layui-menu .layui-menu-item-none:hover, -.dark .layui-menu .layui-menu-item-divider:hover { - background: none; -} -.dark .layui-menu .layui-menu-item-up > .layui-menu-body-title { - color: var(--lay-color-text-1); -} -.dark .layui-menu .layui-menu-item-down:hover > .layui-menu-body-title > .layui-icon, -.dark .layui-menu .layui-menu-item-up > .layui-menu-body-title:hover > .layui-icon { - color: var(--lay-color-text-1); -} -.dark .layui-menu .layui-menu-item-checked, -.dark .layui-menu .layui-menu-item-checked2 { - background-color: var(--lay-color-active) !important; - color: var(--lay-color-secondary); -} -.dark .layui-menu .layui-menu-item-checked a, -.dark .layui-menu .layui-menu-item-checked2 a { - color: var(--lay-color-secondary); -} -.dark .layui-menu .layui-menu-item-checked:after { - border-right: 3px solid var(--lay-color-secondary); -} -.dark .layui-menu-body-title a { - color: var(--lay-color-text-1); -} -.dark .layui-menu-lg .layui-menu-body-title a:hover, -.dark .layui-menu-lg li:hover { - color: var(--lay-color-secondary); -} -.dark .layui-dropdown { - background-color: var(--lay-color-bg-5); -} -.dark .layui-dropdown.layui-panel, -.dark .layui-dropdown .layui-panel { - background-color: var(--lay-color-bg-5); - box-shadow: var(--lay-shadow-2); -} -.dark .layui-dropdown.layui-panel .layui-menu { - background-color: var(--lay-color-bg-5); -} -.dark .layui-nav { - background-color: var(--lay-color-black-6); - color: var(--lay-color-white); -} -.dark .layui-nav .layui-nav-item a { - color: var(--lay-color-text-1); -} -.dark .layui-nav .layui-this:after, -.dark .layui-nav-bar { - background-color: var(--lay-color-secondary); -} -.dark .layui-nav .layui-nav-item a:hover, -.dark .layui-nav .layui-this a { - color: var(--lay-color-text-1); -} -.dark .layui-nav-child { - box-shadow: var(--lay-shadow-2); - border: 1px solid var(--lay-color-border-2); - background-color: var(--lay-color-bg-5); -} -.dark .layui-nav .layui-nav-child a { - color: var(--lay-color-text-1); -} -.dark .layui-nav .layui-nav-child a:hover { - background-color: var(--lay-color-bg-5); - color: var(--lay-color-text-1); -} -.dark .layui-nav-child dd.layui-this { - background-color: var(--lay-color-bg-5); - color: var(--lay-color-text-1); -} -.dark .layui-nav-tree .layui-nav-child dd.layui-this, -.dark .layui-nav-tree .layui-nav-child dd.layui-this a, -.dark .layui-nav-tree .layui-this, -.dark .layui-nav-tree .layui-this > a, -.dark .layui-nav-tree .layui-this > a:hover { - background-color: var(--lay-color-primary); - color: var(--lay-color-white); -} -.dark .layui-nav-itemed > a, -.dark .layui-nav-tree .layui-nav-title a, -.dark .layui-nav-tree .layui-nav-title a:hover { - color: var(--lay-color-white) !important; -} -.dark .layui-nav-tree .layui-nav-bar { - background-color: var(--lay-color-primary); -} -.dark .layui-nav-tree .layui-nav-child { - background: none; - background-color: rgba(0, 0, 0, 0.3); - border: none; - box-shadow: none; -} -.dark .layui-nav-tree .layui-nav-child a { - color: var(--lay-color-white); - color: var(--lay-color-text-1); -} -.dark .layui-nav-tree .layui-nav-child a:hover { - background: none; - color: var(--lay-color-white); -} -.dark .layui-nav.layui-bg-gray, -.dark .layui-nav-tree.layui-bg-gray { - background-color: var(--lay-color-bg-2) !important; - color: var(--lay-color-text-1); -} -.dark .layui-nav-tree.layui-bg-gray .layui-nav-child { - background-color: rgba(0, 0, 0, 0.3) !important; -} -.dark .layui-nav-tree.layui-bg-gray a, -.dark .layui-nav.layui-bg-gray .layui-nav-item a { - color: var(--lay-color-text-1); -} -.dark .layui-nav.layui-bg-gray .layui-nav-child { - background-color: var(--lay-color-bg-5); -} -.dark .layui-nav-tree.layui-bg-gray .layui-nav-itemed > a { - color: var(--lay-color-text-1) !important; -} -.dark .layui-nav.layui-bg-gray .layui-this a { - color: var(--lay-color-secondary); -} -.dark .layui-nav-tree.layui-bg-gray .layui-nav-child dd.layui-this, -.dark .layui-nav-tree.layui-bg-gray .layui-nav-child dd.layui-this a, -.dark .layui-nav-tree.layui-bg-gray .layui-this, -.dark .layui-nav-tree.layui-bg-gray .layui-this > a { - color: var(--lay-color-secondary) !important; -} -.dark .layui-nav-tree.layui-bg-gray .layui-nav-bar { - background-color: var(--lay-color-secondary); -} -.dark .layui-breadcrumb a { - color: var(--lay-color-gray-7) !important; -} -.dark .layui-breadcrumb a:hover { - color: var(--lay-color-secondary) !important; -} -.dark .layui-breadcrumb a cite { - color: var(--lay-color-gray-8); -} -.dark .layui-breadcrumb span[lay-separator] { - color: var(--lay-color-gray-7); -} -.dark .layui-tab .layui-tab-title:after { - border-bottom-color: var(--lay-color-border-1); -} -.dark .layui-tab-title .layui-this { - color: var(--lay-color-text-2); -} -.dark .layui-tab-title .layui-this:after { - border-bottom-color: var(--lay-color-bg-1); -} -.dark .layui-tab-bar { - background-color: var(--lay-color-bg-3); -} -.dark .layui-tab-more li.layui-this:after { - border-bottom-color: var(--lay-color-border-1); -} -.dark .layui-tab-title li .layui-tab-close { - color: var(--lay-color-gray-8); -} -.dark .layui-tab-title li .layui-tab-close:hover { - background-color: var(--lay-color-danger); - color: var(--lay-color-white); -} -.dark .layui-tab-brief > .layui-tab-title .layui-this { - color: var(--lay-color-primary); -} -.dark .layui-tab-brief > .layui-tab-more li.layui-this:after, -.dark .layui-tab-brief > .layui-tab-title .layui-this:after { - border-bottom: 2px solid var(--lay-color-secondary); -} -.dark .layui-tab-card { - box-shadow: var(--lay-shadow-1); -} -.dark .layui-tab-card > .layui-tab-title { - background-color: var(--lay-color-bg-2); -} -.dark .layui-tab-card > .layui-tab-title .layui-this { - background-color: var(--lay-color-bg-1); -} -.dark .layui-tab-card > .layui-tab-title .layui-this:after { - border-bottom-color: var(--lay-color-bg-1); -} -.dark .layui-tab-card > .layui-tab-more .layui-this { - color: var(--lay-color-secondary); -} -.dark .layui-tabs-header:after, -.dark .layui-tabs-scroll:after { - border-bottom-color: var(--lay-color-border-1); -} -.dark .layui-tabs-card > .layui-tabs-header .layui-this { - background-color: transparent; -} -.dark .layui-tabs-card > .layui-tabs-header .layui-this:after { - border-color: var(--lay-color-border-1); - border-bottom-color: var(--lay-color-bg-1); -} -.dark .layui-tabs-card.layui-panel > .layui-tabs-header .layui-this:after { - border-bottom-color: var(--lay-color-bg-2); -} -.dark .layui-tabs-bar .layui-icon { - background-color: var(--lay-color-bg-1); - color: var(--lay-color-text-2); - border-color: var(--lay-color-border-1); - box-shadow: 2px 0 5px 0 rgba(0, 0, 0, 0.32); -} -.dark .layui-tabs-bar .layui-icon-next { - box-shadow: -2px 0 5px 0 rgba(0, 0, 0, 0.32); -} -.dark .layui-timeline-axis { - background-color: var(--lay-color-bg-4); - color: var(--lay-color-secondary); -} -.dark .layui-timeline-axis:hover { - color: var(--lay-color-red-6); -} -.dark .layui-timeline-item:before { - background-color: var(--lay-color-bg-3); -} -.dark .layui-badge, -.dark .layui-badge-dot, -.dark .layui-badge-rim { - background-color: var(--lay-color-red-6); - color: var(--lay-color-white); -} -.dark .layui-badge-rim { - background-color: var(--lay-color-white); - color: var(--lay-color-black-6); -} -.dark .layui-carousel { - background-color: var(--lay-color-gray-2); -} -.dark .layui-carousel > [carousel-item]:before { - color: var(--lay-color-gray-8); - -moz-osx-font-smoothing: grayscale; -} -.dark .layui-carousel > [carousel-item] > * { - background-color: var(--lay-color-gray-2); -} -.dark .layui-carousel-arrow { - background-color: rgba(0, 0, 0, 0.2); - color: var(--lay-color-white); -} -.dark .layui-carousel-arrow:hover, -.dark .layui-carousel-ind ul:hover { - background-color: var(--lay-color-black); -} -.dark .layui-carousel[lay-indicator=outside] .layui-carousel-ind ul { - background-color: var(--lay-color-black); -} -.dark .layui-carousel-ind ul { - background-color: rgba(0, 0, 0, 0.2); -} -.dark .layui-carousel-ind ul li { - background-color: var(--lay-color-gray-3); - background-color: var(--lay-color-text-3); -} -.dark .layui-carousel-ind ul li:hover { - background-color: var(--lay-color-white); -} -.dark .layui-carousel-ind ul li.layui-this { - background-color: var(--lay-color-white); -} -.dark .layui-fixbar li { - background-color: var(--lay-color-black-5); - color: var(--lay-color-text-1); -} -.dark body .layui-util-face .layui-layer-content { - background-color: var(--lay-color-bg-5); - color: var(--lay-color-text-2); -} -.dark .layui-util-face ul { - border: 1px solid var(--lay-color-border-3); - background-color: var(--lay-color-bg-5); - box-shadow: var(--lay-shadow-2); -} -.dark .layui-util-face ul li { - border: 1px solid var(--lay-color-border-2); -} -.dark .layui-util-face ul li:hover { - border: 1px solid var(--lay-color-red-7); - background: var(--lay-color-text-1); -} -.dark .layui-code { - border: 1px solid var(--lay-color-border-2); - background-color: var(--lay-color-bg-white); - color: var(--lay-color-text-2); -} -.dark .layui-transfer-box, -.dark .layui-transfer-header, -.dark .layui-transfer-search { - border-color: var(--lay-color-border-2); -} -.dark .layui-transfer-box { - background-color: var(--lay-color-bg-2); -} -.dark .layui-transfer-search .layui-icon-search { - color: var(--lay-color-gray-8); -} -.dark .layui-transfer-active .layui-btn { - background-color: var(--lay-color-secondary); - border-color: var(--lay-color-secondary); - color: var(--lay-color-white); -} -.dark .layui-transfer-active .layui-btn-disabled { - background-color: var(--lay-color-gray-2); - border-color: var(--lay-color-gray-3); - color: var(--lay-color-gray-8); -} -.dark .layui-transfer-data li:hover { - background-color: var(--lay-color-active); -} -.dark .layui-transfer-data li:hover:has([lay-filter="layTransferCheckbox"][disabled]) { - background-color: var(--lay-color-bg-2); -} -.dark .layui-transfer-data .layui-none { - color: var(--lay-color-gray-7); -} -.dark .layui-rate li i.layui-icon { - color: var(--lay-color-orange-6); -} -.dark .layui-colorpicker { - border: 1px solid var(--lay-color-border-1); -} -.dark .layui-colorpicker:hover { - border-color: var(--lay-color-border-2); -} -.dark .layui-colorpicker-trigger-span { - border: 1px solid var(--lay-color-border-1); -} -.dark .layui-colorpicker-trigger-i { - color: var(--lay-color-white); -} -.dark .layui-colorpicker-trigger-i.layui-icon-close { - color: var(--lay-color-black-7); -} -.dark .layui-colorpicker-main { - background: var(--lay-color-bg-2); - border: 1px solid var(--lay-color-border-2); - box-shadow: var(--lay-shadow-2); -} -.dark .layui-colorpicker-basis-white { - background: linear-gradient(90deg, #fff, hsla(0, 0%, 100%, 0)); -} -.dark .layui-colorpicker-basis-black { - background: linear-gradient(0deg, #000, transparent); -} -.dark .layui-colorpicker-basis-cursor { - border: 1px solid var(--lay-color-white); -} -.dark .layui-colorpicker-side { - background: linear-gradient(linear-gradient(#F00, #FF0, #0F0, #0FF, #00F, #F0F, #F00)); -} -.dark .layui-colorpicker-side-slider { - box-shadow: var(--lay-shadow-1); - background: var(--lay-color-white); - border: 1px solid var(--lay-color-gray-2); -} -.dark .layui-colorpicker-alpha-slider { - box-shadow: var(--lay-shadow-1); - background: var(--lay-color-white); - border: 1px solid var(--lay-color-gray-2); -} -.dark .layui-colorpicker-pre.layui-this { - box-shadow: var(--lay-shadow-1); -} -.dark .layui-colorpicker-pre.selected { - box-shadow: var(--lay-shadow-1); -} -.dark .layui-colorpicker-main-input input.layui-input { - color: var(--lay-color-text-2); -} -.dark .layui-slider { - background: var(--lay-color-bg-5); -} -.dark .layui-slider-step { - background: var(--lay-color-fill-4); -} -.dark .layui-slider-wrap-btn { - background: var(--lay-color-bg-4); -} -.dark .layui-slider-tips { - color: var(--lay-color-text-1); - background: var(--lay-color-black); - box-shadow: var(--lay-shadow-3); -} -.dark .layui-slider-tips:after { - border-color: var(--lay-color-black) transparent transparent transparent; -} -.dark .layui-slider-input { - border: 1px solid var(--lay-color-border-1); -} -.dark .layui-slider-input-btn { - border-left: 1px solid var(--lay-color-border-1); -} -.dark .layui-slider-input-btn i { - color: var(--lay-color-gray-9); -} -.dark .layui-slider-input-btn i:first-child { - border-bottom: 1px solid var(--lay-color-border-1); -} -.dark .layui-slider-input-btn i:hover { - color: var(--lay-color-primary); -} -.dark .layui-tree-line .layui-tree-set .layui-tree-set:after { - border-top: 1px dotted var(--lay-color-gray-7); -} -.dark .layui-tree-entry:hover { - background-color: var(--lay-color-bg-4); -} -.dark .layui-tree-line .layui-tree-entry:hover { - background-color: var(--lay-color-black); -} -.dark .layui-tree-line .layui-tree-entry:hover .layui-tree-txt { - color: var(--lay-color-text-3); -} -.dark .layui-tree-entry:hover:has(span.layui-tree-txt.layui-disabled) { - background-color: transparent !important; -} -.dark .layui-tree-line .layui-tree-set:before { - border-left: 1px dotted var(--lay-color-gray-7); -} -.dark .layui-tree-iconClick { - color: var(--lay-color-gray-7); -} -.dark .layui-tree-icon { - border: 1px solid var(--lay-color-gray-8); -} -.dark .layui-tree-icon .layui-icon { - color: var(--lay-color-text-1); -} -.dark .layui-tree-iconArrow:after { - border-color: transparent transparent transparent var(--lay-color-gray-7); -} -.dark .layui-tree-txt { - color: var(--lay-color-text-2); -} -.dark .layui-tree-search { - color: var(--lay-color-black-7); -} -.dark .layui-tree-btnGroup .layui-icon:hover { - color: var(--lay-color-text-2); -} -.dark .layui-tree-editInput { - background-color: var(--lay-color-fill-2); -} -.dark .layui-tree-emptyText { - color: var(--lay-color-text-2); -} -.dark .layui-code-view { - border: 1px solid var(--lay-color-border-1); -} -.dark .layui-code-view:not(.layui-code-hl) { - background-color: var(--lay-color-bg-2); - color: var(--lay-color-text-2); -} -.dark .layui-code-header { - border-bottom: 1px solid var(--lay-color-border-1); - background-color: var(--lay-color-bg-2); -} -.dark .layui-code-header > .layui-code-header-about { - color: var(--lay-color-text-2); -} -.dark .layui-code-view:not(.layui-code-hl) .layui-code-ln-side { - border-color: var(--lay-color-border-1); - background-color: var(--lay-color-bg-2); -} -.dark .layui-code-nowrap > .layui-code-ln-side { - background: none !important; -} -.dark .layui-code-fixbar > span { - color: var(--lay-color-text-3); -} -.dark .layui-code-fixbar > span:hover { - color: var(--lay-color-secondary-hover); -} -.dark .layui-code-theme-dark, -.dark .layui-code-theme-dark > .layui-code-header { - border-color: rgba(126, 122, 122, 0.15); - background-color: #1f1f1f; -} -.dark .layui-code-theme-dark { - border-width: 1px; - color: #ccc; -} -.dark .layui-code-theme-dark > .layui-code-ln-side { - border-right-color: #2a2a2a; - background: none; - color: #6e7681; -} -.dark .layui-code-view.layui-code-hl > .layui-code-ln-side { - background-color: transparent; -} -.dark .layui-code-theme-dark.layui-code-hl, -.dark .layui-code-theme-dark.layui-code-hl > .layui-code-ln-side { - border-color: rgba(126, 122, 122, 0.15); -} -.dark .layui-code-full { - background-color: var(--lay-color-bg-1); -} -.dark .layui-laydate-header i { - color: var(--lay-color-gray-8); -} -.dark .laydate-day-holidays:before { - color: var(--lay-color-red-6); -} -.dark .layui-laydate .layui-this .laydate-day-holidays:before { - color: var(--lay-color-white); -} -.dark .layui-laydate-footer span { - border: 1px solid var(--lay-color-border-2); - background-color: var(--lay-color-bg-5); -} -.dark .layui-laydate-footer span:hover { - color: var(--lay-color-secondary); -} -.dark .layui-laydate-footer span.layui-laydate-preview { - border-color: transparent!important; -} -.dark .layui-laydate-footer span.layui-laydate-preview:hover { - color: var(--lay-color-text-1) !important; -} -.dark .layui-laydate-shortcut + .layui-laydate-main { - border-left: 1px solid var(--lay-color-border-2); -} -.dark .layui-laydate .layui-laydate-list { - background-color: var(--lay-color-bg-5); -} -.dark .layui-laydate-hint { - color: var(--lay-color-danger); -} -.dark .layui-laydate-range .laydate-main-list-1 .layui-laydate-content, -.dark .layui-laydate-range .laydate-main-list-1 .layui-laydate-header { - border-left: 1px solid var(--lay-color-border-2); -} -.dark .layui-laydate, -.dark .layui-laydate-hint { - border-color: var(--lay-color-border-2); - box-shadow: var(--lay-shadow-3); - background-color: var(--lay-color-bg-5); - color: var(--lay-color-text-1); -} -.dark .layui-laydate { - box-shadow: var(--lay-shadow-2); -} -.dark .layui-laydate-hint { - border-color: var(--lay-color-border-1); -} -.dark .layui-laydate-header { - border-bottom: 1px solid var(--lay-color-border-2); -} -.dark .layui-laydate-header i:hover, -.dark .layui-laydate-header span:hover { - color: var(--lay-color-secondary); -} -.dark .layui-laydate-content th { - color: var(--lay-color-text-1); -} -.dark .layui-laydate-content td { - color: var(--lay-color-text-1); -} -.dark .layui-laydate-content td.laydate-day-now { - color: var(--lay-color-secondary); -} -.dark .layui-laydate-content td.laydate-day-now:after { - border: 1px solid var(--lay-color-secondary); -} -.dark .layui-laydate-linkage .layui-laydate-content td.laydate-selected > div { - background-color: var(--lay-color-green-8); -} -.dark .layui-laydate-linkage .laydate-selected:hover > div { - background-color: var(--lay-color-green-8) !important; -} -.dark .layui-laydate-content td > div:hover, -.dark .layui-laydate-list li:hover, -.dark .layui-laydate-shortcut > li:hover { - background-color: var(--lay-color-fill-2); - color: var(--lay-color-text-2); -} -.dark .layui-laydate-content td.laydate-disabled > div:hover { - background-color: var(--lay-color-bg-5); - color: var(--lay-color-text-4); -} -.dark .laydate-time-list li ol { - border: 1px solid var(--lay-color-border-2); -} -.dark .laydate-time-list > li:hover { - background: 0 0; -} -.dark .layui-laydate-content .laydate-day-next, -.dark .layui-laydate-content .laydate-day-prev { - color: var(--lay-color-text-3); -} -.dark .layui-laydate-linkage .laydate-selected.laydate-day-next > div, -.dark .layui-laydate-linkage .laydate-selected.laydate-day-prev > div { - background: none !important; -} -.dark .layui-laydate-footer { - border-top: 1px solid var(--lay-color-border-2); -} -.dark .layui-laydate-hint { - color: var(--lay-color-danger); -} -.dark .laydate-day-mark::after { - background-color: var(--lay-color-secondary); -} -.dark .layui-laydate-footer span[lay-type=date] { - color: var(--lay-color-secondary); -} -.dark .layui-laydate .layui-this, -.dark .layui-laydate .layui-this > div { - background-color: var(--lay-color-secondary) !important; - color: var(--lay-color-white) !important; -} -.dark .layui-laydate .laydate-disabled, -.dark .layui-laydate .laydate-disabled:hover { - color: var(--lay-color-text-4) !important; -} -.dark .layui-laydate .layui-this.laydate-disabled, -.dark .layui-laydate .layui-this.laydate-disabled > div { - background-color: var(--lay-color-fill-1) !important; - color: var(--lay-color-text-4) !important; -} -.dark .laydate-theme-molv .layui-laydate-header { - background-color: var(--lay-color-primary); -} -.dark .laydate-theme-molv .layui-laydate-header i, -.dark .laydate-theme-molv .layui-laydate-header span { - color: var(--lay-color-gray-2); -} -.dark .laydate-theme-molv .layui-laydate-header i:hover, -.dark .laydate-theme-molv .layui-laydate-header span:hover { - color: var(--lay-color-white); -} -.dark .laydate-theme-molv .layui-laydate-content { - border: 1px solid var(--lay-color-border-2); -} -.dark .laydate-theme-molv .layui-this, -.dark .laydate-theme-molv .layui-this > div { - background-color: var(--lay-color-primary) !important; -} -.dark .laydate-theme-molv .layui-laydate-footer { - border: 1px solid var(--lay-color-border-2); -} -.dark .laydate-theme-grid .laydate-month-list > li, -.dark .laydate-theme-grid .laydate-year-list > li, -.dark .laydate-theme-grid .layui-laydate-content td, -.dark .laydate-theme-grid .layui-laydate-content thead { - border: 1px solid var(--lay-color-border-2); -} -.dark .layui-laydate-linkage.laydate-theme-grid .laydate-selected, -.dark .layui-laydate-linkage.laydate-theme-grid .laydate-selected:hover { - background-color: var(--lay-color-gray-3) !important; - color: var(--lay-color-primary) !important; -} -.dark .layui-laydate-linkage.laydate-theme-grid .laydate-selected.laydate-day-next, -.dark .layui-laydate-linkage.laydate-theme-grid .laydate-selected.laydate-day-prev { - color: var(--lay-color-gray-6) !important; -} -.dark .layui-laydate.laydate-theme-circle .layui-laydate-content table td.layui-this { - background-color: transparent !important; -} -.dark .layui-layer { - background-color: var(--lay-color-bg-3); - box-shadow: var(--lay-shadow-3); -} -.dark .layui-layer-border { - border: 1px solid var(--lay-color-border-2); - box-shadow: var(--lay-shadow-3); -} -.dark .layui-layer-move { - background-color: var(--lay-color-bg-5); -} -.dark .layui-layer-title { - border-bottom: 1px solid var(--lay-color-border-2); - color: var(--lay-color-text-1); -} -.dark .layui-layer-setwin span { - color: var(--lay-color-text-1); -} -.dark .layui-layer-setwin .layui-layer-min:before { - border-bottom-color: var(--lay-color-text-1); -} -.dark .layui-layer-setwin .layui-layer-min:hover:before { - border-bottom-color: var(--lay-color-info-hover); -} -.dark .layui-layer-setwin .layui-layer-max:after, -.dark .layui-layer-setwin .layui-layer-max:before { - border: 1px solid var(--lay-color-text-3); -} -.dark .layui-layer-setwin .layui-layer-max:hover:after, -.dark .layui-layer-setwin .layui-layer-max:hover:before { - border-color: var(--lay-color-info-hover); -} -.dark .layui-layer-setwin .layui-layer-maxmin:after, -.dark .layui-layer-setwin .layui-layer-maxmin:before { - background-color: var(--lay-color-bg-5); -} -.dark .layui-layer-setwin .layui-layer-close2 { - color: var(--lay-color-text-1); - background-color: var(--lay-color-gray-10); -} -.dark .layui-layer-setwin .layui-layer-close2:hover { - background-color: var(--lay-color-normal); -} -.dark .layui-layer-btn a { - border: 1px solid var(--lay-color-border-2); - background-color: var(--lay-color-bg-3); - color: var(--lay-color-text-2); -} -.dark .layui-layer-btn .layui-layer-btn0 { - border-color: transparent; - background-color: var(--lay-color-normal); - color: var(--lay-color-text-1); -} -.dark .layui-layer-dialog .layui-layer-content .layui-layer-face { - color: var(--lay-color-gray-9); -} -.dark .layui-layer-dialog .layui-layer-content .layui-icon-tips { - color: var(--lay-color-warning); -} -.dark .layui-layer-dialog .layui-layer-content .layui-icon-success { - color: var(--lay-color-success); -} -.dark .layui-layer-dialog .layui-layer-content .layui-icon-error { - top: 19px; - color: var(--lay-color-danger); -} -.dark .layui-layer-dialog .layui-layer-content .layui-icon-question { - color: var(--lay-color-warning); -} -.dark .layui-layer-dialog .layui-layer-content .layui-icon-lock { - color: var(--lay-color-gray-10); -} -.dark .layui-layer-dialog .layui-layer-content .layui-icon-face-cry { - color: var(--lay-color-danger); -} -.dark .layui-layer-dialog .layui-layer-content .layui-icon-face-smile { - color: var(--lay-color-success); -} -.dark .layui-layer-rim { - border: 6px solid var(--lay-color-gray-8); - border: 6px solid var(--lay-color-border-2); -} -.dark .layui-layer-msg { - border: 1px solid var(--lay-color-border-1); -} -.dark .layui-layer-hui { - background-color: var(--lay-color-bg-3); - color: var(--lay-color-text-1); -} -.dark .layui-layer-hui .layui-layer-close { - color: var(--lay-color-white); -} -.dark .layui-layer-loading-icon { - color: var(--lay-color-gray-9); -} -.dark .layui-layer-loading-2:after, -.dark .layui-layer-loading-2:before { - border: 3px solid var(--lay-color-gray-6); -} -.dark .layui-layer-loading-2:after { - border-color: transparent; - border-left-color: var(--lay-color-normal); -} -.dark .layui-layer-tips .layui-layer-content { - box-shadow: var(--lay-shadow-3); - background-color: var(--lay-color-bg-5); - color: var(--lay-color-text-1); -} -.dark .layui-layer-tips i.layui-layer-TipsG { - border-color: transparent; -} -.dark .layui-layer-tips i.layui-layer-TipsB, -.dark .layui-layer-tips i.layui-layer-TipsT { - border-right-color: var(--lay-color-black); -} -.dark .layui-layer-tips i.layui-layer-TipsL, -.dark .layui-layer-tips i.layui-layer-TipsR { - border-bottom-color: var(--lay-color-black); -} -.dark .layui-layer-lan .layui-layer-title { - background: var(--lay-color-blue-5); - color: var(--lay-color-text-1); -} -.dark .layui-layer-lan .layui-layer-btn { - border-top: 1px solid var(--lay-color-border-3); -} -.dark .layui-layer-lan .layui-layer-btn a { - background: var(--lay-color-white); - border-color: var(--lay-color-border-3); - color: var(--lay-color-black-7); -} -.dark .layui-layer-lan .layui-layer-btn .layui-layer-btn1 { - background: var(--lay-color-gray-7); -} -.dark .layui-layer-molv .layui-layer-title { - background: var(--lay-color-layuigreen-6); - color: var(--lay-color-text-1); -} -.dark .layui-layer-molv .layui-layer-btn a { - background: var(--lay-color-layuigreen-6); - border-color: var(--lay-color-layuigreen-6); -} -.dark .layui-layer-molv .layui-layer-btn .layui-layer-btn1 { - background: var(--lay-color-gray-7); -} -.dark .layui-layer-win10 { - border-color: var(--lay-color-border-2); -} -.dark .layui-layer-win10 .layui-layer-btn { - background-color: var(--lay-color-bg-2); - border-color: var(--lay-color-border-2); -} -.dark .layui-layer-win10.layui-layer-dialog .layui-layer-content { - color: var(--lay-color-blue-7); -} -.dark .layui-layer-win10 .layui-layer-btn .layui-layer-btn0 { - border-color: var(--lay-color-blue-9); - background-color: var(--lay-color-bg-5); - color: var(--lay-color-text-1); -} -.dark .layui-layer-win10 .layui-layer-btn .layui-layer-btn1 { - border-color: var(--lay-color-border-2); - background-color: var(--lay-color-bg-5); - color: var(--lay-color-text-1); -} -.dark .layui-layer-win10 .layui-layer-btn a:hover { - background-color: var(--lay-color-blue-10); - border-color: var(--lay-color-blue-8); -} -.dark .layui-layer-prompt .layui-layer-input { - border: 1px solid var(--lay-color-border-2); - color: var(--lay-color-text-2); -} -.dark .layui-layer-tab { - box-shadow: var(--lay-shadow-3); -} -.dark .layui-layer-tab .layui-layer-title span.layui-this { - border-left: 1px solid var(--lay-color-border-2); - border-right: 1px solid var(--lay-color-border-2); - background-color: var(--lay-color-bg-3); -} -.dark .layui-layer-photos { - background: none; - box-shadow: none; -} -.dark .layui-layer-photos-prev, -.dark .layui-layer-photos-next { - color: var(--lay-color-gray-9); -} -.dark .layui-layer-photos-prev:hover, -.dark .layui-layer-photos-next:hover { - color: var(--lay-color-text-1); -} -.dark .layui-layer-photos-toolbar { - background-color: #333; - background-color: var(--lay-color-bg-5); - color: var(--lay-color-text-1); -} -.dark .layui-layer-photos-toolbar * { - color: var(--lay-color-text-1); -} -.dark .layui-layer-photos-toolbar a:hover { - color: var(--lay-color-text-2); -} -.dark .layui-layer-photos-header > span:hover { - background-color: var(--lay-color-fill-2); -} -.dark .layui-layer-tips i.layui-layer-TipsB, -.dark .layui-layer-tips i.layui-layer-TipsT { - border-right-color: var(--lay-color-bg-5); -} -.dark .layui-layer-tips i.layui-layer-TipsL, -.dark .layui-layer-tips i.layui-layer-TipsR { - border-bottom-color: var(--lay-color-bg-5); -} -.dark .layui-layer-prompt .layui-layer-input { - border: 1px solid var(--lay-color-border-2); - color: var(--lay-color-text-1); - background-color: var(--lay-color-black); -} -.dark .layui-layer-prompt .layui-layer-input:focus { - outline: 0; -} -.dark .layui-layer-loading { - background: 0 0; - box-shadow: 0 0; -} -.dark .layui-btn-primary { - border-color: transparent; -} -.dark .layui-btn-group .layui-btn:first-child { - border-left: none; -} -.dark .layui-btn-group .layui-btn-primary:hover { - border-top-color: transparent; - border-bottom-color: transparent; -} -.dark .layui-menu li:hover { - background-color: var(--lay-color-fill-2); -} -.dark .layui-nav-child dd.layui-this { - background-color: var(--lay-color-fill-2); -} -.dark .layui-nav .layui-nav-child a:hover { - background-color: var(--lay-color-fill-2); -} -.dark .layui-nav .layui-nav-item a:hover, -.dark .layui-nav .layui-this a { - background-color: var(--lay-color-fill-2); -} -.dark .layui-nav-child dd.layui-this { - background-color: var(--lay-color-fill-2); -} -.dark .layui-tab-card > .layui-tab-title .layui-this:after { - border-bottom-color: var(--lay-color-bg-1); -} -.dark .layui-form-select dl dd:hover { - background-color: var(--lay-color-fill-2); -} -.dark .layui-form-select dl dd.layui-this { - background-color: var(--lay-color-fill-2); -} -.dark .layui-laypage button { - color: var(--lay-color-text-1); -} -.dark .layui-table[lay-even] tbody tr:nth-child(even) { - background-color: var(--lay-color-fill-4); -} -.dark .layui-menu .layui-menu-item-checked, -.dark .layui-menu .layui-menu-item-checked2 { - background-color: var(--lay-color-fill-2) !important; -} -.dark .layui-input-split { - background-color: var(--lay-color-bg-2); -} -.dark .layui-input-wrap .layui-input-prefix.layui-input-split { - border-width: 1px; -} -.dark .layui-input-wrap .layui-input-split:has(+.layui-input:hover) { - border-color: var(--lay-color-border-2); -} -.dark .layui-input-wrap .layui-input-split:has(+.layui-input:focus) { - border-color: var(--lay-color-secondary-hover); -} -.dark .layui-layer-tab .layui-layer-title span:first-child { - border-left: none !important; -} -.dark .layui-slider-input.layui-input, -.dark .layui-slider-input .layui-input { - background-color: var(--lay-color-bg-2); -} - -/*# sourceMappingURL=layui-theme-dark-selector.css.map */ diff --git a/web/static/src/layui-theme-dark-selector.css.map b/web/static/src/layui-theme-dark-selector.css.map deleted file mode 100644 index 476861e..0000000 --- a/web/static/src/layui-theme-dark-selector.css.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["css-variables.css","override.css"],"names":[],"mappings":"AAAA,KAAK;EAGH,sBAAA;EACA,sBAAA;EAEA,0BAAA;EACA,0BAAA;EAEA,0BAAA;EACA,0BAAA;EACA,0BAAA;EACA,0BAAA;EACA,0BAAA;EACA,0BAAA;EACA,0BAAA;EACA,0BAAA;EACA,0BAAA;EACA,2BAAA;EAEA,2BAAA;EACA,2BAAA;EACA,2BAAA;EACA,2BAAA;EACA,2BAAA;EACA,2BAAA;EACA,2BAAA;EACA,2BAAA;EACA,2BAAA;EACA,4BAAA;EAEA,gCAAA;EACA,gCAAA;EACA,gCAAA;EACA,gCAAA;EACA,gCAAA;EACA,gCAAA;EACA,gCAAA;EACA,gCAAA;EACA,gCAAA;EACA,iCAAA;EAEA,iCAAA;EACA,iCAAA;EACA,iCAAA;EACA,iCAAA;EACA,iCAAA;EACA,iCAAA;EACA,iCAAA;EACA,iCAAA;EACA,iCAAA;EACA,kCAAA;EAEA,4BAAA;EACA,4BAAA;EACA,4BAAA;EACA,4BAAA;EACA,4BAAA;EACA,4BAAA;EACA,4BAAA;EACA,4BAAA;EACA,4BAAA;EACA,6BAAA;EAEA,6BAAA;EACA,6BAAA;EACA,6BAAA;EACA,6BAAA;EACA,6BAAA;EACA,6BAAA;EACA,6BAAA;EACA,6BAAA;EACA,6BAAA;EACA,8BAAA;EAEA,2BAAA;EACA,2BAAA;EACA,2BAAA;EACA,2BAAA;EACA,2BAAA;EACA,2BAAA;EACA,2BAAA;EACA,2BAAA;EACA,2BAAA;EACA,4BAAA;EAEA,6BAAA;EACA,6BAAA;EACA,6BAAA;EACA,6BAAA;EACA,6BAAA;EACA,6BAAA;EACA,6BAAA;EACA,6BAAA;EACA,6BAAA;EACA,8BAAA;EAEA,4BAAA;EACA,4BAAA;EACA,4BAAA;EACA,4BAAA;EACA,4BAAA;EACA,4BAAA;EACA,4BAAA;EACA,4BAAA;EACA,4BAAA;EACA,6BAAA;EAEA,2BAAA;EACA,2BAAA;EACA,2BAAA;EACA,2BAAA;EACA,2BAAA;EACA,2BAAA;EACA,2BAAA;EACA,2BAAA;EACA,2BAAA;EACA,4BAAA;EAEA,4BAAA;EACA,4BAAA;EACA,4BAAA;EAIA,qBAAqB,6BAArB;EACA,2BAA2B,6BAA3B;EACA,4BAA4B,6BAA5B;EACA,8BAA8B,6BAA9B;EACA,2BAA2B,6BAA3B;EAGA,uBAAuB,wBAAvB;EACA,6BAA6B,wBAA7B;EACA,8BAA8B,wBAA9B;EACA,gCAAgC,wBAAhC;EACA,6BAA6B,wBAA7B;EAGA,kBAAkB,4BAAlB;EACA,wBAAwB,4BAAxB;EACA,yBAAyB,4BAAzB;EACA,2BAA2B,4BAA3B;EACA,wBAAwB,4BAAxB;EAGA,oBAAoB,uBAApB;EACA,0BAA0B,uBAA1B;EACA,2BAA2B,uBAA3B;EACA,6BAA6B,uBAA7B;EACA,0BAA0B,uBAA1B;EAGA,qBAAqB,yBAArB;EACA,2BAA2B,yBAA3B;EACA,4BAA4B,yBAA5B;EACA,8BAA8B,yBAA9B;EACA,2BAA2B,yBAA3B;EAGA,qBAAqB,wBAArB;EACA,2BAA2B,wBAA3B;EACA,4BAA4B,wBAA5B;EACA,8BAA8B,wBAA9B;EACA,2BAA2B,wBAA3B;EAGA,oBAAoB,sBAApB;EACA,0BAA0B,sBAA1B;EACA,2BAA2B,sBAA3B;EACA,6BAA6B,sBAA7B;EACA,0BAA0B,sBAA1B;EAEA,yBAAA;EACA,yBAAA;EACA,yBAAA;EACA,yBAAA;EACA,yBAAA;EACA,6BAAA;EAEA,4CAAA;EACA,4CAAA;EACA,4CAAA;EACA,4CAAA;EAEA,6BAAA;EACA,6BAAA;EACA,6BAAA;EACA,6BAAA;EAEA,6CAAA;EACA,6CAAA;EACA,6CAAA;EACA,6CAAA;EAEA,mBAAmB,uBAAnB;EACA,oBAAoB,uBAApB;EAEA,4GAAA;EACA,4GAAA;EACA,8GAAA;;ACxMF,KAAM,CAAA;AAAN,KAAiB,CAAA;AAAjB,KAAsB,CAAA;AAAtB,KAA6B,CAAA;AAA7B,KAAgC,CAAA;AAAhC,KAAoC,CAAA;AAApC,KAAuC,CAAA;AAAvC,KAA0C,CAAA;AAA1C,KAA+C,CAAA;AAA/C,KAAkD,CAAA;AAAlD,KAAqD,CAAA;AAArD,KAAwD,CAAA;AAAxD,KAA2D,CAAA;AAA3D,KAA8D,CAAA;AAA9D,KAAiE,CAAA;AAAjE,KAAuE,CAAA;AAAvE,KAA0E,CAAA;AAA1E,KAA6E,CAAA;AAA7E,KAA+E,CAAA;AAA/E,KAAmF,CAAA;AAAnF,KAAsF,CAAA;AAAtF,KAA+F,CAAA;AAA/F,KAAkG,CAAA;EAAG,6CAAA;;AAArG,KACA;EAAK,OAAM,uBAAN;EAA8B,kBAAkB,qBAAlB;EAAyC,kBAAA;;AAD5E,KAEA;EAAG,yBAAwB,yBAAxB;;AAFH,KAGA;EAAE,OAAM,uBAAN;;AAHF,KAIA,EAAC;EAAO,OAAM,uBAAN;;AAJR,KAMA;EAAY,yBAAA;;AANZ,KAOA;EAAgB,qBAAoB,yBAApB;;AAPhB,KAQA;EAAkB,mBAAkB,yBAAlB;;AARlB,KASA;EAAmB,kBAAiB,yBAAjB;;AATnB,KAUA;EAAiB,oBAAmB,yBAAnB;;AAVjB,KAYA;AAZA,KAYgB,CAAA,eAAe;EAAO,OAAM,uBAAN;;AAZtC,KAcA;EAAY,kCAAA;;AAdZ,KAgBA,oBAAoB;EAAc,kBAAiB,qBAAjB;;AAhBlC,KAiBA,oBAAoB;EAAc,0CAAA;EAAuC,kBAAiB,qBAAjB;;AAjBzE,KAkBA,oBAAoB;EAAY,OAAM,wBAAN;EAA+B,2CAAA;;AAlB/D,KAoBA;EAAkB,uBAAsB,0BAAtB;EAAiD,kBAAiB,uBAAjB;;AApBnE,KAqBA;EAAgB,cAAc,uBAAd;;AArBhB,KAuBA;EAAgB,kBAAkB,qBAAlB;;AAvBhB,KAwBA;EAAoB,kBAAiB,0BAAjB;;AAxBpB,KAyBA;EAAqB,OAAM,uBAAN;;AAzBrB,KA0BA,oBAAoB;EAAqB,OAAO,uBAAP;;AA1BzC,KA4BA;EAAmB,OAAO,uBAAP;EAA+B,kBAAkB,qBAAlB;;AA5BlD,KA6BA;EAAqB,OAAM,uBAAN;;AA7BrB,KA+BA;EAAY,kBAAkB,qBAAlB;EAAwC,YAAW,mBAAX;;AA/BpD,KAgCA;EAAmB,yBAAwB,yBAAxB;EAAkD,OAAM,uBAAN;;AAhCrE,KAkCA;EAAa,YAAW,mBAAX;EAA+B,kBAAkB,qBAAlB;EAAyC,OAAO,uBAAP;;AAlCrF,KAmCA;EAAuB,YAAY,mBAAZ;;AAnCvB,KAqCA;EAAoB,sBAAqB,yBAArB;EAA+C,kBAAkB,qBAAlB;;AArCnE,KAuCA;EAAc,kBAAiB,sBAAjB;EAAkD,OAAO,sBAAP;;AAvChE,KAwCA;EAAiB,kBAAiB,yBAAjB;EAAqD,OAAO,sBAAP;;AAxCtE,KAyCA;EAAgB,kBAAiB,6BAAjB;EAAyD,OAAO,sBAAP;;AAzCzE,KA0CA;EAAe,kBAAiB,uBAAjB;EAAmD,OAAO,sBAAP;;AA1ClE,KA2CA;EAAe,kBAAkB,uBAAlB;EAAoD,OAAO,sBAAP;;AA3CnE,KA4CA;EAAgB,kBAAiB,wBAAjB;EAAoD,OAAO,sBAAP;;AA5CpE,KA6CA;EAAiB,kBAAkB,yBAAlB;EAAuD,OAAO,sBAAP;;AA7CxE,KA8CA;EAAe,kBAAiB,uBAAjB;EAAmD,OAAO,wBAAP;;AA9ClE,KAgDA;AAhDA,KAgDiB,CAAA;AAhDjB,KAgD+B,CAAA;AAhD/B,KAgDoD,CAAA;AAhDpD,KAgDsE,CAAA;AAhDtE,KAgDsF,CAAA;AAhDtF,KAgDwG,CAAA,gBAAiB,iBAAgB;AAhDzI,KAgDgJ,CAAA,gBAAiB;AAhDjK,KAgDmL,CAAA;AAhDnL,KAgDgM,CAAA;AAhDhM,KAgDmN,CAAA;AAhDnN,KAgDgO,CAAA;AAhDhO,KAgD8O,CAAA;AAhD9O,KAgD6P,CAAA;AAhD7P,KAgD6Q,CAAA;AAhD7Q,KAgD8R,CAAA,gBAAiB,YAAW;AAhD1T,KAgDiU,CAAA;EAAgB,cAAc,yBAAd;;AAhDjV,KAkDA;EAAc,OAAM,uBAAN;;AAlDd,KAmDA;EAAkB,cAAa,sBAAb;EAA8C,OAAM,sBAAN;;AAnDhE,KAoDA;EAAqB,cAAa,yBAAb;EAAiD,OAAM,yBAAN;;AApDtE,KAqDA;EAAoB,cAAa,6BAAb;EAAqD,OAAM,6BAAN;;AArDzE,KAsDA;EAAmB,cAAa,uBAAb;EAA+C,OAAM,uBAAN;;AAtDlE,KAuDA;EAAmB,cAAc,uBAAd;EAAgD,OAAO,uBAAP;;AAvDnE,KAwDA;EAAqB,cAAc,yBAAd;EAAmD,OAAO,yBAAP;;AAxDxE,KAyDA;EAAoB,cAAa,wBAAb;EAAgD,OAAM,uBAAN;;AAzDpE,KA2DA;EAAY,OAAM,uBAAN;;AA3DZ,KA4DA;AA5DA,KA4De,CAAA;EAAgB,OAAO,uBAAP;;AA5D/B,KA6DA,YAAY,EAAC,IAAI;EAAa,OAAM,4BAAN;;AA7D9B,KA8DA,YAAY,WAAU,IAAI;EAAoB,uBAAsB,yBAAtB;;AA9D9C,KAgEA;EAAgB,OAAM,sBAAN;;AAhEhB,KAiEA;EAAmB,OAAM,yBAAN;;AAjEnB,KAkEA;EAAkB,OAAM,6BAAN;;AAlElB,KAmEA;EAAiB,OAAM,uBAAN;;AAnEjB,KAoEA;EAAiB,OAAM,4BAAN;;AApEjB,KAqEA;EAAkB,OAAM,sBAAN;;AArElB,KAsEA;EAAmB,OAAM,yBAAN;;AAtEnB,KAuEA;EAAiB,OAAM,uBAAN;;AAvEjB,KAyEA;EAAW,6BAAA;EAA6B,kBAAiB,wBAAjB;EAA0C,OAAO,uBAAP;;AAzElF,KA0EA,WAAU;EAAO,OAAO,uBAAP;;AA1EjB,KA2EA;EAAmB,cAAa,yBAAb;EAAuC,OAAM,uBAAN;EAA8B,kBAAkB,qBAAlB;;AA3ExF,KA4EA,mBAAkB;EAAO,yBAAA;EAA0B,OAAM,uBAAN;;AA5EnD,KA6EA;EAAkB,kBAAkB,uBAAlB;;AA7ElB,KA8EA;EAAgB,kBAAiB,wBAAjB;;AA9EhB,KA+EA;EAAkB,kBAAiB,uBAAjB;;AA/ElB,KAgFA;EAAmB,kBAAiB,wBAAjB;;AAhFnB,KAiFA;AAjFA,KAiFoB,CAAA,mBAAmB;AAjFvC,KAiF+C,CAAA,mBAAmB;EAAO,cAAc,yBAAd;EAAkD,kBAAkB,qBAAlB;EAAkD,OAAO,uBAAP;;AAjF7K,KAkFA,iBAAiB;EAAW,uBAAuB,yBAAvB;;AAlF5B,KAmFA,iBAAiB,mBAAkB;EAAO,cAAa,yBAAb;EAAuC,OAAM,wBAAN;;AAnFjF,KAoFA,iBAAiB,mBAAkB;EAAa,uBAAsB,uBAAtB;;AApFhD,KAsFA;AAtFA,KAsFa,CAAA;AAtFb,KAsF2B,CAAA;EAAgB,kBAAkB,uBAAlB;EAA0C,OAAO,uBAAP;;AAtFrF,KAuFA,aAAY;AAvFZ,KAuFmB,CAAA,eAAe;EAAO,cAAc,yBAAd;;AAvFzC,KAwFA,aAAY;AAxFZ,KAwFmB,CAAA,eAAe;EAAO,cAAc,gCAAd;EAAyD,kBAAkB,qBAAlB;EAAwC,8CAAA;;AAxF1I,KAyFA,aAAY;AAzFZ,KAyFuB,CAAA,aAAa;AAzFpC,KAyF+C,CAAA,eAAe;AAzF9D,KAyFyE,CAAA,YAAY;AAzFrF,KAyFqG,CAAA,eAAe;EAAgB,kBAAkB,uBAAlB;EAA0C,OAAO,uBAAP;EAA+B,cAAc,yBAAd;EAAkD,mBAAA;;AAzF/P,KA0FA,mBAAkB,qBAAoB;AA1FtC,KA0FmD,CAAA,kBAAkB;EAAO,cAAa,uBAAb;EAA+C,6CAAA;;AA1F3H,KA4FA,oBAAoB;AA5FpB,KA4FgC,CAAA,kBAAmB;AA5FnD,KA4F+D,CAAA,mBAAoB;EAAY,OAAO,uBAAP;;AA5F/F,KA6FA,kBAAkB,aAAY,MAAM;EAAoB,cAAc,yBAAd;;AA7FxD,KA8FA,kBAAkB,aAAY,UAAU,MAAM;EAAoB,cAAc,yBAAd;;AA9FlE,KA+FA,kBAAkB,aAAY,MAAM;EAAoB,cAAc,gCAAd;;AA/FxD,KAgGA,kBAAkB,aAAY,kBAAkB,MAAO;EAAqB,cAAc,uBAAd;;AAhG5E,KAiGA,mBAAmB;EAAY,OAAO,uBAAP;;AAjG/B,KAkGA,mBAAmB;EAAkB,OAAM,uBAAN;;AAlGrC,KAmGA,mBAAmB,YAAW;EAAO,OAAM,uBAAN;;AAnGrC,KAqGA,kBAAkB,oBAAoB;EAAe,qBAAoB,yBAApB;;AArGrD,KAsGA,kBAAkB,aAAY,eAAe;EAAiC,OAAM,uBAAN;;AAtG9E,KAwGA;EAAmB,OAAM,uBAAN;;AAxGnB,KAyGA,mBAAmB;EAAY,kBAAiB,uBAAjB;;AAzG/B,KA0GA,mBAAmB;EAAG,kBAAkB,yBAAlB;EAA6C,kBAAkB,qBAAlB;EAAwC,YAAW,mBAAX;;AA1G3G,KA2GA,mBAAmB,GAAG;EAAG,OAAM,uBAAN;;AA3GzB,KA4GA,mBAAmB,GAAG,GAAE;EAAO,kBAAiB,uBAAjB;;AA5G/B,KA6GA,mBAAmB,GAAG,GAAE;EAAmB,OAAM,uBAAN;;AA7G3C,KA8GA,mBAAmB,GAAG,GAAE;EAAY,kBAAkB,uBAAlB;EAA0C,OAAO,uBAAP;;AA9G9E,KA+GA,mBAAmB,GAAG,GAAE;AA/GxB,KA+GwC,CAAA,kBAAmB,GAAG,GAAE,MAAM;EAAgB,kBAAkB,qBAAlB;;AA/GtF,KAgHA;EAAmB,OAAM,wBAAN;;AAhHnB,KAiHA,uBAAuB;EAAgB,cAAa,yBAAb;;AAjHvC,KAkHA,uBAAuB;EAAY,kBAAiB,uBAAjB;;AAlHnC,KAoHA;EAAqB,kBAAiB,uBAAjB;;AApHrB,KAqHA,qBAAoB;EAAK,kBAAiB,uBAAjB;EAAyC,OAAM,uBAAN;;AArHlE,KAsHA,qBAAoB,MAAM;EAAK,kBAAkB,uBAAlB;;AAtH/B,KAuHA,qBAAoB;EAAG,kBAAkB,uBAAlB;EAA0C,kBAAiB,yBAAjB;EAA2C,oBAAmB,yBAAnB;EAA6C,qBAAoB,yBAApB;EAA8C,0BAAA;EAA0B,OAAM,uBAAN;;AAvHjO,KAwHA,qBAAoB,MAAM;EAAG,cAAa,yBAAb;EAAuC,OAAM,uBAAN;;AAxHpE,KAyHA;AAzHA,KAyHoB,CAAA,mBAAmB;EAAO,cAAa,iCAAb;;AAzH9C,KA0HA,oBAAmB;AA1HnB,KA0HwB,CAAA,mBAAmB,MAAM;EAAK,kBAAiB,0BAAjB;;AA1HtD,KA2HA,oBAAmB;AA3HnB,KA2HsB,CAAA,mBAAmB,MAAM;EAAG,OAAM,gCAAN;;AA3HlD,KA4HA,qBAAoB,wBAAwB;EAAK,kBAAkB,uBAAlB;;AA5HjD,KA8HA,qBAAoB;EAAmB,sBAAA;EAAsB,yBAAA;EAAyB,qBAAA;;AA9HtF,KA+HA,qBAAoB,kBAAkB;EAAK,sBAAA;EAAsB,yBAAA;EAAyB,OAAM,uBAAN;;AA/H1F,KAgIA,qBAAoB,kBAAkB;EAAG,cAAa,yBAAb;EAAuC,kBAAiB,uBAAjB;;AAhIhF,KAiIA,qBAAoB,kBAAkB,MAAM;EAAG,cAAa,gCAAb;EAA8C,OAAM,uBAAN;;AAjI7F,KAkIA,oBAAmB,kBAAkB;EAAG,kBAAiB,0BAAjB;EAA4C,OAAM,uBAAN;EAA8B,cAAa,iCAAb;;AAlIlH,KAmIA,yBAAwB,kBAAmB;EAAK,0BAAA;EAA0B,OAAM,uBAAN;;AAnI1E,KAoIA,oBAAmB,wBAAwB,kBAAkB;EAAG,kBAAiB,uBAAjB;EAAmD,cAAa,yBAAb;;AApInH,KAqIA,yBAAwB,kBAAkB,MAAM;EAAG,cAAa,yBAAb;;AArInD,KAsIA,qBAAoB,oBAAoB,4BAA0B;EAAQ,kBAAkB,gCAAlB;EAAmD,UAAA;;AAtI7H,KAuIA,qBAAoB,oBAAoB,MAAM,4BAA0B;EAAQ,UAAA;;AAvIhF,KAwIA,qBAAoB,oBAAoB;EAA2B,cAAc,gCAAd;;AAxInE,KA0IA;EAAmB,cAAa,yBAAb;EAAuC,kBAAiB,uBAAjB;;AA1I1D,KA2IA,mBAAkB;EAAG,kBAAiB,uBAAjB;;AA3IrB,KA4IA,mBAAkB,wBAAwB;EAAG,kBAAiB,uBAAjB;;AA5I7C,KA6IA,mBAAkB;EAAK,OAAM,uBAAN;;AA7IvB,KA8IA;EAAqB,cAAa,iCAAb;EAA+C,kBAAiB,0BAAjB;;AA9IpE,KA+IA,qBAAoB;EAAG,kBAAiB,uBAAjB;;AA/IvB,KAgJA,qBAAoB;EAAK,OAAM,uBAAN;;AAhJzB,KAiJA;EAAyB,cAAa,yBAAb;;AAjJzB,KAkJA,yBAAwB;EAAK,kBAAiB,uBAAjB;EAAmD,OAAO,uBAAP;;AAlJhF,KAmJA,yBAAwB;EAAG,cAAa,yBAAb;;AAnJ3B,KAoJA,yBAAwB,MAAM;EAAG,OAAM,uBAAN;;AApJjC,KAqJA,mBAAkB,wBAAwB;EAAK,mCAAA;EAAmC,OAAO,uBAAP;;AArJlF,KAuJA,qBAAoB,IAAE;EAAQ,UAAA;EAAU,wBAAA;;AAvJxC,KAwJA,qBAAoB,MAAM,IAAE;EAAQ,UAAA;EAAU,0BAAA;;AAxJ9C,KAyJA,oBAAmB,wBAAwB,MAAM,IAAE;AAzJnD,KAyJ2D,CAAA,mBAAmB,MAAM,IAAE;AAzJtF,KAyJ8F,CAAA,mBAAmB,IAAE;EAAQ,UAAA;EAAU,0BAAA;;AAzJrI,KA0JA,qBAAoB,kBAAkB,MAAM,IAAE;EAAQ,UAAA;EAAU,wBAAA;;AA1JhE,KA2JA,oBAAmB,kBAAkB,MAAM,IAAE;EAAQ,UAAA;EAAU,0BAAA;;AA3J/D,KA4JA,yBAAwB,MAAM,IAAE;EAAQ,UAAA;EAAU,wBAAA;;AA5JlD,KA8JA,kBAAiB;EAAG,OAAM,uBAAN;;AA9JpB,KA+JA,kBAAiB,MAAM;AA/JvB,KA+J0B,CAAA;AA/J1B,KA+J8C,CAAA,mBAAmB;EAAG,OAAM,0BAAN;;AA/JpE,KAgKA,sBAAqB;EAAG,OAAM,uBAAN;;AAhKxB,KAiKA,sBAAqB;EAAG,OAAM,uBAAN;;AAjKxB,KAmKA,iBAAiB;EAAkB,kBAAiB,qBAAjB;;AAnKnC,KAqKA,eAAe;AArKf,KAqKiB,CAAA,cAAe;AArKhC,KAqKuC,CAAA,cAAe;AArKtD,KAqK4D,CAAA,cAAe;AArK3E,KAqKkF,CAAA,cAAe;EAAK,kBAAkB,yBAAlB;;AArKtG,KAsKA,eAAe;AAtKf,KAsKiB,CAAA,cAAe;EAAK,kBAAkB,qBAAlB;EAAwC,OAAO,uBAAP;;AAtK7E,KAuKA,eAAe,EAAC;EAAY,OAAM,uBAAN;;AAvK5B,KAwKA,eAAe,EAAC;EAAO,OAAO,wBAAP;;AAxKvB,KAyKA,eAAe;EAAmB,OAAM,uBAAN;;AAzKlC,KA0KA,eAAe,oBAAoB;EAAG,OAAO,sBAAP;;AA1KtC,KA2KA,eAAe,oBAAoB;EAAkB,kBAAkB,wBAAlB;;AA3KrD,KA4KA,eAAe;EAAoB,OAAM,uBAAN;;AA5KnC,KA6KA,eAAe;AA7Kf,KA6KsB,CAAA,cAAe;EAAM,kBAAkB,qBAAlB;;AA7K3C,KA8KA,eAAe,MAAK;AA9KpB,KA8K2B,CAAA,cAAe,OAAM;EAAO,cAAc,wBAAd;;AA9KvD,KAgLA;EAAiB,OAAM,uBAAN;;AAhLjB,KAiLA,iBAAiB,EAAE;EAAK,kBAAkB,qBAAlB;EAAwC,OAAO,uBAAP;;AAjLhE,KAkLA,iBAAiB,EAAE;EAAE,OAAM,uBAAN;;AAlLrB,KAoLA;EAAa,kBAAkB,qBAAlB;EAAwC,OAAO,uBAAP;;AApLrD,KAqLA;EAAkB,kBAAkB,qBAAlB;;AArLlB,KAsLA;AAtLA,KAsLmB,CAAA;AAtLnB,KAsLsC,CAAA,YAAY,UAAW,MAAM,GAAE,UAAU;EAAO,kBAAiB,uBAAjB;;AAtLtF,KAuLA;EAAqB,kBAAkB,uBAAlB;EAA0C,OAAO,uBAAP;;AAvL/D,KAwLA,qBAAoB;AAxLpB,KAwLuC,CAAA,oBAAoB;EAAmB,kBAAkB,uBAAlB;;AAxL9E,KAyLA,aAAa;AAzLb,KAyLgB,CAAA,YAAa;AAzL7B,KAyLgC,CAAA;AAzLhC,KAyLqD,CAAA;AAzLrD,KAyL0E,CAAA;AAzL1E,KAyLiG,CAAA;AAzLjG,KAyLqH,CAAA;AAzLrH,KAyLuI,CAAA;AAzLvI,KAyLyJ,CAAA;AAzLzJ,KAyLgL,CAAA;AAzLhL,KAyLkM,CAAA;AAzLlM,KAyLqN,CAAA;AAzLrN,KAyLuO,CAAA,YAAY;AAzLnP,KAyLmQ,CAAA,YAAY;EAAe,cAAc,yBAAd;;AAzL9R,KA0LA,kBAAiB;EAAQ,kBAAkB,yBAAlB;;AA1LzB,KA2LA,kBAAkB,aAAa,GAAE,WAAW,MAAM;EAAO,kBAAiB,+BAAjB;;AA3LzD,KA4LA,0BAA0B;EAAY,OAAM,uBAAN;;AA5LtC,KA6LA;EAAkB,kBAAkB,qBAAlB;;AA7LlB,KA8LA,kBAAkB,eAAe;AA9LjC,KA+LA,kBAAkB,eAAe;EAAK,YAAA;;AA/LtC,KAgMA;EAAkB,kBAAkB,qBAAlB;;AAhMlB,KAiMA,kBAAkB,cAAa;EAAY,OAAM,uBAAN;EAA8B,kBAAiB,yBAAjB;;AAjMzE,KAkMA,kBAAkB,cAAa,WAAW;EAAO,kBAAiB,yBAAjB;;AAlMjD,KAmMA;EAAwB,OAAO,uBAAP;EAAgC,kBAAkB,yBAAlB;EAA4C,kBAAkB,qBAAlB;EAAwC,YAAW,mBAAX;;AAnM5I,KAoMA,wBAAwB,GAAE;EAAO,kBAAiB,uBAAjB;;AApMjC,KAqMA;EAAqB,kBAAkB,sBAAlB;;AArMrB,KAsMA,kBAAkB;EAAsB,qBAAoB,uBAApB;;AAtMxC,KAuMA,kBAAkB,sBAAqB;EAAO,qBAAoB,wBAApB;;AAvM9C,KAwMA,kBAAkB;EAAuB,kBAAiB,uBAAjB;;AAxMzC,KAyMA,kBAAkB,uBAAsB;EAAO,kBAAiB,wBAAjB;;AAzM/C,KA0MA,kBAAiB,cAAe;EAAsB,qBAAoB,wBAApB;;AA1MtD,KA2MA,kBAAiB,eAAgB;EAAuB,kBAAiB,wBAAjB;;AA3MxD,KA4MA,kBAAkB;EAAkB,OAAO,4BAAP;;AA5MpC,KA6MA,kBAAkB;EAAY,OAAM,uBAAN;;AA7M9B,KA8MA;EAAqB,6BAAA;;AA9MrB,KA+MA;EAAqB,8BAAA;;AA/MrB,KAgNA;EAAkB,YAAW,mBAAX;EAA+B,kBAAkB,qBAAlB;;AAhNjD,KAiNA,kBAAiB;EAAO,cAAa,0BAAb;;AAjNxB,KAkNA,OAAM;EAAkB,cAAa,yBAAb;;AAlNxB,KAmNA;EAAuB,kBAAkB,qBAAlB;EAAwC,OAAM,uBAAN;;AAnN/D,KAoNA,uBAAsB;EAAO,kBAAiB,qBAAjB;;AApN7B,KAsNA;EAAoB,kBAAkB,wBAAlB;EAA2C,OAAO,uBAAP;EAAgC,cAAc,yBAAd;;AAtN/F,KAuNA,oBAAmB;EAAO,cAAc,gCAAd;;AAvN1B,KAyNA,KAAK,kBAAkB;EAAqB,YAAW,mBAAX;;AAzN5C,KA0NA;EAAuB,kBAAkB,qBAAlB;EAAwC,OAAO,uBAAP;;AA1N/D,KA2NA;EAAoB,kBAAiB,wBAAjB;EAA0C,OAAO,uBAAP;;AA3N9D,KA4NA,oBAAmB;EAAO,kBAAiB,wBAAjB;;AA5N1B,KA8NA;EAAqB,OAAM,uBAAN;;AA9NrB,KA+NA;EAAmB,mBAAkB,yBAAlB;EAA6C,kBAAkB,qBAAlB;EAAwC,OAAO,uBAAP;;AA/NxG,KAgOA,mBAAmB;EAAY,OAAO,wBAAP;;AAhO/B,KAiOA,mBAAkB;EAAW,cAAc,wBAAd;;AAjO7B,KAmOA;EAAY,kBAAkB,qBAAlB;;AAnOZ,KAoOA,YAAY;EAAG,OAAO,uBAAP;;AApOf,KAqOA,YAAY,GAAE;EAAO,kBAAkB,qBAAlB;;AArOrB,KAsOA,YAAY,GAAE;AAtOd,KAsO8B,CAAA,WAAY,GAAE,eAAgB;EAAE,OAAM,uBAAN;;AAtO9D,KAuOA,YAAY,uBAAsB;EAAwB,OAAO,uBAAP;;AAvO1D,KAwOA,YAAY;EAAsB,OAAO,uBAAP;;AAxOlC,KAyOA,YAAY;EAAyB,yBAAwB,yBAAxB;;AAzOrC,KA0OA,YAAY,uBAAsB;AA1OlC,KA2OA,YAAY,sBAAqB;AA3OjC,KA4OA,YAAY,yBAAwB;EAAO,gBAAA;;AA5O3C,KA6OA,YAAY,oBAAmB;EAAwB,OAAO,uBAAP;;AA7OvD,KA8OA,YAAY,sBAAqB,MAAM,yBAAuB;AA9O9D,KA8O2E,CAAA,WAAY,oBAAmB,yBAAuB,MAAM;EAAa,OAAO,uBAAP;;AA9OpJ,KA+OA,YAAY;AA/OZ,KA+OqC,CAAA,WAAY;EAA0B,kBAAiB,uBAAjB;EAAmD,OAAM,0BAAN;;AA/O9H,KAgPA,YAAY,yBAAyB;AAhPrC,KAgPuC,CAAA,WAAY,0BAA0B;EAAE,OAAM,0BAAN;;AAhP/E,KAiPA,YAAY,yBAAwB;EAAO,wBAAuB,0BAAvB;;AAjP3C,KAkPA,uBAAuB;EAAE,OAAO,uBAAP;;AAlPzB,KAmPA,eAAe,uBAAuB,EAAC;AAnPvC,KAmP8C,CAAA,cAAe,GAAE;EAAO,OAAM,0BAAN;;AAnPtE,KAqPA;EAAgB,kBAAkB,qBAAlB;;AArPhB,KAsPA,gBAAe;AAtPf,KAsP4B,CAAA,eAAgB;EAAa,kBAAkB,qBAAlB;EAAwC,YAAY,mBAAZ;;AAtPjG,KAuPA,gBAAe,YAAa;EAAY,kBAAkB,qBAAlB;;AAvPxC,KAyPA;EAAW,kBAAiB,wBAAjB;EAA0C,OAAO,sBAAP;;AAzPrD,KA0PA,WAAW,gBAAgB;EAAE,OAAO,uBAAP;;AA1P7B,KA2PA,WAAW,YAAW;AA3PtB,KA2P6B,CAAA;EAAe,kBAAiB,0BAAjB;;AA3P5C,KA4PA,WAAW,gBAAgB,EAAC;AA5P5B,KA4PmC,CAAA,UAAW,YAAY;EAAE,OAAO,uBAAP;;AA5P5D,KA6PA;EAAiB,YAAW,mBAAX;EAA+B,kBAAiB,yBAAjB;EAA2C,kBAAkB,qBAAlB;;AA7P3F,KA8PA,WAAW,iBAAiB;EAAE,OAAO,uBAAP;;AA9P9B,KA+PA,WAAW,iBAAiB,EAAC;EAAO,kBAAkB,qBAAlB;EAAwC,OAAO,uBAAP;;AA/P5E,KAgQA,iBAAiB,GAAE;EAAY,kBAAkB,qBAAlB;EAAwC,OAAO,uBAAP;;AAhQvE,KAiQA,gBAAgB,iBAAiB,GAAE;AAjQnC,KAiQ+C,CAAA,eAAgB,iBAAiB,GAAE,WAAY;AAjQ9F,KAiQgG,CAAA,eAAgB;AAjQhH,KAiQ4H,CAAA,eAAgB,YAAW;AAjQvJ,KAiQ0J,CAAA,eAAgB,YAAW,IAAE;EAAO,kBAAkB,wBAAlB;EAA2C,OAAO,sBAAP;;AAjQzO,KAkQA,kBAAiB;AAlQjB,KAkQoB,CAAA,eAAgB,iBAAiB;AAlQrD,KAkQuD,CAAA,eAAgB,iBAAiB,EAAC;EAAO,OAAO,sBAAP;;AAlQhG,KAmQA,gBAAgB;EAAe,kBAAiB,wBAAjB;;AAnQ/B,KAoQA,gBAAgB;EAAiB,gBAAA;EAAkB,oCAAA;EAAoC,YAAA;EAAc,gBAAA;;AApQrG,KAqQA,gBAAgB,iBAAiB;EAAE,OAAO,sBAAP;EAA8B,OAAO,uBAAP;;AArQjE,KAsQA,gBAAgB,iBAAiB,EAAC;EAAO,gBAAA;EAAkB,OAAO,sBAAP;;AAtQ3D,KAuQA,WAAU;AAvQV,KAuQyB,CAAA,eAAe;EAAe,kBAAkB,qBAAlB;EAAmD,OAAO,uBAAP;;AAvQ1G,KAwQA,gBAAe,cAAe;EAAiB,oCAAA;;AAxQ/C,KAyQA,gBAAe,cAAe;AAzQ9B,KAyQgC,CAAA,UAAU,cAAe,gBAAgB;EAAE,OAAO,uBAAP;;AAzQ3E,KA0QA,WAAU,cAAe;EAAiB,kBAAkB,qBAAlB;;AA1Q1C,KA2QA,gBAAe,cAAe,kBAAiB;EAAG,OAAO,uBAAP;;AA3QlD,KA4QA,WAAU,cAAe,YAAY;EAAE,OAAM,0BAAN;;AA5QvC,KA6QA,gBAAe,cAAe,iBAAiB,GAAE;AA7QjD,KA6Q6D,CAAA,eAAe,cAAe,iBAAiB,GAAE,WAAY;AA7Q1H,KA6Q4H,CAAA,eAAe,cAAe;AA7Q1J,KA6QsK,CAAA,eAAe,cAAe,YAAW;EAAG,OAAM,0BAAN;;AA7QlN,KA8QA,gBAAe,cAAe;EAAe,kBAAiB,0BAAjB;;AA9Q7C,KAgRA,kBAAkB;EAAE,OAAM,uBAAN;;AAhRpB,KAiRA,kBAAkB,EAAC;EAAO,OAAM,0BAAN;;AAjR1B,KAkRA,kBAAkB,EAAE;EAAK,OAAM,uBAAN;;AAlRzB,KAmRA,kBAAkB,KAAI;EAAgB,OAAM,uBAAN;;AAnRtC,KAqRA,WAAW,iBAAgB;EAAO,qBAAqB,yBAArB;;AArRlC,KAsRA,iBAAiB;EAAY,OAAO,uBAAP;;AAtR7B,KAuRA,iBAAiB,YAAW;EAAO,qBAAqB,qBAArB;;AAvRnC,KAwRA;EAAe,kBAAkB,qBAAlB;;AAxRf,KAyRA,gBAAgB,GAAE,WAAW;EAAO,qBAAoB,yBAApB;;AAzRpC,KA0RA,iBAAiB,GAAG;EAAiB,OAAM,uBAAN;;AA1RrC,KA2RA,iBAAiB,GAAG,iBAAgB;EAAO,kBAAiB,uBAAjB;EAAyC,OAAO,sBAAP;;AA3RpF,KA4RA,iBAAgB,mBAAkB;EAAY,OAAM,wBAAN;;AA5R9C,KA6RA,iBAAgB,kBAAiB,GAAE,WAAW;AA7R9C,KA6RqD,CAAA,gBAAgB,mBAAkB,YAAW;EAAO,yBAAwB,0BAAxB;;AA7RzG,KA8RA;EAAgB,YAAY,mBAAZ;;AA9RhB,KA+RA,gBAAe;EAAkB,kBAAkB,qBAAlB;;AA/RjC,KAgSA,gBAAe,mBAAkB;EAAY,kBAAkB,qBAAlB;;AAhS7C,KAiSA,gBAAe,mBAAkB,YAAW;EAAO,qBAAqB,qBAArB;;AAjSnD,KAkSA,gBAAe,kBAAiB;EAAY,OAAM,0BAAN;;AAlS5C,KAqSA,mBAAkB;AArSlB,KAsSA,mBAAkB;EAAO,qBAAqB,yBAArB;;AAtSzB,KAuSA,iBAAgB,qBAAoB;EAAY,6BAAA;;AAvShD,KAwSA,iBAAgB,qBAAoB,YAAW;EAAO,cAAc,yBAAd;EAAyC,qBAAqB,qBAArB;;AAxS/F,KAySA,iBAAgB,YAAY,qBAAoB,YAAW;EAAO,qBAAqB,qBAArB;;AAzSlE,KA0SA,gBAAgB;EAAY,kBAAkB,qBAAlB;EAAyC,OAAO,uBAAP;EAAgC,cAAc,yBAAd;EAAyC,2CAAA;;AA1S9I,KA2SA,gBAAgB;EAAiB,4CAAA;;AA3SjC,KA8SA;EAAqB,kBAAkB,qBAAlB;EAAwC,OAAM,0BAAN;;AA9S7D,KA+SA,qBAAoB;EAAO,OAAM,sBAAN;;AA/S3B,KAgTA,qBAAoB;EAAQ,kBAAkB,qBAAlB;;AAhT5B,KAkTA;AAlTA,KAkTa,CAAA;AAlTb,KAkT8B,CAAA;EAAiB,kBAAiB,sBAAjB;EAAwC,OAAO,sBAAP;;AAlTvF,KAmTA;EAAiB,kBAAkB,sBAAlB;EAAyC,OAAM,wBAAN;;AAnT1D,KAqTA;EAAgB,kBAAiB,uBAAjB;;AArThB,KAsTA,gBAAe,kBAAgB;EAAQ,OAAM,uBAAN;EAA8B,kCAAA;;AAtTrE,KAuTA,gBAAe,kBAAgB;EAAG,kBAAiB,uBAAjB;;AAvTlC,KAwTA;EAAsB,oCAAA;EAAgC,OAAO,sBAAP;;AAxTtD,KAyTA,sBAAqB;AAzTrB,KAyT4B,CAAA,mBAAoB,GAAE;EAAO,kBAAiB,sBAAjB;;AAzTzD,KA0TA,gBAAe,uBAAwB,oBAAoB;EAAG,kBAAiB,sBAAjB;;AA1T9D,KA2TA,oBAAoB;EAAG,oCAAA;;AA3TvB,KA4TA,oBAAoB,GAAG;EAAG,kBAAiB,uBAAjB;EAAyC,kBAAkB,uBAAlB;;AA5TnE,KA6TA,oBAAoB,GAAG,GAAE;EAAO,kBAAkB,sBAAlB;;AA7ThC,KA8TA,oBAAoB,GAAG,GAAE;EAAY,kBAAkB,sBAAlB;;AA9TrC,KAgUA,cAAc;EAAG,kBAAiB,wBAAjB;EAA0C,OAAO,uBAAP;;AAhU3D,KAkUA,KAAK,iBAAiB;EAAqB,kBAAkB,qBAAlB;EAAwC,OAAM,uBAAN;;AAlUnF,KAmUA,iBAAiB;EAAG,kBAAiB,yBAAjB;EAA2C,kBAAkB,qBAAlB;EAAwC,YAAW,mBAAX;;AAnUvG,KAoUA,iBAAiB,GAAG;EAAG,kBAAiB,yBAAjB;;AApUvB,KAqUA,iBAAiB,GAAG,GAAE;EAAO,kBAAiB,sBAAjB;EAAwC,YAAY,uBAAZ;;AArUrE,KAuUA;EAAY,kBAAiB,yBAAjB;EAA2C,kBAAkB,yBAAlB;EAA4C,OAAO,uBAAP;;AAvUnG,KAyUA;AAzUA,KAyUoB,CAAA;AAzUpB,KAyU2C,CAAA;EAAuB,cAAc,yBAAd;;AAzUlE,KA0UA;EAAoB,kBAAkB,qBAAlB;;AA1UpB,KA2UA,uBAAuB;EAAmB,OAAM,uBAAN;;AA3U1C,KA4UA,uBAAuB;EAAW,kBAAiB,0BAAjB;EAA6C,cAAa,0BAAb;EAAyC,OAAO,sBAAP;;AA5UxH,KA6UA,uBAAuB;EAAoB,kBAAiB,uBAAjB;EAAyC,cAAa,uBAAb;EAAqC,OAAM,uBAAN;;AA7UzH,KA8UA,qBAAqB,GAAE;EAAO,kBAAiB,uBAAjB;;AA9U9B,KAgVA,qBAAqB,GAAE,MAAM,IAAI;EAA+C,kBAAiB,qBAAjB;;AAhVhF,KAiVA,qBAAqB;EAAY,OAAM,uBAAN;;AAjVjC,KAmVA,YAAY,GAAG,EAAC;EAAY,OAAM,yBAAN;;AAnV5B,KAqVA;EAAmB,kBAAiB,yBAAjB;;AArVnB,KAsVA,mBAAkB;EAAO,cAAc,yBAAd;;AAtVzB,KAuVA;EAAgC,kBAAiB,yBAAjB;;AAvVhC,KAwVA;EAA6B,OAAO,sBAAP;;AAxV7B,KAyVA,6BAA4B;EAAkB,OAAM,wBAAN;;AAzV9C,KA0VA;EAAwB,YAAY,qBAAZ;EAAkC,kBAAiB,yBAAjB;EAA4C,YAAW,mBAAX;;AA1VtG,KA2VA;EAA+B,YAAW,kDAAX;;AA3V/B,KA4VA;EAA+B,YAAW,wCAAX;;AA5V/B,KA6VA;EAAgC,kBAAiB,sBAAjB;;AA7VhC,KA8VA;EAAwB,YAAW,gBAAgB,0DAA3B;;AA9VxB,KA+VA;EAA+B,YAAW,mBAAX;EAA+B,YAAY,sBAAZ;EAAmC,kBAAiB,uBAAjB;;AA/VjG,KAgWA;EAAgC,YAAW,mBAAX;EAA+B,YAAY,sBAAZ;EAAmC,kBAAiB,uBAAjB;;AAhWlG,KAiWA,uBAAsB;EAAY,YAAW,mBAAX;;AAjWlC,KAkWA,uBAAsB;EAAU,YAAW,mBAAX;;AAlWhC,KAmWA,8BAA8B,MAAK;EAAa,OAAO,uBAAP;;AAnWhD,KAqWA;EAAc,YAAY,qBAAZ;;AArWd,KAsWA;EAAmB,YAAY,uBAAZ;;AAtWnB,KAuWA;EAAuB,YAAY,qBAAZ;;AAvWvB,KAwWA;EAAmB,OAAO,uBAAP;EAA+B,YAAW,sBAAX;EAAkC,YAAY,mBAAZ;;AAxWpF,KAyWA,mBAAkB;EAAO,cAAa,0DAAb;;AAzWzB,KA0WA;EAAoB,kBAAkB,yBAAlB;;AA1WpB,KA2WA;EAAwB,uBAAuB,yBAAvB;;AA3WxB,KA4WA,wBAAwB;EAAE,OAAM,uBAAN;;AA5W1B,KA6WA,wBAAwB,EAAC;EAAa,yBAAyB,yBAAzB;;AA7WtC,KA8WA,wBAAwB,EAAC;EAAO,OAAM,wBAAN;;AA9WhC,KAgXA,iBAAiB,gBAAgB,gBAAe;EAAO,uBAAsB,uBAAtB;;AAhXvD,KAiXA,kBAAiB;EAAO,kBAAkB,qBAAlB;;AAjXxB,KAkXA,iBAAiB,kBAAiB;EAAO,kBAAiB,sBAAjB;;AAlXzC,KAmXA,iBAAiB,kBAAiB,MAAO;EAAgB,OAAM,uBAAN;;AAnXzD,KAoXA,kBAAiB,MAAM,IAAI;EAAqC,6BAAA;;AApXhE,KAqXA,iBAAiB,gBAAe;EAAQ,wBAAuB,uBAAvB;;AArXxC,KAsXA;EAAsB,OAAM,uBAAN;;AAtXtB,KAuXA;EAAiB,kBAAiB,uBAAjB;;AAvXjB,KAwXA,iBAAiB;EAAY,OAAM,uBAAN;;AAxX7B,KAyXA,sBAAqB;EAAO,kDAAiD,uBAAjD;;AAzX5B,KA0XA;EAAgB,OAAM,uBAAN;;AA1XhB,KA2XA;EAAmB,OAAM,wBAAN;;AA3XnB,KA4XA,qBAAqB,YAAW;EAAO,OAAM,uBAAN;;AA5XvC,KA6XA;EAAsB,kBAAiB,uBAAjB;;AA7XtB,KA8XA;EAAsB,OAAM,uBAAN;;AA9XtB,KAgYA;EAAiB,kBAAiB,yBAAjB;;AAhYjB,KAiYA,iBAAgB,IAAI;EAAiB,kBAAkB,qBAAlB;EAAwC,OAAO,uBAAP;;AAjY7E,KAkYA;EAAmB,yBAAyB,yBAAzB;EAAoD,kBAAkB,qBAAlB;;AAlYvE,KAmYA,mBAAmB;EAA2B,OAAO,uBAAP;;AAnY9C,KAoYA,iBAAgB,IAAI,gBAAiB;EAAoB,cAAc,yBAAd;EAAyC,kBAAkB,qBAAlB;;AApYlG,KAqYA,mBAAmB;EAAsB,2BAAA;;AArYzC,KAsYA,mBAAmB;EAAO,OAAO,uBAAP;;AAtY1B,KAuYA,mBAAmB,OAAM;EAAO,OAAO,gCAAP;;AAvYhC,KAyYA;AAzYA,KA0YA,uBAAuB;EAAqB,uCAAA;EAAsC,yBAAA;;AA1YlF,KA2YA;EAAuB,iBAAA;EAAmB,WAAA;;AA3Y1C,KA4YA,uBAAuB;EAAsB,2BAAA;EAA6B,gBAAA;EAAkB,cAAA;;AA5Y5F,KA8YA,iBAAgB,cAAe;EAAsB,6BAAA;;AA9YrD,KA+YA,uBAAsB;AA/YtB,KAgZA,uBAAsB,cAAe;EAAsB,uCAAA;;AAhZ3D,KAkZA;EAAiB,kBAAkB,qBAAlB;;AAlZjB,KAoZA,sBAAsB;EAAE,OAAM,uBAAN;;AApZxB,KAqZA,sBAAqB;EAAQ,OAAM,sBAAN;;AArZ7B,KAsZA,eAAe,YAAY,sBAAqB;EAAQ,OAAO,sBAAP;;AAtZxD,KAuZA,sBAAsB;EAAK,kBAAkB,yBAAlB;EAA4C,kBAAkB,qBAAlB;;AAvZvE,KAwZA,sBAAsB,KAAI;EAAO,OAAM,0BAAN;;AAxZjC,KAyZA,sBAAsB,KAAI;EAAuB,mCAAA;;AAzZjD,KA0ZA,sBAAsB,KAAI,sBAAsB;EAAO,OAAM,uBAAN;;AA1ZvD,KA2ZA,wBAAuB;EAAqB,uBAAuB,yBAAvB;;AA3Z5C,KA4ZA,eAAe;EAAoB,kBAAkB,qBAAlB;;AA5ZnC,KA6ZA;EAAoB,OAAM,uBAAN;;AA7ZpB,KA8ZA,qBAAqB,qBAAqB;AA9Z1C,KA8ZiE,CAAA,oBAAqB,qBAAqB;EAAsB,uBAAuB,yBAAvB;;AA9ZjI,KA+ZA;AA/ZA,KA+Ze,CAAA;EAAoB,cAAc,yBAAd;EAAwC,YAAW,mBAAX;EAA+B,kBAAkB,qBAAlB;EAAwC,OAAO,uBAAP;;AA/ZlJ,KAgaA;EAAe,YAAY,mBAAZ;;AAhaf,KAiaA;EAAoB,cAAa,yBAAb;;AAjapB,KAkaA;EAAsB,yBAAyB,yBAAzB;;AAlatB,KAmaA,sBAAsB,EAAC;AAnavB,KAma8B,CAAA,qBAAsB,KAAI;EAAO,OAAM,0BAAN;;AAna/D,KAoaA,uBAAuB;EAAG,OAAO,uBAAP;;AApa1B,KAqaA,uBAAuB;EAAG,OAAO,uBAAP;;AAra1B,KAsaA,uBAAuB,GAAE;EAAiB,OAAM,0BAAN;;AAta1C,KAuaA,uBAAuB,GAAE,gBAAgB;EAAO,kBAAiB,0BAAjB;;AAvahD,KAwaA,uBAAuB,uBAAuB,GAAE,iBAAiB;EAAK,kBAAiB,wBAAjB;;AAxatE,KAyaA,uBAAuB,kBAAiB,MAAM;EAAK,kBAAiB,wBAAjB;;AAzanD,KA0aA,uBAAuB,GAAE,MAAI;AA1a7B,KA0aoC,CAAA,mBAAoB,GAAE;AA1a1D,KA0aiE,CAAA,uBAAuB,KAAG;EAAO,kBAAkB,uBAAlB;EAA0C,OAAO,uBAAP;;AA1a5I,KA2aA,uBAAuB,GAAE,iBAAiB,MAAI;EAAO,kBAAkB,qBAAlB;EAAwC,OAAO,uBAAP;;AA3a7F,KA4aA,mBAAmB,GAAG;EAAG,kBAAkB,yBAAlB;;AA5azB,KA6aA,mBAAkB,KAAG;EAAO,eAAA;;AA7a5B,KA8aA,uBAAuB;AA9avB,KA8ayC,CAAA,sBAAuB;EAAkB,OAAO,uBAAP;;AA9alF,KA+aA,uBAAuB,kBAAiB,iBAAiB;AA/azD,KA+a8D,CAAA,sBAAuB,kBAAiB,iBAAiB;EAAK,gBAAA;;AA/a5H,KAgbA;EAAsB,sBAAsB,yBAAtB;;AAhbtB,KAibA;EAAoB,OAAM,uBAAN;;AAjbpB,KAkbA,kBAAiB;EAAQ,kBAAiB,0BAAjB;;AAlbzB,KAmbA,sBAAsB,KAAI;EAAgB,OAAM,0BAAN;;AAnb1C,KAobA,eAAe;AApbf,KAob2B,CAAA,cAAe,YAAW;EAAK,kBAAiB,0BAAjB;EAAsD,OAAO,sBAAP;;AApbhH,KAqbA,eAAe;AArbf,KAqbiC,CAAA,cAAe,kBAAiB;EAAO,OAAO,uBAAP;;AArbxE,KAsbA,eAAe,YAAW;AAtb1B,KAsb4C,CAAA,cAAe,YAAW,iBAAiB;EAAK,kBAAkB,uBAAlB;EAAqD,OAAO,uBAAP;;AAtbjJ,KAubA,oBAAoB;EAAsB,kBAAiB,wBAAjB;;AAvb1C,KAwbA,oBAAoB,sBAAsB;AAxb1C,KAwb4C,CAAA,mBAAoB,sBAAsB;EAAK,OAAM,uBAAN;;AAxb3F,KAybA,oBAAoB,sBAAsB,EAAC;AAzb3C,KAybkD,CAAA,mBAAoB,sBAAsB,KAAI;EAAO,OAAO,sBAAP;;AAzbvG,KA0bA,oBAAoB;EAAuB,kBAAiB,yBAAjB;;AA1b3C,KA2bA,oBAAoB;AA3bpB,KA2biC,oBAAoB,YAAW;EAAK,kBAAkB,wBAAlB;;AA3brE,KA4bA,oBAAoB;EAAsB,kBAAiB,yBAAjB;;AA5b1C,KA6bA,oBAAoB,oBAAmB;AA7bvC,KA6b2C,CAAA,mBAAoB,mBAAkB;AA7bjF,KA6bqF,CAAA,mBAAoB,uBAAuB;AA7bhI,KA6bmI,CAAA,mBAAoB,uBAAuB;EAAM,kBAAkB,yBAAlB;;AA7bpL,KA8bA,uBAAsB,mBAAoB;AA9b1C,KA8b4D,CAAA,sBAAsB,mBAAoB,kBAAiB;EAAO,kBAAiB,uBAAjB;EAAmD,OAAM,wBAAN;;AA9bjL,KA+bA,uBAAsB,mBAAoB,kBAAiB;AA/b3D,KA+b6E,CAAA,sBAAsB,mBAAoB,kBAAiB;EAAkB,OAAM,uBAAN;;AA/b1J,KAgcA,eAAc,qBAAsB,uBAAuB,MAAM,GAAE;EAAY,6BAAA;;AAhc/E,KAkcA;EAAa,kBAAkB,qBAAlB;EAAwC,YAAW,mBAAX;;AAlcrD,KAmcA;EAAoB,kBAAiB,yBAAjB;EAA2C,YAAW,mBAAX;;AAnc/D,KAocA;EAAkB,kBAAkB,qBAAlB;;AApclB,KAqcA;EAAmB,yBAAwB,yBAAxB;EAAkD,OAAO,uBAAP;;AArcrE,KAscA,oBAAoB;EAAK,OAAO,uBAAP;;AAtczB,KAucA,oBAAoB,iBAAgB;EAAQ,qBAAoB,uBAApB;;AAvc5C,KAwcA,oBAAoB,iBAAgB,MAAM;EAAQ,qBAAoB,2BAApB;;AAxclD,KAycA,oBAAoB,iBAAgB;AAzcpC,KAyc2C,CAAA,mBAAoB,iBAAgB;EAAQ,kBAAiB,uBAAjB;;AAzcvF,KA0cA,oBAAoB,iBAAgB,MAAM;AA1c1C,KA0ciD,CAAA,mBAAoB,iBAAgB,MAAM;EAAQ,cAAa,2BAAb;;AA1cnG,KA2cA,oBAAoB,oBAAmB;AA3cvC,KA2c8C,CAAA,mBAAoB,oBAAmB;EAAQ,kBAAkB,qBAAlB;;AA3c7F,KA4cA,oBAAoB;EAAoB,OAAM,uBAAN;EAA8B,kBAAiB,wBAAjB;;AA5ctE,KA6cA,oBAAoB,oBAAmB;EAAO,kBAAiB,uBAAjB;;AA7c9C,KA8cA,iBAAiB;EAAE,kBAAkB,yBAAlB;EAA4C,kBAAkB,qBAAlB;EAAyC,OAAO,uBAAP;;AA9cxG,KA+cA,iBAAiB;EAAkB,yBAAA;EAA0B,kBAAkB,uBAAlB;EAA0C,OAAO,uBAAP;;AA/cvG,KAgdA,oBAAoB,qBAAqB;EAAkB,OAAM,uBAAN;;AAhd3D,KAidA,oBAAoB,qBAAqB;EAAiB,OAAM,wBAAN;;AAjd1D,KAkdA,oBAAoB,qBAAqB;EAAoB,OAAO,wBAAP;;AAld7D,KAmdA,oBAAoB,qBAAqB;EAAkB,SAAA;EAAW,OAAO,uBAAP;;AAndtE,KAodA,oBAAoB,qBAAqB;EAAqB,OAAO,wBAAP;;AApd9D,KAqdA,oBAAoB,qBAAqB;EAAiB,OAAO,wBAAP;;AArd1D,KAsdA,oBAAoB,qBAAqB;EAAqB,OAAM,uBAAN;;AAtd9D,KAudA,oBAAoB,qBAAqB;EAAuB,OAAM,wBAAN;;AAvdhE,KAwdA;EAAiB,kBAAiB,uBAAjB;EAAyC,kBAAiB,yBAAjB;;AAxd1D,KAydA;EAAiB,kBAAiB,yBAAjB;;AAzdjB,KA0dA;EAAiB,kBAAkB,qBAAlB;EAAwC,OAAO,uBAAP;;AA1dzD,KA2dA,iBAAiB;EAAmB,OAAO,sBAAP;;AA3dpC,KA4dA;EAA0B,OAAM,uBAAN;;AA5d1B,KA6dA,uBAAsB;AA7dtB,KA6d6B,CAAA,sBAAsB;EAAQ,kBAAiB,uBAAjB;;AA7d3D,KA8dA,uBAAsB;EAAO,yBAAA;EAAyB,mBAAmB,uBAAnB;;AA9dtD,KA+dA,kBAAkB;EAAqB,YAAY,mBAAZ;EAAgC,kBAAkB,qBAAlB;EAAwC,OAAO,uBAAP;;AA/d/G,KAgeA,kBAAkB,EAAC;EAAmB,yBAAA;;AAhetC,KAieA,kBAAkB,EAAC;AAjenB,KAiesC,CAAA,iBAAkB,EAAC;EAAmB,oBAAmB,sBAAnB;;AAje5E,KAkeA,kBAAkB,EAAC;AAlenB,KAkesC,CAAA,iBAAkB,EAAC;EAAmB,qBAAoB,sBAApB;;AAle5E,KAmeA,iBAAiB;EAAmB,YAAW,uBAAX;EAAmC,OAAO,uBAAP;;AAnevE,KAoeA,iBAAiB;EAAiB,sBAAqB,yBAArB;;AApelC,KAqeA,iBAAiB,iBAAiB;EAAE,YAAY,sBAAZ;EAAmC,cAAa,yBAAb;EAAuC,OAAO,wBAAP;;AAre9G,KAseA,iBAAiB,iBAAiB;EAAkB,YAAY,uBAAZ;;AAtepD,KAueA,kBAAkB;EAAmB,YAAW,6BAAX;EAAyC,OAAO,uBAAP;;AAve9E,KAweA,kBAAkB,iBAAiB;EAAE,YAAW,6BAAX;EAAyC,cAAa,6BAAb;;AAxe9E,KAyeA,kBAAkB,iBAAiB;EAAkB,YAAW,uBAAX;;AAzerD,KA0eA;EAAmB,cAAc,yBAAd;;AA1enB,KA2eA,mBAAmB;EAAiB,kBAAkB,qBAAlB;EAAwC,cAAc,yBAAd;;AA3e5E,KA4eA,mBAAkB,mBAAoB;EAAqB,OAAO,uBAAP;;AA5e3D,KA6eA,mBAAmB,iBAAiB;EAAkB,cAAc,uBAAd;EAAsC,kBAAkB,qBAAlB;EAAwC,OAAO,uBAAP;;AA7epI,KA8eA,mBAAmB,iBAAiB;EAAkB,cAAc,yBAAd;EAAwC,kBAAkB,qBAAlB;EAAwC,OAAO,uBAAP;;AA9etI,KA+eA,mBAAmB,iBAAiB,EAAC;EAAO,kBAAkB,wBAAlB;EAA2C,cAAc,uBAAd;;AA/evF,KAgfA,oBAAoB;EAAmB,kBAAiB,yBAAjB;EAA2C,OAAO,uBAAP;;AAhflF,KAifA;EAAiB,YAAW,mBAAX;;AAjfjB,KAkfA,iBAAiB,mBAAmB,KAAI;EAAY,uBAAuB,yBAAvB;EAAiD,wBAAwB,yBAAxB;EAAkD,kBAAkB,qBAAlB;;AAlfvJ,KAmfA;EAAoB,gBAAA;EAAkB,gBAAA;;AAnftC,KAofA;AApfA,KAofyB,CAAA;EAAyB,OAAM,uBAAN;;AApflD,KAqfA,yBAAwB;AArfxB,KAqf+B,CAAA,wBAAwB;EAAO,OAAM,uBAAN;;AArf9D,KAsfA;EAA4B,sBAAA;EAAsB,kBAAkB,qBAAlB;EAAwC,OAAO,uBAAP;;AAtf1F,KAufA,4BAA4B;EAAE,OAAO,uBAAP;;AAvf9B,KAwfA,4BAA4B,EAAC;EAAO,OAAO,uBAAP;;AAxfpC,KAyfA,2BAA2B,OAAM;EAAO,kBAAkB,uBAAlB;;AAzfxC,KA0fA,kBAAkB,EAAC;AA1fnB,KA0fsC,CAAA,iBAAkB,EAAC;EAAmB,oBAAoB,qBAApB;;AA1f5E,KA2fA,kBAAkB,EAAC;AA3fnB,KA2fsC,CAAA,iBAAkB,EAAC;EAAmB,qBAAqB,qBAArB;;AA3f5E,KA4fA,oBAAoB;EAAmB,kBAAiB,yBAAjB;EAA2C,OAAM,uBAAN;EAA8B,kBAAiB,sBAAjB;;AA5fhH,KA6fA,oBAAoB,mBAAkB;EAAO,UAAA;;AA7f7C,KAggBA;EAAqB,eAAA;EAAe,eAAA;;AAhgBpC,KAigBA;EAAmB,yBAAA;;AAjgBnB,KAkgBA,iBAAiB,WAAU;EAAa,iBAAA;;AAlgBxC,KAmgBA,iBAAiB,mBAAkB;EAAO,6BAAA;EAA8B,gCAAA;;AAngBxE,KAogBA,YAAY,GAAE;EAAO,kBAAiB,uBAAjB;;AApgBrB,KAqgBA,iBAAiB,GAAE;EAAY,kBAAiB,uBAAjB;;AArgB/B,KAsgBA,WAAW,iBAAiB,EAAC;EAAO,kBAAiB,uBAAjB;;AAtgBpC,KAugBA,WAAW,gBAAgB,EAAC;AAvgB5B,KAugBmC,CAAA,UAAW,YAAY;EAAE,kBAAkB,uBAAlB;;AAvgB5D,KAwgBA,iBAAiB,GAAE;EAAY,kBAAkB,uBAAlB;;AAxgB/B,KAygBA,gBAAe,mBAAkB,YAAW;EAAO,qBAAoB,qBAApB;;AAzgBnD,KA0gBA,mBAAmB,GAAG,GAAE;EAAO,kBAAiB,uBAAjB;;AA1gB/B,KA2gBA,mBAAmB,GAAG,GAAE;EAAY,kBAAiB,uBAAjB;;AA3gBpC,KA4gBA,eAAe;EAAO,OAAM,uBAAN;;AA5gBtB,KA6gBA,aAAY,UAAW,MAAM,GAAE,UAAU;EAAO,kBAAiB,uBAAjB;;AA7gBhD,KA8gBA,YAAY;AA9gBZ,KA8gBqC,CAAA,WAAY;EAA0B,kBAAiB,uBAAjB;;AA9gB3E,KA+gBA;EAAmB,kBAAkB,qBAAlB;;AA/gBnB,KAghBA,kBAAkB,oBAAmB;EAAmB,iBAAA;;AAhhBxD,KAihBA,kBAAkB,mBAAkB,IAAI;EAAuB,cAAc,yBAAd;;AAjhB/D,KAkhBA,kBAAkB,mBAAkB,IAAI;EAAuB,cAAc,gCAAd;;AAlhB/D,KAmhBA,iBAAiB,mBAAmB,KAAI;EAAa,4BAAA;;AAnhBrD,KAohBA,oBAAmB;AAphBnB,KAqhBA,oBAAoB;EAAc,kBAAkB,qBAAlB","file":"layui-theme-dark-selector.css","sourcesContent":[":root{\r\n /* =====色板===== */\r\n /*常量,不随明暗主题变化*/\r\n --color-white: #FFFFFF;\r\n --color-black: #000000;\r\n\r\n --lay-color-white: #FAFAFA;\r\n --lay-color-black: #333333;\r\n\r\n --lay-color-red-1: #FFF1E8; \r\n --lay-color-red-2: #FFD7C0; \r\n --lay-color-red-3: #FFBB99; \r\n --lay-color-red-4: #FF9C71; \r\n --lay-color-red-5: #FF7A4A; \r\n --lay-color-red-6: #FF5722; \r\n --lay-color-red-7: #D23B15; \r\n --lay-color-red-8: #A6250B; \r\n --lay-color-red-9: #791404; \r\n --lay-color-red-10: #4D0800;\r\n\r\n --lay-color-blue-1: #E8F9FF;\r\n --lay-color-blue-2: #C0ECFF;\r\n --lay-color-blue-3: #97DCFF;\r\n --lay-color-blue-4: #6FCAFF;\r\n --lay-color-blue-5: #46B5FF;\r\n --lay-color-blue-6: #1E9FFF;\r\n --lay-color-blue-7: #1379D2;\r\n --lay-color-blue-8: #0A58A6;\r\n --lay-color-blue-9: #043A79;\r\n --lay-color-blue-10: #00214D;\r\n\r\n --lay-color-lightblue-1: #E8FDFF;\r\n --lay-color-lightblue-2: #C1F4FB;\r\n --lay-color-lightblue-3: #9CEAF7;\r\n --lay-color-lightblue-4: #77DDF4;\r\n --lay-color-lightblue-5: #53CEF0;\r\n --lay-color-lightblue-6: #31BDEC;\r\n --lay-color-lightblue-7: #1F95C4;\r\n --lay-color-lightblue-8: #10709C;\r\n --lay-color-lightblue-9: #064E74;\r\n --lay-color-lightblue-10: #002F4D;\r\n\r\n --lay-color-layuigreen-1: #E8FFF9;\r\n --lay-color-layuigreen-2: #B5F1E3;\r\n --lay-color-layuigreen-3: #87E3D1;\r\n --lay-color-layuigreen-4: #5DD6C1;\r\n --lay-color-layuigreen-5: #37C8B5;\r\n --lay-color-layuigreen-6: #16BAAA;\r\n --lay-color-layuigreen-7: #0E9F95;\r\n --lay-color-layuigreen-8: #08837F;\r\n --lay-color-layuigreen-9: #036868;\r\n --lay-color-layuigreen-10: #004A4D;\r\n\r\n --lay-color-green-1: #E8FFF2;\r\n --lay-color-green-2: #B5F1D1;\r\n --lay-color-green-3: #86E2B4;\r\n --lay-color-green-4: #5CD49C;\r\n --lay-color-green-5: #37C588;\r\n --lay-color-green-6: #16B777;\r\n --lay-color-green-7: #0E9C68;\r\n --lay-color-green-8: #088259;\r\n --lay-color-green-9: #036749;\r\n --lay-color-green-10: #004D38;\r\n\r\n --lay-color-orange-1: #FFFCE8;\r\n --lay-color-orange-2: #FFF5BA;\r\n --lay-color-orange-3: #FFEA8B;\r\n --lay-color-orange-4: #FFDC5D;\r\n --lay-color-orange-5: #FFCB2E;\r\n --lay-color-orange-6: #FFB800;\r\n --lay-color-orange-7: #D29000;\r\n --lay-color-orange-8: #A66C00;\r\n --lay-color-orange-9: #794B00;\r\n --lay-color-orange-10: #4D2D00;\r\n\r\n --lay-color-cyan-1: #E8F6FF;\r\n --lay-color-cyan-2: #B9CEDD;\r\n --lay-color-cyan-3: #8FA7BB;\r\n --lay-color-cyan-4: #6A829A;\r\n --lay-color-cyan-5: #4A5F78;\r\n --lay-color-cyan-6: #2F4056;\r\n --lay-color-cyan-7: #223654;\r\n --lay-color-cyan-8: #162C51;\r\n --lay-color-cyan-9: #0B214F;\r\n --lay-color-cyan-10: #00174D;\r\n\r\n --lay-color-purple-1: #FDE8FF;\r\n --lay-color-purple-2: #EDBEF4;\r\n --lay-color-purple-3: #DC97E8;\r\n --lay-color-purple-4: #C972DD;\r\n --lay-color-purple-5: #B651D1;\r\n --lay-color-purple-6: #A233C6;\r\n --lay-color-purple-7: #8120A8;\r\n --lay-color-purple-8: #631289;\r\n --lay-color-purple-9: #48076B;\r\n --lay-color-purple-10: #2F004D;\r\n\r\n --lay-color-black-1: #E8F8FF;\r\n --lay-color-black-2: #BFD0D8;\r\n --lay-color-black-3: #98A8B1;\r\n --lay-color-black-4: #73818A;\r\n --lay-color-black-5: #505B63;\r\n --lay-color-black-6: #2F363C;\r\n --lay-color-black-7: #23303C;\r\n --lay-color-black-8: #18293C;\r\n --lay-color-black-9: #0C213C;\r\n --lay-color-black-10: #00183C;\r\n\r\n --lay-color-gray-1: #FAFAFA;\r\n --lay-color-gray-2: #F6F6F6;\r\n --lay-color-gray-3: #EEEEEE;\r\n --lay-color-gray-4: #E2E2E2;\r\n --lay-color-gray-5: #DDDDDD;\r\n --lay-color-gray-6: #D2D2D2;\r\n --lay-color-gray-7: #CCCCCC;\r\n --lay-color-gray-8: #C2C2C2;\r\n --lay-color-gray-9: #AAAAAA;\r\n --lay-color-gray-10: #939393;\r\n\r\n --lay-color-gray-11: #858585;\r\n --lay-color-gray-12: #7b7b7b;\r\n --lay-color-gray-13: #686868;\r\n\r\n /* =====语义===== */\r\n /* 主色 */\r\n --lay-color-primary: var(--lay-color-layuigreen-6); \r\n --lay-color-primary-hover: var(--lay-color-layuigreen-5);\r\n --lay-color-primary-active: var(--lay-color-layuigreen-7);\r\n --lay-color-primary-disabled: var(--lay-color-layuigreen-3);\r\n --lay-color-primary-light: var(--lay-color-layuigreen-4);\r\n\r\n /* 次色 */\r\n --lay-color-secondary: var(--lay-color-green-6);\r\n --lay-color-secondary-hover: var(--lay-color-green-5);\r\n --lay-color-secondary-active: var(--lay-color-green-7);\r\n --lay-color-secondary-disabled: var(--lay-color-green-3);\r\n --lay-color-secondary-light: var(--lay-color-green-4);\r\n\r\n /* 引导 */\r\n --lay-color-info: var(--lay-color-lightblue-6);\r\n --lay-color-info-hover: var(--lay-color-lightblue-5);\r\n --lay-color-info-active: var(--lay-color-lightblue-7);\r\n --lay-color-info-disabled: var(--lay-color-lightblue-3);\r\n --lay-color-info-light: var(--lay-color-lightblue-4);\r\n\r\n /* 百搭 */\r\n --lay-color-normal: var(--lay-color-blue-6);\r\n --lay-color-normal-hover: var(--lay-color-blue-5);\r\n --lay-color-normal-active: var(--lay-color-blue-7);\r\n --lay-color-normal-disabled: var(--lay-color-blue-3);\r\n --lay-color-normal-light: var(--lay-color-blue-4);\r\n\r\n /* 警示 */\r\n --lay-color-warning: var(--lay-color-orange-6);\r\n --lay-color-warning-hover: var(--lay-color-orange-5);\r\n --lay-color-warning-active: var(--lay-color-orange-7);\r\n --lay-color-warning-disabled: var(--lay-color-orange-3);\r\n --lay-color-warning-light: var(--lay-color-orange-4);\r\n\r\n /* 成功 */\r\n --lay-color-success: var(--lay-color-green-6);\r\n --lay-color-success-hover: var(--lay-color-green-5);\r\n --lay-color-success-active: var(--lay-color-green-7);\r\n --lay-color-success-disabled: var(--lay-color-green-3);\r\n --lay-color-success-light: var(--lay-color-green-4);\r\n\r\n /* 错误 */\r\n --lay-color-danger: var(--lay-color-red-6);\r\n --lay-color-danger-hover: var(--lay-color-red-5);\r\n --lay-color-danger-active: var(--lay-color-red-7);\r\n --lay-color-danger-disabled: var(--lay-color-red-3);\r\n --lay-color-danger-light: var(--lay-color-red-4);\r\n\r\n --lay-color-bg-1: #17171A; /*整体背景*/\r\n --lay-color-bg-2: #232324; /*一级容器背景,卡片,面板*/\r\n --lay-color-bg-3: #2a2a2b; /*二级容器背景*/\r\n --lay-color-bg-4: #313132; /*三级容器背景*/\r\n --lay-color-bg-5: #373739; /*下拉弹出框、Tooltip 背景颜色*/\r\n --lay-color-bg-white: #f6f6f6; /*白色背景*/\r\n\r\n --lay-color-text-1: rgba(255,255,255,.9); /*强调/正文标题*/\r\n --lay-color-text-2: rgba(255,255,255,.7); /*次强调/语句*/\r\n --lay-color-text-3: rgba(255,255,255,.5); /*次要信息*/\r\n --lay-color-text-4: rgba(255,255,255,.3);/*禁用状态文字 */\r\n\r\n --lay-color-border-1: #2e2e30;\r\n --lay-color-border-2: #484849;\r\n --lay-color-border-3: #5f5f60;\r\n --lay-color-border-4: #929293;\r\n\r\n --lay-color-fill-1: rgba(255,255,255,.04);/*浅/禁用*/\r\n --lay-color-fill-2: rgba(255,255,255,.08);/*常规/白底悬浮*/\r\n --lay-color-fill-3: rgba(255,255,255,.12); /*深/灰底悬浮*/\r\n --lay-color-fill-4: rgba(255,255,255,.16);/*重/特殊场景*/\r\n\r\n --lay-color-hover: var(--lay-color-fill-3); /*bg*/\r\n --lay-color-active: var(--lay-color-fill-3); /*bg*/\r\n\r\n --lay-shadow-1: 0 4px 6px rgba(0, 0, 0, 6%), 0 1px 10px rgba(0, 0, 0, 8%), 0 2px 4px rgba(0, 0, 0, 12%);/*基础/下层投影 卡片面板*/\r\n --lay-shadow-2: 0 8px 10px rgba(0, 0, 0, 12%), 0 3px 14px rgba(0, 0, 0, 10%), 0 5px 5px rgba(0, 0, 0, 16%);/*中层投影 下拉菜单,选择器*/\r\n --lay-shadow-3: 0 16px 24px rgba(0, 0, 0, 14%), 0 6px 30px rgba(0, 0, 0, 12%), 0 8px 10px rgba(0, 0, 0, 20%);/*上层投影 弹窗*/\r\n}\r\n","blockquote,body,button,dd,div,dl,dt,form,h1,h2,h3,h4,h5,h6,input,li,ol,p,pre,td,textarea,th,ul{-webkit-tap-highlight-color: rgba(0, 0, 0, 0)} /*danger: 勿改*/\nbody{color:var(--lay-color-text-2);background-color: var(--lay-color-bg-1); color-scheme: dark;}\nhr{border-bottom:1px solid var(--lay-color-border-2)!important}\na{color:var(--lay-color-text-1);}\na:hover{color:var(--lay-color-text-3)}\n/* 三角形 */\n.layui-edge{border-color:transparent}\n.layui-edge-top{border-bottom-color:var(--lay-color-border-4)}\n.layui-edge-right{border-left-color:var(--lay-color-border-4)}\n.layui-edge-bottom{border-top-color:var(--lay-color-border-4)}\n.layui-edge-left{border-right-color:var(--lay-color-border-4)}\n/* 禁用文字 */\n.layui-disabled,.layui-disabled:hover{color:var(--lay-color-text-4)!important}\n/* 图标 */\n.layui-icon{-moz-osx-font-smoothing:grayscale}\n/* admin 布局 */\n.layui-layout-admin .layui-header{background-color:var(--lay-color-bg-2)}\n.layui-layout-admin .layui-footer{box-shadow:-1px 0 4px rgb(0 0 0 / 12%);background-color:var(--lay-color-bg-2)}\n.layui-layout-admin .layui-logo{color:var(--lay-color-primary);box-shadow:0 1px 2px 0 rgb(0 0 0 / 15%)}\n/* 引用 */\n.layui-elem-quote{border-left:5px solid var(--lay-color-secondary);background-color:var(--lay-color-fill-1)}\n.layui-quote-nm{border-color: var(--lay-color-fill-1)}\n/* 进度条 */\n.layui-progress{background-color: var(--lay-color-bg-3)}\n.layui-progress-bar{background-color:var( --lay-color-secondary)}\n.layui-progress-text{color:var(--lay-color-text-2)}\n.layui-progress-big .layui-progress-text{color: var(--lay-color-text-1)}\n/* 折叠面板 */\n.layui-colla-title{color: var(--lay-color-text-1);background-color: var(--lay-color-bg-2)}\n.layui-colla-content{color:var(--lay-color-text-2)}\n/* 卡片面板 */\n.layui-card{background-color: var(--lay-color-bg-2);box-shadow:var(--lay-shadow-1)}\n.layui-card-header{border-bottom:1px solid var(--lay-color-border-2);color:var(--lay-color-text-1)}\n/* 常规面板 */\n.layui-panel{box-shadow:var(--lay-shadow-1);background-color: var( --lay-color-bg-2);color: var(--lay-color-text-1)}\n.layui-menu-body-panel{box-shadow: var(--lay-shadow-2)}\n/* 窗口面板 */\n.layui-panel-window{border-top:5px solid var(--lay-color-border-2);background-color: var(--lay-color-bg-2)}\n/* 背景颜色 */\n.layui-bg-red{background-color:var(--lay-color-red-6)!important;color: var(--lay-color-white)!important}\n.layui-bg-orange{background-color:var(--lay-color-orange-6)!important;color: var(--lay-color-white)!important}\n.layui-bg-green{background-color:var(--lay-color-layuigreen-6)!important;color: var(--lay-color-white)!important}\n.layui-bg-cyan{background-color:var(--lay-color-cyan-6)!important;color: var(--lay-color-white)!important}\n.layui-bg-blue{background-color: var(--lay-color-blue-6)!important;color: var(--lay-color-white)!important}\n.layui-bg-black{background-color:var(--lay-color-black-6)!important;color: var(--lay-color-white)!important}\n.layui-bg-purple{background-color: var(--lay-color-purple-6)!important; color: var(--lay-color-white)!important;}\n.layui-bg-gray{background-color:var(--lay-color-gray-1)!important;color: var(--lay-color-black-6)!important}\n/* 徽章 */\n.layui-badge-rim,.layui-border,.layui-colla-content,.layui-colla-item,.layui-collapse,.layui-elem-field,.layui-form-pane .layui-form-item[pane],.layui-form-pane .layui-form-label,.layui-input,.layui-input-split,.layui-panel,.layui-select,.layui-tab-bar,.layui-tab-card,.layui-tab-title,.layui-tab-title .layui-this:after,.layui-textarea{border-color: var(--lay-color-border-1)}\n/* 边框颜色 */\n.layui-border{color:var(--lay-color-text-1)!important}\n.layui-border-red{border-color:var(--lay-color-red-6)!important;color:var(--lay-color-red-6)!important}\n.layui-border-orange{border-color:var(--lay-color-orange-6)!important;color:var(--lay-color-orange-6)!important}\n.layui-border-green{border-color:var(--lay-color-layuigreen-6)!important;color:var(--lay-color-layuigreen-6)!important}\n.layui-border-cyan{border-color:var(--lay-color-cyan-6)!important;color:var(--lay-color-cyan-6)!important}\n.layui-border-blue{border-color: var(--lay-color-blue-6)!important;color: var(--lay-color-blue-6)!important}\n.layui-border-purple{border-color: var(--lay-color-purple-6)!important; color: var(--lay-color-purple-6)!important;}\n.layui-border-black{border-color:var(--lay-color-black-6)!important;color:var(--lay-color-text-1)!important}\n/* 文本区域 */\n.layui-text{color:var(--lay-color-text-2)}\n.layui-text-em,.layui-word-aux{color: var(--lay-color-text-3)!important}\n.layui-text a:not(.layui-btn){color:var(--lay-color-lightblue-6)}\n.layui-text blockquote:not(.layui-elem-quote){border-left:5px solid var(--lay-color-border-4)}\n/* 字体颜色 */\n.layui-font-red{color:var(--lay-color-red-6)!important}\n.layui-font-orange{color:var(--lay-color-orange-6)!important}\n.layui-font-green{color:var(--lay-color-layuigreen-6)!important}\n.layui-font-cyan{color:var(--lay-color-cyan-6)!important}\n.layui-font-blue{color:var(--lay-color-lightblue-6)!important}\n.layui-font-black{color:var(--lay-color-black)!important}\n.layui-font-purple{color:var(--lay-color-purple-6)!important;}\n.layui-font-gray{color:var(--lay-color-gray-7)!important}\n/* 按钮 */\n.layui-btn{border:1px solid transparent;background-color:var(--lay-color-primary);color: var(--lay-color-text-1)}\n.layui-btn:hover{color: var(--lay-color-text-2)}\n.layui-btn-primary{border-color:var(--lay-color-border-2);color:var(--lay-color-text-1);background-color: var(--lay-color-bg-4)}\n.layui-btn-primary:hover{border-color: transparent;color:var(--lay-color-text-2)}\n.layui-btn-normal{background-color: var(--lay-color-normal)}\n.layui-btn-warm{background-color:var(--lay-color-warning)}\n.layui-btn-danger{background-color:var(--lay-color-danger)}\n.layui-btn-checked{background-color:var(--lay-color-success)}\n.layui-btn-disabled,.layui-btn-disabled:active,.layui-btn-disabled:hover{border-color: var(--lay-color-border-2)!important;background-color: var(--lay-color-bg-2)!important;color: var(--lay-color-text-4)!important}\n.layui-btn-group .layui-btn{border-left:1px solid var(--lay-color-border-2)}\n.layui-btn-group .layui-btn-primary:hover{border-color:var(--lay-color-border-2);color:var(--lay-color-primary)}\n.layui-btn-group .layui-btn-primary:first-child{border-left:1px solid var(--lay-color-gray-5)}\n/*表单*/\n.layui-input,.layui-select,.layui-textarea{background-color: var(--lay-color-fill-2);color: var(--lay-color-text-2)}\n.layui-input:hover,.layui-textarea:hover{border-color: var(--lay-color-border-2)!important}\n.layui-input:focus,.layui-textarea:focus{border-color: var(--lay-color-secondary-hover)!important;background-color: var(--lay-color-bg-2);box-shadow: 0 0 0 3px rgba(22, 183, 119, 0.08);}\n.layui-input[disabled],.layui-select[disabled],.layui-textarea[disabled],.layui-input.layui-disabled,.layui-textarea.layui-disabled{background-color: var(--lay-color-fill-1);color: var(--lay-color-text-4);border-color: var(--lay-color-border-1)!important;box-shadow: 0 0 0 0;}\n.layui-form-danger+.layui-form-select .layui-input,.layui-form-danger:focus{border-color:var(--lay-color-danger)!important;box-shadow: 0 0 0 3px rgba(255, 87, 34, 0.08);}\n/* 输入框点缀 */\n.layui-input-prefix .layui-icon,.layui-input-split .layui-icon,.layui-input-suffix .layui-icon{color: var(--lay-color-gray-8)}\n.layui-input-wrap .layui-input:hover+.layui-input-split{border-color: var(--lay-color-border-2)}\n.layui-input-wrap .layui-input[disabled]:hover+.layui-input-split{border-color: var(--lay-color-border-1)}\n.layui-input-wrap .layui-input:focus+.layui-input-split{border-color: var(--lay-color-secondary-hover)}\n.layui-input-wrap .layui-input.layui-form-danger:focus + .layui-input-split{border-color: var(--lay-color-danger);}\n.layui-input-affix .layui-icon{color: var(--lay-color-text-2)}\n.layui-input-affix .layui-icon-clear{color:var(--lay-color-text-2)}\n.layui-input-affix .layui-icon:hover{color:var(--lay-color-text-3)}\n/* 数字输入框动态点缀 */\n.layui-input-wrap .layui-input-number .layui-icon-up{border-bottom-color:var(--lay-color-border-1)}\n.layui-input-wrap .layui-input[type=\"number\"].layui-input-number-out-of-range{color:var(--lay-color-danger)}\n/* 下拉选择 */\n.layui-form-select{color:var(--lay-color-text-2)}\n.layui-form-select .layui-edge{border-top-color:var(--lay-color-gray-8)}\n.layui-form-select dl{border:1px solid var( --lay-color-border-2);background-color: var(--lay-color-bg-5);box-shadow:var(--lay-shadow-2)}\n.layui-form-select dl dt{color:var(--lay-color-gray-8)}\n.layui-form-select dl dd:hover{background-color:var(--lay-color-active)}\n.layui-form-select dl dd.layui-select-tips{color:var(--lay-color-text-2)}\n.layui-form-select dl dd.layui-this{background-color: var(--lay-color-active);color: var(--lay-color-text-1)}\n.layui-form-select dl dd.layui-disabled,.layui-form-select dl dd:hover.layui-disabled{background-color: var(--lay-color-bg-5)}\n.layui-select-none{color:var(--lay-color-black-8)}\n.layui-select-disabled .layui-disabled{border-color:var(--lay-color-border-1)!important}\n.layui-select-disabled .layui-edge{border-top-color:var(--lay-color-gray-6)}\n/* 复选框 */\n.layui-form-checkbox{background-color:var(--lay-color-fill-2)}\n.layui-form-checkbox>div{background-color:var(--lay-color-fill-3);color:var(--lay-color-text-2)}\n.layui-form-checkbox:hover>div{background-color: var(--lay-color-active)}\n.layui-form-checkbox>i{background-color: var(--lay-color-fill-1);border-top-color:var(--lay-color-border-1);border-right-color:var(--lay-color-border-1);border-bottom-color:var(--lay-color-border-1);border-left-color:initial;color:var(--lay-color-text-1)}\n.layui-form-checkbox:hover>i{border-color:var(--lay-color-border-2);color:var(--lay-color-text-4)}\n.layui-form-checked,.layui-form-checked:hover{border-color:var(--lay-color-secondary-active)}\n.layui-form-checked>div,.layui-form-checked:hover>div{background-color:var(--lay-color-secondary)}\n.layui-form-checked>i,.layui-form-checked:hover>i{color:var(--lay-color-secondary-hover)}\n.layui-form-checkbox.layui-checkbox-disabled>div{background-color: var(--lay-color-fill-3) !important;}\n/* 复选框-默认风格 */\n.layui-form-checkbox[lay-skin=primary]{background-image:none;background-color:initial;border-color:initial!important}\n.layui-form-checkbox[lay-skin=primary]>div{background-image:none;background-color:initial;color:var(--lay-color-text-2)}\n.layui-form-checkbox[lay-skin=primary]>i{border-color:var(--lay-color-border-1);background-color:var(--lay-color-fill-2)}\n.layui-form-checkbox[lay-skin=primary]:hover>i{border-color:var(--lay-color-secondary-hover);color:var(--lay-color-text-1)}\n.layui-form-checked[lay-skin=primary]>i{background-color:var(--lay-color-secondary);color:var(--lay-color-text-1);border-color:var(--lay-color-secondary-active)!important}\n.layui-checkbox-disabled[lay-skin=primary] >div{background:none!important;color:var(--lay-color-text-4)!important}\n.layui-form-checked.layui-checkbox-disabled[lay-skin=primary]>i{background-color:var(--lay-color-fill-1)!important;border-color:var(--lay-color-border-2)!important}\n.layui-checkbox-disabled[lay-skin=primary]:hover>i{border-color:var(--lay-color-border-1)}\n.layui-form-checkbox[lay-skin=\"primary\"]>.layui-icon-indeterminate:before{background-color: var(--lay-color-secondary-hover);opacity: 1;}\n.layui-form-checkbox[lay-skin=\"primary\"]:hover>.layui-icon-indeterminate:before{opacity: 1;}\n.layui-form-checkbox[lay-skin=\"primary\"]>.layui-icon-indeterminate{border-color: var(--lay-color-secondary-hover);}\n/* 复选框-开关风格 */\n.layui-form-switch{border-color:var(--lay-color-border-2);background-color:var(--lay-color-fill-2)}\n.layui-form-switch>i{background-color:var(--lay-color-gray-4)}\n.layui-form-switch.layui-checkbox-disabled>i{background-color:var(--lay-color-gray-7);}\n.layui-form-switch>div{color:var(--lay-color-gray-8)!important}\n.layui-form-onswitch{border-color:var(--lay-color-secondary-active);background-color:var(--lay-color-secondary)}\n.layui-form-onswitch>i{background-color:var(--lay-color-gray-4)}\n.layui-form-onswitch>div{color:var(--lay-color-text-1)!important}\n.layui-checkbox-disabled{border-color:var(--lay-color-border-2)!important}\n.layui-checkbox-disabled>div{background-color:var(--lay-color-fill-3)!important;color: var(--lay-color-text-4)!important;}\n.layui-checkbox-disabled>i{border-color:var(--lay-color-border-2)!important}\n.layui-checkbox-disabled:hover>i{color:var(--lay-color-text-1)!important}\n.layui-form-switch.layui-checkbox-disabled>div{background-color:initial!important;color: var(--lay-color-text-3)!important;}\n/*复选框背景优化*/\n.layui-form-checkbox>i:before{opacity:0;filter:alpha(opacity=0)}\n.layui-form-checkbox:hover>i:before{opacity:1;filter:alpha(opacity=100)}\n.layui-form-checked.layui-checkbox-disabled:hover>i:before,.layui-form-checked:hover>i:before,.layui-form-checked>i:before{opacity:1;filter:alpha(opacity=100)}\n.layui-form-checkbox[lay-skin=primary]:hover>i:before{opacity:0;filter:alpha(opacity=0)}\n.layui-form-checked[lay-skin=primary]:hover>i:before{opacity:1;filter:alpha(opacity=100)}\n.layui-checkbox-disabled:hover>i:before{opacity:0;filter:alpha(opacity=0)}\n/*单选框*/\n.layui-form-radio>i{color:var(--lay-color-gray-8)}\n.layui-form-radio:hover>*,.layui-form-radioed,.layui-form-radioed>i{color:var(--lay-color-secondary)}\n.layui-radio-disabled>i{color:var(--lay-color-text-4)!important}\n.layui-radio-disabled>*{color:var(--lay-color-text-4)!important}\n/* 表单方框风格 */\n.layui-form-pane .layui-form-label{background-color:var(--lay-color-bg-2)}\n/** 分页 **/\n.layui-laypage a,.layui-laypage button,.layui-laypage input,.layui-laypage select,.layui-laypage span{border:1px solid var(--lay-color-border-2)}\n.layui-laypage a,.layui-laypage span{background-color: var(--lay-color-bg-2);color: var(--lay-color-text-2)}\n.layui-laypage a[data-page]{color:var(--lay-color-text-2)}\n.layui-laypage a:hover{color: var(--lay-color-primary)}\n.layui-laypage .layui-laypage-spr{color:var(--lay-color-text-3)}\n.layui-laypage .layui-laypage-curr em{color: var(--lay-color-white)}\n.layui-laypage .layui-laypage-curr .layui-laypage-em{background-color: var(--lay-color-primary)}\n.layui-laypage .layui-laypage-skip{color:var(--lay-color-text-3)}\n.layui-laypage button,.layui-laypage input{background-color: var(--lay-color-bg-2)}\n.layui-laypage input:focus,.layui-laypage select:focus{border-color: var(--lay-color-primary)!important}\n/** 流加载 **/\n.layui-flow-more{color:var(--lay-color-text-1)}\n.layui-flow-more a cite{background-color: var(--lay-color-bg-4);color: var(--lay-color-text-1)}\n.layui-flow-more a i{color:var(--lay-color-text-2)}\n/** 表格 **/\n.layui-table{background-color: var(--lay-color-bg-2);color: var(--lay-color-text-2)}\n.layui-table-mend{background-color: var(--lay-color-bg-2)}\n.layui-table-click,.layui-table-hover,.layui-table[lay-even] tbody tr:nth-child(even){background-color:var(--lay-color-fill-3)}\n.layui-table-checked{background-color: var(--lay-color-fill-2);color: var(--lay-color-text-1)}\n.layui-table-checked.layui-table-hover,.layui-table-checked.layui-table-click{background-color: var(--lay-color-fill-3);}\n.layui-table td,.layui-table th,.layui-table-col-set,.layui-table-fixed-r,.layui-table-grid-down,.layui-table-header,.layui-table-mend,.layui-table-page,.layui-table-tips-main,.layui-table-tool,.layui-table-total,.layui-table-view,.layui-table[lay-skin=line],.layui-table[lay-skin=row]{border-color: var(--lay-color-border-2)}\n.layui-table-view:after {background-color: var(--lay-color-border-2);}\n.layui-table-view .layui-table td[data-edit]:hover:after{border:1px solid var(--lay-color-primary-active)}\n.layui-table-loading-icon .layui-icon{color:var(--lay-color-gray-8);}\n.layui-table-page{background-color: var(--lay-color-bg-2);}\n.layui-table-page .layui-laypage a,\n.layui-table-page .layui-laypage span{border: none;}\n.layui-table-tool{background-color: var(--lay-color-bg-2);}\n.layui-table-tool .layui-inline[lay-event]{color:var(--lay-color-text-3);border:1px solid var(--lay-color-border-2)}\n.layui-table-tool .layui-inline[lay-event]:hover{border:1px solid var(--lay-color-border-3)}\n.layui-table-tool-panel{color: var(--lay-color-text-1); border:1px solid var(--lay-color-border-2);background-color: var(--lay-color-bg-5);box-shadow:var(--lay-shadow-2)}\n.layui-table-tool-panel li:hover{background-color:var(--lay-color-active)}\n.layui-table-col-set{background-color: var(--lay-color-white)}\n.layui-table-sort .layui-table-sort-asc{border-bottom-color:var(--lay-color-gray-8)}\n.layui-table-sort .layui-table-sort-asc:hover{border-bottom-color:var(--lay-color-gray-11)}\n.layui-table-sort .layui-table-sort-desc{border-top-color:var(--lay-color-gray-8)}\n.layui-table-sort .layui-table-sort-desc:hover{border-top-color:var(--lay-color-gray-11)}\n.layui-table-sort[lay-sort=asc] .layui-table-sort-asc{border-bottom-color:var(--lay-color-gray-13)}\n.layui-table-sort[lay-sort=desc] .layui-table-sort-desc{border-top-color:var(--lay-color-gray-13)}\n.layui-table-cell .layui-table-link{color: var(--lay-color-lightblue-5)}\n.layui-table-body .layui-none{color:var(--lay-color-gray-8)}\n.layui-table-fixed-l{box-shadow:1px 0 8px rgba(0,0,0,1)}\n.layui-table-fixed-r{box-shadow:-1px 0 8px rgba(0,0,0,1)}\n.layui-table-edit{box-shadow:var(--lay-shadow-1);background-color: var(--lay-color-bg-2)}\n.layui-table-edit:focus{border-color:var(--lay-color-secondary)!important}\nselect.layui-table-edit{border-color:var(--lay-color-border-2)}\n.layui-table-grid-down{background-color: var(--lay-color-bg-5);color:var(--lay-color-gray-8)}\n.layui-table-grid-down:hover{background-color:var(--lay-color-bg-5)}\n/* 单元格多行展开风格 */\n.layui-table-cell-c{background-color: var(--lay-color-gray-13);color: var(--lay-color-text-1); border-color: var(--lay-color-border-3);}\n.layui-table-cell-c:hover{border-color: var(--lay-color-secondary-hover);}\n/* 单元格 TIPS 展开风格 */\nbody .layui-table-tips .layui-layer-content{box-shadow:var(--lay-shadow-3)}\n.layui-table-tips-main{background-color: var(--lay-color-bg-5);color: var(--lay-color-text-3)}\n.layui-table-tips-c{background-color:var(--lay-color-gray-13);color: var(--lay-color-text-1)}\n.layui-table-tips-c:hover{background-color:var(--lay-color-gray-10)}\n/** 文件上传 **/\n.layui-upload-choose{color:var(--lay-color-gray-8)}\n.layui-upload-drag{border:1px dashed var( --lay-color-border-2);background-color: var(--lay-color-bg-4);color: var(--lay-color-text-2)}\n.layui-upload-drag .layui-icon{color: var(--lay-color-primary)}\n.layui-upload-drag[lay-over]{border-color: var(--lay-color-primary)}\n/* 基础菜单元素 */\n.layui-menu{background-color: var(--lay-color-bg-2)}\n.layui-menu li{color: var(--lay-color-text-1)}\n.layui-menu li:hover{background-color: var(--lay-color-bg-5)}\n.layui-menu li.layui-disabled,.layui-menu li.layui-disabled *{color:var(--lay-color-text-4)!important}\n.layui-menu .layui-menu-item-group>.layui-menu-body-title{color: var(--lay-color-text-3)}\n.layui-menu .layui-menu-item-none{color: var(--lay-color-text-3);}\n.layui-menu .layui-menu-item-divider{border-bottom:1px solid var(--lay-color-border-2)}\n.layui-menu .layui-menu-item-group:hover,\n.layui-menu .layui-menu-item-none:hover,\n.layui-menu .layui-menu-item-divider:hover{background: none;}\n.layui-menu .layui-menu-item-up>.layui-menu-body-title{color: var(--lay-color-text-1)}\n.layui-menu .layui-menu-item-down:hover>.layui-menu-body-title>.layui-icon,.layui-menu .layui-menu-item-up>.layui-menu-body-title:hover>.layui-icon{color: var(--lay-color-text-1)}\n.layui-menu .layui-menu-item-checked,.layui-menu .layui-menu-item-checked2{background-color:var(--lay-color-active)!important;color:var(--lay-color-secondary)}\n.layui-menu .layui-menu-item-checked a,.layui-menu .layui-menu-item-checked2 a{color:var(--lay-color-secondary)}\n.layui-menu .layui-menu-item-checked:after{border-right:3px solid var(--lay-color-secondary)}\n.layui-menu-body-title a{color: var(--lay-color-text-1)}\n.layui-menu-lg .layui-menu-body-title a:hover,.layui-menu-lg li:hover{color:var(--lay-color-secondary)}\n/* 下拉菜单 */\n.layui-dropdown{background-color: var(--lay-color-bg-5)}\n.layui-dropdown.layui-panel,.layui-dropdown .layui-panel{background-color: var(--lay-color-bg-5);box-shadow: var(--lay-shadow-2)}\n.layui-dropdown.layui-panel .layui-menu{background-color: var(--lay-color-bg-5)}\n/** 导航菜单 **/\n.layui-nav{background-color:var(--lay-color-black-6);color: var(--lay-color-white)}\n.layui-nav .layui-nav-item a{color: var(--lay-color-text-1);}\n.layui-nav .layui-this:after,.layui-nav-bar{background-color:var(--lay-color-secondary)}\n.layui-nav .layui-nav-item a:hover,.layui-nav .layui-this a{color: var(--lay-color-text-1)}\n.layui-nav-child{box-shadow:var(--lay-shadow-2);border:1px solid var(--lay-color-border-2);background-color: var(--lay-color-bg-5)}\n.layui-nav .layui-nav-child a{color: var(--lay-color-text-1)}\n.layui-nav .layui-nav-child a:hover{background-color: var(--lay-color-bg-5);color: var(--lay-color-text-1)}\n.layui-nav-child dd.layui-this{background-color: var(--lay-color-bg-5);color: var(--lay-color-text-1)}\n.layui-nav-tree .layui-nav-child dd.layui-this,.layui-nav-tree .layui-nav-child dd.layui-this a,.layui-nav-tree .layui-this,.layui-nav-tree .layui-this>a,.layui-nav-tree .layui-this>a:hover{background-color: var(--lay-color-primary);color: var(--lay-color-white)}\n.layui-nav-itemed>a,.layui-nav-tree .layui-nav-title a,.layui-nav-tree .layui-nav-title a:hover{color: var(--lay-color-white)!important}\n.layui-nav-tree .layui-nav-bar{background-color:var(--lay-color-primary)}\n.layui-nav-tree .layui-nav-child{background: none; background-color:rgba(0, 0, 0, .3); border: none; box-shadow: none;}\n.layui-nav-tree .layui-nav-child a{color: var(--lay-color-white);color: var(--lay-color-text-1)}\n.layui-nav-tree .layui-nav-child a:hover{background: none; color: var(--lay-color-white)}\n.layui-nav.layui-bg-gray,.layui-nav-tree.layui-bg-gray{background-color: var(--lay-color-bg-2) !important;color: var(--lay-color-text-1);}\n.layui-nav-tree.layui-bg-gray .layui-nav-child{background-color: rgba(0, 0, 0, .3) !important;}\n.layui-nav-tree.layui-bg-gray a,.layui-nav.layui-bg-gray .layui-nav-item a{color: var(--lay-color-text-1)}\n.layui-nav.layui-bg-gray .layui-nav-child{background-color: var(--lay-color-bg-5);}\n.layui-nav-tree.layui-bg-gray .layui-nav-itemed>a{color: var(--lay-color-text-1)!important}\n.layui-nav.layui-bg-gray .layui-this a{color:var(--lay-color-secondary)}\n.layui-nav-tree.layui-bg-gray .layui-nav-child dd.layui-this,.layui-nav-tree.layui-bg-gray .layui-nav-child dd.layui-this a,.layui-nav-tree.layui-bg-gray .layui-this,.layui-nav-tree.layui-bg-gray .layui-this>a{color:var(--lay-color-secondary)!important}\n.layui-nav-tree.layui-bg-gray .layui-nav-bar{background-color:var(--lay-color-secondary)}\n/** 面包屑 **/\n.layui-breadcrumb a{color:var(--lay-color-gray-7)!important}\n.layui-breadcrumb a:hover{color:var(--lay-color-secondary)!important}\n.layui-breadcrumb a cite{color:var(--lay-color-gray-8)}\n.layui-breadcrumb span[lay-separator]{color:var(--lay-color-gray-7)}\n/** Tab 选项卡 **/\n.layui-tab .layui-tab-title:after{border-bottom-color: var(--lay-color-border-1);}\n.layui-tab-title .layui-this{color: var(--lay-color-text-2)}\n.layui-tab-title .layui-this:after{border-bottom-color: var(--lay-color-bg-1)}\n.layui-tab-bar{background-color: var(--lay-color-bg-3)}\n.layui-tab-more li.layui-this:after{border-bottom-color:var(--lay-color-border-1)}\n.layui-tab-title li .layui-tab-close{color:var(--lay-color-gray-8)}\n.layui-tab-title li .layui-tab-close:hover{background-color:var(--lay-color-danger);color: var(--lay-color-white)}\n.layui-tab-brief>.layui-tab-title .layui-this{color:var( --lay-color-primary)}\n.layui-tab-brief>.layui-tab-more li.layui-this:after,.layui-tab-brief>.layui-tab-title .layui-this:after{border-bottom:2px solid var(--lay-color-secondary)}\n.layui-tab-card{box-shadow: var(--lay-shadow-1)}\n.layui-tab-card>.layui-tab-title{background-color: var(--lay-color-bg-2)}\n.layui-tab-card>.layui-tab-title .layui-this{background-color: var(--lay-color-bg-1)}\n.layui-tab-card>.layui-tab-title .layui-this:after{border-bottom-color: var(--lay-color-bg-1)}\n.layui-tab-card>.layui-tab-more .layui-this{color:var(--lay-color-secondary)}\n\n/** tabs 标签页 **/\n.layui-tabs-header:after,\n.layui-tabs-scroll:after{border-bottom-color: var(--lay-color-border-1);}\n.layui-tabs-card>.layui-tabs-header .layui-this{background-color: transparent;}\n.layui-tabs-card>.layui-tabs-header .layui-this:after{border-color: var(--lay-color-border-1); border-bottom-color: var(--lay-color-bg-1);}\n.layui-tabs-card.layui-panel>.layui-tabs-header .layui-this:after{border-bottom-color: var(--lay-color-bg-2);}\n.layui-tabs-bar .layui-icon{background-color: var(--lay-color-bg-1); color: var(--lay-color-text-2); border-color: var(--lay-color-border-1); box-shadow: 2px 0 5px 0 rgb(0 0 0 / 32%);}\n.layui-tabs-bar .layui-icon-next{box-shadow: -2px 0 5px 0 rgb(0 0 0 / 32%);}\n\n/*时间线*/\n.layui-timeline-axis{background-color: var(--lay-color-bg-4);color:var(--lay-color-secondary)}\n.layui-timeline-axis:hover{color:var(--lay-color-red-6)}\n.layui-timeline-item:before{background-color: var(--lay-color-bg-3)}\n/*徽章*/\n.layui-badge,.layui-badge-dot,.layui-badge-rim{background-color:var(--lay-color-red-6);color: var(--lay-color-white)}\n.layui-badge-rim{background-color: var(--lay-color-white);color:var(--lay-color-black-6)}\n/* carousel 轮播 */\n.layui-carousel{background-color:var(--lay-color-gray-2)}\n.layui-carousel>[carousel-item]:before{color:var(--lay-color-gray-8);-moz-osx-font-smoothing:grayscale}\n.layui-carousel>[carousel-item]>*{background-color:var(--lay-color-gray-2)}\n.layui-carousel-arrow{background-color:rgba(0,0,0,.2);color: var(--lay-color-white)}\n.layui-carousel-arrow:hover,.layui-carousel-ind ul:hover{background-color:var(--lay-color-black)}\n.layui-carousel[lay-indicator=outside] .layui-carousel-ind ul{background-color:var(--lay-color-black)}\n.layui-carousel-ind ul{background-color:rgba(0,0,0,.2)}\n.layui-carousel-ind ul li{background-color:var(--lay-color-gray-3);background-color: var(--lay-color-text-3)}\n.layui-carousel-ind ul li:hover{background-color: var(--lay-color-white)}\n.layui-carousel-ind ul li.layui-this{background-color: var(--lay-color-white)}\n/** fixbar **/\n.layui-fixbar li{background-color:var(--lay-color-black-5);color: var(--lay-color-text-1)}\n/** 表情面板 **/\nbody .layui-util-face .layui-layer-content{background-color: var(--lay-color-bg-5);color:var(--lay-color-text-2)}\n.layui-util-face ul{border:1px solid var(--lay-color-border-3);background-color: var(--lay-color-bg-5);box-shadow:var(--lay-shadow-2)}\n.layui-util-face ul li{border:1px solid var(--lay-color-border-2)}\n.layui-util-face ul li:hover{border:1px solid var(--lay-color-red-7);background: var(--lay-color-text-1)}\n/** 代码文本修饰 **/\n.layui-code{border:1px solid var(--lay-color-border-2);background-color: var(--lay-color-bg-white);color: var(--lay-color-text-2)}\n/** 穿梭框 **/\n.layui-transfer-box,.layui-transfer-header,.layui-transfer-search{border-color: var(--lay-color-border-2)}\n.layui-transfer-box{background-color: var(--lay-color-bg-2)}\n.layui-transfer-search .layui-icon-search{color:var(--lay-color-gray-8)}\n.layui-transfer-active .layui-btn{background-color:var( --lay-color-secondary);border-color:var( --lay-color-secondary);color: var(--lay-color-white)}\n.layui-transfer-active .layui-btn-disabled{background-color:var(--lay-color-gray-2);border-color:var(--lay-color-gray-3);color:var(--lay-color-gray-8)}\n.layui-transfer-data li:hover{background-color:var(--lay-color-active)}\n/* chrome 105 */\n.layui-transfer-data li:hover:has([lay-filter=\"layTransferCheckbox\"][disabled]){background-color:var(--lay-color-bg-2)}\n.layui-transfer-data .layui-none{color:var(--lay-color-gray-7)}\n/** 评分组件 **/\n.layui-rate li i.layui-icon{color:var(--lay-color-orange-6)}\n/** 颜色选择器 **/\n.layui-colorpicker{border:1px solid var(--lay-color-border-1)}\n.layui-colorpicker:hover{border-color: var(--lay-color-border-2)}\n.layui-colorpicker-trigger-span{border:1px solid var(--lay-color-border-1)}\n.layui-colorpicker-trigger-i{color: var(--lay-color-white)}\n.layui-colorpicker-trigger-i.layui-icon-close{color:var(--lay-color-black-7)}\n.layui-colorpicker-main{background: var(--lay-color-bg-2);border:1px solid var( --lay-color-border-2);box-shadow:var(--lay-shadow-2)}\n.layui-colorpicker-basis-white{background:linear-gradient(90deg, #fff,hsla(0,0%,100%,0))} /* danger: 勿改*/\n.layui-colorpicker-basis-black{background:linear-gradient(0deg,#000,transparent)} /* danger: 勿改*/\n.layui-colorpicker-basis-cursor{border:1px solid var(--lay-color-white)}\n.layui-colorpicker-side{background:linear-gradient(linear-gradient(#F00, #FF0, #0F0, #0FF, #00F, #F0F, #F00))} /* danger: 勿改*/\n.layui-colorpicker-side-slider{box-shadow:var(--lay-shadow-1);background: var(--lay-color-white);border:1px solid var(--lay-color-gray-2)}\n.layui-colorpicker-alpha-slider{box-shadow:var(--lay-shadow-1);background: var(--lay-color-white);border:1px solid var(--lay-color-gray-2)}\n.layui-colorpicker-pre.layui-this{box-shadow:var(--lay-shadow-1)}\n.layui-colorpicker-pre.selected{box-shadow:var(--lay-shadow-1)}\n.layui-colorpicker-main-input input.layui-input{color: var(--lay-color-text-2)}\n/** 滑块 **/\n.layui-slider{background: var( --lay-color-bg-5)}\n.layui-slider-step{background: var(--lay-color-fill-4)}\n.layui-slider-wrap-btn{background: var(--lay-color-bg-4)}\n.layui-slider-tips{color: var(--lay-color-text-1);background:var(--lay-color-black);box-shadow: var(--lay-shadow-3)}\n.layui-slider-tips:after{border-color:var(--lay-color-black) transparent transparent transparent}\n.layui-slider-input{border:1px solid var(--lay-color-border-1)}\n.layui-slider-input-btn{border-left:1px solid var(--lay-color-border-1)}\n.layui-slider-input-btn i{color:var(--lay-color-gray-9)}\n.layui-slider-input-btn i:first-child{border-bottom:1px solid var(--lay-color-border-1)}\n.layui-slider-input-btn i:hover{color:var(--lay-color-primary)}\n/** 树组件 **/\n.layui-tree-line .layui-tree-set .layui-tree-set:after{border-top:1px dotted var(--lay-color-gray-7)}\n.layui-tree-entry:hover{background-color: var(--lay-color-bg-4)}\n.layui-tree-line .layui-tree-entry:hover{background-color:var(--lay-color-black)}\n.layui-tree-line .layui-tree-entry:hover .layui-tree-txt{color:var(--lay-color-text-3)}\n.layui-tree-entry:hover:has(span.layui-tree-txt.layui-disabled){background-color: transparent !important}\n.layui-tree-line .layui-tree-set:before{border-left:1px dotted var(--lay-color-gray-7)}\n.layui-tree-iconClick{color:var(--lay-color-gray-7)}\n.layui-tree-icon{border:1px solid var(--lay-color-gray-8)}\n.layui-tree-icon .layui-icon{color:var(--lay-color-text-1)}\n.layui-tree-iconArrow:after{border-color:transparent transparent transparent var(--lay-color-gray-7)}\n.layui-tree-txt{color:var(--lay-color-text-2)}\n.layui-tree-search{color:var(--lay-color-black-7)}\n.layui-tree-btnGroup .layui-icon:hover{color:var(--lay-color-text-2)}\n.layui-tree-editInput{background-color:var(--lay-color-fill-2)}\n.layui-tree-emptyText{color:var(--lay-color-text-2)}\n/*code 不处理*/\n.layui-code-view{border:1px solid var(--lay-color-border-1);}\n.layui-code-view:not(.layui-code-hl){background-color: var(--lay-color-bg-2);color: var(--lay-color-text-2);}\n.layui-code-header{border-bottom: 1px solid var(--lay-color-border-1); background-color: var(--lay-color-bg-2)}\n.layui-code-header > .layui-code-header-about{color: var(--lay-color-text-2);}\n.layui-code-view:not(.layui-code-hl) .layui-code-ln-side{border-color: var(--lay-color-border-1); background-color: var(--lay-color-bg-2);}\n.layui-code-nowrap > .layui-code-ln-side{background: none !important;}\n.layui-code-fixbar > span{color: var(--lay-color-text-3);}\n.layui-code-fixbar > span:hover{color: var(--lay-color-secondary-hover);}\n\n.layui-code-theme-dark,\n.layui-code-theme-dark > .layui-code-header{border-color: rgb(126 122 122 / 15%); background-color: #1f1f1f;}\n.layui-code-theme-dark{border-width: 1px; color: #ccc;}\n.layui-code-theme-dark > .layui-code-ln-side{border-right-color: #2a2a2a; background: none; color: #6e7681;}\n\n.layui-code-view.layui-code-hl > .layui-code-ln-side{background-color: transparent;}\n.layui-code-theme-dark.layui-code-hl,\n.layui-code-theme-dark.layui-code-hl > .layui-code-ln-side{border-color: rgb(126 122 122 / 15%);}\n\n.layui-code-full{background-color: var(--lay-color-bg-1)}\n/*日期选择器*/\n.layui-laydate-header i{color:var(--lay-color-gray-8)}\n.laydate-day-holidays:before{color:var(--lay-color-red-6)}\n.layui-laydate .layui-this .laydate-day-holidays:before{color: var(--lay-color-white)}\n.layui-laydate-footer span{border:1px solid var(--lay-color-border-2);background-color: var(--lay-color-bg-5)}\n.layui-laydate-footer span:hover{color:var(--lay-color-secondary)}\n.layui-laydate-footer span.layui-laydate-preview{border-color:transparent!important;}\n.layui-laydate-footer span.layui-laydate-preview:hover{color:var(--lay-color-text-1) !important}\n.layui-laydate-shortcut+.layui-laydate-main{border-left:1px solid var(--lay-color-border-2)}\n.layui-laydate .layui-laydate-list{background-color: var(--lay-color-bg-5)}\n.layui-laydate-hint{color:var(--lay-color-danger)}\n.layui-laydate-range .laydate-main-list-1 .layui-laydate-content,.layui-laydate-range .laydate-main-list-1 .layui-laydate-header{border-left:1px solid var(--lay-color-border-2)}\n.layui-laydate,.layui-laydate-hint{border-color: var(--lay-color-border-2);box-shadow:var(--lay-shadow-3);background-color: var(--lay-color-bg-5);color: var(--lay-color-text-1)}\n.layui-laydate{box-shadow: var(--lay-shadow-2)}\n.layui-laydate-hint{border-color:var(--lay-color-border-1)}\n.layui-laydate-header{border-bottom:1px solid var( --lay-color-border-2)}\n.layui-laydate-header i:hover,.layui-laydate-header span:hover{color:var(--lay-color-secondary)}\n.layui-laydate-content th{color: var(--lay-color-text-1)}\n.layui-laydate-content td{color: var(--lay-color-text-1)}\n.layui-laydate-content td.laydate-day-now{color:var(--lay-color-secondary)}\n.layui-laydate-content td.laydate-day-now:after{border:1px solid var(--lay-color-secondary)}\n.layui-laydate-linkage .layui-laydate-content td.laydate-selected>div{background-color:var(--lay-color-green-8);}\n.layui-laydate-linkage .laydate-selected:hover>div{background-color:var(--lay-color-green-8)!important}\n.layui-laydate-content td>div:hover,.layui-laydate-list li:hover,.layui-laydate-shortcut>li:hover{background-color: var(--lay-color-fill-2);color: var(--lay-color-text-2)}\n.layui-laydate-content td.laydate-disabled>div:hover{background-color: var(--lay-color-bg-5);color: var(--lay-color-text-4)}\n.laydate-time-list li ol{border:1px solid var(--lay-color-border-2)}\n.laydate-time-list>li:hover{background: 0 0;}\n.layui-laydate-content .laydate-day-next,.layui-laydate-content .laydate-day-prev{color: var(--lay-color-text-3)}\n.layui-laydate-linkage .laydate-selected.laydate-day-next>div,.layui-laydate-linkage .laydate-selected.laydate-day-prev>div{background: none!important}\n.layui-laydate-footer{border-top:1px solid var(--lay-color-border-2)}\n.layui-laydate-hint{color:var(--lay-color-danger)}\n.laydate-day-mark::after{background-color:var(--lay-color-secondary)}\n.layui-laydate-footer span[lay-type=date]{color:var(--lay-color-secondary)}\n.layui-laydate .layui-this,.layui-laydate .layui-this>div{background-color:var(--lay-color-secondary)!important;color: var(--lay-color-white)!important}\n.layui-laydate .laydate-disabled,.layui-laydate .laydate-disabled:hover{color: var(--lay-color-text-4)!important}\n.layui-laydate .layui-this.laydate-disabled,.layui-laydate .layui-this.laydate-disabled>div{background-color: var(--lay-color-fill-1) !important;color: var(--lay-color-text-4) !important;}\n.laydate-theme-molv .layui-laydate-header{background-color:var(--lay-color-primary)}\n.laydate-theme-molv .layui-laydate-header i,.laydate-theme-molv .layui-laydate-header span{color:var(--lay-color-gray-2)}\n.laydate-theme-molv .layui-laydate-header i:hover,.laydate-theme-molv .layui-laydate-header span:hover{color: var(--lay-color-white)}\n.laydate-theme-molv .layui-laydate-content{border:1px solid var(--lay-color-border-2)}\n.laydate-theme-molv .layui-this, .laydate-theme-molv .layui-this>div{background-color: var(--lay-color-primary) !important;}\n.laydate-theme-molv .layui-laydate-footer{border:1px solid var(--lay-color-border-2)}\n.laydate-theme-grid .laydate-month-list>li,.laydate-theme-grid .laydate-year-list>li,.laydate-theme-grid .layui-laydate-content td,.laydate-theme-grid .layui-laydate-content thead{border:1px solid var(--lay-color-border-2)}\n.layui-laydate-linkage.laydate-theme-grid .laydate-selected,.layui-laydate-linkage.laydate-theme-grid .laydate-selected:hover{background-color:var(--lay-color-gray-3)!important;color:var(--lay-color-primary)!important}\n.layui-laydate-linkage.laydate-theme-grid .laydate-selected.laydate-day-next,.layui-laydate-linkage.laydate-theme-grid .laydate-selected.laydate-day-prev{color:var(--lay-color-gray-6)!important}\n.layui-laydate.laydate-theme-circle .layui-laydate-content table td.layui-this{background-color:transparent!important}\n/*layer*/\n.layui-layer{background-color: var(--lay-color-bg-3);box-shadow:var(--lay-shadow-3)}\n.layui-layer-border{border:1px solid var(--lay-color-border-2);box-shadow:var(--lay-shadow-3)}\n.layui-layer-move{background-color: var(--lay-color-bg-5)}\n.layui-layer-title{border-bottom:1px solid var(--lay-color-border-2);color: var(--lay-color-text-1)}\n.layui-layer-setwin span{color: var(--lay-color-text-1)}\n.layui-layer-setwin .layui-layer-min:before{border-bottom-color:var(--lay-color-text-1)}\n.layui-layer-setwin .layui-layer-min:hover:before{border-bottom-color:var(--lay-color-info-hover)}\n.layui-layer-setwin .layui-layer-max:after,.layui-layer-setwin .layui-layer-max:before{border:1px solid var(--lay-color-text-3)}\n.layui-layer-setwin .layui-layer-max:hover:after,.layui-layer-setwin .layui-layer-max:hover:before{border-color:var(--lay-color-info-hover)}\n.layui-layer-setwin .layui-layer-maxmin:after,.layui-layer-setwin .layui-layer-maxmin:before{background-color: var(--lay-color-bg-5)}\n.layui-layer-setwin .layui-layer-close2{color:var(--lay-color-text-1);background-color:var(--lay-color-gray-10)}\n.layui-layer-setwin .layui-layer-close2:hover{background-color:var(--lay-color-normal)}\n.layui-layer-btn a{border:1px solid var(--lay-color-border-2);background-color: var( --lay-color-bg-3);color: var(--lay-color-text-2)}\n.layui-layer-btn .layui-layer-btn0{border-color: transparent;background-color: var(--lay-color-normal);color: var(--lay-color-text-1)}\n.layui-layer-dialog .layui-layer-content .layui-layer-face{color:var(--lay-color-gray-9)}\n.layui-layer-dialog .layui-layer-content .layui-icon-tips{color:var(--lay-color-warning)}\n.layui-layer-dialog .layui-layer-content .layui-icon-success{color: var(--lay-color-success)}\n.layui-layer-dialog .layui-layer-content .layui-icon-error{top: 19px; color: var(--lay-color-danger)}\n.layui-layer-dialog .layui-layer-content .layui-icon-question{color: var(--lay-color-warning);}\n.layui-layer-dialog .layui-layer-content .layui-icon-lock{color: var(--lay-color-gray-10)}\n.layui-layer-dialog .layui-layer-content .layui-icon-face-cry{color:var(--lay-color-danger)}\n.layui-layer-dialog .layui-layer-content .layui-icon-face-smile{color:var(--lay-color-success)}\n.layui-layer-rim{border:6px solid var(--lay-color-gray-8);border:6px solid var(--lay-color-border-2)}\n.layui-layer-msg{border:1px solid var( --lay-color-border-1)}\n.layui-layer-hui{background-color: var(--lay-color-bg-3);color: var(--lay-color-text-1)}\n.layui-layer-hui .layui-layer-close{color: var(--lay-color-white)}\n.layui-layer-loading-icon{color:var(--lay-color-gray-9)}\n.layui-layer-loading-2:after,.layui-layer-loading-2:before{border:3px solid var(--lay-color-gray-6)}\n.layui-layer-loading-2:after{border-color:transparent;border-left-color: var(--lay-color-normal)}\n.layui-layer-tips .layui-layer-content{box-shadow: var(--lay-shadow-3);background-color: var(--lay-color-bg-5);color: var(--lay-color-text-1)}\n.layui-layer-tips i.layui-layer-TipsG{border-color:transparent}\n.layui-layer-tips i.layui-layer-TipsB,.layui-layer-tips i.layui-layer-TipsT{border-right-color:var(--lay-color-black)}\n.layui-layer-tips i.layui-layer-TipsL,.layui-layer-tips i.layui-layer-TipsR{border-bottom-color:var(--lay-color-black)}\n.layui-layer-lan .layui-layer-title{background:var(--lay-color-blue-5);color: var(--lay-color-text-1)}\n.layui-layer-lan .layui-layer-btn{border-top:1px solid var(--lay-color-border-3)}\n.layui-layer-lan .layui-layer-btn a{background: var(--lay-color-white);border-color:var(--lay-color-border-3);color: var(--lay-color-black-7)}\n.layui-layer-lan .layui-layer-btn .layui-layer-btn1{background: var(--lay-color-gray-7)}\n.layui-layer-molv .layui-layer-title{background:var(--lay-color-layuigreen-6);color: var(--lay-color-text-1)}\n.layui-layer-molv .layui-layer-btn a{background:var(--lay-color-layuigreen-6);border-color:var(--lay-color-layuigreen-6)}\n.layui-layer-molv .layui-layer-btn .layui-layer-btn1{background:var(--lay-color-gray-7)}\n.layui-layer-win10{border-color: var(--lay-color-border-2)}\n.layui-layer-win10 .layui-layer-btn{background-color: var(--lay-color-bg-2);border-color: var(--lay-color-border-2)}\n.layui-layer-win10.layui-layer-dialog .layui-layer-content{color: var(--lay-color-blue-7)}\n.layui-layer-win10 .layui-layer-btn .layui-layer-btn0{border-color: var(--lay-color-blue-9);background-color: var(--lay-color-bg-5);color: var(--lay-color-text-1)}\n.layui-layer-win10 .layui-layer-btn .layui-layer-btn1{border-color: var(--lay-color-border-2);background-color: var(--lay-color-bg-5);color: var(--lay-color-text-1)}\n.layui-layer-win10 .layui-layer-btn a:hover{background-color: var(--lay-color-blue-10);border-color: var(--lay-color-blue-8)}\n.layui-layer-prompt .layui-layer-input{border:1px solid var(--lay-color-border-2);color: var(--lay-color-text-2)}\n.layui-layer-tab{box-shadow:var(--lay-shadow-3)}\n.layui-layer-tab .layui-layer-title span.layui-this{border-left:1px solid var(--lay-color-border-2);border-right:1px solid var(--lay-color-border-2);background-color: var(--lay-color-bg-3)}\n.layui-layer-photos{background: none; box-shadow: none;}\n.layui-layer-photos-prev,.layui-layer-photos-next{color:var(--lay-color-gray-9)}\n.layui-layer-photos-prev:hover,.layui-layer-photos-next:hover{color:var(--lay-color-text-1)}\n.layui-layer-photos-toolbar{background-color:#333;background-color: var(--lay-color-bg-5);color: var(--lay-color-text-1)}\n.layui-layer-photos-toolbar *{color: var(--lay-color-text-1)}\n.layui-layer-photos-toolbar a:hover{color: var(--lay-color-text-2)}\n.layui-layer-photos-header > span:hover{background-color: var(--lay-color-fill-2)}\n.layui-layer-tips i.layui-layer-TipsB,.layui-layer-tips i.layui-layer-TipsT{border-right-color: var(--lay-color-bg-5)}\n.layui-layer-tips i.layui-layer-TipsL,.layui-layer-tips i.layui-layer-TipsR{border-bottom-color: var(--lay-color-bg-5)}\n.layui-layer-prompt .layui-layer-input{border:1px solid var(--lay-color-border-2);color:var(--lay-color-text-1);background-color:var(--lay-color-black)}\n.layui-layer-prompt .layui-layer-input:focus{outline:0}\n\n/*fix style*/\n.layui-layer-loading{background:0 0;box-shadow:0 0}\n.layui-btn-primary{border-color:transparent}\n.layui-btn-group .layui-btn:first-child{border-left:none}\n.layui-btn-group .layui-btn-primary:hover{border-top-color:transparent; border-bottom-color: transparent;}\n.layui-menu li:hover{background-color:var(--lay-color-fill-2)}\n.layui-nav-child dd.layui-this{background-color:var(--lay-color-fill-2)}\n.layui-nav .layui-nav-child a:hover{background-color:var(--lay-color-fill-2)}\n.layui-nav .layui-nav-item a:hover,.layui-nav .layui-this a{background-color: var(--lay-color-fill-2)}\n.layui-nav-child dd.layui-this{background-color: var(--lay-color-fill-2)}\n.layui-tab-card>.layui-tab-title .layui-this:after{border-bottom-color:var(--lay-color-bg-1)}\n.layui-form-select dl dd:hover{background-color:var(--lay-color-fill-2)}\n.layui-form-select dl dd.layui-this{background-color:var(--lay-color-fill-2)}\n.layui-laypage button{color:var(--lay-color-text-1)}\n.layui-table[lay-even] tbody tr:nth-child(even){background-color:var(--lay-color-fill-4)}\n.layui-menu .layui-menu-item-checked,.layui-menu .layui-menu-item-checked2{background-color:var(--lay-color-fill-2)!important}\n.layui-input-split{background-color: var(--lay-color-bg-2);}\n.layui-input-wrap .layui-input-prefix.layui-input-split{border-width: 1px;}\n.layui-input-wrap .layui-input-split:has(+.layui-input:hover) {border-color: var(--lay-color-border-2);}\n.layui-input-wrap .layui-input-split:has(+.layui-input:focus) {border-color: var(--lay-color-secondary-hover);}\n.layui-layer-tab .layui-layer-title span:first-child{border-left: none !important;}\n.layui-slider-input.layui-input,\n.layui-slider-input .layui-input {background-color: var(--lay-color-bg-2);}\n"]} \ No newline at end of file diff --git a/web/static/src/layui-theme-dark.css b/web/static/src/layui-theme-dark.css deleted file mode 100644 index 3c0ee7e..0000000 --- a/web/static/src/layui-theme-dark.css +++ /dev/null @@ -1,738 +0,0 @@ -:root{ - /* =====色板===== */ - /*常量,不随明暗主题变化*/ - --color-white: #FFFFFF; - --color-black: #000000; - - --lay-color-white: #FAFAFA; - --lay-color-black: #333333; - - --lay-color-red-1: #FFF1E8; - --lay-color-red-2: #FFD7C0; - --lay-color-red-3: #FFBB99; - --lay-color-red-4: #FF9C71; - --lay-color-red-5: #FF7A4A; - --lay-color-red-6: #FF5722; - --lay-color-red-7: #D23B15; - --lay-color-red-8: #A6250B; - --lay-color-red-9: #791404; - --lay-color-red-10: #4D0800; - - --lay-color-blue-1: #E8F9FF; - --lay-color-blue-2: #C0ECFF; - --lay-color-blue-3: #97DCFF; - --lay-color-blue-4: #6FCAFF; - --lay-color-blue-5: #46B5FF; - --lay-color-blue-6: #1E9FFF; - --lay-color-blue-7: #1379D2; - --lay-color-blue-8: #0A58A6; - --lay-color-blue-9: #043A79; - --lay-color-blue-10: #00214D; - - --lay-color-lightblue-1: #E8FDFF; - --lay-color-lightblue-2: #C1F4FB; - --lay-color-lightblue-3: #9CEAF7; - --lay-color-lightblue-4: #77DDF4; - --lay-color-lightblue-5: #53CEF0; - --lay-color-lightblue-6: #31BDEC; - --lay-color-lightblue-7: #1F95C4; - --lay-color-lightblue-8: #10709C; - --lay-color-lightblue-9: #064E74; - --lay-color-lightblue-10: #002F4D; - - --lay-color-layuigreen-1: #E8FFF9; - --lay-color-layuigreen-2: #B5F1E3; - --lay-color-layuigreen-3: #87E3D1; - --lay-color-layuigreen-4: #5DD6C1; - --lay-color-layuigreen-5: #37C8B5; - --lay-color-layuigreen-6: #16BAAA; - --lay-color-layuigreen-7: #0E9F95; - --lay-color-layuigreen-8: #08837F; - --lay-color-layuigreen-9: #036868; - --lay-color-layuigreen-10: #004A4D; - - --lay-color-green-1: #E8FFF2; - --lay-color-green-2: #B5F1D1; - --lay-color-green-3: #86E2B4; - --lay-color-green-4: #5CD49C; - --lay-color-green-5: #37C588; - --lay-color-green-6: #16B777; - --lay-color-green-7: #0E9C68; - --lay-color-green-8: #088259; - --lay-color-green-9: #036749; - --lay-color-green-10: #004D38; - - --lay-color-orange-1: #FFFCE8; - --lay-color-orange-2: #FFF5BA; - --lay-color-orange-3: #FFEA8B; - --lay-color-orange-4: #FFDC5D; - --lay-color-orange-5: #FFCB2E; - --lay-color-orange-6: #FFB800; - --lay-color-orange-7: #D29000; - --lay-color-orange-8: #A66C00; - --lay-color-orange-9: #794B00; - --lay-color-orange-10: #4D2D00; - - --lay-color-cyan-1: #E8F6FF; - --lay-color-cyan-2: #B9CEDD; - --lay-color-cyan-3: #8FA7BB; - --lay-color-cyan-4: #6A829A; - --lay-color-cyan-5: #4A5F78; - --lay-color-cyan-6: #2F4056; - --lay-color-cyan-7: #223654; - --lay-color-cyan-8: #162C51; - --lay-color-cyan-9: #0B214F; - --lay-color-cyan-10: #00174D; - - --lay-color-purple-1: #FDE8FF; - --lay-color-purple-2: #EDBEF4; - --lay-color-purple-3: #DC97E8; - --lay-color-purple-4: #C972DD; - --lay-color-purple-5: #B651D1; - --lay-color-purple-6: #A233C6; - --lay-color-purple-7: #8120A8; - --lay-color-purple-8: #631289; - --lay-color-purple-9: #48076B; - --lay-color-purple-10: #2F004D; - - --lay-color-black-1: #E8F8FF; - --lay-color-black-2: #BFD0D8; - --lay-color-black-3: #98A8B1; - --lay-color-black-4: #73818A; - --lay-color-black-5: #505B63; - --lay-color-black-6: #2F363C; - --lay-color-black-7: #23303C; - --lay-color-black-8: #18293C; - --lay-color-black-9: #0C213C; - --lay-color-black-10: #00183C; - - --lay-color-gray-1: #FAFAFA; - --lay-color-gray-2: #F6F6F6; - --lay-color-gray-3: #EEEEEE; - --lay-color-gray-4: #E2E2E2; - --lay-color-gray-5: #DDDDDD; - --lay-color-gray-6: #D2D2D2; - --lay-color-gray-7: #CCCCCC; - --lay-color-gray-8: #C2C2C2; - --lay-color-gray-9: #AAAAAA; - --lay-color-gray-10: #939393; - - --lay-color-gray-11: #858585; - --lay-color-gray-12: #7b7b7b; - --lay-color-gray-13: #686868; - - /* =====语义===== */ - /* 主色 */ - --lay-color-primary: var(--lay-color-layuigreen-6); - --lay-color-primary-hover: var(--lay-color-layuigreen-5); - --lay-color-primary-active: var(--lay-color-layuigreen-7); - --lay-color-primary-disabled: var(--lay-color-layuigreen-3); - --lay-color-primary-light: var(--lay-color-layuigreen-4); - - /* 次色 */ - --lay-color-secondary: var(--lay-color-green-6); - --lay-color-secondary-hover: var(--lay-color-green-5); - --lay-color-secondary-active: var(--lay-color-green-7); - --lay-color-secondary-disabled: var(--lay-color-green-3); - --lay-color-secondary-light: var(--lay-color-green-4); - - /* 引导 */ - --lay-color-info: var(--lay-color-lightblue-6); - --lay-color-info-hover: var(--lay-color-lightblue-5); - --lay-color-info-active: var(--lay-color-lightblue-7); - --lay-color-info-disabled: var(--lay-color-lightblue-3); - --lay-color-info-light: var(--lay-color-lightblue-4); - - /* 百搭 */ - --lay-color-normal: var(--lay-color-blue-6); - --lay-color-normal-hover: var(--lay-color-blue-5); - --lay-color-normal-active: var(--lay-color-blue-7); - --lay-color-normal-disabled: var(--lay-color-blue-3); - --lay-color-normal-light: var(--lay-color-blue-4); - - /* 警示 */ - --lay-color-warning: var(--lay-color-orange-6); - --lay-color-warning-hover: var(--lay-color-orange-5); - --lay-color-warning-active: var(--lay-color-orange-7); - --lay-color-warning-disabled: var(--lay-color-orange-3); - --lay-color-warning-light: var(--lay-color-orange-4); - - /* 成功 */ - --lay-color-success: var(--lay-color-green-6); - --lay-color-success-hover: var(--lay-color-green-5); - --lay-color-success-active: var(--lay-color-green-7); - --lay-color-success-disabled: var(--lay-color-green-3); - --lay-color-success-light: var(--lay-color-green-4); - - /* 错误 */ - --lay-color-danger: var(--lay-color-red-6); - --lay-color-danger-hover: var(--lay-color-red-5); - --lay-color-danger-active: var(--lay-color-red-7); - --lay-color-danger-disabled: var(--lay-color-red-3); - --lay-color-danger-light: var(--lay-color-red-4); - - --lay-color-bg-1: #17171A; /*整体背景*/ - --lay-color-bg-2: #232324; /*一级容器背景,卡片,面板*/ - --lay-color-bg-3: #2a2a2b; /*二级容器背景*/ - --lay-color-bg-4: #313132; /*三级容器背景*/ - --lay-color-bg-5: #373739; /*下拉弹出框、Tooltip 背景颜色*/ - --lay-color-bg-white: #f6f6f6; /*白色背景*/ - - --lay-color-text-1: rgba(255,255,255,.9); /*强调/正文标题*/ - --lay-color-text-2: rgba(255,255,255,.7); /*次强调/语句*/ - --lay-color-text-3: rgba(255,255,255,.5); /*次要信息*/ - --lay-color-text-4: rgba(255,255,255,.3);/*禁用状态文字 */ - - --lay-color-border-1: #2e2e30; - --lay-color-border-2: #484849; - --lay-color-border-3: #5f5f60; - --lay-color-border-4: #929293; - - --lay-color-fill-1: rgba(255,255,255,.04);/*浅/禁用*/ - --lay-color-fill-2: rgba(255,255,255,.08);/*常规/白底悬浮*/ - --lay-color-fill-3: rgba(255,255,255,.12); /*深/灰底悬浮*/ - --lay-color-fill-4: rgba(255,255,255,.16);/*重/特殊场景*/ - - --lay-color-hover: var(--lay-color-fill-3); /*bg*/ - --lay-color-active: var(--lay-color-fill-3); /*bg*/ - - --lay-shadow-1: 0 4px 6px rgba(0, 0, 0, 6%), 0 1px 10px rgba(0, 0, 0, 8%), 0 2px 4px rgba(0, 0, 0, 12%);/*基础/下层投影 卡片面板*/ - --lay-shadow-2: 0 8px 10px rgba(0, 0, 0, 12%), 0 3px 14px rgba(0, 0, 0, 10%), 0 5px 5px rgba(0, 0, 0, 16%);/*中层投影 下拉菜单,选择器*/ - --lay-shadow-3: 0 16px 24px rgba(0, 0, 0, 14%), 0 6px 30px rgba(0, 0, 0, 12%), 0 8px 10px rgba(0, 0, 0, 20%);/*上层投影 弹窗*/ -} -blockquote,body,button,dd,div,dl,dt,form,h1,h2,h3,h4,h5,h6,input,li,ol,p,pre,td,textarea,th,ul{-webkit-tap-highlight-color: rgba(0, 0, 0, 0)} /*danger: 勿改*/ -body{color:var(--lay-color-text-2);background-color: var(--lay-color-bg-1); color-scheme: dark;} -hr{border-bottom:1px solid var(--lay-color-border-2)!important} -a{color:var(--lay-color-text-1);} -a:hover{color:var(--lay-color-text-3)} -/* 三角形 */ -.layui-edge{border-color:transparent} -.layui-edge-top{border-bottom-color:var(--lay-color-border-4)} -.layui-edge-right{border-left-color:var(--lay-color-border-4)} -.layui-edge-bottom{border-top-color:var(--lay-color-border-4)} -.layui-edge-left{border-right-color:var(--lay-color-border-4)} -/* 禁用文字 */ -.layui-disabled,.layui-disabled:hover{color:var(--lay-color-text-4)!important} -/* 图标 */ -.layui-icon{-moz-osx-font-smoothing:grayscale} -/* admin 布局 */ -.layui-layout-admin .layui-header{background-color:var(--lay-color-bg-2)} -.layui-layout-admin .layui-footer{box-shadow:-1px 0 4px rgb(0 0 0 / 12%);background-color:var(--lay-color-bg-2)} -.layui-layout-admin .layui-logo{color:var(--lay-color-primary);box-shadow:0 1px 2px 0 rgb(0 0 0 / 15%)} -/* 引用 */ -.layui-elem-quote{border-left:5px solid var(--lay-color-secondary);background-color:var(--lay-color-fill-1)} -.layui-quote-nm{border-color: var(--lay-color-fill-1)} -/* 进度条 */ -.layui-progress{background-color: var(--lay-color-bg-3)} -.layui-progress-bar{background-color:var( --lay-color-secondary)} -.layui-progress-text{color:var(--lay-color-text-2)} -.layui-progress-big .layui-progress-text{color: var(--lay-color-text-1)} -/* 折叠面板 */ -.layui-colla-title{color: var(--lay-color-text-1);background-color: var(--lay-color-bg-2)} -.layui-colla-content{color:var(--lay-color-text-2)} -/* 卡片面板 */ -.layui-card{background-color: var(--lay-color-bg-2);box-shadow:var(--lay-shadow-1)} -.layui-card-header{border-bottom:1px solid var(--lay-color-border-2);color:var(--lay-color-text-1)} -/* 常规面板 */ -.layui-panel{box-shadow:var(--lay-shadow-1);background-color: var( --lay-color-bg-2);color: var(--lay-color-text-1)} -.layui-menu-body-panel{box-shadow: var(--lay-shadow-2)} -/* 窗口面板 */ -.layui-panel-window{border-top:5px solid var(--lay-color-border-2);background-color: var(--lay-color-bg-2)} -/* 背景颜色 */ -.layui-bg-red{background-color:var(--lay-color-red-6)!important;color: var(--lay-color-white)!important} -.layui-bg-orange{background-color:var(--lay-color-orange-6)!important;color: var(--lay-color-white)!important} -.layui-bg-green{background-color:var(--lay-color-layuigreen-6)!important;color: var(--lay-color-white)!important} -.layui-bg-cyan{background-color:var(--lay-color-cyan-6)!important;color: var(--lay-color-white)!important} -.layui-bg-blue{background-color: var(--lay-color-blue-6)!important;color: var(--lay-color-white)!important} -.layui-bg-black{background-color:var(--lay-color-black-6)!important;color: var(--lay-color-white)!important} -.layui-bg-purple{background-color: var(--lay-color-purple-6)!important; color: var(--lay-color-white)!important;} -.layui-bg-gray{background-color:var(--lay-color-gray-1)!important;color: var(--lay-color-black-6)!important} -/* 徽章 */ -.layui-badge-rim,.layui-border,.layui-colla-content,.layui-colla-item,.layui-collapse,.layui-elem-field,.layui-form-pane .layui-form-item[pane],.layui-form-pane .layui-form-label,.layui-input,.layui-input-split,.layui-panel,.layui-select,.layui-tab-bar,.layui-tab-card,.layui-tab-title,.layui-tab-title .layui-this:after,.layui-textarea{border-color: var(--lay-color-border-1)} -/* 边框颜色 */ -.layui-border{color:var(--lay-color-text-1)!important} -.layui-border-red{border-color:var(--lay-color-red-6)!important;color:var(--lay-color-red-6)!important} -.layui-border-orange{border-color:var(--lay-color-orange-6)!important;color:var(--lay-color-orange-6)!important} -.layui-border-green{border-color:var(--lay-color-layuigreen-6)!important;color:var(--lay-color-layuigreen-6)!important} -.layui-border-cyan{border-color:var(--lay-color-cyan-6)!important;color:var(--lay-color-cyan-6)!important} -.layui-border-blue{border-color: var(--lay-color-blue-6)!important;color: var(--lay-color-blue-6)!important} -.layui-border-purple{border-color: var(--lay-color-purple-6)!important; color: var(--lay-color-purple-6)!important;} -.layui-border-black{border-color:var(--lay-color-black-6)!important;color:var(--lay-color-text-1)!important} -/* 文本区域 */ -.layui-text{color:var(--lay-color-text-2)} -.layui-text-em,.layui-word-aux{color: var(--lay-color-text-3)!important} -.layui-text a:not(.layui-btn){color:var(--lay-color-lightblue-6)} -.layui-text blockquote:not(.layui-elem-quote){border-left:5px solid var(--lay-color-border-4)} -/* 字体颜色 */ -.layui-font-red{color:var(--lay-color-red-6)!important} -.layui-font-orange{color:var(--lay-color-orange-6)!important} -.layui-font-green{color:var(--lay-color-layuigreen-6)!important} -.layui-font-cyan{color:var(--lay-color-cyan-6)!important} -.layui-font-blue{color:var(--lay-color-lightblue-6)!important} -.layui-font-black{color:var(--lay-color-black)!important} -.layui-font-purple{color:var(--lay-color-purple-6)!important;} -.layui-font-gray{color:var(--lay-color-gray-7)!important} -/* 按钮 */ -.layui-btn{border:1px solid transparent;background-color:var(--lay-color-primary);color: var(--lay-color-text-1)} -.layui-btn:hover{color: var(--lay-color-text-2)} -.layui-btn-primary{border-color:var(--lay-color-border-2);color:var(--lay-color-text-1);background-color: var(--lay-color-bg-4)} -.layui-btn-primary:hover{border-color: transparent;color:var(--lay-color-text-2)} -.layui-btn-normal{background-color: var(--lay-color-normal)} -.layui-btn-warm{background-color:var(--lay-color-warning)} -.layui-btn-danger{background-color:var(--lay-color-danger)} -.layui-btn-checked{background-color:var(--lay-color-success)} -.layui-btn-disabled,.layui-btn-disabled:active,.layui-btn-disabled:hover{border-color: var(--lay-color-border-2)!important;background-color: var(--lay-color-bg-2)!important;color: var(--lay-color-text-4)!important} -.layui-btn-group .layui-btn{border-left:1px solid var(--lay-color-border-2)} -.layui-btn-group .layui-btn-primary:hover{border-color:var(--lay-color-border-2);color:var(--lay-color-primary)} -.layui-btn-group .layui-btn-primary:first-child{border-left:1px solid var(--lay-color-gray-5)} -/*表单*/ -.layui-input,.layui-select,.layui-textarea{background-color: var(--lay-color-fill-2);color: var(--lay-color-text-2)} -.layui-input:hover,.layui-textarea:hover{border-color: var(--lay-color-border-2)!important} -.layui-input:focus,.layui-textarea:focus{border-color: var(--lay-color-secondary-hover)!important;background-color: var(--lay-color-bg-2);box-shadow: 0 0 0 3px rgba(22, 183, 119, 0.08);} -.layui-input[disabled],.layui-select[disabled],.layui-textarea[disabled],.layui-input.layui-disabled,.layui-textarea.layui-disabled{background-color: var(--lay-color-fill-1);color: var(--lay-color-text-4);border-color: var(--lay-color-border-1)!important;box-shadow: 0 0 0 0;} -.layui-form-danger+.layui-form-select .layui-input,.layui-form-danger:focus{border-color:var(--lay-color-danger)!important;box-shadow: 0 0 0 3px rgba(255, 87, 34, 0.08);} -/* 输入框点缀 */ -.layui-input-prefix .layui-icon,.layui-input-split .layui-icon,.layui-input-suffix .layui-icon{color: var(--lay-color-gray-8)} -.layui-input-wrap .layui-input:hover+.layui-input-split{border-color: var(--lay-color-border-2)} -.layui-input-wrap .layui-input[disabled]:hover+.layui-input-split{border-color: var(--lay-color-border-1)} -.layui-input-wrap .layui-input:focus+.layui-input-split{border-color: var(--lay-color-secondary-hover)} -.layui-input-wrap .layui-input.layui-form-danger:focus + .layui-input-split{border-color: var(--lay-color-danger);} -.layui-input-affix .layui-icon{color: var(--lay-color-text-2)} -.layui-input-affix .layui-icon-clear{color:var(--lay-color-text-2)} -.layui-input-affix .layui-icon:hover{color:var(--lay-color-text-3)} -/* 数字输入框动态点缀 */ -.layui-input-wrap .layui-input-number .layui-icon-up{border-bottom-color:var(--lay-color-border-1)} -.layui-input-wrap .layui-input[type="number"].layui-input-number-out-of-range{color:var(--lay-color-danger)} -/* 下拉选择 */ -.layui-form-select{color:var(--lay-color-text-2)} -.layui-form-select .layui-edge{border-top-color:var(--lay-color-gray-8)} -.layui-form-select dl{border:1px solid var( --lay-color-border-2);background-color: var(--lay-color-bg-5);box-shadow:var(--lay-shadow-2)} -.layui-form-select dl dt{color:var(--lay-color-gray-8)} -.layui-form-select dl dd:hover{background-color:var(--lay-color-active)} -.layui-form-select dl dd.layui-select-tips{color:var(--lay-color-text-2)} -.layui-form-select dl dd.layui-this{background-color: var(--lay-color-active);color: var(--lay-color-text-1)} -.layui-form-select dl dd.layui-disabled,.layui-form-select dl dd:hover.layui-disabled{background-color: var(--lay-color-bg-5)} -.layui-select-none{color:var(--lay-color-black-8)} -.layui-select-disabled .layui-disabled{border-color:var(--lay-color-border-1)!important} -.layui-select-disabled .layui-edge{border-top-color:var(--lay-color-gray-6)} -/* 复选框 */ -.layui-form-checkbox{background-color:var(--lay-color-fill-2)} -.layui-form-checkbox>div{background-color:var(--lay-color-fill-3);color:var(--lay-color-text-2)} -.layui-form-checkbox:hover>div{background-color: var(--lay-color-active)} -.layui-form-checkbox>i{background-color: var(--lay-color-fill-1);border-top-color:var(--lay-color-border-1);border-right-color:var(--lay-color-border-1);border-bottom-color:var(--lay-color-border-1);border-left-color:initial;color:var(--lay-color-text-1)} -.layui-form-checkbox:hover>i{border-color:var(--lay-color-border-2);color:var(--lay-color-text-4)} -.layui-form-checked,.layui-form-checked:hover{border-color:var(--lay-color-secondary-active)} -.layui-form-checked>div,.layui-form-checked:hover>div{background-color:var(--lay-color-secondary)} -.layui-form-checked>i,.layui-form-checked:hover>i{color:var(--lay-color-secondary-hover)} -.layui-form-checkbox.layui-checkbox-disabled>div{background-color: var(--lay-color-fill-3) !important;} -/* 复选框-默认风格 */ -.layui-form-checkbox[lay-skin=primary]{background-image:none;background-color:initial;border-color:initial!important} -.layui-form-checkbox[lay-skin=primary]>div{background-image:none;background-color:initial;color:var(--lay-color-text-2)} -.layui-form-checkbox[lay-skin=primary]>i{border-color:var(--lay-color-border-1);background-color:var(--lay-color-fill-2)} -.layui-form-checkbox[lay-skin=primary]:hover>i{border-color:var(--lay-color-secondary-hover);color:var(--lay-color-text-1)} -.layui-form-checked[lay-skin=primary]>i{background-color:var(--lay-color-secondary);color:var(--lay-color-text-1);border-color:var(--lay-color-secondary-active)!important} -.layui-checkbox-disabled[lay-skin=primary] >div{background:none!important;color:var(--lay-color-text-4)!important} -.layui-form-checked.layui-checkbox-disabled[lay-skin=primary]>i{background-color:var(--lay-color-fill-1)!important;border-color:var(--lay-color-border-2)!important} -.layui-checkbox-disabled[lay-skin=primary]:hover>i{border-color:var(--lay-color-border-1)} -.layui-form-checkbox[lay-skin="primary"]>.layui-icon-indeterminate:before{background-color: var(--lay-color-secondary-hover);opacity: 1;} -.layui-form-checkbox[lay-skin="primary"]:hover>.layui-icon-indeterminate:before{opacity: 1;} -.layui-form-checkbox[lay-skin="primary"]>.layui-icon-indeterminate{border-color: var(--lay-color-secondary-hover);} -/* 复选框-开关风格 */ -.layui-form-switch{border-color:var(--lay-color-border-2);background-color:var(--lay-color-fill-2)} -.layui-form-switch>i{background-color:var(--lay-color-gray-4)} -.layui-form-switch.layui-checkbox-disabled>i{background-color:var(--lay-color-gray-7);} -.layui-form-switch>div{color:var(--lay-color-gray-8)!important} -.layui-form-onswitch{border-color:var(--lay-color-secondary-active);background-color:var(--lay-color-secondary)} -.layui-form-onswitch>i{background-color:var(--lay-color-gray-4)} -.layui-form-onswitch>div{color:var(--lay-color-text-1)!important} -.layui-checkbox-disabled{border-color:var(--lay-color-border-2)!important} -.layui-checkbox-disabled>div{background-color:var(--lay-color-fill-3)!important;color: var(--lay-color-text-4)!important;} -.layui-checkbox-disabled>i{border-color:var(--lay-color-border-2)!important} -.layui-checkbox-disabled:hover>i{color:var(--lay-color-text-1)!important} -.layui-form-switch.layui-checkbox-disabled>div{background-color:initial!important;color: var(--lay-color-text-3)!important;} -/*复选框背景优化*/ -.layui-form-checkbox>i:before{opacity:0;filter:alpha(opacity=0)} -.layui-form-checkbox:hover>i:before{opacity:1;filter:alpha(opacity=100)} -.layui-form-checked.layui-checkbox-disabled:hover>i:before,.layui-form-checked:hover>i:before,.layui-form-checked>i:before{opacity:1;filter:alpha(opacity=100)} -.layui-form-checkbox[lay-skin=primary]:hover>i:before{opacity:0;filter:alpha(opacity=0)} -.layui-form-checked[lay-skin=primary]:hover>i:before{opacity:1;filter:alpha(opacity=100)} -.layui-checkbox-disabled:hover>i:before{opacity:0;filter:alpha(opacity=0)} -/*单选框*/ -.layui-form-radio>i{color:var(--lay-color-gray-8)} -.layui-form-radio:hover>*,.layui-form-radioed,.layui-form-radioed>i{color:var(--lay-color-secondary)} -.layui-radio-disabled>i{color:var(--lay-color-text-4)!important} -.layui-radio-disabled>*{color:var(--lay-color-text-4)!important} -/* 表单方框风格 */ -.layui-form-pane .layui-form-label{background-color:var(--lay-color-bg-2)} -/** 分页 **/ -.layui-laypage a,.layui-laypage button,.layui-laypage input,.layui-laypage select,.layui-laypage span{border:1px solid var(--lay-color-border-2)} -.layui-laypage a,.layui-laypage span{background-color: var(--lay-color-bg-2);color: var(--lay-color-text-2)} -.layui-laypage a[data-page]{color:var(--lay-color-text-2)} -.layui-laypage a:hover{color: var(--lay-color-primary)} -.layui-laypage .layui-laypage-spr{color:var(--lay-color-text-3)} -.layui-laypage .layui-laypage-curr em{color: var(--lay-color-white)} -.layui-laypage .layui-laypage-curr .layui-laypage-em{background-color: var(--lay-color-primary)} -.layui-laypage .layui-laypage-skip{color:var(--lay-color-text-3)} -.layui-laypage button,.layui-laypage input{background-color: var(--lay-color-bg-2)} -.layui-laypage input:focus,.layui-laypage select:focus{border-color: var(--lay-color-primary)!important} -/** 流加载 **/ -.layui-flow-more{color:var(--lay-color-text-1)} -.layui-flow-more a cite{background-color: var(--lay-color-bg-4);color: var(--lay-color-text-1)} -.layui-flow-more a i{color:var(--lay-color-text-2)} -/** 表格 **/ -.layui-table{background-color: var(--lay-color-bg-2);color: var(--lay-color-text-2)} -.layui-table-mend{background-color: var(--lay-color-bg-2)} -.layui-table-click,.layui-table-hover,.layui-table[lay-even] tbody tr:nth-child(even){background-color:var(--lay-color-fill-3)} -.layui-table-checked{background-color: var(--lay-color-fill-2);color: var(--lay-color-text-1)} -.layui-table-checked.layui-table-hover,.layui-table-checked.layui-table-click{background-color: var(--lay-color-fill-3);} -.layui-table td,.layui-table th,.layui-table-col-set,.layui-table-fixed-r,.layui-table-grid-down,.layui-table-header,.layui-table-mend,.layui-table-page,.layui-table-tips-main,.layui-table-tool,.layui-table-total,.layui-table-view,.layui-table[lay-skin=line],.layui-table[lay-skin=row]{border-color: var(--lay-color-border-2)} -.layui-table-view:after {background-color: var(--lay-color-border-2);} -.layui-table-view .layui-table td[data-edit]:hover:after{border:1px solid var(--lay-color-primary-active)} -.layui-table-loading-icon .layui-icon{color:var(--lay-color-gray-8);} -.layui-table-page{background-color: var(--lay-color-bg-2);} -.layui-table-page .layui-laypage a, -.layui-table-page .layui-laypage span{border: none;} -.layui-table-tool{background-color: var(--lay-color-bg-2);} -.layui-table-tool .layui-inline[lay-event]{color:var(--lay-color-text-3);border:1px solid var(--lay-color-border-2)} -.layui-table-tool .layui-inline[lay-event]:hover{border:1px solid var(--lay-color-border-3)} -.layui-table-tool-panel{color: var(--lay-color-text-1); border:1px solid var(--lay-color-border-2);background-color: var(--lay-color-bg-5);box-shadow:var(--lay-shadow-2)} -.layui-table-tool-panel li:hover{background-color:var(--lay-color-active)} -.layui-table-col-set{background-color: var(--lay-color-white)} -.layui-table-sort .layui-table-sort-asc{border-bottom-color:var(--lay-color-gray-8)} -.layui-table-sort .layui-table-sort-asc:hover{border-bottom-color:var(--lay-color-gray-11)} -.layui-table-sort .layui-table-sort-desc{border-top-color:var(--lay-color-gray-8)} -.layui-table-sort .layui-table-sort-desc:hover{border-top-color:var(--lay-color-gray-11)} -.layui-table-sort[lay-sort=asc] .layui-table-sort-asc{border-bottom-color:var(--lay-color-gray-13)} -.layui-table-sort[lay-sort=desc] .layui-table-sort-desc{border-top-color:var(--lay-color-gray-13)} -.layui-table-cell .layui-table-link{color: var(--lay-color-lightblue-5)} -.layui-table-body .layui-none{color:var(--lay-color-gray-8)} -.layui-table-fixed-l{box-shadow:1px 0 8px rgba(0,0,0,1)} -.layui-table-fixed-r{box-shadow:-1px 0 8px rgba(0,0,0,1)} -.layui-table-edit{box-shadow:var(--lay-shadow-1);background-color: var(--lay-color-bg-2)} -.layui-table-edit:focus{border-color:var(--lay-color-secondary)!important} -select.layui-table-edit{border-color:var(--lay-color-border-2)} -.layui-table-grid-down{background-color: var(--lay-color-bg-5);color:var(--lay-color-gray-8)} -.layui-table-grid-down:hover{background-color:var(--lay-color-bg-5)} -/* 单元格多行展开风格 */ -.layui-table-cell-c{background-color: var(--lay-color-gray-13);color: var(--lay-color-text-1); border-color: var(--lay-color-border-3);} -.layui-table-cell-c:hover{border-color: var(--lay-color-secondary-hover);} -/* 单元格 TIPS 展开风格 */ -body .layui-table-tips .layui-layer-content{box-shadow:var(--lay-shadow-3)} -.layui-table-tips-main{background-color: var(--lay-color-bg-5);color: var(--lay-color-text-3)} -.layui-table-tips-c{background-color:var(--lay-color-gray-13);color: var(--lay-color-text-1)} -.layui-table-tips-c:hover{background-color:var(--lay-color-gray-10)} -/** 文件上传 **/ -.layui-upload-choose{color:var(--lay-color-gray-8)} -.layui-upload-drag{border:1px dashed var( --lay-color-border-2);background-color: var(--lay-color-bg-4);color: var(--lay-color-text-2)} -.layui-upload-drag .layui-icon{color: var(--lay-color-primary)} -.layui-upload-drag[lay-over]{border-color: var(--lay-color-primary)} -/* 基础菜单元素 */ -.layui-menu{background-color: var(--lay-color-bg-2)} -.layui-menu li{color: var(--lay-color-text-1)} -.layui-menu li:hover{background-color: var(--lay-color-bg-5)} -.layui-menu li.layui-disabled,.layui-menu li.layui-disabled *{color:var(--lay-color-text-4)!important} -.layui-menu .layui-menu-item-group>.layui-menu-body-title{color: var(--lay-color-text-3)} -.layui-menu .layui-menu-item-none{color: var(--lay-color-text-3);} -.layui-menu .layui-menu-item-divider{border-bottom:1px solid var(--lay-color-border-2)} -.layui-menu .layui-menu-item-group:hover, -.layui-menu .layui-menu-item-none:hover, -.layui-menu .layui-menu-item-divider:hover{background: none;} -.layui-menu .layui-menu-item-up>.layui-menu-body-title{color: var(--lay-color-text-1)} -.layui-menu .layui-menu-item-down:hover>.layui-menu-body-title>.layui-icon,.layui-menu .layui-menu-item-up>.layui-menu-body-title:hover>.layui-icon{color: var(--lay-color-text-1)} -.layui-menu .layui-menu-item-checked,.layui-menu .layui-menu-item-checked2{background-color:var(--lay-color-active)!important;color:var(--lay-color-secondary)} -.layui-menu .layui-menu-item-checked a,.layui-menu .layui-menu-item-checked2 a{color:var(--lay-color-secondary)} -.layui-menu .layui-menu-item-checked:after{border-right:3px solid var(--lay-color-secondary)} -.layui-menu-body-title a{color: var(--lay-color-text-1)} -.layui-menu-lg .layui-menu-body-title a:hover,.layui-menu-lg li:hover{color:var(--lay-color-secondary)} -/* 下拉菜单 */ -.layui-dropdown{background-color: var(--lay-color-bg-5)} -.layui-dropdown.layui-panel,.layui-dropdown .layui-panel{background-color: var(--lay-color-bg-5);box-shadow: var(--lay-shadow-2)} -.layui-dropdown.layui-panel .layui-menu{background-color: var(--lay-color-bg-5)} -/** 导航菜单 **/ -.layui-nav{background-color:var(--lay-color-black-6);color: var(--lay-color-white)} -.layui-nav .layui-nav-item a{color: var(--lay-color-text-1);} -.layui-nav .layui-this:after,.layui-nav-bar{background-color:var(--lay-color-secondary)} -.layui-nav .layui-nav-item a:hover,.layui-nav .layui-this a{color: var(--lay-color-text-1)} -.layui-nav-child{box-shadow:var(--lay-shadow-2);border:1px solid var(--lay-color-border-2);background-color: var(--lay-color-bg-5)} -.layui-nav .layui-nav-child a{color: var(--lay-color-text-1)} -.layui-nav .layui-nav-child a:hover{background-color: var(--lay-color-bg-5);color: var(--lay-color-text-1)} -.layui-nav-child dd.layui-this{background-color: var(--lay-color-bg-5);color: var(--lay-color-text-1)} -.layui-nav-tree .layui-nav-child dd.layui-this,.layui-nav-tree .layui-nav-child dd.layui-this a,.layui-nav-tree .layui-this,.layui-nav-tree .layui-this>a,.layui-nav-tree .layui-this>a:hover{background-color: var(--lay-color-primary);color: var(--lay-color-white)} -.layui-nav-itemed>a,.layui-nav-tree .layui-nav-title a,.layui-nav-tree .layui-nav-title a:hover{color: var(--lay-color-white)!important} -.layui-nav-tree .layui-nav-bar{background-color:var(--lay-color-primary)} -.layui-nav-tree .layui-nav-child{background: none; background-color:rgba(0, 0, 0, .3); border: none; box-shadow: none;} -.layui-nav-tree .layui-nav-child a{color: var(--lay-color-white);color: var(--lay-color-text-1)} -.layui-nav-tree .layui-nav-child a:hover{background: none; color: var(--lay-color-white)} -.layui-nav.layui-bg-gray,.layui-nav-tree.layui-bg-gray{background-color: var(--lay-color-bg-2) !important;color: var(--lay-color-text-1);} -.layui-nav-tree.layui-bg-gray .layui-nav-child{background-color: rgba(0, 0, 0, .3) !important;} -.layui-nav-tree.layui-bg-gray a,.layui-nav.layui-bg-gray .layui-nav-item a{color: var(--lay-color-text-1)} -.layui-nav.layui-bg-gray .layui-nav-child{background-color: var(--lay-color-bg-5);} -.layui-nav-tree.layui-bg-gray .layui-nav-itemed>a{color: var(--lay-color-text-1)!important} -.layui-nav.layui-bg-gray .layui-this a{color:var(--lay-color-secondary)} -.layui-nav-tree.layui-bg-gray .layui-nav-child dd.layui-this,.layui-nav-tree.layui-bg-gray .layui-nav-child dd.layui-this a,.layui-nav-tree.layui-bg-gray .layui-this,.layui-nav-tree.layui-bg-gray .layui-this>a{color:var(--lay-color-secondary)!important} -.layui-nav-tree.layui-bg-gray .layui-nav-bar{background-color:var(--lay-color-secondary)} -/** 面包屑 **/ -.layui-breadcrumb a{color:var(--lay-color-gray-7)!important} -.layui-breadcrumb a:hover{color:var(--lay-color-secondary)!important} -.layui-breadcrumb a cite{color:var(--lay-color-gray-8)} -.layui-breadcrumb span[lay-separator]{color:var(--lay-color-gray-7)} -/** Tab 选项卡 **/ -.layui-tab .layui-tab-title:after{border-bottom-color: var(--lay-color-border-1);} -.layui-tab-title .layui-this{color: var(--lay-color-text-2)} -.layui-tab-title .layui-this:after{border-bottom-color: var(--lay-color-bg-1)} -.layui-tab-bar{background-color: var(--lay-color-bg-3)} -.layui-tab-more li.layui-this:after{border-bottom-color:var(--lay-color-border-1)} -.layui-tab-title li .layui-tab-close{color:var(--lay-color-gray-8)} -.layui-tab-title li .layui-tab-close:hover{background-color:var(--lay-color-danger);color: var(--lay-color-white)} -.layui-tab-brief>.layui-tab-title .layui-this{color:var( --lay-color-primary)} -.layui-tab-brief>.layui-tab-more li.layui-this:after,.layui-tab-brief>.layui-tab-title .layui-this:after{border-bottom:2px solid var(--lay-color-secondary)} -.layui-tab-card{box-shadow: var(--lay-shadow-1)} -.layui-tab-card>.layui-tab-title{background-color: var(--lay-color-bg-2)} -.layui-tab-card>.layui-tab-title .layui-this{background-color: var(--lay-color-bg-1)} -.layui-tab-card>.layui-tab-title .layui-this:after{border-bottom-color: var(--lay-color-bg-1)} -.layui-tab-card>.layui-tab-more .layui-this{color:var(--lay-color-secondary)} - -/** tabs 标签页 **/ -.layui-tabs-header:after, -.layui-tabs-scroll:after{border-bottom-color: var(--lay-color-border-1);} -.layui-tabs-card>.layui-tabs-header .layui-this{background-color: transparent;} -.layui-tabs-card>.layui-tabs-header .layui-this:after{border-color: var(--lay-color-border-1); border-bottom-color: var(--lay-color-bg-1);} -.layui-tabs-card.layui-panel>.layui-tabs-header .layui-this:after{border-bottom-color: var(--lay-color-bg-2);} -.layui-tabs-bar .layui-icon{background-color: var(--lay-color-bg-1); color: var(--lay-color-text-2); border-color: var(--lay-color-border-1); box-shadow: 2px 0 5px 0 rgb(0 0 0 / 32%);} -.layui-tabs-bar .layui-icon-next{box-shadow: -2px 0 5px 0 rgb(0 0 0 / 32%);} - -/*时间线*/ -.layui-timeline-axis{background-color: var(--lay-color-bg-4);color:var(--lay-color-secondary)} -.layui-timeline-axis:hover{color:var(--lay-color-red-6)} -.layui-timeline-item:before{background-color: var(--lay-color-bg-3)} -/*徽章*/ -.layui-badge,.layui-badge-dot,.layui-badge-rim{background-color:var(--lay-color-red-6);color: var(--lay-color-white)} -.layui-badge-rim{background-color: var(--lay-color-white);color:var(--lay-color-black-6)} -/* carousel 轮播 */ -.layui-carousel{background-color:var(--lay-color-gray-2)} -.layui-carousel>[carousel-item]:before{color:var(--lay-color-gray-8);-moz-osx-font-smoothing:grayscale} -.layui-carousel>[carousel-item]>*{background-color:var(--lay-color-gray-2)} -.layui-carousel-arrow{background-color:rgba(0,0,0,.2);color: var(--lay-color-white)} -.layui-carousel-arrow:hover,.layui-carousel-ind ul:hover{background-color:var(--lay-color-black)} -.layui-carousel[lay-indicator=outside] .layui-carousel-ind ul{background-color:var(--lay-color-black)} -.layui-carousel-ind ul{background-color:rgba(0,0,0,.2)} -.layui-carousel-ind ul li{background-color:var(--lay-color-gray-3);background-color: var(--lay-color-text-3)} -.layui-carousel-ind ul li:hover{background-color: var(--lay-color-white)} -.layui-carousel-ind ul li.layui-this{background-color: var(--lay-color-white)} -/** fixbar **/ -.layui-fixbar li{background-color:var(--lay-color-black-5);color: var(--lay-color-text-1)} -/** 表情面板 **/ -body .layui-util-face .layui-layer-content{background-color: var(--lay-color-bg-5);color:var(--lay-color-text-2)} -.layui-util-face ul{border:1px solid var(--lay-color-border-3);background-color: var(--lay-color-bg-5);box-shadow:var(--lay-shadow-2)} -.layui-util-face ul li{border:1px solid var(--lay-color-border-2)} -.layui-util-face ul li:hover{border:1px solid var(--lay-color-red-7);background: var(--lay-color-text-1)} -/** 代码文本修饰 **/ -.layui-code{border:1px solid var(--lay-color-border-2);background-color: var(--lay-color-bg-white);color: var(--lay-color-text-2)} -/** 穿梭框 **/ -.layui-transfer-box,.layui-transfer-header,.layui-transfer-search{border-color: var(--lay-color-border-2)} -.layui-transfer-box{background-color: var(--lay-color-bg-2)} -.layui-transfer-search .layui-icon-search{color:var(--lay-color-gray-8)} -.layui-transfer-active .layui-btn{background-color:var( --lay-color-secondary);border-color:var( --lay-color-secondary);color: var(--lay-color-white)} -.layui-transfer-active .layui-btn-disabled{background-color:var(--lay-color-gray-2);border-color:var(--lay-color-gray-3);color:var(--lay-color-gray-8)} -.layui-transfer-data li:hover{background-color:var(--lay-color-active)} -/* chrome 105 */ -.layui-transfer-data li:hover:has([lay-filter="layTransferCheckbox"][disabled]){background-color:var(--lay-color-bg-2)} -.layui-transfer-data .layui-none{color:var(--lay-color-gray-7)} -/** 评分组件 **/ -.layui-rate li i.layui-icon{color:var(--lay-color-orange-6)} -/** 颜色选择器 **/ -.layui-colorpicker{border:1px solid var(--lay-color-border-1)} -.layui-colorpicker:hover{border-color: var(--lay-color-border-2)} -.layui-colorpicker-trigger-span{border:1px solid var(--lay-color-border-1)} -.layui-colorpicker-trigger-i{color: var(--lay-color-white)} -.layui-colorpicker-trigger-i.layui-icon-close{color:var(--lay-color-black-7)} -.layui-colorpicker-main{background: var(--lay-color-bg-2);border:1px solid var( --lay-color-border-2);box-shadow:var(--lay-shadow-2)} -.layui-colorpicker-basis-white{background:linear-gradient(90deg, #fff,hsla(0,0%,100%,0))} /* danger: 勿改*/ -.layui-colorpicker-basis-black{background:linear-gradient(0deg,#000,transparent)} /* danger: 勿改*/ -.layui-colorpicker-basis-cursor{border:1px solid var(--lay-color-white)} -.layui-colorpicker-side{background:linear-gradient(linear-gradient(#F00, #FF0, #0F0, #0FF, #00F, #F0F, #F00))} /* danger: 勿改*/ -.layui-colorpicker-side-slider{box-shadow:var(--lay-shadow-1);background: var(--lay-color-white);border:1px solid var(--lay-color-gray-2)} -.layui-colorpicker-alpha-slider{box-shadow:var(--lay-shadow-1);background: var(--lay-color-white);border:1px solid var(--lay-color-gray-2)} -.layui-colorpicker-pre.layui-this{box-shadow:var(--lay-shadow-1)} -.layui-colorpicker-pre.selected{box-shadow:var(--lay-shadow-1)} -.layui-colorpicker-main-input input.layui-input{color: var(--lay-color-text-2)} -/** 滑块 **/ -.layui-slider{background: var( --lay-color-bg-5)} -.layui-slider-step{background: var(--lay-color-fill-4)} -.layui-slider-wrap-btn{background: var(--lay-color-bg-4)} -.layui-slider-tips{color: var(--lay-color-text-1);background:var(--lay-color-black);box-shadow: var(--lay-shadow-3)} -.layui-slider-tips:after{border-color:var(--lay-color-black) transparent transparent transparent} -.layui-slider-input{border:1px solid var(--lay-color-border-1)} -.layui-slider-input-btn{border-left:1px solid var(--lay-color-border-1)} -.layui-slider-input-btn i{color:var(--lay-color-gray-9)} -.layui-slider-input-btn i:first-child{border-bottom:1px solid var(--lay-color-border-1)} -.layui-slider-input-btn i:hover{color:var(--lay-color-primary)} -/** 树组件 **/ -.layui-tree-line .layui-tree-set .layui-tree-set:after{border-top:1px dotted var(--lay-color-gray-7)} -.layui-tree-entry:hover{background-color: var(--lay-color-bg-4)} -.layui-tree-line .layui-tree-entry:hover{background-color:var(--lay-color-black)} -.layui-tree-line .layui-tree-entry:hover .layui-tree-txt{color:var(--lay-color-text-3)} -.layui-tree-entry:hover:has(span.layui-tree-txt.layui-disabled){background-color: transparent !important} -.layui-tree-line .layui-tree-set:before{border-left:1px dotted var(--lay-color-gray-7)} -.layui-tree-iconClick{color:var(--lay-color-gray-7)} -.layui-tree-icon{border:1px solid var(--lay-color-gray-8)} -.layui-tree-icon .layui-icon{color:var(--lay-color-text-1)} -.layui-tree-iconArrow:after{border-color:transparent transparent transparent var(--lay-color-gray-7)} -.layui-tree-txt{color:var(--lay-color-text-2)} -.layui-tree-search{color:var(--lay-color-black-7)} -.layui-tree-btnGroup .layui-icon:hover{color:var(--lay-color-text-2)} -.layui-tree-editInput{background-color:var(--lay-color-fill-2)} -.layui-tree-emptyText{color:var(--lay-color-text-2)} -/*code 不处理*/ -.layui-code-view{border:1px solid var(--lay-color-border-1);} -.layui-code-view:not(.layui-code-hl){background-color: var(--lay-color-bg-2);color: var(--lay-color-text-2);} -.layui-code-header{border-bottom: 1px solid var(--lay-color-border-1); background-color: var(--lay-color-bg-2)} -.layui-code-header > .layui-code-header-about{color: var(--lay-color-text-2);} -.layui-code-view:not(.layui-code-hl) .layui-code-ln-side{border-color: var(--lay-color-border-1); background-color: var(--lay-color-bg-2);} -.layui-code-nowrap > .layui-code-ln-side{background: none !important;} -.layui-code-fixbar > span{color: var(--lay-color-text-3);} -.layui-code-fixbar > span:hover{color: var(--lay-color-secondary-hover);} - -.layui-code-theme-dark, -.layui-code-theme-dark > .layui-code-header{border-color: rgb(126 122 122 / 15%); background-color: #1f1f1f;} -.layui-code-theme-dark{border-width: 1px; color: #ccc;} -.layui-code-theme-dark > .layui-code-ln-side{border-right-color: #2a2a2a; background: none; color: #6e7681;} - -.layui-code-view.layui-code-hl > .layui-code-ln-side{background-color: transparent;} -.layui-code-theme-dark.layui-code-hl, -.layui-code-theme-dark.layui-code-hl > .layui-code-ln-side{border-color: rgb(126 122 122 / 15%);} - -.layui-code-full{background-color: var(--lay-color-bg-1)} -/*日期选择器*/ -.layui-laydate-header i{color:var(--lay-color-gray-8)} -.laydate-day-holidays:before{color:var(--lay-color-red-6)} -.layui-laydate .layui-this .laydate-day-holidays:before{color: var(--lay-color-white)} -.layui-laydate-footer span{border:1px solid var(--lay-color-border-2);background-color: var(--lay-color-bg-5)} -.layui-laydate-footer span:hover{color:var(--lay-color-secondary)} -.layui-laydate-footer span.layui-laydate-preview{border-color:transparent!important;} -.layui-laydate-footer span.layui-laydate-preview:hover{color:var(--lay-color-text-1) !important} -.layui-laydate-shortcut+.layui-laydate-main{border-left:1px solid var(--lay-color-border-2)} -.layui-laydate .layui-laydate-list{background-color: var(--lay-color-bg-5)} -.layui-laydate-hint{color:var(--lay-color-danger)} -.layui-laydate-range .laydate-main-list-1 .layui-laydate-content,.layui-laydate-range .laydate-main-list-1 .layui-laydate-header{border-left:1px solid var(--lay-color-border-2)} -.layui-laydate,.layui-laydate-hint{border-color: var(--lay-color-border-2);box-shadow:var(--lay-shadow-3);background-color: var(--lay-color-bg-5);color: var(--lay-color-text-1)} -.layui-laydate{box-shadow: var(--lay-shadow-2)} -.layui-laydate-hint{border-color:var(--lay-color-border-1)} -.layui-laydate-header{border-bottom:1px solid var( --lay-color-border-2)} -.layui-laydate-header i:hover,.layui-laydate-header span:hover{color:var(--lay-color-secondary)} -.layui-laydate-content th{color: var(--lay-color-text-1)} -.layui-laydate-content td{color: var(--lay-color-text-1)} -.layui-laydate-content td.laydate-day-now{color:var(--lay-color-secondary)} -.layui-laydate-content td.laydate-day-now:after{border:1px solid var(--lay-color-secondary)} -.layui-laydate-linkage .layui-laydate-content td.laydate-selected>div{background-color:var(--lay-color-green-8);} -.layui-laydate-linkage .laydate-selected:hover>div{background-color:var(--lay-color-green-8)!important} -.layui-laydate-content td>div:hover,.layui-laydate-list li:hover,.layui-laydate-shortcut>li:hover{background-color: var(--lay-color-fill-2);color: var(--lay-color-text-2)} -.layui-laydate-content td.laydate-disabled>div:hover{background-color: var(--lay-color-bg-5);color: var(--lay-color-text-4)} -.laydate-time-list li ol{border:1px solid var(--lay-color-border-2)} -.laydate-time-list>li:hover{background: 0 0;} -.layui-laydate-content .laydate-day-next,.layui-laydate-content .laydate-day-prev{color: var(--lay-color-text-3)} -.layui-laydate-linkage .laydate-selected.laydate-day-next>div,.layui-laydate-linkage .laydate-selected.laydate-day-prev>div{background: none!important} -.layui-laydate-footer{border-top:1px solid var(--lay-color-border-2)} -.layui-laydate-hint{color:var(--lay-color-danger)} -.laydate-day-mark::after{background-color:var(--lay-color-secondary)} -.layui-laydate-footer span[lay-type=date]{color:var(--lay-color-secondary)} -.layui-laydate .layui-this,.layui-laydate .layui-this>div{background-color:var(--lay-color-secondary)!important;color: var(--lay-color-white)!important} -.layui-laydate .laydate-disabled,.layui-laydate .laydate-disabled:hover{color: var(--lay-color-text-4)!important} -.layui-laydate .layui-this.laydate-disabled,.layui-laydate .layui-this.laydate-disabled>div{background-color: var(--lay-color-fill-1) !important;color: var(--lay-color-text-4) !important;} -.laydate-theme-molv .layui-laydate-header{background-color:var(--lay-color-primary)} -.laydate-theme-molv .layui-laydate-header i,.laydate-theme-molv .layui-laydate-header span{color:var(--lay-color-gray-2)} -.laydate-theme-molv .layui-laydate-header i:hover,.laydate-theme-molv .layui-laydate-header span:hover{color: var(--lay-color-white)} -.laydate-theme-molv .layui-laydate-content{border:1px solid var(--lay-color-border-2)} -.laydate-theme-molv .layui-this, .laydate-theme-molv .layui-this>div{background-color: var(--lay-color-primary) !important;} -.laydate-theme-molv .layui-laydate-footer{border:1px solid var(--lay-color-border-2)} -.laydate-theme-grid .laydate-month-list>li,.laydate-theme-grid .laydate-year-list>li,.laydate-theme-grid .layui-laydate-content td,.laydate-theme-grid .layui-laydate-content thead{border:1px solid var(--lay-color-border-2)} -.layui-laydate-linkage.laydate-theme-grid .laydate-selected,.layui-laydate-linkage.laydate-theme-grid .laydate-selected:hover{background-color:var(--lay-color-gray-3)!important;color:var(--lay-color-primary)!important} -.layui-laydate-linkage.laydate-theme-grid .laydate-selected.laydate-day-next,.layui-laydate-linkage.laydate-theme-grid .laydate-selected.laydate-day-prev{color:var(--lay-color-gray-6)!important} -.layui-laydate.laydate-theme-circle .layui-laydate-content table td.layui-this{background-color:transparent!important} -/*layer*/ -.layui-layer{background-color: var(--lay-color-bg-3);box-shadow:var(--lay-shadow-3)} -.layui-layer-border{border:1px solid var(--lay-color-border-2);box-shadow:var(--lay-shadow-3)} -.layui-layer-move{background-color: var(--lay-color-bg-5)} -.layui-layer-title{border-bottom:1px solid var(--lay-color-border-2);color: var(--lay-color-text-1)} -.layui-layer-setwin span{color: var(--lay-color-text-1)} -.layui-layer-setwin .layui-layer-min:before{border-bottom-color:var(--lay-color-text-1)} -.layui-layer-setwin .layui-layer-min:hover:before{border-bottom-color:var(--lay-color-info-hover)} -.layui-layer-setwin .layui-layer-max:after,.layui-layer-setwin .layui-layer-max:before{border:1px solid var(--lay-color-text-3)} -.layui-layer-setwin .layui-layer-max:hover:after,.layui-layer-setwin .layui-layer-max:hover:before{border-color:var(--lay-color-info-hover)} -.layui-layer-setwin .layui-layer-maxmin:after,.layui-layer-setwin .layui-layer-maxmin:before{background-color: var(--lay-color-bg-5)} -.layui-layer-setwin .layui-layer-close2{color:var(--lay-color-text-1);background-color:var(--lay-color-gray-10)} -.layui-layer-setwin .layui-layer-close2:hover{background-color:var(--lay-color-normal)} -.layui-layer-btn a{border:1px solid var(--lay-color-border-2);background-color: var( --lay-color-bg-3);color: var(--lay-color-text-2)} -.layui-layer-btn .layui-layer-btn0{border-color: transparent;background-color: var(--lay-color-normal);color: var(--lay-color-text-1)} -.layui-layer-dialog .layui-layer-content .layui-layer-face{color:var(--lay-color-gray-9)} -.layui-layer-dialog .layui-layer-content .layui-icon-tips{color:var(--lay-color-warning)} -.layui-layer-dialog .layui-layer-content .layui-icon-success{color: var(--lay-color-success)} -.layui-layer-dialog .layui-layer-content .layui-icon-error{top: 19px; color: var(--lay-color-danger)} -.layui-layer-dialog .layui-layer-content .layui-icon-question{color: var(--lay-color-warning);} -.layui-layer-dialog .layui-layer-content .layui-icon-lock{color: var(--lay-color-gray-10)} -.layui-layer-dialog .layui-layer-content .layui-icon-face-cry{color:var(--lay-color-danger)} -.layui-layer-dialog .layui-layer-content .layui-icon-face-smile{color:var(--lay-color-success)} -.layui-layer-rim{border:6px solid var(--lay-color-gray-8);border:6px solid var(--lay-color-border-2)} -.layui-layer-msg{border:1px solid var( --lay-color-border-1)} -.layui-layer-hui{background-color: var(--lay-color-bg-3);color: var(--lay-color-text-1)} -.layui-layer-hui .layui-layer-close{color: var(--lay-color-white)} -.layui-layer-loading-icon{color:var(--lay-color-gray-9)} -.layui-layer-loading-2:after,.layui-layer-loading-2:before{border:3px solid var(--lay-color-gray-6)} -.layui-layer-loading-2:after{border-color:transparent;border-left-color: var(--lay-color-normal)} -.layui-layer-tips .layui-layer-content{box-shadow: var(--lay-shadow-3);background-color: var(--lay-color-bg-5);color: var(--lay-color-text-1)} -.layui-layer-tips i.layui-layer-TipsG{border-color:transparent} -.layui-layer-tips i.layui-layer-TipsB,.layui-layer-tips i.layui-layer-TipsT{border-right-color:var(--lay-color-black)} -.layui-layer-tips i.layui-layer-TipsL,.layui-layer-tips i.layui-layer-TipsR{border-bottom-color:var(--lay-color-black)} -.layui-layer-lan .layui-layer-title{background:var(--lay-color-blue-5);color: var(--lay-color-text-1)} -.layui-layer-lan .layui-layer-btn{border-top:1px solid var(--lay-color-border-3)} -.layui-layer-lan .layui-layer-btn a{background: var(--lay-color-white);border-color:var(--lay-color-border-3);color: var(--lay-color-black-7)} -.layui-layer-lan .layui-layer-btn .layui-layer-btn1{background: var(--lay-color-gray-7)} -.layui-layer-molv .layui-layer-title{background:var(--lay-color-layuigreen-6);color: var(--lay-color-text-1)} -.layui-layer-molv .layui-layer-btn a{background:var(--lay-color-layuigreen-6);border-color:var(--lay-color-layuigreen-6)} -.layui-layer-molv .layui-layer-btn .layui-layer-btn1{background:var(--lay-color-gray-7)} -.layui-layer-win10{border-color: var(--lay-color-border-2)} -.layui-layer-win10 .layui-layer-btn{background-color: var(--lay-color-bg-2);border-color: var(--lay-color-border-2)} -.layui-layer-win10.layui-layer-dialog .layui-layer-content{color: var(--lay-color-blue-7)} -.layui-layer-win10 .layui-layer-btn .layui-layer-btn0{border-color: var(--lay-color-blue-9);background-color: var(--lay-color-bg-5);color: var(--lay-color-text-1)} -.layui-layer-win10 .layui-layer-btn .layui-layer-btn1{border-color: var(--lay-color-border-2);background-color: var(--lay-color-bg-5);color: var(--lay-color-text-1)} -.layui-layer-win10 .layui-layer-btn a:hover{background-color: var(--lay-color-blue-10);border-color: var(--lay-color-blue-8)} -.layui-layer-prompt .layui-layer-input{border:1px solid var(--lay-color-border-2);color: var(--lay-color-text-2)} -.layui-layer-tab{box-shadow:var(--lay-shadow-3)} -.layui-layer-tab .layui-layer-title span.layui-this{border-left:1px solid var(--lay-color-border-2);border-right:1px solid var(--lay-color-border-2);background-color: var(--lay-color-bg-3)} -.layui-layer-photos{background: none; box-shadow: none;} -.layui-layer-photos-prev,.layui-layer-photos-next{color:var(--lay-color-gray-9)} -.layui-layer-photos-prev:hover,.layui-layer-photos-next:hover{color:var(--lay-color-text-1)} -.layui-layer-photos-toolbar{background-color:#333;background-color: var(--lay-color-bg-5);color: var(--lay-color-text-1)} -.layui-layer-photos-toolbar *{color: var(--lay-color-text-1)} -.layui-layer-photos-toolbar a:hover{color: var(--lay-color-text-2)} -.layui-layer-photos-header > span:hover{background-color: var(--lay-color-fill-2)} -.layui-layer-tips i.layui-layer-TipsB,.layui-layer-tips i.layui-layer-TipsT{border-right-color: var(--lay-color-bg-5)} -.layui-layer-tips i.layui-layer-TipsL,.layui-layer-tips i.layui-layer-TipsR{border-bottom-color: var(--lay-color-bg-5)} -.layui-layer-prompt .layui-layer-input{border:1px solid var(--lay-color-border-2);color:var(--lay-color-text-1);background-color:var(--lay-color-black)} -.layui-layer-prompt .layui-layer-input:focus{outline:0} - -/*fix style*/ -.layui-layer-loading{background:0 0;box-shadow:0 0} -.layui-btn-primary{border-color:transparent} -.layui-btn-group .layui-btn:first-child{border-left:none} -.layui-btn-group .layui-btn-primary:hover{border-top-color:transparent; border-bottom-color: transparent;} -.layui-menu li:hover{background-color:var(--lay-color-fill-2)} -.layui-nav-child dd.layui-this{background-color:var(--lay-color-fill-2)} -.layui-nav .layui-nav-child a:hover{background-color:var(--lay-color-fill-2)} -.layui-nav .layui-nav-item a:hover,.layui-nav .layui-this a{background-color: var(--lay-color-fill-2)} -.layui-nav-child dd.layui-this{background-color: var(--lay-color-fill-2)} -.layui-tab-card>.layui-tab-title .layui-this:after{border-bottom-color:var(--lay-color-bg-1)} -.layui-form-select dl dd:hover{background-color:var(--lay-color-fill-2)} -.layui-form-select dl dd.layui-this{background-color:var(--lay-color-fill-2)} -.layui-laypage button{color:var(--lay-color-text-1)} -.layui-table[lay-even] tbody tr:nth-child(even){background-color:var(--lay-color-fill-4)} -.layui-menu .layui-menu-item-checked,.layui-menu .layui-menu-item-checked2{background-color:var(--lay-color-fill-2)!important} -.layui-input-split{background-color: var(--lay-color-bg-2);} -.layui-input-wrap .layui-input-prefix.layui-input-split{border-width: 1px;} -.layui-input-wrap .layui-input-split:has(+.layui-input:hover) {border-color: var(--lay-color-border-2);} -.layui-input-wrap .layui-input-split:has(+.layui-input:focus) {border-color: var(--lay-color-secondary-hover);} -.layui-layer-tab .layui-layer-title span:first-child{border-left: none !important;} -.layui-slider-input.layui-input, -.layui-slider-input .layui-input {background-color: var(--lay-color-bg-2);} - -/*# sourceMappingURL=layui-theme-dark.css.map */ diff --git a/web/static/src/layui-theme-dark.css.map b/web/static/src/layui-theme-dark.css.map deleted file mode 100644 index 1377307..0000000 --- a/web/static/src/layui-theme-dark.css.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["css-variables.css","override.css"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AC1MA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"layui-theme-dark.css","sourcesContent":[":root{\r\n /* =====色板===== */\r\n /*常量,不随明暗主题变化*/\r\n --color-white: #FFFFFF;\r\n --color-black: #000000;\r\n\r\n --lay-color-white: #FAFAFA;\r\n --lay-color-black: #333333;\r\n\r\n --lay-color-red-1: #FFF1E8; \r\n --lay-color-red-2: #FFD7C0; \r\n --lay-color-red-3: #FFBB99; \r\n --lay-color-red-4: #FF9C71; \r\n --lay-color-red-5: #FF7A4A; \r\n --lay-color-red-6: #FF5722; \r\n --lay-color-red-7: #D23B15; \r\n --lay-color-red-8: #A6250B; \r\n --lay-color-red-9: #791404; \r\n --lay-color-red-10: #4D0800;\r\n\r\n --lay-color-blue-1: #E8F9FF;\r\n --lay-color-blue-2: #C0ECFF;\r\n --lay-color-blue-3: #97DCFF;\r\n --lay-color-blue-4: #6FCAFF;\r\n --lay-color-blue-5: #46B5FF;\r\n --lay-color-blue-6: #1E9FFF;\r\n --lay-color-blue-7: #1379D2;\r\n --lay-color-blue-8: #0A58A6;\r\n --lay-color-blue-9: #043A79;\r\n --lay-color-blue-10: #00214D;\r\n\r\n --lay-color-lightblue-1: #E8FDFF;\r\n --lay-color-lightblue-2: #C1F4FB;\r\n --lay-color-lightblue-3: #9CEAF7;\r\n --lay-color-lightblue-4: #77DDF4;\r\n --lay-color-lightblue-5: #53CEF0;\r\n --lay-color-lightblue-6: #31BDEC;\r\n --lay-color-lightblue-7: #1F95C4;\r\n --lay-color-lightblue-8: #10709C;\r\n --lay-color-lightblue-9: #064E74;\r\n --lay-color-lightblue-10: #002F4D;\r\n\r\n --lay-color-layuigreen-1: #E8FFF9;\r\n --lay-color-layuigreen-2: #B5F1E3;\r\n --lay-color-layuigreen-3: #87E3D1;\r\n --lay-color-layuigreen-4: #5DD6C1;\r\n --lay-color-layuigreen-5: #37C8B5;\r\n --lay-color-layuigreen-6: #16BAAA;\r\n --lay-color-layuigreen-7: #0E9F95;\r\n --lay-color-layuigreen-8: #08837F;\r\n --lay-color-layuigreen-9: #036868;\r\n --lay-color-layuigreen-10: #004A4D;\r\n\r\n --lay-color-green-1: #E8FFF2;\r\n --lay-color-green-2: #B5F1D1;\r\n --lay-color-green-3: #86E2B4;\r\n --lay-color-green-4: #5CD49C;\r\n --lay-color-green-5: #37C588;\r\n --lay-color-green-6: #16B777;\r\n --lay-color-green-7: #0E9C68;\r\n --lay-color-green-8: #088259;\r\n --lay-color-green-9: #036749;\r\n --lay-color-green-10: #004D38;\r\n\r\n --lay-color-orange-1: #FFFCE8;\r\n --lay-color-orange-2: #FFF5BA;\r\n --lay-color-orange-3: #FFEA8B;\r\n --lay-color-orange-4: #FFDC5D;\r\n --lay-color-orange-5: #FFCB2E;\r\n --lay-color-orange-6: #FFB800;\r\n --lay-color-orange-7: #D29000;\r\n --lay-color-orange-8: #A66C00;\r\n --lay-color-orange-9: #794B00;\r\n --lay-color-orange-10: #4D2D00;\r\n\r\n --lay-color-cyan-1: #E8F6FF;\r\n --lay-color-cyan-2: #B9CEDD;\r\n --lay-color-cyan-3: #8FA7BB;\r\n --lay-color-cyan-4: #6A829A;\r\n --lay-color-cyan-5: #4A5F78;\r\n --lay-color-cyan-6: #2F4056;\r\n --lay-color-cyan-7: #223654;\r\n --lay-color-cyan-8: #162C51;\r\n --lay-color-cyan-9: #0B214F;\r\n --lay-color-cyan-10: #00174D;\r\n\r\n --lay-color-purple-1: #FDE8FF;\r\n --lay-color-purple-2: #EDBEF4;\r\n --lay-color-purple-3: #DC97E8;\r\n --lay-color-purple-4: #C972DD;\r\n --lay-color-purple-5: #B651D1;\r\n --lay-color-purple-6: #A233C6;\r\n --lay-color-purple-7: #8120A8;\r\n --lay-color-purple-8: #631289;\r\n --lay-color-purple-9: #48076B;\r\n --lay-color-purple-10: #2F004D;\r\n\r\n --lay-color-black-1: #E8F8FF;\r\n --lay-color-black-2: #BFD0D8;\r\n --lay-color-black-3: #98A8B1;\r\n --lay-color-black-4: #73818A;\r\n --lay-color-black-5: #505B63;\r\n --lay-color-black-6: #2F363C;\r\n --lay-color-black-7: #23303C;\r\n --lay-color-black-8: #18293C;\r\n --lay-color-black-9: #0C213C;\r\n --lay-color-black-10: #00183C;\r\n\r\n --lay-color-gray-1: #FAFAFA;\r\n --lay-color-gray-2: #F6F6F6;\r\n --lay-color-gray-3: #EEEEEE;\r\n --lay-color-gray-4: #E2E2E2;\r\n --lay-color-gray-5: #DDDDDD;\r\n --lay-color-gray-6: #D2D2D2;\r\n --lay-color-gray-7: #CCCCCC;\r\n --lay-color-gray-8: #C2C2C2;\r\n --lay-color-gray-9: #AAAAAA;\r\n --lay-color-gray-10: #939393;\r\n\r\n --lay-color-gray-11: #858585;\r\n --lay-color-gray-12: #7b7b7b;\r\n --lay-color-gray-13: #686868;\r\n\r\n /* =====语义===== */\r\n /* 主色 */\r\n --lay-color-primary: var(--lay-color-layuigreen-6); \r\n --lay-color-primary-hover: var(--lay-color-layuigreen-5);\r\n --lay-color-primary-active: var(--lay-color-layuigreen-7);\r\n --lay-color-primary-disabled: var(--lay-color-layuigreen-3);\r\n --lay-color-primary-light: var(--lay-color-layuigreen-4);\r\n\r\n /* 次色 */\r\n --lay-color-secondary: var(--lay-color-green-6);\r\n --lay-color-secondary-hover: var(--lay-color-green-5);\r\n --lay-color-secondary-active: var(--lay-color-green-7);\r\n --lay-color-secondary-disabled: var(--lay-color-green-3);\r\n --lay-color-secondary-light: var(--lay-color-green-4);\r\n\r\n /* 引导 */\r\n --lay-color-info: var(--lay-color-lightblue-6);\r\n --lay-color-info-hover: var(--lay-color-lightblue-5);\r\n --lay-color-info-active: var(--lay-color-lightblue-7);\r\n --lay-color-info-disabled: var(--lay-color-lightblue-3);\r\n --lay-color-info-light: var(--lay-color-lightblue-4);\r\n\r\n /* 百搭 */\r\n --lay-color-normal: var(--lay-color-blue-6);\r\n --lay-color-normal-hover: var(--lay-color-blue-5);\r\n --lay-color-normal-active: var(--lay-color-blue-7);\r\n --lay-color-normal-disabled: var(--lay-color-blue-3);\r\n --lay-color-normal-light: var(--lay-color-blue-4);\r\n\r\n /* 警示 */\r\n --lay-color-warning: var(--lay-color-orange-6);\r\n --lay-color-warning-hover: var(--lay-color-orange-5);\r\n --lay-color-warning-active: var(--lay-color-orange-7);\r\n --lay-color-warning-disabled: var(--lay-color-orange-3);\r\n --lay-color-warning-light: var(--lay-color-orange-4);\r\n\r\n /* 成功 */\r\n --lay-color-success: var(--lay-color-green-6);\r\n --lay-color-success-hover: var(--lay-color-green-5);\r\n --lay-color-success-active: var(--lay-color-green-7);\r\n --lay-color-success-disabled: var(--lay-color-green-3);\r\n --lay-color-success-light: var(--lay-color-green-4);\r\n\r\n /* 错误 */\r\n --lay-color-danger: var(--lay-color-red-6);\r\n --lay-color-danger-hover: var(--lay-color-red-5);\r\n --lay-color-danger-active: var(--lay-color-red-7);\r\n --lay-color-danger-disabled: var(--lay-color-red-3);\r\n --lay-color-danger-light: var(--lay-color-red-4);\r\n\r\n --lay-color-bg-1: #17171A; /*整体背景*/\r\n --lay-color-bg-2: #232324; /*一级容器背景,卡片,面板*/\r\n --lay-color-bg-3: #2a2a2b; /*二级容器背景*/\r\n --lay-color-bg-4: #313132; /*三级容器背景*/\r\n --lay-color-bg-5: #373739; /*下拉弹出框、Tooltip 背景颜色*/\r\n --lay-color-bg-white: #f6f6f6; /*白色背景*/\r\n\r\n --lay-color-text-1: rgba(255,255,255,.9); /*强调/正文标题*/\r\n --lay-color-text-2: rgba(255,255,255,.7); /*次强调/语句*/\r\n --lay-color-text-3: rgba(255,255,255,.5); /*次要信息*/\r\n --lay-color-text-4: rgba(255,255,255,.3);/*禁用状态文字 */\r\n\r\n --lay-color-border-1: #2e2e30;\r\n --lay-color-border-2: #484849;\r\n --lay-color-border-3: #5f5f60;\r\n --lay-color-border-4: #929293;\r\n\r\n --lay-color-fill-1: rgba(255,255,255,.04);/*浅/禁用*/\r\n --lay-color-fill-2: rgba(255,255,255,.08);/*常规/白底悬浮*/\r\n --lay-color-fill-3: rgba(255,255,255,.12); /*深/灰底悬浮*/\r\n --lay-color-fill-4: rgba(255,255,255,.16);/*重/特殊场景*/\r\n\r\n --lay-color-hover: var(--lay-color-fill-3); /*bg*/\r\n --lay-color-active: var(--lay-color-fill-3); /*bg*/\r\n\r\n --lay-shadow-1: 0 4px 6px rgba(0, 0, 0, 6%), 0 1px 10px rgba(0, 0, 0, 8%), 0 2px 4px rgba(0, 0, 0, 12%);/*基础/下层投影 卡片面板*/\r\n --lay-shadow-2: 0 8px 10px rgba(0, 0, 0, 12%), 0 3px 14px rgba(0, 0, 0, 10%), 0 5px 5px rgba(0, 0, 0, 16%);/*中层投影 下拉菜单,选择器*/\r\n --lay-shadow-3: 0 16px 24px rgba(0, 0, 0, 14%), 0 6px 30px rgba(0, 0, 0, 12%), 0 8px 10px rgba(0, 0, 0, 20%);/*上层投影 弹窗*/\r\n}\r\n","blockquote,body,button,dd,div,dl,dt,form,h1,h2,h3,h4,h5,h6,input,li,ol,p,pre,td,textarea,th,ul{-webkit-tap-highlight-color: rgba(0, 0, 0, 0)} /*danger: 勿改*/\nbody{color:var(--lay-color-text-2);background-color: var(--lay-color-bg-1); color-scheme: dark;}\nhr{border-bottom:1px solid var(--lay-color-border-2)!important}\na{color:var(--lay-color-text-1);}\na:hover{color:var(--lay-color-text-3)}\n/* 三角形 */\n.layui-edge{border-color:transparent}\n.layui-edge-top{border-bottom-color:var(--lay-color-border-4)}\n.layui-edge-right{border-left-color:var(--lay-color-border-4)}\n.layui-edge-bottom{border-top-color:var(--lay-color-border-4)}\n.layui-edge-left{border-right-color:var(--lay-color-border-4)}\n/* 禁用文字 */\n.layui-disabled,.layui-disabled:hover{color:var(--lay-color-text-4)!important}\n/* 图标 */\n.layui-icon{-moz-osx-font-smoothing:grayscale}\n/* admin 布局 */\n.layui-layout-admin .layui-header{background-color:var(--lay-color-bg-2)}\n.layui-layout-admin .layui-footer{box-shadow:-1px 0 4px rgb(0 0 0 / 12%);background-color:var(--lay-color-bg-2)}\n.layui-layout-admin .layui-logo{color:var(--lay-color-primary);box-shadow:0 1px 2px 0 rgb(0 0 0 / 15%)}\n/* 引用 */\n.layui-elem-quote{border-left:5px solid var(--lay-color-secondary);background-color:var(--lay-color-fill-1)}\n.layui-quote-nm{border-color: var(--lay-color-fill-1)}\n/* 进度条 */\n.layui-progress{background-color: var(--lay-color-bg-3)}\n.layui-progress-bar{background-color:var( --lay-color-secondary)}\n.layui-progress-text{color:var(--lay-color-text-2)}\n.layui-progress-big .layui-progress-text{color: var(--lay-color-text-1)}\n/* 折叠面板 */\n.layui-colla-title{color: var(--lay-color-text-1);background-color: var(--lay-color-bg-2)}\n.layui-colla-content{color:var(--lay-color-text-2)}\n/* 卡片面板 */\n.layui-card{background-color: var(--lay-color-bg-2);box-shadow:var(--lay-shadow-1)}\n.layui-card-header{border-bottom:1px solid var(--lay-color-border-2);color:var(--lay-color-text-1)}\n/* 常规面板 */\n.layui-panel{box-shadow:var(--lay-shadow-1);background-color: var( --lay-color-bg-2);color: var(--lay-color-text-1)}\n.layui-menu-body-panel{box-shadow: var(--lay-shadow-2)}\n/* 窗口面板 */\n.layui-panel-window{border-top:5px solid var(--lay-color-border-2);background-color: var(--lay-color-bg-2)}\n/* 背景颜色 */\n.layui-bg-red{background-color:var(--lay-color-red-6)!important;color: var(--lay-color-white)!important}\n.layui-bg-orange{background-color:var(--lay-color-orange-6)!important;color: var(--lay-color-white)!important}\n.layui-bg-green{background-color:var(--lay-color-layuigreen-6)!important;color: var(--lay-color-white)!important}\n.layui-bg-cyan{background-color:var(--lay-color-cyan-6)!important;color: var(--lay-color-white)!important}\n.layui-bg-blue{background-color: var(--lay-color-blue-6)!important;color: var(--lay-color-white)!important}\n.layui-bg-black{background-color:var(--lay-color-black-6)!important;color: var(--lay-color-white)!important}\n.layui-bg-purple{background-color: var(--lay-color-purple-6)!important; color: var(--lay-color-white)!important;}\n.layui-bg-gray{background-color:var(--lay-color-gray-1)!important;color: var(--lay-color-black-6)!important}\n/* 徽章 */\n.layui-badge-rim,.layui-border,.layui-colla-content,.layui-colla-item,.layui-collapse,.layui-elem-field,.layui-form-pane .layui-form-item[pane],.layui-form-pane .layui-form-label,.layui-input,.layui-input-split,.layui-panel,.layui-select,.layui-tab-bar,.layui-tab-card,.layui-tab-title,.layui-tab-title .layui-this:after,.layui-textarea{border-color: var(--lay-color-border-1)}\n/* 边框颜色 */\n.layui-border{color:var(--lay-color-text-1)!important}\n.layui-border-red{border-color:var(--lay-color-red-6)!important;color:var(--lay-color-red-6)!important}\n.layui-border-orange{border-color:var(--lay-color-orange-6)!important;color:var(--lay-color-orange-6)!important}\n.layui-border-green{border-color:var(--lay-color-layuigreen-6)!important;color:var(--lay-color-layuigreen-6)!important}\n.layui-border-cyan{border-color:var(--lay-color-cyan-6)!important;color:var(--lay-color-cyan-6)!important}\n.layui-border-blue{border-color: var(--lay-color-blue-6)!important;color: var(--lay-color-blue-6)!important}\n.layui-border-purple{border-color: var(--lay-color-purple-6)!important; color: var(--lay-color-purple-6)!important;}\n.layui-border-black{border-color:var(--lay-color-black-6)!important;color:var(--lay-color-text-1)!important}\n/* 文本区域 */\n.layui-text{color:var(--lay-color-text-2)}\n.layui-text-em,.layui-word-aux{color: var(--lay-color-text-3)!important}\n.layui-text a:not(.layui-btn){color:var(--lay-color-lightblue-6)}\n.layui-text blockquote:not(.layui-elem-quote){border-left:5px solid var(--lay-color-border-4)}\n/* 字体颜色 */\n.layui-font-red{color:var(--lay-color-red-6)!important}\n.layui-font-orange{color:var(--lay-color-orange-6)!important}\n.layui-font-green{color:var(--lay-color-layuigreen-6)!important}\n.layui-font-cyan{color:var(--lay-color-cyan-6)!important}\n.layui-font-blue{color:var(--lay-color-lightblue-6)!important}\n.layui-font-black{color:var(--lay-color-black)!important}\n.layui-font-purple{color:var(--lay-color-purple-6)!important;}\n.layui-font-gray{color:var(--lay-color-gray-7)!important}\n/* 按钮 */\n.layui-btn{border:1px solid transparent;background-color:var(--lay-color-primary);color: var(--lay-color-text-1)}\n.layui-btn:hover{color: var(--lay-color-text-2)}\n.layui-btn-primary{border-color:var(--lay-color-border-2);color:var(--lay-color-text-1);background-color: var(--lay-color-bg-4)}\n.layui-btn-primary:hover{border-color: transparent;color:var(--lay-color-text-2)}\n.layui-btn-normal{background-color: var(--lay-color-normal)}\n.layui-btn-warm{background-color:var(--lay-color-warning)}\n.layui-btn-danger{background-color:var(--lay-color-danger)}\n.layui-btn-checked{background-color:var(--lay-color-success)}\n.layui-btn-disabled,.layui-btn-disabled:active,.layui-btn-disabled:hover{border-color: var(--lay-color-border-2)!important;background-color: var(--lay-color-bg-2)!important;color: var(--lay-color-text-4)!important}\n.layui-btn-group .layui-btn{border-left:1px solid var(--lay-color-border-2)}\n.layui-btn-group .layui-btn-primary:hover{border-color:var(--lay-color-border-2);color:var(--lay-color-primary)}\n.layui-btn-group .layui-btn-primary:first-child{border-left:1px solid var(--lay-color-gray-5)}\n/*表单*/\n.layui-input,.layui-select,.layui-textarea{background-color: var(--lay-color-fill-2);color: var(--lay-color-text-2)}\n.layui-input:hover,.layui-textarea:hover{border-color: var(--lay-color-border-2)!important}\n.layui-input:focus,.layui-textarea:focus{border-color: var(--lay-color-secondary-hover)!important;background-color: var(--lay-color-bg-2);box-shadow: 0 0 0 3px rgba(22, 183, 119, 0.08);}\n.layui-input[disabled],.layui-select[disabled],.layui-textarea[disabled],.layui-input.layui-disabled,.layui-textarea.layui-disabled{background-color: var(--lay-color-fill-1);color: var(--lay-color-text-4);border-color: var(--lay-color-border-1)!important;box-shadow: 0 0 0 0;}\n.layui-form-danger+.layui-form-select .layui-input,.layui-form-danger:focus{border-color:var(--lay-color-danger)!important;box-shadow: 0 0 0 3px rgba(255, 87, 34, 0.08);}\n/* 输入框点缀 */\n.layui-input-prefix .layui-icon,.layui-input-split .layui-icon,.layui-input-suffix .layui-icon{color: var(--lay-color-gray-8)}\n.layui-input-wrap .layui-input:hover+.layui-input-split{border-color: var(--lay-color-border-2)}\n.layui-input-wrap .layui-input[disabled]:hover+.layui-input-split{border-color: var(--lay-color-border-1)}\n.layui-input-wrap .layui-input:focus+.layui-input-split{border-color: var(--lay-color-secondary-hover)}\n.layui-input-wrap .layui-input.layui-form-danger:focus + .layui-input-split{border-color: var(--lay-color-danger);}\n.layui-input-affix .layui-icon{color: var(--lay-color-text-2)}\n.layui-input-affix .layui-icon-clear{color:var(--lay-color-text-2)}\n.layui-input-affix .layui-icon:hover{color:var(--lay-color-text-3)}\n/* 数字输入框动态点缀 */\n.layui-input-wrap .layui-input-number .layui-icon-up{border-bottom-color:var(--lay-color-border-1)}\n.layui-input-wrap .layui-input[type=\"number\"].layui-input-number-out-of-range{color:var(--lay-color-danger)}\n/* 下拉选择 */\n.layui-form-select{color:var(--lay-color-text-2)}\n.layui-form-select .layui-edge{border-top-color:var(--lay-color-gray-8)}\n.layui-form-select dl{border:1px solid var( --lay-color-border-2);background-color: var(--lay-color-bg-5);box-shadow:var(--lay-shadow-2)}\n.layui-form-select dl dt{color:var(--lay-color-gray-8)}\n.layui-form-select dl dd:hover{background-color:var(--lay-color-active)}\n.layui-form-select dl dd.layui-select-tips{color:var(--lay-color-text-2)}\n.layui-form-select dl dd.layui-this{background-color: var(--lay-color-active);color: var(--lay-color-text-1)}\n.layui-form-select dl dd.layui-disabled,.layui-form-select dl dd:hover.layui-disabled{background-color: var(--lay-color-bg-5)}\n.layui-select-none{color:var(--lay-color-black-8)}\n.layui-select-disabled .layui-disabled{border-color:var(--lay-color-border-1)!important}\n.layui-select-disabled .layui-edge{border-top-color:var(--lay-color-gray-6)}\n/* 复选框 */\n.layui-form-checkbox{background-color:var(--lay-color-fill-2)}\n.layui-form-checkbox>div{background-color:var(--lay-color-fill-3);color:var(--lay-color-text-2)}\n.layui-form-checkbox:hover>div{background-color: var(--lay-color-active)}\n.layui-form-checkbox>i{background-color: var(--lay-color-fill-1);border-top-color:var(--lay-color-border-1);border-right-color:var(--lay-color-border-1);border-bottom-color:var(--lay-color-border-1);border-left-color:initial;color:var(--lay-color-text-1)}\n.layui-form-checkbox:hover>i{border-color:var(--lay-color-border-2);color:var(--lay-color-text-4)}\n.layui-form-checked,.layui-form-checked:hover{border-color:var(--lay-color-secondary-active)}\n.layui-form-checked>div,.layui-form-checked:hover>div{background-color:var(--lay-color-secondary)}\n.layui-form-checked>i,.layui-form-checked:hover>i{color:var(--lay-color-secondary-hover)}\n.layui-form-checkbox.layui-checkbox-disabled>div{background-color: var(--lay-color-fill-3) !important;}\n/* 复选框-默认风格 */\n.layui-form-checkbox[lay-skin=primary]{background-image:none;background-color:initial;border-color:initial!important}\n.layui-form-checkbox[lay-skin=primary]>div{background-image:none;background-color:initial;color:var(--lay-color-text-2)}\n.layui-form-checkbox[lay-skin=primary]>i{border-color:var(--lay-color-border-1);background-color:var(--lay-color-fill-2)}\n.layui-form-checkbox[lay-skin=primary]:hover>i{border-color:var(--lay-color-secondary-hover);color:var(--lay-color-text-1)}\n.layui-form-checked[lay-skin=primary]>i{background-color:var(--lay-color-secondary);color:var(--lay-color-text-1);border-color:var(--lay-color-secondary-active)!important}\n.layui-checkbox-disabled[lay-skin=primary] >div{background:none!important;color:var(--lay-color-text-4)!important}\n.layui-form-checked.layui-checkbox-disabled[lay-skin=primary]>i{background-color:var(--lay-color-fill-1)!important;border-color:var(--lay-color-border-2)!important}\n.layui-checkbox-disabled[lay-skin=primary]:hover>i{border-color:var(--lay-color-border-1)}\n.layui-form-checkbox[lay-skin=\"primary\"]>.layui-icon-indeterminate:before{background-color: var(--lay-color-secondary-hover);opacity: 1;}\n.layui-form-checkbox[lay-skin=\"primary\"]:hover>.layui-icon-indeterminate:before{opacity: 1;}\n.layui-form-checkbox[lay-skin=\"primary\"]>.layui-icon-indeterminate{border-color: var(--lay-color-secondary-hover);}\n/* 复选框-开关风格 */\n.layui-form-switch{border-color:var(--lay-color-border-2);background-color:var(--lay-color-fill-2)}\n.layui-form-switch>i{background-color:var(--lay-color-gray-4)}\n.layui-form-switch.layui-checkbox-disabled>i{background-color:var(--lay-color-gray-7);}\n.layui-form-switch>div{color:var(--lay-color-gray-8)!important}\n.layui-form-onswitch{border-color:var(--lay-color-secondary-active);background-color:var(--lay-color-secondary)}\n.layui-form-onswitch>i{background-color:var(--lay-color-gray-4)}\n.layui-form-onswitch>div{color:var(--lay-color-text-1)!important}\n.layui-checkbox-disabled{border-color:var(--lay-color-border-2)!important}\n.layui-checkbox-disabled>div{background-color:var(--lay-color-fill-3)!important;color: var(--lay-color-text-4)!important;}\n.layui-checkbox-disabled>i{border-color:var(--lay-color-border-2)!important}\n.layui-checkbox-disabled:hover>i{color:var(--lay-color-text-1)!important}\n.layui-form-switch.layui-checkbox-disabled>div{background-color:initial!important;color: var(--lay-color-text-3)!important;}\n/*复选框背景优化*/\n.layui-form-checkbox>i:before{opacity:0;filter:alpha(opacity=0)}\n.layui-form-checkbox:hover>i:before{opacity:1;filter:alpha(opacity=100)}\n.layui-form-checked.layui-checkbox-disabled:hover>i:before,.layui-form-checked:hover>i:before,.layui-form-checked>i:before{opacity:1;filter:alpha(opacity=100)}\n.layui-form-checkbox[lay-skin=primary]:hover>i:before{opacity:0;filter:alpha(opacity=0)}\n.layui-form-checked[lay-skin=primary]:hover>i:before{opacity:1;filter:alpha(opacity=100)}\n.layui-checkbox-disabled:hover>i:before{opacity:0;filter:alpha(opacity=0)}\n/*单选框*/\n.layui-form-radio>i{color:var(--lay-color-gray-8)}\n.layui-form-radio:hover>*,.layui-form-radioed,.layui-form-radioed>i{color:var(--lay-color-secondary)}\n.layui-radio-disabled>i{color:var(--lay-color-text-4)!important}\n.layui-radio-disabled>*{color:var(--lay-color-text-4)!important}\n/* 表单方框风格 */\n.layui-form-pane .layui-form-label{background-color:var(--lay-color-bg-2)}\n/** 分页 **/\n.layui-laypage a,.layui-laypage button,.layui-laypage input,.layui-laypage select,.layui-laypage span{border:1px solid var(--lay-color-border-2)}\n.layui-laypage a,.layui-laypage span{background-color: var(--lay-color-bg-2);color: var(--lay-color-text-2)}\n.layui-laypage a[data-page]{color:var(--lay-color-text-2)}\n.layui-laypage a:hover{color: var(--lay-color-primary)}\n.layui-laypage .layui-laypage-spr{color:var(--lay-color-text-3)}\n.layui-laypage .layui-laypage-curr em{color: var(--lay-color-white)}\n.layui-laypage .layui-laypage-curr .layui-laypage-em{background-color: var(--lay-color-primary)}\n.layui-laypage .layui-laypage-skip{color:var(--lay-color-text-3)}\n.layui-laypage button,.layui-laypage input{background-color: var(--lay-color-bg-2)}\n.layui-laypage input:focus,.layui-laypage select:focus{border-color: var(--lay-color-primary)!important}\n/** 流加载 **/\n.layui-flow-more{color:var(--lay-color-text-1)}\n.layui-flow-more a cite{background-color: var(--lay-color-bg-4);color: var(--lay-color-text-1)}\n.layui-flow-more a i{color:var(--lay-color-text-2)}\n/** 表格 **/\n.layui-table{background-color: var(--lay-color-bg-2);color: var(--lay-color-text-2)}\n.layui-table-mend{background-color: var(--lay-color-bg-2)}\n.layui-table-click,.layui-table-hover,.layui-table[lay-even] tbody tr:nth-child(even){background-color:var(--lay-color-fill-3)}\n.layui-table-checked{background-color: var(--lay-color-fill-2);color: var(--lay-color-text-1)}\n.layui-table-checked.layui-table-hover,.layui-table-checked.layui-table-click{background-color: var(--lay-color-fill-3);}\n.layui-table td,.layui-table th,.layui-table-col-set,.layui-table-fixed-r,.layui-table-grid-down,.layui-table-header,.layui-table-mend,.layui-table-page,.layui-table-tips-main,.layui-table-tool,.layui-table-total,.layui-table-view,.layui-table[lay-skin=line],.layui-table[lay-skin=row]{border-color: var(--lay-color-border-2)}\n.layui-table-view:after {background-color: var(--lay-color-border-2);}\n.layui-table-view .layui-table td[data-edit]:hover:after{border:1px solid var(--lay-color-primary-active)}\n.layui-table-loading-icon .layui-icon{color:var(--lay-color-gray-8);}\n.layui-table-page{background-color: var(--lay-color-bg-2);}\n.layui-table-page .layui-laypage a,\n.layui-table-page .layui-laypage span{border: none;}\n.layui-table-tool{background-color: var(--lay-color-bg-2);}\n.layui-table-tool .layui-inline[lay-event]{color:var(--lay-color-text-3);border:1px solid var(--lay-color-border-2)}\n.layui-table-tool .layui-inline[lay-event]:hover{border:1px solid var(--lay-color-border-3)}\n.layui-table-tool-panel{color: var(--lay-color-text-1); border:1px solid var(--lay-color-border-2);background-color: var(--lay-color-bg-5);box-shadow:var(--lay-shadow-2)}\n.layui-table-tool-panel li:hover{background-color:var(--lay-color-active)}\n.layui-table-col-set{background-color: var(--lay-color-white)}\n.layui-table-sort .layui-table-sort-asc{border-bottom-color:var(--lay-color-gray-8)}\n.layui-table-sort .layui-table-sort-asc:hover{border-bottom-color:var(--lay-color-gray-11)}\n.layui-table-sort .layui-table-sort-desc{border-top-color:var(--lay-color-gray-8)}\n.layui-table-sort .layui-table-sort-desc:hover{border-top-color:var(--lay-color-gray-11)}\n.layui-table-sort[lay-sort=asc] .layui-table-sort-asc{border-bottom-color:var(--lay-color-gray-13)}\n.layui-table-sort[lay-sort=desc] .layui-table-sort-desc{border-top-color:var(--lay-color-gray-13)}\n.layui-table-cell .layui-table-link{color: var(--lay-color-lightblue-5)}\n.layui-table-body .layui-none{color:var(--lay-color-gray-8)}\n.layui-table-fixed-l{box-shadow:1px 0 8px rgba(0,0,0,1)}\n.layui-table-fixed-r{box-shadow:-1px 0 8px rgba(0,0,0,1)}\n.layui-table-edit{box-shadow:var(--lay-shadow-1);background-color: var(--lay-color-bg-2)}\n.layui-table-edit:focus{border-color:var(--lay-color-secondary)!important}\nselect.layui-table-edit{border-color:var(--lay-color-border-2)}\n.layui-table-grid-down{background-color: var(--lay-color-bg-5);color:var(--lay-color-gray-8)}\n.layui-table-grid-down:hover{background-color:var(--lay-color-bg-5)}\n/* 单元格多行展开风格 */\n.layui-table-cell-c{background-color: var(--lay-color-gray-13);color: var(--lay-color-text-1); border-color: var(--lay-color-border-3);}\n.layui-table-cell-c:hover{border-color: var(--lay-color-secondary-hover);}\n/* 单元格 TIPS 展开风格 */\nbody .layui-table-tips .layui-layer-content{box-shadow:var(--lay-shadow-3)}\n.layui-table-tips-main{background-color: var(--lay-color-bg-5);color: var(--lay-color-text-3)}\n.layui-table-tips-c{background-color:var(--lay-color-gray-13);color: var(--lay-color-text-1)}\n.layui-table-tips-c:hover{background-color:var(--lay-color-gray-10)}\n/** 文件上传 **/\n.layui-upload-choose{color:var(--lay-color-gray-8)}\n.layui-upload-drag{border:1px dashed var( --lay-color-border-2);background-color: var(--lay-color-bg-4);color: var(--lay-color-text-2)}\n.layui-upload-drag .layui-icon{color: var(--lay-color-primary)}\n.layui-upload-drag[lay-over]{border-color: var(--lay-color-primary)}\n/* 基础菜单元素 */\n.layui-menu{background-color: var(--lay-color-bg-2)}\n.layui-menu li{color: var(--lay-color-text-1)}\n.layui-menu li:hover{background-color: var(--lay-color-bg-5)}\n.layui-menu li.layui-disabled,.layui-menu li.layui-disabled *{color:var(--lay-color-text-4)!important}\n.layui-menu .layui-menu-item-group>.layui-menu-body-title{color: var(--lay-color-text-3)}\n.layui-menu .layui-menu-item-none{color: var(--lay-color-text-3);}\n.layui-menu .layui-menu-item-divider{border-bottom:1px solid var(--lay-color-border-2)}\n.layui-menu .layui-menu-item-group:hover,\n.layui-menu .layui-menu-item-none:hover,\n.layui-menu .layui-menu-item-divider:hover{background: none;}\n.layui-menu .layui-menu-item-up>.layui-menu-body-title{color: var(--lay-color-text-1)}\n.layui-menu .layui-menu-item-down:hover>.layui-menu-body-title>.layui-icon,.layui-menu .layui-menu-item-up>.layui-menu-body-title:hover>.layui-icon{color: var(--lay-color-text-1)}\n.layui-menu .layui-menu-item-checked,.layui-menu .layui-menu-item-checked2{background-color:var(--lay-color-active)!important;color:var(--lay-color-secondary)}\n.layui-menu .layui-menu-item-checked a,.layui-menu .layui-menu-item-checked2 a{color:var(--lay-color-secondary)}\n.layui-menu .layui-menu-item-checked:after{border-right:3px solid var(--lay-color-secondary)}\n.layui-menu-body-title a{color: var(--lay-color-text-1)}\n.layui-menu-lg .layui-menu-body-title a:hover,.layui-menu-lg li:hover{color:var(--lay-color-secondary)}\n/* 下拉菜单 */\n.layui-dropdown{background-color: var(--lay-color-bg-5)}\n.layui-dropdown.layui-panel,.layui-dropdown .layui-panel{background-color: var(--lay-color-bg-5);box-shadow: var(--lay-shadow-2)}\n.layui-dropdown.layui-panel .layui-menu{background-color: var(--lay-color-bg-5)}\n/** 导航菜单 **/\n.layui-nav{background-color:var(--lay-color-black-6);color: var(--lay-color-white)}\n.layui-nav .layui-nav-item a{color: var(--lay-color-text-1);}\n.layui-nav .layui-this:after,.layui-nav-bar{background-color:var(--lay-color-secondary)}\n.layui-nav .layui-nav-item a:hover,.layui-nav .layui-this a{color: var(--lay-color-text-1)}\n.layui-nav-child{box-shadow:var(--lay-shadow-2);border:1px solid var(--lay-color-border-2);background-color: var(--lay-color-bg-5)}\n.layui-nav .layui-nav-child a{color: var(--lay-color-text-1)}\n.layui-nav .layui-nav-child a:hover{background-color: var(--lay-color-bg-5);color: var(--lay-color-text-1)}\n.layui-nav-child dd.layui-this{background-color: var(--lay-color-bg-5);color: var(--lay-color-text-1)}\n.layui-nav-tree .layui-nav-child dd.layui-this,.layui-nav-tree .layui-nav-child dd.layui-this a,.layui-nav-tree .layui-this,.layui-nav-tree .layui-this>a,.layui-nav-tree .layui-this>a:hover{background-color: var(--lay-color-primary);color: var(--lay-color-white)}\n.layui-nav-itemed>a,.layui-nav-tree .layui-nav-title a,.layui-nav-tree .layui-nav-title a:hover{color: var(--lay-color-white)!important}\n.layui-nav-tree .layui-nav-bar{background-color:var(--lay-color-primary)}\n.layui-nav-tree .layui-nav-child{background: none; background-color:rgba(0, 0, 0, .3); border: none; box-shadow: none;}\n.layui-nav-tree .layui-nav-child a{color: var(--lay-color-white);color: var(--lay-color-text-1)}\n.layui-nav-tree .layui-nav-child a:hover{background: none; color: var(--lay-color-white)}\n.layui-nav.layui-bg-gray,.layui-nav-tree.layui-bg-gray{background-color: var(--lay-color-bg-2) !important;color: var(--lay-color-text-1);}\n.layui-nav-tree.layui-bg-gray .layui-nav-child{background-color: rgba(0, 0, 0, .3) !important;}\n.layui-nav-tree.layui-bg-gray a,.layui-nav.layui-bg-gray .layui-nav-item a{color: var(--lay-color-text-1)}\n.layui-nav.layui-bg-gray .layui-nav-child{background-color: var(--lay-color-bg-5);}\n.layui-nav-tree.layui-bg-gray .layui-nav-itemed>a{color: var(--lay-color-text-1)!important}\n.layui-nav.layui-bg-gray .layui-this a{color:var(--lay-color-secondary)}\n.layui-nav-tree.layui-bg-gray .layui-nav-child dd.layui-this,.layui-nav-tree.layui-bg-gray .layui-nav-child dd.layui-this a,.layui-nav-tree.layui-bg-gray .layui-this,.layui-nav-tree.layui-bg-gray .layui-this>a{color:var(--lay-color-secondary)!important}\n.layui-nav-tree.layui-bg-gray .layui-nav-bar{background-color:var(--lay-color-secondary)}\n/** 面包屑 **/\n.layui-breadcrumb a{color:var(--lay-color-gray-7)!important}\n.layui-breadcrumb a:hover{color:var(--lay-color-secondary)!important}\n.layui-breadcrumb a cite{color:var(--lay-color-gray-8)}\n.layui-breadcrumb span[lay-separator]{color:var(--lay-color-gray-7)}\n/** Tab 选项卡 **/\n.layui-tab .layui-tab-title:after{border-bottom-color: var(--lay-color-border-1);}\n.layui-tab-title .layui-this{color: var(--lay-color-text-2)}\n.layui-tab-title .layui-this:after{border-bottom-color: var(--lay-color-bg-1)}\n.layui-tab-bar{background-color: var(--lay-color-bg-3)}\n.layui-tab-more li.layui-this:after{border-bottom-color:var(--lay-color-border-1)}\n.layui-tab-title li .layui-tab-close{color:var(--lay-color-gray-8)}\n.layui-tab-title li .layui-tab-close:hover{background-color:var(--lay-color-danger);color: var(--lay-color-white)}\n.layui-tab-brief>.layui-tab-title .layui-this{color:var( --lay-color-primary)}\n.layui-tab-brief>.layui-tab-more li.layui-this:after,.layui-tab-brief>.layui-tab-title .layui-this:after{border-bottom:2px solid var(--lay-color-secondary)}\n.layui-tab-card{box-shadow: var(--lay-shadow-1)}\n.layui-tab-card>.layui-tab-title{background-color: var(--lay-color-bg-2)}\n.layui-tab-card>.layui-tab-title .layui-this{background-color: var(--lay-color-bg-1)}\n.layui-tab-card>.layui-tab-title .layui-this:after{border-bottom-color: var(--lay-color-bg-1)}\n.layui-tab-card>.layui-tab-more .layui-this{color:var(--lay-color-secondary)}\n\n/** tabs 标签页 **/\n.layui-tabs-header:after,\n.layui-tabs-scroll:after{border-bottom-color: var(--lay-color-border-1);}\n.layui-tabs-card>.layui-tabs-header .layui-this{background-color: transparent;}\n.layui-tabs-card>.layui-tabs-header .layui-this:after{border-color: var(--lay-color-border-1); border-bottom-color: var(--lay-color-bg-1);}\n.layui-tabs-card.layui-panel>.layui-tabs-header .layui-this:after{border-bottom-color: var(--lay-color-bg-2);}\n.layui-tabs-bar .layui-icon{background-color: var(--lay-color-bg-1); color: var(--lay-color-text-2); border-color: var(--lay-color-border-1); box-shadow: 2px 0 5px 0 rgb(0 0 0 / 32%);}\n.layui-tabs-bar .layui-icon-next{box-shadow: -2px 0 5px 0 rgb(0 0 0 / 32%);}\n\n/*时间线*/\n.layui-timeline-axis{background-color: var(--lay-color-bg-4);color:var(--lay-color-secondary)}\n.layui-timeline-axis:hover{color:var(--lay-color-red-6)}\n.layui-timeline-item:before{background-color: var(--lay-color-bg-3)}\n/*徽章*/\n.layui-badge,.layui-badge-dot,.layui-badge-rim{background-color:var(--lay-color-red-6);color: var(--lay-color-white)}\n.layui-badge-rim{background-color: var(--lay-color-white);color:var(--lay-color-black-6)}\n/* carousel 轮播 */\n.layui-carousel{background-color:var(--lay-color-gray-2)}\n.layui-carousel>[carousel-item]:before{color:var(--lay-color-gray-8);-moz-osx-font-smoothing:grayscale}\n.layui-carousel>[carousel-item]>*{background-color:var(--lay-color-gray-2)}\n.layui-carousel-arrow{background-color:rgba(0,0,0,.2);color: var(--lay-color-white)}\n.layui-carousel-arrow:hover,.layui-carousel-ind ul:hover{background-color:var(--lay-color-black)}\n.layui-carousel[lay-indicator=outside] .layui-carousel-ind ul{background-color:var(--lay-color-black)}\n.layui-carousel-ind ul{background-color:rgba(0,0,0,.2)}\n.layui-carousel-ind ul li{background-color:var(--lay-color-gray-3);background-color: var(--lay-color-text-3)}\n.layui-carousel-ind ul li:hover{background-color: var(--lay-color-white)}\n.layui-carousel-ind ul li.layui-this{background-color: var(--lay-color-white)}\n/** fixbar **/\n.layui-fixbar li{background-color:var(--lay-color-black-5);color: var(--lay-color-text-1)}\n/** 表情面板 **/\nbody .layui-util-face .layui-layer-content{background-color: var(--lay-color-bg-5);color:var(--lay-color-text-2)}\n.layui-util-face ul{border:1px solid var(--lay-color-border-3);background-color: var(--lay-color-bg-5);box-shadow:var(--lay-shadow-2)}\n.layui-util-face ul li{border:1px solid var(--lay-color-border-2)}\n.layui-util-face ul li:hover{border:1px solid var(--lay-color-red-7);background: var(--lay-color-text-1)}\n/** 代码文本修饰 **/\n.layui-code{border:1px solid var(--lay-color-border-2);background-color: var(--lay-color-bg-white);color: var(--lay-color-text-2)}\n/** 穿梭框 **/\n.layui-transfer-box,.layui-transfer-header,.layui-transfer-search{border-color: var(--lay-color-border-2)}\n.layui-transfer-box{background-color: var(--lay-color-bg-2)}\n.layui-transfer-search .layui-icon-search{color:var(--lay-color-gray-8)}\n.layui-transfer-active .layui-btn{background-color:var( --lay-color-secondary);border-color:var( --lay-color-secondary);color: var(--lay-color-white)}\n.layui-transfer-active .layui-btn-disabled{background-color:var(--lay-color-gray-2);border-color:var(--lay-color-gray-3);color:var(--lay-color-gray-8)}\n.layui-transfer-data li:hover{background-color:var(--lay-color-active)}\n/* chrome 105 */\n.layui-transfer-data li:hover:has([lay-filter=\"layTransferCheckbox\"][disabled]){background-color:var(--lay-color-bg-2)}\n.layui-transfer-data .layui-none{color:var(--lay-color-gray-7)}\n/** 评分组件 **/\n.layui-rate li i.layui-icon{color:var(--lay-color-orange-6)}\n/** 颜色选择器 **/\n.layui-colorpicker{border:1px solid var(--lay-color-border-1)}\n.layui-colorpicker:hover{border-color: var(--lay-color-border-2)}\n.layui-colorpicker-trigger-span{border:1px solid var(--lay-color-border-1)}\n.layui-colorpicker-trigger-i{color: var(--lay-color-white)}\n.layui-colorpicker-trigger-i.layui-icon-close{color:var(--lay-color-black-7)}\n.layui-colorpicker-main{background: var(--lay-color-bg-2);border:1px solid var( --lay-color-border-2);box-shadow:var(--lay-shadow-2)}\n.layui-colorpicker-basis-white{background:linear-gradient(90deg, #fff,hsla(0,0%,100%,0))} /* danger: 勿改*/\n.layui-colorpicker-basis-black{background:linear-gradient(0deg,#000,transparent)} /* danger: 勿改*/\n.layui-colorpicker-basis-cursor{border:1px solid var(--lay-color-white)}\n.layui-colorpicker-side{background:linear-gradient(linear-gradient(#F00, #FF0, #0F0, #0FF, #00F, #F0F, #F00))} /* danger: 勿改*/\n.layui-colorpicker-side-slider{box-shadow:var(--lay-shadow-1);background: var(--lay-color-white);border:1px solid var(--lay-color-gray-2)}\n.layui-colorpicker-alpha-slider{box-shadow:var(--lay-shadow-1);background: var(--lay-color-white);border:1px solid var(--lay-color-gray-2)}\n.layui-colorpicker-pre.layui-this{box-shadow:var(--lay-shadow-1)}\n.layui-colorpicker-pre.selected{box-shadow:var(--lay-shadow-1)}\n.layui-colorpicker-main-input input.layui-input{color: var(--lay-color-text-2)}\n/** 滑块 **/\n.layui-slider{background: var( --lay-color-bg-5)}\n.layui-slider-step{background: var(--lay-color-fill-4)}\n.layui-slider-wrap-btn{background: var(--lay-color-bg-4)}\n.layui-slider-tips{color: var(--lay-color-text-1);background:var(--lay-color-black);box-shadow: var(--lay-shadow-3)}\n.layui-slider-tips:after{border-color:var(--lay-color-black) transparent transparent transparent}\n.layui-slider-input{border:1px solid var(--lay-color-border-1)}\n.layui-slider-input-btn{border-left:1px solid var(--lay-color-border-1)}\n.layui-slider-input-btn i{color:var(--lay-color-gray-9)}\n.layui-slider-input-btn i:first-child{border-bottom:1px solid var(--lay-color-border-1)}\n.layui-slider-input-btn i:hover{color:var(--lay-color-primary)}\n/** 树组件 **/\n.layui-tree-line .layui-tree-set .layui-tree-set:after{border-top:1px dotted var(--lay-color-gray-7)}\n.layui-tree-entry:hover{background-color: var(--lay-color-bg-4)}\n.layui-tree-line .layui-tree-entry:hover{background-color:var(--lay-color-black)}\n.layui-tree-line .layui-tree-entry:hover .layui-tree-txt{color:var(--lay-color-text-3)}\n.layui-tree-entry:hover:has(span.layui-tree-txt.layui-disabled){background-color: transparent !important}\n.layui-tree-line .layui-tree-set:before{border-left:1px dotted var(--lay-color-gray-7)}\n.layui-tree-iconClick{color:var(--lay-color-gray-7)}\n.layui-tree-icon{border:1px solid var(--lay-color-gray-8)}\n.layui-tree-icon .layui-icon{color:var(--lay-color-text-1)}\n.layui-tree-iconArrow:after{border-color:transparent transparent transparent var(--lay-color-gray-7)}\n.layui-tree-txt{color:var(--lay-color-text-2)}\n.layui-tree-search{color:var(--lay-color-black-7)}\n.layui-tree-btnGroup .layui-icon:hover{color:var(--lay-color-text-2)}\n.layui-tree-editInput{background-color:var(--lay-color-fill-2)}\n.layui-tree-emptyText{color:var(--lay-color-text-2)}\n/*code 不处理*/\n.layui-code-view{border:1px solid var(--lay-color-border-1);}\n.layui-code-view:not(.layui-code-hl){background-color: var(--lay-color-bg-2);color: var(--lay-color-text-2);}\n.layui-code-header{border-bottom: 1px solid var(--lay-color-border-1); background-color: var(--lay-color-bg-2)}\n.layui-code-header > .layui-code-header-about{color: var(--lay-color-text-2);}\n.layui-code-view:not(.layui-code-hl) .layui-code-ln-side{border-color: var(--lay-color-border-1); background-color: var(--lay-color-bg-2);}\n.layui-code-nowrap > .layui-code-ln-side{background: none !important;}\n.layui-code-fixbar > span{color: var(--lay-color-text-3);}\n.layui-code-fixbar > span:hover{color: var(--lay-color-secondary-hover);}\n\n.layui-code-theme-dark,\n.layui-code-theme-dark > .layui-code-header{border-color: rgb(126 122 122 / 15%); background-color: #1f1f1f;}\n.layui-code-theme-dark{border-width: 1px; color: #ccc;}\n.layui-code-theme-dark > .layui-code-ln-side{border-right-color: #2a2a2a; background: none; color: #6e7681;}\n\n.layui-code-view.layui-code-hl > .layui-code-ln-side{background-color: transparent;}\n.layui-code-theme-dark.layui-code-hl,\n.layui-code-theme-dark.layui-code-hl > .layui-code-ln-side{border-color: rgb(126 122 122 / 15%);}\n\n.layui-code-full{background-color: var(--lay-color-bg-1)}\n/*日期选择器*/\n.layui-laydate-header i{color:var(--lay-color-gray-8)}\n.laydate-day-holidays:before{color:var(--lay-color-red-6)}\n.layui-laydate .layui-this .laydate-day-holidays:before{color: var(--lay-color-white)}\n.layui-laydate-footer span{border:1px solid var(--lay-color-border-2);background-color: var(--lay-color-bg-5)}\n.layui-laydate-footer span:hover{color:var(--lay-color-secondary)}\n.layui-laydate-footer span.layui-laydate-preview{border-color:transparent!important;}\n.layui-laydate-footer span.layui-laydate-preview:hover{color:var(--lay-color-text-1) !important}\n.layui-laydate-shortcut+.layui-laydate-main{border-left:1px solid var(--lay-color-border-2)}\n.layui-laydate .layui-laydate-list{background-color: var(--lay-color-bg-5)}\n.layui-laydate-hint{color:var(--lay-color-danger)}\n.layui-laydate-range .laydate-main-list-1 .layui-laydate-content,.layui-laydate-range .laydate-main-list-1 .layui-laydate-header{border-left:1px solid var(--lay-color-border-2)}\n.layui-laydate,.layui-laydate-hint{border-color: var(--lay-color-border-2);box-shadow:var(--lay-shadow-3);background-color: var(--lay-color-bg-5);color: var(--lay-color-text-1)}\n.layui-laydate{box-shadow: var(--lay-shadow-2)}\n.layui-laydate-hint{border-color:var(--lay-color-border-1)}\n.layui-laydate-header{border-bottom:1px solid var( --lay-color-border-2)}\n.layui-laydate-header i:hover,.layui-laydate-header span:hover{color:var(--lay-color-secondary)}\n.layui-laydate-content th{color: var(--lay-color-text-1)}\n.layui-laydate-content td{color: var(--lay-color-text-1)}\n.layui-laydate-content td.laydate-day-now{color:var(--lay-color-secondary)}\n.layui-laydate-content td.laydate-day-now:after{border:1px solid var(--lay-color-secondary)}\n.layui-laydate-linkage .layui-laydate-content td.laydate-selected>div{background-color:var(--lay-color-green-8);}\n.layui-laydate-linkage .laydate-selected:hover>div{background-color:var(--lay-color-green-8)!important}\n.layui-laydate-content td>div:hover,.layui-laydate-list li:hover,.layui-laydate-shortcut>li:hover{background-color: var(--lay-color-fill-2);color: var(--lay-color-text-2)}\n.layui-laydate-content td.laydate-disabled>div:hover{background-color: var(--lay-color-bg-5);color: var(--lay-color-text-4)}\n.laydate-time-list li ol{border:1px solid var(--lay-color-border-2)}\n.laydate-time-list>li:hover{background: 0 0;}\n.layui-laydate-content .laydate-day-next,.layui-laydate-content .laydate-day-prev{color: var(--lay-color-text-3)}\n.layui-laydate-linkage .laydate-selected.laydate-day-next>div,.layui-laydate-linkage .laydate-selected.laydate-day-prev>div{background: none!important}\n.layui-laydate-footer{border-top:1px solid var(--lay-color-border-2)}\n.layui-laydate-hint{color:var(--lay-color-danger)}\n.laydate-day-mark::after{background-color:var(--lay-color-secondary)}\n.layui-laydate-footer span[lay-type=date]{color:var(--lay-color-secondary)}\n.layui-laydate .layui-this,.layui-laydate .layui-this>div{background-color:var(--lay-color-secondary)!important;color: var(--lay-color-white)!important}\n.layui-laydate .laydate-disabled,.layui-laydate .laydate-disabled:hover{color: var(--lay-color-text-4)!important}\n.layui-laydate .layui-this.laydate-disabled,.layui-laydate .layui-this.laydate-disabled>div{background-color: var(--lay-color-fill-1) !important;color: var(--lay-color-text-4) !important;}\n.laydate-theme-molv .layui-laydate-header{background-color:var(--lay-color-primary)}\n.laydate-theme-molv .layui-laydate-header i,.laydate-theme-molv .layui-laydate-header span{color:var(--lay-color-gray-2)}\n.laydate-theme-molv .layui-laydate-header i:hover,.laydate-theme-molv .layui-laydate-header span:hover{color: var(--lay-color-white)}\n.laydate-theme-molv .layui-laydate-content{border:1px solid var(--lay-color-border-2)}\n.laydate-theme-molv .layui-this, .laydate-theme-molv .layui-this>div{background-color: var(--lay-color-primary) !important;}\n.laydate-theme-molv .layui-laydate-footer{border:1px solid var(--lay-color-border-2)}\n.laydate-theme-grid .laydate-month-list>li,.laydate-theme-grid .laydate-year-list>li,.laydate-theme-grid .layui-laydate-content td,.laydate-theme-grid .layui-laydate-content thead{border:1px solid var(--lay-color-border-2)}\n.layui-laydate-linkage.laydate-theme-grid .laydate-selected,.layui-laydate-linkage.laydate-theme-grid .laydate-selected:hover{background-color:var(--lay-color-gray-3)!important;color:var(--lay-color-primary)!important}\n.layui-laydate-linkage.laydate-theme-grid .laydate-selected.laydate-day-next,.layui-laydate-linkage.laydate-theme-grid .laydate-selected.laydate-day-prev{color:var(--lay-color-gray-6)!important}\n.layui-laydate.laydate-theme-circle .layui-laydate-content table td.layui-this{background-color:transparent!important}\n/*layer*/\n.layui-layer{background-color: var(--lay-color-bg-3);box-shadow:var(--lay-shadow-3)}\n.layui-layer-border{border:1px solid var(--lay-color-border-2);box-shadow:var(--lay-shadow-3)}\n.layui-layer-move{background-color: var(--lay-color-bg-5)}\n.layui-layer-title{border-bottom:1px solid var(--lay-color-border-2);color: var(--lay-color-text-1)}\n.layui-layer-setwin span{color: var(--lay-color-text-1)}\n.layui-layer-setwin .layui-layer-min:before{border-bottom-color:var(--lay-color-text-1)}\n.layui-layer-setwin .layui-layer-min:hover:before{border-bottom-color:var(--lay-color-info-hover)}\n.layui-layer-setwin .layui-layer-max:after,.layui-layer-setwin .layui-layer-max:before{border:1px solid var(--lay-color-text-3)}\n.layui-layer-setwin .layui-layer-max:hover:after,.layui-layer-setwin .layui-layer-max:hover:before{border-color:var(--lay-color-info-hover)}\n.layui-layer-setwin .layui-layer-maxmin:after,.layui-layer-setwin .layui-layer-maxmin:before{background-color: var(--lay-color-bg-5)}\n.layui-layer-setwin .layui-layer-close2{color:var(--lay-color-text-1);background-color:var(--lay-color-gray-10)}\n.layui-layer-setwin .layui-layer-close2:hover{background-color:var(--lay-color-normal)}\n.layui-layer-btn a{border:1px solid var(--lay-color-border-2);background-color: var( --lay-color-bg-3);color: var(--lay-color-text-2)}\n.layui-layer-btn .layui-layer-btn0{border-color: transparent;background-color: var(--lay-color-normal);color: var(--lay-color-text-1)}\n.layui-layer-dialog .layui-layer-content .layui-layer-face{color:var(--lay-color-gray-9)}\n.layui-layer-dialog .layui-layer-content .layui-icon-tips{color:var(--lay-color-warning)}\n.layui-layer-dialog .layui-layer-content .layui-icon-success{color: var(--lay-color-success)}\n.layui-layer-dialog .layui-layer-content .layui-icon-error{top: 19px; color: var(--lay-color-danger)}\n.layui-layer-dialog .layui-layer-content .layui-icon-question{color: var(--lay-color-warning);}\n.layui-layer-dialog .layui-layer-content .layui-icon-lock{color: var(--lay-color-gray-10)}\n.layui-layer-dialog .layui-layer-content .layui-icon-face-cry{color:var(--lay-color-danger)}\n.layui-layer-dialog .layui-layer-content .layui-icon-face-smile{color:var(--lay-color-success)}\n.layui-layer-rim{border:6px solid var(--lay-color-gray-8);border:6px solid var(--lay-color-border-2)}\n.layui-layer-msg{border:1px solid var( --lay-color-border-1)}\n.layui-layer-hui{background-color: var(--lay-color-bg-3);color: var(--lay-color-text-1)}\n.layui-layer-hui .layui-layer-close{color: var(--lay-color-white)}\n.layui-layer-loading-icon{color:var(--lay-color-gray-9)}\n.layui-layer-loading-2:after,.layui-layer-loading-2:before{border:3px solid var(--lay-color-gray-6)}\n.layui-layer-loading-2:after{border-color:transparent;border-left-color: var(--lay-color-normal)}\n.layui-layer-tips .layui-layer-content{box-shadow: var(--lay-shadow-3);background-color: var(--lay-color-bg-5);color: var(--lay-color-text-1)}\n.layui-layer-tips i.layui-layer-TipsG{border-color:transparent}\n.layui-layer-tips i.layui-layer-TipsB,.layui-layer-tips i.layui-layer-TipsT{border-right-color:var(--lay-color-black)}\n.layui-layer-tips i.layui-layer-TipsL,.layui-layer-tips i.layui-layer-TipsR{border-bottom-color:var(--lay-color-black)}\n.layui-layer-lan .layui-layer-title{background:var(--lay-color-blue-5);color: var(--lay-color-text-1)}\n.layui-layer-lan .layui-layer-btn{border-top:1px solid var(--lay-color-border-3)}\n.layui-layer-lan .layui-layer-btn a{background: var(--lay-color-white);border-color:var(--lay-color-border-3);color: var(--lay-color-black-7)}\n.layui-layer-lan .layui-layer-btn .layui-layer-btn1{background: var(--lay-color-gray-7)}\n.layui-layer-molv .layui-layer-title{background:var(--lay-color-layuigreen-6);color: var(--lay-color-text-1)}\n.layui-layer-molv .layui-layer-btn a{background:var(--lay-color-layuigreen-6);border-color:var(--lay-color-layuigreen-6)}\n.layui-layer-molv .layui-layer-btn .layui-layer-btn1{background:var(--lay-color-gray-7)}\n.layui-layer-win10{border-color: var(--lay-color-border-2)}\n.layui-layer-win10 .layui-layer-btn{background-color: var(--lay-color-bg-2);border-color: var(--lay-color-border-2)}\n.layui-layer-win10.layui-layer-dialog .layui-layer-content{color: var(--lay-color-blue-7)}\n.layui-layer-win10 .layui-layer-btn .layui-layer-btn0{border-color: var(--lay-color-blue-9);background-color: var(--lay-color-bg-5);color: var(--lay-color-text-1)}\n.layui-layer-win10 .layui-layer-btn .layui-layer-btn1{border-color: var(--lay-color-border-2);background-color: var(--lay-color-bg-5);color: var(--lay-color-text-1)}\n.layui-layer-win10 .layui-layer-btn a:hover{background-color: var(--lay-color-blue-10);border-color: var(--lay-color-blue-8)}\n.layui-layer-prompt .layui-layer-input{border:1px solid var(--lay-color-border-2);color: var(--lay-color-text-2)}\n.layui-layer-tab{box-shadow:var(--lay-shadow-3)}\n.layui-layer-tab .layui-layer-title span.layui-this{border-left:1px solid var(--lay-color-border-2);border-right:1px solid var(--lay-color-border-2);background-color: var(--lay-color-bg-3)}\n.layui-layer-photos{background: none; box-shadow: none;}\n.layui-layer-photos-prev,.layui-layer-photos-next{color:var(--lay-color-gray-9)}\n.layui-layer-photos-prev:hover,.layui-layer-photos-next:hover{color:var(--lay-color-text-1)}\n.layui-layer-photos-toolbar{background-color:#333;background-color: var(--lay-color-bg-5);color: var(--lay-color-text-1)}\n.layui-layer-photos-toolbar *{color: var(--lay-color-text-1)}\n.layui-layer-photos-toolbar a:hover{color: var(--lay-color-text-2)}\n.layui-layer-photos-header > span:hover{background-color: var(--lay-color-fill-2)}\n.layui-layer-tips i.layui-layer-TipsB,.layui-layer-tips i.layui-layer-TipsT{border-right-color: var(--lay-color-bg-5)}\n.layui-layer-tips i.layui-layer-TipsL,.layui-layer-tips i.layui-layer-TipsR{border-bottom-color: var(--lay-color-bg-5)}\n.layui-layer-prompt .layui-layer-input{border:1px solid var(--lay-color-border-2);color:var(--lay-color-text-1);background-color:var(--lay-color-black)}\n.layui-layer-prompt .layui-layer-input:focus{outline:0}\n\n/*fix style*/\n.layui-layer-loading{background:0 0;box-shadow:0 0}\n.layui-btn-primary{border-color:transparent}\n.layui-btn-group .layui-btn:first-child{border-left:none}\n.layui-btn-group .layui-btn-primary:hover{border-top-color:transparent; border-bottom-color: transparent;}\n.layui-menu li:hover{background-color:var(--lay-color-fill-2)}\n.layui-nav-child dd.layui-this{background-color:var(--lay-color-fill-2)}\n.layui-nav .layui-nav-child a:hover{background-color:var(--lay-color-fill-2)}\n.layui-nav .layui-nav-item a:hover,.layui-nav .layui-this a{background-color: var(--lay-color-fill-2)}\n.layui-nav-child dd.layui-this{background-color: var(--lay-color-fill-2)}\n.layui-tab-card>.layui-tab-title .layui-this:after{border-bottom-color:var(--lay-color-bg-1)}\n.layui-form-select dl dd:hover{background-color:var(--lay-color-fill-2)}\n.layui-form-select dl dd.layui-this{background-color:var(--lay-color-fill-2)}\n.layui-laypage button{color:var(--lay-color-text-1)}\n.layui-table[lay-even] tbody tr:nth-child(even){background-color:var(--lay-color-fill-4)}\n.layui-menu .layui-menu-item-checked,.layui-menu .layui-menu-item-checked2{background-color:var(--lay-color-fill-2)!important}\n.layui-input-split{background-color: var(--lay-color-bg-2);}\n.layui-input-wrap .layui-input-prefix.layui-input-split{border-width: 1px;}\n.layui-input-wrap .layui-input-split:has(+.layui-input:hover) {border-color: var(--lay-color-border-2);}\n.layui-input-wrap .layui-input-split:has(+.layui-input:focus) {border-color: var(--lay-color-secondary-hover);}\n.layui-layer-tab .layui-layer-title span:first-child{border-left: none !important;}\n.layui-slider-input.layui-input,\n.layui-slider-input .layui-input {background-color: var(--lay-color-bg-2);}\n"]} \ No newline at end of file diff --git a/web/static/src/override.css b/web/static/src/override.css deleted file mode 100644 index 45a46db..0000000 --- a/web/static/src/override.css +++ /dev/null @@ -1,534 +0,0 @@ -blockquote,body,button,dd,div,dl,dt,form,h1,h2,h3,h4,h5,h6,input,li,ol,p,pre,td,textarea,th,ul{-webkit-tap-highlight-color: rgba(0, 0, 0, 0)} /*danger: 勿改*/ -body{color:var(--lay-color-text-2);background-color: var(--lay-color-bg-1); color-scheme: dark;} -hr{border-bottom:1px solid var(--lay-color-border-2)!important} -a{color:var(--lay-color-text-1);} -a:hover{color:var(--lay-color-text-3)} -/* 三角形 */ -.layui-edge{border-color:transparent} -.layui-edge-top{border-bottom-color:var(--lay-color-border-4)} -.layui-edge-right{border-left-color:var(--lay-color-border-4)} -.layui-edge-bottom{border-top-color:var(--lay-color-border-4)} -.layui-edge-left{border-right-color:var(--lay-color-border-4)} -/* 禁用文字 */ -.layui-disabled,.layui-disabled:hover{color:var(--lay-color-text-4)!important} -/* 图标 */ -.layui-icon{-moz-osx-font-smoothing:grayscale} -/* admin 布局 */ -.layui-layout-admin .layui-header{background-color:var(--lay-color-bg-2)} -.layui-layout-admin .layui-footer{box-shadow:-1px 0 4px rgb(0 0 0 / 12%);background-color:var(--lay-color-bg-2)} -.layui-layout-admin .layui-logo{color:var(--lay-color-primary);box-shadow:0 1px 2px 0 rgb(0 0 0 / 15%)} -/* 引用 */ -.layui-elem-quote{border-left:5px solid var(--lay-color-secondary);background-color:var(--lay-color-fill-1)} -.layui-quote-nm{border-color: var(--lay-color-fill-1)} -/* 进度条 */ -.layui-progress{background-color: var(--lay-color-bg-3)} -.layui-progress-bar{background-color:var( --lay-color-secondary)} -.layui-progress-text{color:var(--lay-color-text-2)} -.layui-progress-big .layui-progress-text{color: var(--lay-color-text-1)} -/* 折叠面板 */ -.layui-colla-title{color: var(--lay-color-text-1);background-color: var(--lay-color-bg-2)} -.layui-colla-content{color:var(--lay-color-text-2)} -/* 卡片面板 */ -.layui-card{background-color: var(--lay-color-bg-2);box-shadow:var(--lay-shadow-1)} -.layui-card-header{border-bottom:1px solid var(--lay-color-border-2);color:var(--lay-color-text-1)} -/* 常规面板 */ -.layui-panel{box-shadow:var(--lay-shadow-1);background-color: var( --lay-color-bg-2);color: var(--lay-color-text-1)} -.layui-menu-body-panel{box-shadow: var(--lay-shadow-2)} -/* 窗口面板 */ -.layui-panel-window{border-top:5px solid var(--lay-color-border-2);background-color: var(--lay-color-bg-2)} -/* 背景颜色 */ -.layui-bg-red{background-color:var(--lay-color-red-6)!important;color: var(--lay-color-white)!important} -.layui-bg-orange{background-color:var(--lay-color-orange-6)!important;color: var(--lay-color-white)!important} -.layui-bg-green{background-color:var(--lay-color-layuigreen-6)!important;color: var(--lay-color-white)!important} -.layui-bg-cyan{background-color:var(--lay-color-cyan-6)!important;color: var(--lay-color-white)!important} -.layui-bg-blue{background-color: var(--lay-color-blue-6)!important;color: var(--lay-color-white)!important} -.layui-bg-black{background-color:var(--lay-color-black-6)!important;color: var(--lay-color-white)!important} -.layui-bg-purple{background-color: var(--lay-color-purple-6)!important; color: var(--lay-color-white)!important;} -.layui-bg-gray{background-color:var(--lay-color-gray-1)!important;color: var(--lay-color-black-6)!important} -/* 徽章 */ -.layui-badge-rim,.layui-border,.layui-colla-content,.layui-colla-item,.layui-collapse,.layui-elem-field,.layui-form-pane .layui-form-item[pane],.layui-form-pane .layui-form-label,.layui-input,.layui-input-split,.layui-panel,.layui-select,.layui-tab-bar,.layui-tab-card,.layui-tab-title,.layui-tab-title .layui-this:after,.layui-textarea{border-color: var(--lay-color-border-1)} -/* 边框颜色 */ -.layui-border{color:var(--lay-color-text-1)!important} -.layui-border-red{border-color:var(--lay-color-red-6)!important;color:var(--lay-color-red-6)!important} -.layui-border-orange{border-color:var(--lay-color-orange-6)!important;color:var(--lay-color-orange-6)!important} -.layui-border-green{border-color:var(--lay-color-layuigreen-6)!important;color:var(--lay-color-layuigreen-6)!important} -.layui-border-cyan{border-color:var(--lay-color-cyan-6)!important;color:var(--lay-color-cyan-6)!important} -.layui-border-blue{border-color: var(--lay-color-blue-6)!important;color: var(--lay-color-blue-6)!important} -.layui-border-purple{border-color: var(--lay-color-purple-6)!important; color: var(--lay-color-purple-6)!important;} -.layui-border-black{border-color:var(--lay-color-black-6)!important;color:var(--lay-color-text-1)!important} -/* 文本区域 */ -.layui-text{color:var(--lay-color-text-2)} -.layui-text-em,.layui-word-aux{color: var(--lay-color-text-3)!important} -.layui-text a:not(.layui-btn){color:var(--lay-color-lightblue-6)} -.layui-text blockquote:not(.layui-elem-quote){border-left:5px solid var(--lay-color-border-4)} -/* 字体颜色 */ -.layui-font-red{color:var(--lay-color-red-6)!important} -.layui-font-orange{color:var(--lay-color-orange-6)!important} -.layui-font-green{color:var(--lay-color-layuigreen-6)!important} -.layui-font-cyan{color:var(--lay-color-cyan-6)!important} -.layui-font-blue{color:var(--lay-color-lightblue-6)!important} -.layui-font-black{color:var(--lay-color-black)!important} -.layui-font-purple{color:var(--lay-color-purple-6)!important;} -.layui-font-gray{color:var(--lay-color-gray-7)!important} -/* 按钮 */ -.layui-btn{border:1px solid transparent;background-color:var(--lay-color-primary);color: var(--lay-color-text-1)} -.layui-btn:hover{color: var(--lay-color-text-2)} -.layui-btn-primary{border-color:var(--lay-color-border-2);color:var(--lay-color-text-1);background-color: var(--lay-color-bg-4)} -.layui-btn-primary:hover{border-color: transparent;color:var(--lay-color-text-2)} -.layui-btn-normal{background-color: var(--lay-color-normal)} -.layui-btn-warm{background-color:var(--lay-color-warning)} -.layui-btn-danger{background-color:var(--lay-color-danger)} -.layui-btn-checked{background-color:var(--lay-color-success)} -.layui-btn-disabled,.layui-btn-disabled:active,.layui-btn-disabled:hover{border-color: var(--lay-color-border-2)!important;background-color: var(--lay-color-bg-2)!important;color: var(--lay-color-text-4)!important} -.layui-btn-group .layui-btn{border-left:1px solid var(--lay-color-border-2)} -.layui-btn-group .layui-btn-primary:hover{border-color:var(--lay-color-border-2);color:var(--lay-color-primary)} -.layui-btn-group .layui-btn-primary:first-child{border-left:1px solid var(--lay-color-gray-5)} -/*表单*/ -.layui-input,.layui-select,.layui-textarea{background-color: var(--lay-color-fill-2);color: var(--lay-color-text-2)} -.layui-input:hover,.layui-textarea:hover{border-color: var(--lay-color-border-2)!important} -.layui-input:focus,.layui-textarea:focus{border-color: var(--lay-color-secondary-hover)!important;background-color: var(--lay-color-bg-2);box-shadow: 0 0 0 3px rgba(22, 183, 119, 0.08);} -.layui-input[disabled],.layui-select[disabled],.layui-textarea[disabled],.layui-input.layui-disabled,.layui-textarea.layui-disabled{background-color: var(--lay-color-fill-1);color: var(--lay-color-text-4);border-color: var(--lay-color-border-1)!important;box-shadow: 0 0 0 0;} -.layui-form-danger+.layui-form-select .layui-input,.layui-form-danger:focus{border-color:var(--lay-color-danger)!important;box-shadow: 0 0 0 3px rgba(255, 87, 34, 0.08);} -/* 输入框点缀 */ -.layui-input-prefix .layui-icon,.layui-input-split .layui-icon,.layui-input-suffix .layui-icon{color: var(--lay-color-gray-8)} -.layui-input-wrap .layui-input:hover+.layui-input-split{border-color: var(--lay-color-border-2)} -.layui-input-wrap .layui-input[disabled]:hover+.layui-input-split{border-color: var(--lay-color-border-1)} -.layui-input-wrap .layui-input:focus+.layui-input-split{border-color: var(--lay-color-secondary-hover)} -.layui-input-wrap .layui-input.layui-form-danger:focus + .layui-input-split{border-color: var(--lay-color-danger);} -.layui-input-affix .layui-icon{color: var(--lay-color-text-2)} -.layui-input-affix .layui-icon-clear{color:var(--lay-color-text-2)} -.layui-input-affix .layui-icon:hover{color:var(--lay-color-text-3)} -/* 数字输入框动态点缀 */ -.layui-input-wrap .layui-input-number .layui-icon-up{border-bottom-color:var(--lay-color-border-1)} -.layui-input-wrap .layui-input[type="number"].layui-input-number-out-of-range{color:var(--lay-color-danger)} -/* 下拉选择 */ -.layui-form-select{color:var(--lay-color-text-2)} -.layui-form-select .layui-edge{border-top-color:var(--lay-color-gray-8)} -.layui-form-select dl{border:1px solid var( --lay-color-border-2);background-color: var(--lay-color-bg-5);box-shadow:var(--lay-shadow-2)} -.layui-form-select dl dt{color:var(--lay-color-gray-8)} -.layui-form-select dl dd:hover{background-color:var(--lay-color-active)} -.layui-form-select dl dd.layui-select-tips{color:var(--lay-color-text-2)} -.layui-form-select dl dd.layui-this{background-color: var(--lay-color-active);color: var(--lay-color-text-1)} -.layui-form-select dl dd.layui-disabled,.layui-form-select dl dd:hover.layui-disabled{background-color: var(--lay-color-bg-5)} -.layui-select-none{color:var(--lay-color-black-8)} -.layui-select-disabled .layui-disabled{border-color:var(--lay-color-border-1)!important} -.layui-select-disabled .layui-edge{border-top-color:var(--lay-color-gray-6)} -/* 复选框 */ -.layui-form-checkbox{background-color:var(--lay-color-fill-2)} -.layui-form-checkbox>div{background-color:var(--lay-color-fill-3);color:var(--lay-color-text-2)} -.layui-form-checkbox:hover>div{background-color: var(--lay-color-active)} -.layui-form-checkbox>i{background-color: var(--lay-color-fill-1);border-top-color:var(--lay-color-border-1);border-right-color:var(--lay-color-border-1);border-bottom-color:var(--lay-color-border-1);border-left-color:initial;color:var(--lay-color-text-1)} -.layui-form-checkbox:hover>i{border-color:var(--lay-color-border-2);color:var(--lay-color-text-4)} -.layui-form-checked,.layui-form-checked:hover{border-color:var(--lay-color-secondary-active)} -.layui-form-checked>div,.layui-form-checked:hover>div{background-color:var(--lay-color-secondary)} -.layui-form-checked>i,.layui-form-checked:hover>i{color:var(--lay-color-secondary-hover)} -.layui-form-checkbox.layui-checkbox-disabled>div{background-color: var(--lay-color-fill-3) !important;} -/* 复选框-默认风格 */ -.layui-form-checkbox[lay-skin=primary]{background-image:none;background-color:initial;border-color:initial!important} -.layui-form-checkbox[lay-skin=primary]>div{background-image:none;background-color:initial;color:var(--lay-color-text-2)} -.layui-form-checkbox[lay-skin=primary]>i{border-color:var(--lay-color-border-1);background-color:var(--lay-color-fill-2)} -.layui-form-checkbox[lay-skin=primary]:hover>i{border-color:var(--lay-color-secondary-hover);color:var(--lay-color-text-1)} -.layui-form-checked[lay-skin=primary]>i{background-color:var(--lay-color-secondary);color:var(--lay-color-text-1);border-color:var(--lay-color-secondary-active)!important} -.layui-checkbox-disabled[lay-skin=primary] >div{background:none!important;color:var(--lay-color-text-4)!important} -.layui-form-checked.layui-checkbox-disabled[lay-skin=primary]>i{background-color:var(--lay-color-fill-1)!important;border-color:var(--lay-color-border-2)!important} -.layui-checkbox-disabled[lay-skin=primary]:hover>i{border-color:var(--lay-color-border-1)} -.layui-form-checkbox[lay-skin="primary"]>.layui-icon-indeterminate:before{background-color: var(--lay-color-secondary-hover);opacity: 1;} -.layui-form-checkbox[lay-skin="primary"]:hover>.layui-icon-indeterminate:before{opacity: 1;} -.layui-form-checkbox[lay-skin="primary"]>.layui-icon-indeterminate{border-color: var(--lay-color-secondary-hover);} -/* 复选框-开关风格 */ -.layui-form-switch{border-color:var(--lay-color-border-2);background-color:var(--lay-color-fill-2)} -.layui-form-switch>i{background-color:var(--lay-color-gray-4)} -.layui-form-switch.layui-checkbox-disabled>i{background-color:var(--lay-color-gray-7);} -.layui-form-switch>div{color:var(--lay-color-gray-8)!important} -.layui-form-onswitch{border-color:var(--lay-color-secondary-active);background-color:var(--lay-color-secondary)} -.layui-form-onswitch>i{background-color:var(--lay-color-gray-4)} -.layui-form-onswitch>div{color:var(--lay-color-text-1)!important} -.layui-checkbox-disabled{border-color:var(--lay-color-border-2)!important} -.layui-checkbox-disabled>div{background-color:var(--lay-color-fill-3)!important;color: var(--lay-color-text-4)!important;} -.layui-checkbox-disabled>i{border-color:var(--lay-color-border-2)!important} -.layui-checkbox-disabled:hover>i{color:var(--lay-color-text-1)!important} -.layui-form-switch.layui-checkbox-disabled>div{background-color:initial!important;color: var(--lay-color-text-3)!important;} -/*复选框背景优化*/ -.layui-form-checkbox>i:before{opacity:0;filter:alpha(opacity=0)} -.layui-form-checkbox:hover>i:before{opacity:1;filter:alpha(opacity=100)} -.layui-form-checked.layui-checkbox-disabled:hover>i:before,.layui-form-checked:hover>i:before,.layui-form-checked>i:before{opacity:1;filter:alpha(opacity=100)} -.layui-form-checkbox[lay-skin=primary]:hover>i:before{opacity:0;filter:alpha(opacity=0)} -.layui-form-checked[lay-skin=primary]:hover>i:before{opacity:1;filter:alpha(opacity=100)} -.layui-checkbox-disabled:hover>i:before{opacity:0;filter:alpha(opacity=0)} -/*单选框*/ -.layui-form-radio>i{color:var(--lay-color-gray-8)} -.layui-form-radio:hover>*,.layui-form-radioed,.layui-form-radioed>i{color:var(--lay-color-secondary)} -.layui-radio-disabled>i{color:var(--lay-color-text-4)!important} -.layui-radio-disabled>*{color:var(--lay-color-text-4)!important} -/* 表单方框风格 */ -.layui-form-pane .layui-form-label{background-color:var(--lay-color-bg-2)} -/** 分页 **/ -.layui-laypage a,.layui-laypage button,.layui-laypage input,.layui-laypage select,.layui-laypage span{border:1px solid var(--lay-color-border-2)} -.layui-laypage a,.layui-laypage span{background-color: var(--lay-color-bg-2);color: var(--lay-color-text-2)} -.layui-laypage a[data-page]{color:var(--lay-color-text-2)} -.layui-laypage a:hover{color: var(--lay-color-primary)} -.layui-laypage .layui-laypage-spr{color:var(--lay-color-text-3)} -.layui-laypage .layui-laypage-curr em{color: var(--lay-color-white)} -.layui-laypage .layui-laypage-curr .layui-laypage-em{background-color: var(--lay-color-primary)} -.layui-laypage .layui-laypage-skip{color:var(--lay-color-text-3)} -.layui-laypage button,.layui-laypage input{background-color: var(--lay-color-bg-2)} -.layui-laypage input:focus,.layui-laypage select:focus{border-color: var(--lay-color-primary)!important} -/** 流加载 **/ -.layui-flow-more{color:var(--lay-color-text-1)} -.layui-flow-more a cite{background-color: var(--lay-color-bg-4);color: var(--lay-color-text-1)} -.layui-flow-more a i{color:var(--lay-color-text-2)} -/** 表格 **/ -.layui-table{background-color: var(--lay-color-bg-2);color: var(--lay-color-text-2)} -.layui-table-mend{background-color: var(--lay-color-bg-2)} -.layui-table-click,.layui-table-hover,.layui-table[lay-even] tbody tr:nth-child(even){background-color:var(--lay-color-fill-3)} -.layui-table-checked{background-color: var(--lay-color-fill-2);color: var(--lay-color-text-1)} -.layui-table-checked.layui-table-hover,.layui-table-checked.layui-table-click{background-color: var(--lay-color-fill-3);} -.layui-table td,.layui-table th,.layui-table-col-set,.layui-table-fixed-r,.layui-table-grid-down,.layui-table-header,.layui-table-mend,.layui-table-page,.layui-table-tips-main,.layui-table-tool,.layui-table-total,.layui-table-view,.layui-table[lay-skin=line],.layui-table[lay-skin=row]{border-color: var(--lay-color-border-2)} -.layui-table-view:after {background-color: var(--lay-color-border-2);} -.layui-table-view .layui-table td[data-edit]:hover:after{border:1px solid var(--lay-color-primary-active)} -.layui-table-loading-icon .layui-icon{color:var(--lay-color-gray-8);} -.layui-table-page{background-color: var(--lay-color-bg-2);} -.layui-table-page .layui-laypage a, -.layui-table-page .layui-laypage span{border: none;} -.layui-table-tool{background-color: var(--lay-color-bg-2);} -.layui-table-tool .layui-inline[lay-event]{color:var(--lay-color-text-3);border:1px solid var(--lay-color-border-2)} -.layui-table-tool .layui-inline[lay-event]:hover{border:1px solid var(--lay-color-border-3)} -.layui-table-tool-panel{color: var(--lay-color-text-1); border:1px solid var(--lay-color-border-2);background-color: var(--lay-color-bg-5);box-shadow:var(--lay-shadow-2)} -.layui-table-tool-panel li:hover{background-color:var(--lay-color-active)} -.layui-table-col-set{background-color: var(--lay-color-white)} -.layui-table-sort .layui-table-sort-asc{border-bottom-color:var(--lay-color-gray-8)} -.layui-table-sort .layui-table-sort-asc:hover{border-bottom-color:var(--lay-color-gray-11)} -.layui-table-sort .layui-table-sort-desc{border-top-color:var(--lay-color-gray-8)} -.layui-table-sort .layui-table-sort-desc:hover{border-top-color:var(--lay-color-gray-11)} -.layui-table-sort[lay-sort=asc] .layui-table-sort-asc{border-bottom-color:var(--lay-color-gray-13)} -.layui-table-sort[lay-sort=desc] .layui-table-sort-desc{border-top-color:var(--lay-color-gray-13)} -.layui-table-cell .layui-table-link{color: var(--lay-color-lightblue-5)} -.layui-table-body .layui-none{color:var(--lay-color-gray-8)} -.layui-table-fixed-l{box-shadow:1px 0 8px rgba(0,0,0,1)} -.layui-table-fixed-r{box-shadow:-1px 0 8px rgba(0,0,0,1)} -.layui-table-edit{box-shadow:var(--lay-shadow-1);background-color: var(--lay-color-bg-2)} -.layui-table-edit:focus{border-color:var(--lay-color-secondary)!important} -select.layui-table-edit{border-color:var(--lay-color-border-2)} -.layui-table-grid-down{background-color: var(--lay-color-bg-5);color:var(--lay-color-gray-8)} -.layui-table-grid-down:hover{background-color:var(--lay-color-bg-5)} -/* 单元格多行展开风格 */ -.layui-table-cell-c{background-color: var(--lay-color-gray-13);color: var(--lay-color-text-1); border-color: var(--lay-color-border-3);} -.layui-table-cell-c:hover{border-color: var(--lay-color-secondary-hover);} -/* 单元格 TIPS 展开风格 */ -body .layui-table-tips .layui-layer-content{box-shadow:var(--lay-shadow-3)} -.layui-table-tips-main{background-color: var(--lay-color-bg-5);color: var(--lay-color-text-3)} -.layui-table-tips-c{background-color:var(--lay-color-gray-13);color: var(--lay-color-text-1)} -.layui-table-tips-c:hover{background-color:var(--lay-color-gray-10)} -/** 文件上传 **/ -.layui-upload-choose{color:var(--lay-color-gray-8)} -.layui-upload-drag{border:1px dashed var( --lay-color-border-2);background-color: var(--lay-color-bg-4);color: var(--lay-color-text-2)} -.layui-upload-drag .layui-icon{color: var(--lay-color-primary)} -.layui-upload-drag[lay-over]{border-color: var(--lay-color-primary)} -/* 基础菜单元素 */ -.layui-menu{background-color: var(--lay-color-bg-2)} -.layui-menu li{color: var(--lay-color-text-1)} -.layui-menu li:hover{background-color: var(--lay-color-bg-5)} -.layui-menu li.layui-disabled,.layui-menu li.layui-disabled *{color:var(--lay-color-text-4)!important} -.layui-menu .layui-menu-item-group>.layui-menu-body-title{color: var(--lay-color-text-3)} -.layui-menu .layui-menu-item-none{color: var(--lay-color-text-3);} -.layui-menu .layui-menu-item-divider{border-bottom:1px solid var(--lay-color-border-2)} -.layui-menu .layui-menu-item-group:hover, -.layui-menu .layui-menu-item-none:hover, -.layui-menu .layui-menu-item-divider:hover{background: none;} -.layui-menu .layui-menu-item-up>.layui-menu-body-title{color: var(--lay-color-text-1)} -.layui-menu .layui-menu-item-down:hover>.layui-menu-body-title>.layui-icon,.layui-menu .layui-menu-item-up>.layui-menu-body-title:hover>.layui-icon{color: var(--lay-color-text-1)} -.layui-menu .layui-menu-item-checked,.layui-menu .layui-menu-item-checked2{background-color:var(--lay-color-active)!important;color:var(--lay-color-secondary)} -.layui-menu .layui-menu-item-checked a,.layui-menu .layui-menu-item-checked2 a{color:var(--lay-color-secondary)} -.layui-menu .layui-menu-item-checked:after{border-right:3px solid var(--lay-color-secondary)} -.layui-menu-body-title a{color: var(--lay-color-text-1)} -.layui-menu-lg .layui-menu-body-title a:hover,.layui-menu-lg li:hover{color:var(--lay-color-secondary)} -/* 下拉菜单 */ -.layui-dropdown{background-color: var(--lay-color-bg-5)} -.layui-dropdown.layui-panel,.layui-dropdown .layui-panel{background-color: var(--lay-color-bg-5);box-shadow: var(--lay-shadow-2)} -.layui-dropdown.layui-panel .layui-menu{background-color: var(--lay-color-bg-5)} -/** 导航菜单 **/ -.layui-nav{background-color:var(--lay-color-black-6);color: var(--lay-color-white)} -.layui-nav .layui-nav-item a{color: var(--lay-color-text-1);} -.layui-nav .layui-this:after,.layui-nav-bar{background-color:var(--lay-color-secondary)} -.layui-nav .layui-nav-item a:hover,.layui-nav .layui-this a{color: var(--lay-color-text-1)} -.layui-nav-child{box-shadow:var(--lay-shadow-2);border:1px solid var(--lay-color-border-2);background-color: var(--lay-color-bg-5)} -.layui-nav .layui-nav-child a{color: var(--lay-color-text-1)} -.layui-nav .layui-nav-child a:hover{background-color: var(--lay-color-bg-5);color: var(--lay-color-text-1)} -.layui-nav-child dd.layui-this{background-color: var(--lay-color-bg-5);color: var(--lay-color-text-1)} -.layui-nav-tree .layui-nav-child dd.layui-this,.layui-nav-tree .layui-nav-child dd.layui-this a,.layui-nav-tree .layui-this,.layui-nav-tree .layui-this>a,.layui-nav-tree .layui-this>a:hover{background-color: var(--lay-color-primary);color: var(--lay-color-white)} -.layui-nav-itemed>a,.layui-nav-tree .layui-nav-title a,.layui-nav-tree .layui-nav-title a:hover{color: var(--lay-color-white)!important} -.layui-nav-tree .layui-nav-bar{background-color:var(--lay-color-primary)} -.layui-nav-tree .layui-nav-child{background: none; background-color:rgba(0, 0, 0, .3); border: none; box-shadow: none;} -.layui-nav-tree .layui-nav-child a{color: var(--lay-color-white);color: var(--lay-color-text-1)} -.layui-nav-tree .layui-nav-child a:hover{background: none; color: var(--lay-color-white)} -.layui-nav.layui-bg-gray,.layui-nav-tree.layui-bg-gray{background-color: var(--lay-color-bg-2) !important;color: var(--lay-color-text-1);} -.layui-nav-tree.layui-bg-gray .layui-nav-child{background-color: rgba(0, 0, 0, .3) !important;} -.layui-nav-tree.layui-bg-gray a,.layui-nav.layui-bg-gray .layui-nav-item a{color: var(--lay-color-text-1)} -.layui-nav.layui-bg-gray .layui-nav-child{background-color: var(--lay-color-bg-5);} -.layui-nav-tree.layui-bg-gray .layui-nav-itemed>a{color: var(--lay-color-text-1)!important} -.layui-nav.layui-bg-gray .layui-this a{color:var(--lay-color-secondary)} -.layui-nav-tree.layui-bg-gray .layui-nav-child dd.layui-this,.layui-nav-tree.layui-bg-gray .layui-nav-child dd.layui-this a,.layui-nav-tree.layui-bg-gray .layui-this,.layui-nav-tree.layui-bg-gray .layui-this>a{color:var(--lay-color-secondary)!important} -.layui-nav-tree.layui-bg-gray .layui-nav-bar{background-color:var(--lay-color-secondary)} -/** 面包屑 **/ -.layui-breadcrumb a{color:var(--lay-color-gray-7)!important} -.layui-breadcrumb a:hover{color:var(--lay-color-secondary)!important} -.layui-breadcrumb a cite{color:var(--lay-color-gray-8)} -.layui-breadcrumb span[lay-separator]{color:var(--lay-color-gray-7)} -/** Tab 选项卡 **/ -.layui-tab .layui-tab-title:after{border-bottom-color: var(--lay-color-border-1);} -.layui-tab-title .layui-this{color: var(--lay-color-text-2)} -.layui-tab-title .layui-this:after{border-bottom-color: var(--lay-color-bg-1)} -.layui-tab-bar{background-color: var(--lay-color-bg-3)} -.layui-tab-more li.layui-this:after{border-bottom-color:var(--lay-color-border-1)} -.layui-tab-title li .layui-tab-close{color:var(--lay-color-gray-8)} -.layui-tab-title li .layui-tab-close:hover{background-color:var(--lay-color-danger);color: var(--lay-color-white)} -.layui-tab-brief>.layui-tab-title .layui-this{color:var( --lay-color-primary)} -.layui-tab-brief>.layui-tab-more li.layui-this:after,.layui-tab-brief>.layui-tab-title .layui-this:after{border-bottom:2px solid var(--lay-color-secondary)} -.layui-tab-card{box-shadow: var(--lay-shadow-1)} -.layui-tab-card>.layui-tab-title{background-color: var(--lay-color-bg-2)} -.layui-tab-card>.layui-tab-title .layui-this{background-color: var(--lay-color-bg-1)} -.layui-tab-card>.layui-tab-title .layui-this:after{border-bottom-color: var(--lay-color-bg-1)} -.layui-tab-card>.layui-tab-more .layui-this{color:var(--lay-color-secondary)} - -/** tabs 标签页 **/ -.layui-tabs-header:after, -.layui-tabs-scroll:after{border-bottom-color: var(--lay-color-border-1);} -.layui-tabs-card>.layui-tabs-header .layui-this{background-color: transparent;} -.layui-tabs-card>.layui-tabs-header .layui-this:after{border-color: var(--lay-color-border-1); border-bottom-color: var(--lay-color-bg-1);} -.layui-tabs-card.layui-panel>.layui-tabs-header .layui-this:after{border-bottom-color: var(--lay-color-bg-2);} -.layui-tabs-bar .layui-icon{background-color: var(--lay-color-bg-1); color: var(--lay-color-text-2); border-color: var(--lay-color-border-1); box-shadow: 2px 0 5px 0 rgb(0 0 0 / 32%);} -.layui-tabs-bar .layui-icon-next{box-shadow: -2px 0 5px 0 rgb(0 0 0 / 32%);} - -/*时间线*/ -.layui-timeline-axis{background-color: var(--lay-color-bg-4);color:var(--lay-color-secondary)} -.layui-timeline-axis:hover{color:var(--lay-color-red-6)} -.layui-timeline-item:before{background-color: var(--lay-color-bg-3)} -/*徽章*/ -.layui-badge,.layui-badge-dot,.layui-badge-rim{background-color:var(--lay-color-red-6);color: var(--lay-color-white)} -.layui-badge-rim{background-color: var(--lay-color-white);color:var(--lay-color-black-6)} -/* carousel 轮播 */ -.layui-carousel{background-color:var(--lay-color-gray-2)} -.layui-carousel>[carousel-item]:before{color:var(--lay-color-gray-8);-moz-osx-font-smoothing:grayscale} -.layui-carousel>[carousel-item]>*{background-color:var(--lay-color-gray-2)} -.layui-carousel-arrow{background-color:rgba(0,0,0,.2);color: var(--lay-color-white)} -.layui-carousel-arrow:hover,.layui-carousel-ind ul:hover{background-color:var(--lay-color-black)} -.layui-carousel[lay-indicator=outside] .layui-carousel-ind ul{background-color:var(--lay-color-black)} -.layui-carousel-ind ul{background-color:rgba(0,0,0,.2)} -.layui-carousel-ind ul li{background-color:var(--lay-color-gray-3);background-color: var(--lay-color-text-3)} -.layui-carousel-ind ul li:hover{background-color: var(--lay-color-white)} -.layui-carousel-ind ul li.layui-this{background-color: var(--lay-color-white)} -/** fixbar **/ -.layui-fixbar li{background-color:var(--lay-color-black-5);color: var(--lay-color-text-1)} -/** 表情面板 **/ -body .layui-util-face .layui-layer-content{background-color: var(--lay-color-bg-5);color:var(--lay-color-text-2)} -.layui-util-face ul{border:1px solid var(--lay-color-border-3);background-color: var(--lay-color-bg-5);box-shadow:var(--lay-shadow-2)} -.layui-util-face ul li{border:1px solid var(--lay-color-border-2)} -.layui-util-face ul li:hover{border:1px solid var(--lay-color-red-7);background: var(--lay-color-text-1)} -/** 代码文本修饰 **/ -.layui-code{border:1px solid var(--lay-color-border-2);background-color: var(--lay-color-bg-white);color: var(--lay-color-text-2)} -/** 穿梭框 **/ -.layui-transfer-box,.layui-transfer-header,.layui-transfer-search{border-color: var(--lay-color-border-2)} -.layui-transfer-box{background-color: var(--lay-color-bg-2)} -.layui-transfer-search .layui-icon-search{color:var(--lay-color-gray-8)} -.layui-transfer-active .layui-btn{background-color:var( --lay-color-secondary);border-color:var( --lay-color-secondary);color: var(--lay-color-white)} -.layui-transfer-active .layui-btn-disabled{background-color:var(--lay-color-gray-2);border-color:var(--lay-color-gray-3);color:var(--lay-color-gray-8)} -.layui-transfer-data li:hover{background-color:var(--lay-color-active)} -/* chrome 105 */ -.layui-transfer-data li:hover:has([lay-filter="layTransferCheckbox"][disabled]){background-color:var(--lay-color-bg-2)} -.layui-transfer-data .layui-none{color:var(--lay-color-gray-7)} -/** 评分组件 **/ -.layui-rate li i.layui-icon{color:var(--lay-color-orange-6)} -/** 颜色选择器 **/ -.layui-colorpicker{border:1px solid var(--lay-color-border-1)} -.layui-colorpicker:hover{border-color: var(--lay-color-border-2)} -.layui-colorpicker-trigger-span{border:1px solid var(--lay-color-border-1)} -.layui-colorpicker-trigger-i{color: var(--lay-color-white)} -.layui-colorpicker-trigger-i.layui-icon-close{color:var(--lay-color-black-7)} -.layui-colorpicker-main{background: var(--lay-color-bg-2);border:1px solid var( --lay-color-border-2);box-shadow:var(--lay-shadow-2)} -.layui-colorpicker-basis-white{background:linear-gradient(90deg, #fff,hsla(0,0%,100%,0))} /* danger: 勿改*/ -.layui-colorpicker-basis-black{background:linear-gradient(0deg,#000,transparent)} /* danger: 勿改*/ -.layui-colorpicker-basis-cursor{border:1px solid var(--lay-color-white)} -.layui-colorpicker-side{background:linear-gradient(linear-gradient(#F00, #FF0, #0F0, #0FF, #00F, #F0F, #F00))} /* danger: 勿改*/ -.layui-colorpicker-side-slider{box-shadow:var(--lay-shadow-1);background: var(--lay-color-white);border:1px solid var(--lay-color-gray-2)} -.layui-colorpicker-alpha-slider{box-shadow:var(--lay-shadow-1);background: var(--lay-color-white);border:1px solid var(--lay-color-gray-2)} -.layui-colorpicker-pre.layui-this{box-shadow:var(--lay-shadow-1)} -.layui-colorpicker-pre.selected{box-shadow:var(--lay-shadow-1)} -.layui-colorpicker-main-input input.layui-input{color: var(--lay-color-text-2)} -/** 滑块 **/ -.layui-slider{background: var( --lay-color-bg-5)} -.layui-slider-step{background: var(--lay-color-fill-4)} -.layui-slider-wrap-btn{background: var(--lay-color-bg-4)} -.layui-slider-tips{color: var(--lay-color-text-1);background:var(--lay-color-black);box-shadow: var(--lay-shadow-3)} -.layui-slider-tips:after{border-color:var(--lay-color-black) transparent transparent transparent} -.layui-slider-input{border:1px solid var(--lay-color-border-1)} -.layui-slider-input-btn{border-left:1px solid var(--lay-color-border-1)} -.layui-slider-input-btn i{color:var(--lay-color-gray-9)} -.layui-slider-input-btn i:first-child{border-bottom:1px solid var(--lay-color-border-1)} -.layui-slider-input-btn i:hover{color:var(--lay-color-primary)} -/** 树组件 **/ -.layui-tree-line .layui-tree-set .layui-tree-set:after{border-top:1px dotted var(--lay-color-gray-7)} -.layui-tree-entry:hover{background-color: var(--lay-color-bg-4)} -.layui-tree-line .layui-tree-entry:hover{background-color:var(--lay-color-black)} -.layui-tree-line .layui-tree-entry:hover .layui-tree-txt{color:var(--lay-color-text-3)} -.layui-tree-entry:hover:has(span.layui-tree-txt.layui-disabled){background-color: transparent !important} -.layui-tree-line .layui-tree-set:before{border-left:1px dotted var(--lay-color-gray-7)} -.layui-tree-iconClick{color:var(--lay-color-gray-7)} -.layui-tree-icon{border:1px solid var(--lay-color-gray-8)} -.layui-tree-icon .layui-icon{color:var(--lay-color-text-1)} -.layui-tree-iconArrow:after{border-color:transparent transparent transparent var(--lay-color-gray-7)} -.layui-tree-txt{color:var(--lay-color-text-2)} -.layui-tree-search{color:var(--lay-color-black-7)} -.layui-tree-btnGroup .layui-icon:hover{color:var(--lay-color-text-2)} -.layui-tree-editInput{background-color:var(--lay-color-fill-2)} -.layui-tree-emptyText{color:var(--lay-color-text-2)} -/*code 不处理*/ -.layui-code-view{border:1px solid var(--lay-color-border-1);} -.layui-code-view:not(.layui-code-hl){background-color: var(--lay-color-bg-2);color: var(--lay-color-text-2);} -.layui-code-header{border-bottom: 1px solid var(--lay-color-border-1); background-color: var(--lay-color-bg-2)} -.layui-code-header > .layui-code-header-about{color: var(--lay-color-text-2);} -.layui-code-view:not(.layui-code-hl) .layui-code-ln-side{border-color: var(--lay-color-border-1); background-color: var(--lay-color-bg-2);} -.layui-code-nowrap > .layui-code-ln-side{background: none !important;} -.layui-code-fixbar > span{color: var(--lay-color-text-3);} -.layui-code-fixbar > span:hover{color: var(--lay-color-secondary-hover);} - -.layui-code-theme-dark, -.layui-code-theme-dark > .layui-code-header{border-color: rgb(126 122 122 / 15%); background-color: #1f1f1f;} -.layui-code-theme-dark{border-width: 1px; color: #ccc;} -.layui-code-theme-dark > .layui-code-ln-side{border-right-color: #2a2a2a; background: none; color: #6e7681;} - -.layui-code-view.layui-code-hl > .layui-code-ln-side{background-color: transparent;} -.layui-code-theme-dark.layui-code-hl, -.layui-code-theme-dark.layui-code-hl > .layui-code-ln-side{border-color: rgb(126 122 122 / 15%);} - -.layui-code-full{background-color: var(--lay-color-bg-1)} -/*日期选择器*/ -.layui-laydate-header i{color:var(--lay-color-gray-8)} -.laydate-day-holidays:before{color:var(--lay-color-red-6)} -.layui-laydate .layui-this .laydate-day-holidays:before{color: var(--lay-color-white)} -.layui-laydate-footer span{border:1px solid var(--lay-color-border-2);background-color: var(--lay-color-bg-5)} -.layui-laydate-footer span:hover{color:var(--lay-color-secondary)} -.layui-laydate-footer span.layui-laydate-preview{border-color:transparent!important;} -.layui-laydate-footer span.layui-laydate-preview:hover{color:var(--lay-color-text-1) !important} -.layui-laydate-shortcut+.layui-laydate-main{border-left:1px solid var(--lay-color-border-2)} -.layui-laydate .layui-laydate-list{background-color: var(--lay-color-bg-5)} -.layui-laydate-hint{color:var(--lay-color-danger)} -.layui-laydate-range .laydate-main-list-1 .layui-laydate-content,.layui-laydate-range .laydate-main-list-1 .layui-laydate-header{border-left:1px solid var(--lay-color-border-2)} -.layui-laydate,.layui-laydate-hint{border-color: var(--lay-color-border-2);box-shadow:var(--lay-shadow-3);background-color: var(--lay-color-bg-5);color: var(--lay-color-text-1)} -.layui-laydate{box-shadow: var(--lay-shadow-2)} -.layui-laydate-hint{border-color:var(--lay-color-border-1)} -.layui-laydate-header{border-bottom:1px solid var( --lay-color-border-2)} -.layui-laydate-header i:hover,.layui-laydate-header span:hover{color:var(--lay-color-secondary)} -.layui-laydate-content th{color: var(--lay-color-text-1)} -.layui-laydate-content td{color: var(--lay-color-text-1)} -.layui-laydate-content td.laydate-day-now{color:var(--lay-color-secondary)} -.layui-laydate-content td.laydate-day-now:after{border:1px solid var(--lay-color-secondary)} -.layui-laydate-linkage .layui-laydate-content td.laydate-selected>div{background-color:var(--lay-color-green-8);} -.layui-laydate-linkage .laydate-selected:hover>div{background-color:var(--lay-color-green-8)!important} -.layui-laydate-content td>div:hover,.layui-laydate-list li:hover,.layui-laydate-shortcut>li:hover{background-color: var(--lay-color-fill-2);color: var(--lay-color-text-2)} -.layui-laydate-content td.laydate-disabled>div:hover{background-color: var(--lay-color-bg-5);color: var(--lay-color-text-4)} -.laydate-time-list li ol{border:1px solid var(--lay-color-border-2)} -.laydate-time-list>li:hover{background: 0 0;} -.layui-laydate-content .laydate-day-next,.layui-laydate-content .laydate-day-prev{color: var(--lay-color-text-3)} -.layui-laydate-linkage .laydate-selected.laydate-day-next>div,.layui-laydate-linkage .laydate-selected.laydate-day-prev>div{background: none!important} -.layui-laydate-footer{border-top:1px solid var(--lay-color-border-2)} -.layui-laydate-hint{color:var(--lay-color-danger)} -.laydate-day-mark::after{background-color:var(--lay-color-secondary)} -.layui-laydate-footer span[lay-type=date]{color:var(--lay-color-secondary)} -.layui-laydate .layui-this,.layui-laydate .layui-this>div{background-color:var(--lay-color-secondary)!important;color: var(--lay-color-white)!important} -.layui-laydate .laydate-disabled,.layui-laydate .laydate-disabled:hover{color: var(--lay-color-text-4)!important} -.layui-laydate .layui-this.laydate-disabled,.layui-laydate .layui-this.laydate-disabled>div{background-color: var(--lay-color-fill-1) !important;color: var(--lay-color-text-4) !important;} -.laydate-theme-molv .layui-laydate-header{background-color:var(--lay-color-primary)} -.laydate-theme-molv .layui-laydate-header i,.laydate-theme-molv .layui-laydate-header span{color:var(--lay-color-gray-2)} -.laydate-theme-molv .layui-laydate-header i:hover,.laydate-theme-molv .layui-laydate-header span:hover{color: var(--lay-color-white)} -.laydate-theme-molv .layui-laydate-content{border:1px solid var(--lay-color-border-2)} -.laydate-theme-molv .layui-this, .laydate-theme-molv .layui-this>div{background-color: var(--lay-color-primary) !important;} -.laydate-theme-molv .layui-laydate-footer{border:1px solid var(--lay-color-border-2)} -.laydate-theme-grid .laydate-month-list>li,.laydate-theme-grid .laydate-year-list>li,.laydate-theme-grid .layui-laydate-content td,.laydate-theme-grid .layui-laydate-content thead{border:1px solid var(--lay-color-border-2)} -.layui-laydate-linkage.laydate-theme-grid .laydate-selected,.layui-laydate-linkage.laydate-theme-grid .laydate-selected:hover{background-color:var(--lay-color-gray-3)!important;color:var(--lay-color-primary)!important} -.layui-laydate-linkage.laydate-theme-grid .laydate-selected.laydate-day-next,.layui-laydate-linkage.laydate-theme-grid .laydate-selected.laydate-day-prev{color:var(--lay-color-gray-6)!important} -.layui-laydate.laydate-theme-circle .layui-laydate-content table td.layui-this{background-color:transparent!important} -/*layer*/ -.layui-layer{background-color: var(--lay-color-bg-3);box-shadow:var(--lay-shadow-3)} -.layui-layer-border{border:1px solid var(--lay-color-border-2);box-shadow:var(--lay-shadow-3)} -.layui-layer-move{background-color: var(--lay-color-bg-5)} -.layui-layer-title{border-bottom:1px solid var(--lay-color-border-2);color: var(--lay-color-text-1)} -.layui-layer-setwin span{color: var(--lay-color-text-1)} -.layui-layer-setwin .layui-layer-min:before{border-bottom-color:var(--lay-color-text-1)} -.layui-layer-setwin .layui-layer-min:hover:before{border-bottom-color:var(--lay-color-info-hover)} -.layui-layer-setwin .layui-layer-max:after,.layui-layer-setwin .layui-layer-max:before{border:1px solid var(--lay-color-text-3)} -.layui-layer-setwin .layui-layer-max:hover:after,.layui-layer-setwin .layui-layer-max:hover:before{border-color:var(--lay-color-info-hover)} -.layui-layer-setwin .layui-layer-maxmin:after,.layui-layer-setwin .layui-layer-maxmin:before{background-color: var(--lay-color-bg-5)} -.layui-layer-setwin .layui-layer-close2{color:var(--lay-color-text-1);background-color:var(--lay-color-gray-10)} -.layui-layer-setwin .layui-layer-close2:hover{background-color:var(--lay-color-normal)} -.layui-layer-btn a{border:1px solid var(--lay-color-border-2);background-color: var( --lay-color-bg-3);color: var(--lay-color-text-2)} -.layui-layer-btn .layui-layer-btn0{border-color: transparent;background-color: var(--lay-color-normal);color: var(--lay-color-text-1)} -.layui-layer-dialog .layui-layer-content .layui-layer-face{color:var(--lay-color-gray-9)} -.layui-layer-dialog .layui-layer-content .layui-icon-tips{color:var(--lay-color-warning)} -.layui-layer-dialog .layui-layer-content .layui-icon-success{color: var(--lay-color-success)} -.layui-layer-dialog .layui-layer-content .layui-icon-error{top: 19px; color: var(--lay-color-danger)} -.layui-layer-dialog .layui-layer-content .layui-icon-question{color: var(--lay-color-warning);} -.layui-layer-dialog .layui-layer-content .layui-icon-lock{color: var(--lay-color-gray-10)} -.layui-layer-dialog .layui-layer-content .layui-icon-face-cry{color:var(--lay-color-danger)} -.layui-layer-dialog .layui-layer-content .layui-icon-face-smile{color:var(--lay-color-success)} -.layui-layer-rim{border:6px solid var(--lay-color-gray-8);border:6px solid var(--lay-color-border-2)} -.layui-layer-msg{border:1px solid var( --lay-color-border-1)} -.layui-layer-hui{background-color: var(--lay-color-bg-3);color: var(--lay-color-text-1)} -.layui-layer-hui .layui-layer-close{color: var(--lay-color-white)} -.layui-layer-loading-icon{color:var(--lay-color-gray-9)} -.layui-layer-loading-2:after,.layui-layer-loading-2:before{border:3px solid var(--lay-color-gray-6)} -.layui-layer-loading-2:after{border-color:transparent;border-left-color: var(--lay-color-normal)} -.layui-layer-tips .layui-layer-content{box-shadow: var(--lay-shadow-3);background-color: var(--lay-color-bg-5);color: var(--lay-color-text-1)} -.layui-layer-tips i.layui-layer-TipsG{border-color:transparent} -.layui-layer-tips i.layui-layer-TipsB,.layui-layer-tips i.layui-layer-TipsT{border-right-color:var(--lay-color-black)} -.layui-layer-tips i.layui-layer-TipsL,.layui-layer-tips i.layui-layer-TipsR{border-bottom-color:var(--lay-color-black)} -.layui-layer-lan .layui-layer-title{background:var(--lay-color-blue-5);color: var(--lay-color-text-1)} -.layui-layer-lan .layui-layer-btn{border-top:1px solid var(--lay-color-border-3)} -.layui-layer-lan .layui-layer-btn a{background: var(--lay-color-white);border-color:var(--lay-color-border-3);color: var(--lay-color-black-7)} -.layui-layer-lan .layui-layer-btn .layui-layer-btn1{background: var(--lay-color-gray-7)} -.layui-layer-molv .layui-layer-title{background:var(--lay-color-layuigreen-6);color: var(--lay-color-text-1)} -.layui-layer-molv .layui-layer-btn a{background:var(--lay-color-layuigreen-6);border-color:var(--lay-color-layuigreen-6)} -.layui-layer-molv .layui-layer-btn .layui-layer-btn1{background:var(--lay-color-gray-7)} -.layui-layer-win10{border-color: var(--lay-color-border-2)} -.layui-layer-win10 .layui-layer-btn{background-color: var(--lay-color-bg-2);border-color: var(--lay-color-border-2)} -.layui-layer-win10.layui-layer-dialog .layui-layer-content{color: var(--lay-color-blue-7)} -.layui-layer-win10 .layui-layer-btn .layui-layer-btn0{border-color: var(--lay-color-blue-9);background-color: var(--lay-color-bg-5);color: var(--lay-color-text-1)} -.layui-layer-win10 .layui-layer-btn .layui-layer-btn1{border-color: var(--lay-color-border-2);background-color: var(--lay-color-bg-5);color: var(--lay-color-text-1)} -.layui-layer-win10 .layui-layer-btn a:hover{background-color: var(--lay-color-blue-10);border-color: var(--lay-color-blue-8)} -.layui-layer-prompt .layui-layer-input{border:1px solid var(--lay-color-border-2);color: var(--lay-color-text-2)} -.layui-layer-tab{box-shadow:var(--lay-shadow-3)} -.layui-layer-tab .layui-layer-title span.layui-this{border-left:1px solid var(--lay-color-border-2);border-right:1px solid var(--lay-color-border-2);background-color: var(--lay-color-bg-3)} -.layui-layer-photos{background: none; box-shadow: none;} -.layui-layer-photos-prev,.layui-layer-photos-next{color:var(--lay-color-gray-9)} -.layui-layer-photos-prev:hover,.layui-layer-photos-next:hover{color:var(--lay-color-text-1)} -.layui-layer-photos-toolbar{background-color:#333;background-color: var(--lay-color-bg-5);color: var(--lay-color-text-1)} -.layui-layer-photos-toolbar *{color: var(--lay-color-text-1)} -.layui-layer-photos-toolbar a:hover{color: var(--lay-color-text-2)} -.layui-layer-photos-header > span:hover{background-color: var(--lay-color-fill-2)} -.layui-layer-tips i.layui-layer-TipsB,.layui-layer-tips i.layui-layer-TipsT{border-right-color: var(--lay-color-bg-5)} -.layui-layer-tips i.layui-layer-TipsL,.layui-layer-tips i.layui-layer-TipsR{border-bottom-color: var(--lay-color-bg-5)} -.layui-layer-prompt .layui-layer-input{border:1px solid var(--lay-color-border-2);color:var(--lay-color-text-1);background-color:var(--lay-color-black)} -.layui-layer-prompt .layui-layer-input:focus{outline:0} - -/*fix style*/ -.layui-layer-loading{background:0 0;box-shadow:0 0} -.layui-btn-primary{border-color:transparent} -.layui-btn-group .layui-btn:first-child{border-left:none} -.layui-btn-group .layui-btn-primary:hover{border-top-color:transparent; border-bottom-color: transparent;} -.layui-menu li:hover{background-color:var(--lay-color-fill-2)} -.layui-nav-child dd.layui-this{background-color:var(--lay-color-fill-2)} -.layui-nav .layui-nav-child a:hover{background-color:var(--lay-color-fill-2)} -.layui-nav .layui-nav-item a:hover,.layui-nav .layui-this a{background-color: var(--lay-color-fill-2)} -.layui-nav-child dd.layui-this{background-color: var(--lay-color-fill-2)} -.layui-tab-card>.layui-tab-title .layui-this:after{border-bottom-color:var(--lay-color-bg-1)} -.layui-form-select dl dd:hover{background-color:var(--lay-color-fill-2)} -.layui-form-select dl dd.layui-this{background-color:var(--lay-color-fill-2)} -.layui-laypage button{color:var(--lay-color-text-1)} -.layui-table[lay-even] tbody tr:nth-child(even){background-color:var(--lay-color-fill-4)} -.layui-menu .layui-menu-item-checked,.layui-menu .layui-menu-item-checked2{background-color:var(--lay-color-fill-2)!important} -.layui-input-split{background-color: var(--lay-color-bg-2);} -.layui-input-wrap .layui-input-prefix.layui-input-split{border-width: 1px;} -.layui-input-wrap .layui-input-split:has(+.layui-input:hover) {border-color: var(--lay-color-border-2);} -.layui-input-wrap .layui-input-split:has(+.layui-input:focus) {border-color: var(--lay-color-secondary-hover);} -.layui-layer-tab .layui-layer-title span:first-child{border-left: none !important;} -.layui-slider-input.layui-input, -.layui-slider-input .layui-input {background-color: var(--lay-color-bg-2);} diff --git a/web/static/tpl/theme.html b/web/static/tpl/theme.html deleted file mode 100644 index d828f2d..0000000 --- a/web/static/tpl/theme.html +++ /dev/null @@ -1,240 +0,0 @@ - -
      -
      -
      - - - -
      -
      - - -
      -
      -
      -
      - -
      -
      - -
      -
      - - - - - - - diff --git a/web/template/admin/apis.html b/web/template/admin/apis.html deleted file mode 100644 index cfdc909..0000000 --- a/web/template/admin/apis.html +++ /dev/null @@ -1,661 +0,0 @@ -{{ define "apis.html" }} -
      -

      接口设置

      -
      -

      筛选

      -
      -
      -
      -
      - -
      - -
      -
      -
      - -
      - -
      -
      -
      - -
      -
      -
      -
      -
      - -
      -

      接口列表

      -
      -
      - - -
      -
      - - - - -
      - - - -{{ end }} \ No newline at end of file diff --git a/web/template/admin/apps.html b/web/template/admin/apps.html deleted file mode 100644 index 18d9ee3..0000000 --- a/web/template/admin/apps.html +++ /dev/null @@ -1,1232 +0,0 @@ -{{ define "apps.html" }} -
      -

      应用程序

      -
      - - - - -
      - -
      -

      筛选

      -
      -
      -
      -
      - -
      - -
      -
      -
      - - -
      -
      -
      -
      -
      - -
      -

      应用列表

      -
      -
      - - -
      -
      - - - - - - - - - - - - - - -
      -{{ end }} \ No newline at end of file diff --git a/web/template/admin/dashboard.html b/web/template/admin/dashboard.html deleted file mode 100644 index 822c439..0000000 --- a/web/template/admin/dashboard.html +++ /dev/null @@ -1,181 +0,0 @@ -{{ define "dashboard.html" }} -
      -

      系统信息

      -
      - -
      -
      -
      -

      系统信息

      - - - - - - - - - - - - - - - - - - - -
      程序版本 - v{{ .Version }} -
      存储方案 - {{ .DBType }} -
      开发模式 - {{ if .Mode }} - 开启 - {{ else }} - 关闭 - {{ end }} -
      运行时长 - {{ .Uptime }} -
      -
      -
      -
      - - -
      -
      -
      -

      系统统计

      - - - - - - - - - - - - - - - - - - - -
      应用总数 - 0 -
      启用应用 - 0 -
      禁用应用 - 0 -
      变量总数 - 0 -
      -
      -
      -
      -
      - -

      最近登录日志

      -
      -
      -
      -
      -
      -
      - - -{{ end }} \ No newline at end of file diff --git a/web/template/admin/functions.html b/web/template/admin/functions.html deleted file mode 100644 index 5326e14..0000000 --- a/web/template/admin/functions.html +++ /dev/null @@ -1,489 +0,0 @@ -{{ define "functions.html" }} -
      -

      公共函数

      -
      - - -
      - -
      -

      筛选

      -
      -
      -
      -
      - -
      - -
      -
      -
      - -
      - -
      -
      -
      - - -
      -
      -
      -
      -
      - -
      -

      函数列表

      -
      -
      -
      -
      - - - - - - - - -
      -{{ end }} \ No newline at end of file diff --git a/web/template/admin/layout.html b/web/template/admin/layout.html deleted file mode 100644 index a4ac0eb..0000000 --- a/web/template/admin/layout.html +++ /dev/null @@ -1,83 +0,0 @@ - - - - - - - {{ .Title }} - {{ .SystemName }} - - - - - - - - -
      -
      - -
        - -
      • - -
      • -
      - -
      - -
      - - -
      - -
      - - - - \ No newline at end of file diff --git a/web/template/admin/login.html b/web/template/admin/login.html deleted file mode 100644 index 8d85569..0000000 --- a/web/template/admin/login.html +++ /dev/null @@ -1,280 +0,0 @@ -{{/* 管理员登录页面模板:使用layui构建的登录界面 */}} - - - - - - - {{ .Title }} - - - - - - - - -
      - -
      - - - - - - \ No newline at end of file diff --git a/web/template/admin/login_logs.html b/web/template/admin/login_logs.html deleted file mode 100644 index 352e76e..0000000 --- a/web/template/admin/login_logs.html +++ /dev/null @@ -1,171 +0,0 @@ -{{ define "login_logs.html" }} -
      -

      登录日志

      -
      -

      筛选

      -
      -
      -
      -
      - -
      - - - -
      -
      -
      - -
      - -
      -
      -
      - -
      - -
      -
      -
      - -
      - -
      -
      -
      - - -
      -
      -
      -
      -
      - -
      -

      日志列表

      -
      - -
      -
      -
      -
      - - -{{ end }} diff --git a/web/template/admin/operation_logs.html b/web/template/admin/operation_logs.html deleted file mode 100644 index 7943d9f..0000000 --- a/web/template/admin/operation_logs.html +++ /dev/null @@ -1,155 +0,0 @@ -{{ define "operation_logs.html" }} -
      -

      日志操作

      -
      -

      筛选

      -
      -
      -
      -
      - -
      - - - -
      -
      -
      - -
      - -
      -
      -
      - -
      - -
      -
      -
      - - -
      -
      -
      -
      -
      - -
      -

      日志列表

      -
      - -
      -
      -
      -
      - - -{{ end }} \ No newline at end of file diff --git a/web/template/admin/profile.html b/web/template/admin/profile.html deleted file mode 100644 index 0162473..0000000 --- a/web/template/admin/profile.html +++ /dev/null @@ -1,340 +0,0 @@ -{{ define "profile.html" }} -
      -

      账户管理

      -
      -
        -
      • 修改密码
      • -
      • 修改用户名
      • -
      -
      - -
      -
      -

      修改密码

      -
      -
      -
      - -
      -
      - -
      -
      -
      -
      - -
      -
      - -
      -
      -
      -
      - -
      -
      - -
      -
      -
      -
      -
      - - -
      -
      -
      -
      -
      -
      - - -
      -
      -

      修改用户名

      -
      -
      -
      - -
      - -
      -
      -
      - -
      - -
      -
      -
      - -
      -
      - -
      -
      -
      -
      -
      - - -
      -
      -
      -
      -
      -
      -
      -
      - - -
      -{{ end }} \ No newline at end of file diff --git a/web/template/admin/settings.html b/web/template/admin/settings.html deleted file mode 100644 index 1501b0e..0000000 --- a/web/template/admin/settings.html +++ /dev/null @@ -1,508 +0,0 @@ -{{ define "settings.html" }} -
      -

      系统设置

      - -
      -

      安全配置

      -
      -
      -
      - -
      -
      - -
      -
      -
      -
      - -
      -
      - - -
      -
      -
      -
      - -
      -
      - - -
      -
      -
      -
      - -
      -
      - - 小时(至少1小时) -
      -
      -
      -
      - -
      -
      - - 小时(至少1小时) -
      -
      -
      -
      -
      - - -
      -
      -
      -
      -
      - - -
      -

      Cookie 设置

      -
      -
      -
      - -
      -
      - -
      -
      -
      -
      - -
      - -
      -
      -
      - -
      - -
      -
      -
      - -
      -
      - - -
      -
      -
      - -
      -
      - - -
      -
      -
      -
      -
      - - -
      -

      日志清理设置

      -
      -
      -
      - -
      -
      - 保留 - - 天,且保留最近 - - 条(0为不限制) -
      -
      -
      -
      - -
      -
      - 保留 - - 天,且保留最近 - - 条(0为不限制) -
      -
      -
      -
      -
      - - -
      -
      -
      -
      -
      - - -
      -

      基本信息设置

      -
      -
      -
      - -
      - -
      -
      -
      - -
      - -
      -
      -
      - -
      - -
      -
      -
      - -
      - -
      -
      -
      -
      - - -
      -
      -
      -
      -
      - - -
      -

      页脚与备案

      -
      -
      -
      - -
      - -
      -
      -
      - -
      - -
      -
      -
      - -
      - -
      -
      -
      - -
      - -
      -
      -
      - -
      - -
      -
      -
      -
      - - -
      -
      -
      -
      -
      -
      - - -{{ end }} diff --git a/web/template/admin/variables.html b/web/template/admin/variables.html deleted file mode 100644 index bb340e5..0000000 --- a/web/template/admin/variables.html +++ /dev/null @@ -1,489 +0,0 @@ -{{ define "variables.html" }} -
      -

      公共变量

      -
      - - -
      - -
      -

      筛选

      -
      -
      -
      -
      - -
      - -
      -
      -
      - -
      - -
      -
      -
      - - -
      -
      -
      -
      -
      - -
      -

      变量列表

      -
      -
      -
      -
      - - - - - - - - -
      -{{ end }} \ No newline at end of file diff --git a/web/template/default/index.html b/web/template/default/index.html deleted file mode 100644 index dc71072..0000000 --- a/web/template/default/index.html +++ /dev/null @@ -1,374 +0,0 @@ - - - - {{ .Title }} - - - - - - - - - - {{ if .Description }}{{ end }} - {{ if .Keywords }}{{ end }} - - - - - - - - - - - -
      - -
      -
      -
      -

      {{ .SystemName }}

      -
      -
      -
      -
      {{ .WarningText }}
      -
      -
      -
      {{ .InfoText }}
      -
      -
      - - {{ if .ICPRecord }} - - {{ end }} -
      -
      - - - - - \ No newline at end of file diff --git a/web/template/install/install.html b/web/template/install/install.html deleted file mode 100644 index 645f1cc..0000000 --- a/web/template/install/install.html +++ /dev/null @@ -1,209 +0,0 @@ - - - - - {{ .title }} - - - - - - -
      -
      -

      系统初始化

      -

      欢迎使用,请完成以下初始化设置

      -
      - -
      - -
      - 1. 数据库配置 -
      - -
      - -
      - - -
      -
      - - - -
      - 2. 站点信息 -
      - -
      - -
      - -
      -
      - -
      - 3. 管理员设置 -
      - -
      - -
      - -
      -
      - -
      - -
      - -
      -
      - -
      - -
      - -
      -
      - -
      - -
      -
      -
      - - - - - -