66 Commits
1.0.0 ... 1.1.0

Author SHA1 Message Date
谦君
00d7f15380 Merge pull request #4 from coolxitech/main
重构构建方式
2025-12-14 15:40:44 +08:00
酷曦科技
1cbc9f0ea8 Update .github/workflows/build.yml
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
2025-12-14 14:40:05 +08:00
coolxitech
6e5c0cc745 docs(readme): 更新下载链接和文档结构
- 在 README 中添加了桌面版下载链接
- 完善了服务端和桌面版的分类说明
- 补充了 Ubuntu 和 MacOS 的安装包链接
- 优化了英文文档的标题和结构
- 统一了下载链接的展示格式
- 增加了必要的空行提升可读性
2025-12-14 14:23:14 +08:00
coolxitech
9451b7619d docs(readme): 更新桌面版下载链接
- 将 Windows 桌面版下载链接更新为 OGame.Setup.exe
- 将 Linux 桌面版下载链接更新为 OGame.AppImage
- 将 MacOS 桌面版下载链接更新为 OGame-mac.dmg
- 将 Linux 系统标注从 "Linux" 更改为 "Ubuntu"
2025-12-14 14:21:13 +08:00
coolxitech
5e8fdea34a chore(package): 更新包元数据信息 2025-12-14 14:14:52 +08:00
coolxitech
dbd95689be chore(package): 更新包元数据信息 2025-12-14 14:11:51 +08:00
coolxitech
77b4a7adf2 chore(package): 更新包元数据信息 2025-12-14 14:10:48 +08:00
coolxitech
face17971e feat(electron): 配置多平台构建产物名称
- 为 Windows 平台设置安装包文件名格式
- 添加 macOS 平台支持并配置产物命名规则
- 配置 Linux 平台构建选项及文件命名方式
- 统一各平台构建产物的命名变量使用
- 确保所有目标平台的 artifactName 格式一致
- 更新 electron-builder 配置以支持跨平台部署
2025-12-14 14:03:37 +08:00
coolxitech
9a8d9ff820 fix(docker): 更新Nginx配置文件路径
- 将nginx.conf复制目标从/etc/nginx/nginx.conf改为/etc/nginx/conf.d/default.conf
- 确保Nginx配置能正确加载默认站点配置
- 保持与Alpine版Nginx的目录结构一致
2025-12-14 13:50:48 +08:00
coolxitech
452874c9cb docs(readme): 更新构建工具描述和下载链接
- 在 README 和 README-EN 中添加 Electron 构建说明
- 更新 Golang 构建目标描述为 Web 服务端
- 添加桌面版应用程序的下载链接
- 重新组织下载部分结构,区分服务端和桌面版
- 为不同平台添加对应的桌面版可执行文件链接
2025-12-14 13:50:29 +08:00
coolxitech
070f12a5a0 Merge remote-tracking branch 'origin/main' 2025-12-14 13:30:14 +08:00
coolxitech
f29366330d build(docker): 优化Docker构建流程并配置Nginx
- 合并RUN指令以减少镜像层数
- 移除不必要的cd和mkdir命令
- 添加Nginx配置文件复制步骤
- 清理HTML目录内容
- 暴露端口80用于Web服务
2025-12-14 13:30:01 +08:00
酷曦科技
b6f9999cdc Update README-EN.md
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
2025-12-14 13:29:07 +08:00
coolxitech
f1d90eb06c feat(electron): 设置窗口尺寸并移除菜单栏
- 设置主窗口默认尺寸为 1200x800
- 移除窗口菜单栏显示
- 更新构建脚本使用 pnpm 替代 npm
2025-12-14 13:15:44 +08:00
coolxitech
61dee24933 fix(build): 修复 GitHub Release 上传失败问题
- 调整 artifacts 下载方式,避免文件覆盖冲突
- 手动扁平化并重命名发布资产文件
- 确保服务端可执行文件唯一性
- 排除 electron 构建产生的 unpacked 目录
- 统一上传目录内容至 GitHub Release
- 避免使用通配符导致的重复匹配问题
2025-12-14 13:01:00 +08:00
coolxitech
00853372cd fix(build): 修复发布流程中上传文件的问题
- 调整 artifact 下载路径并启用平铺模式
- 清理中间产物目录避免上传无关文件
- 更新上传规则以支持多种安装包格式
- 优化 release assets 文件匹配逻辑
- 移除冗余的 zip 包上传配置项
- 增强构建脚本的健壮性和可维护性
2025-12-14 12:53:19 +08:00
coolxitech
37b330c4d6 chore(workflow): 优化构建与发布流程
- 统一上传步骤命名,增强可读性
- 精确指定上传文件后缀,避免多余目录或文件被上传
- 合并下载与上传步骤,简化 release 流程
- 移除冗余的权限声明与注释
- 修复 release assets 路径引用问题
2025-12-14 12:46:12 +08:00
coolxitech
e2666e1d73 chore(workflow): 优化 Release 工作流以提高稳定性
- 调整作业依赖顺序,确保构建完成后再执行发布
- 明确设置 GitHub 权限,增强对 PR 和内容的访问控制
- 重构版本号获取逻辑,使用更清晰的脚本方式
- 分步创建 Release 并上传资产,避免并发冲突
- 指定具体文件路径进行上传,防止误传 package.json
- 启用自动生成 Release Notes 功能
- 统一管理下载路径并明确文件命名规则
2025-12-14 12:41:13 +08:00
coolxitech
ec77a0656a chore(workflow): 优化构建与发布流程
- 统一可执行文件命名规则,去除架构后缀
- 合并 Node 与 Go 环境设置步骤
- 简化前端与服务端构建流程
- 显式指定 Electron 安装包上传路径
- 优化 Release Assets 下载与合并方式
- 修复版本号获取逻辑并显式声明发布文件类型
- 排除 package.json 文件被误上传至 Release 页面
2025-12-14 12:36:15 +08:00
coolxitech
10071f5e54 chore(workflow): 优化 GitHub Actions 构建流程
- 合并前端安装与构建步骤以提高效率
- 移除重复的 checkout 和 setup 步骤
- 简化 artifact 上传路径配置
- 调整 release 步骤中的版本号获取逻辑
- 更新注释说明以反映最新改动
- 统一 Electron 构建命令执行方式
2025-12-14 12:27:28 +08:00
coolxitech
e3f95cd69b chore(workflow): 迁移构建流程至 pnpm
- 在 GitHub Actions 中安装 pnpm 并指定版本为 8
- 将 Node.js 缓存策略从 npm 更改为 pnpm
- 使用 pnpm 替代 npm 安装依赖和执行构建命令
- 更新 Electron 构建脚本参数传递方式以适配 pnpm
- 移除冗余的 npm 配置并统一使用 pnpm 管理前端依赖
2025-12-14 12:23:03 +08:00
coolxitech
9fc76ff6c1 ci(build): 更新构建流程以包含前端资源
- 修改服务器构建步骤以嵌入前端静态资源
- 添加 Node.js 设置和前端依赖安装
- 更新 Electron 构建脚本和输出路径
- 调整 package.json 中的构建命令
- 优化构建注释和版本获取方式
2025-12-14 12:18:56 +08:00
coolxitech
37862ae7ac chore(build): 优化多平台构建流程并更新依赖
- 更新 GitHub Actions 工作流名称,明确区分服务端与客户端构建
- 修改 Go 服务端构建任务命名及输出 artifact 名称
- 升级 Electron 构建环境从 Bun 到 Node.js 并调整相关指令
- 调整构建脚本以适配 npm 和标准 Electron 打包命令
- 增加 Debian 包支持并扩展上传安装包的路径规则
- 改进版本号提取逻辑,确保正确读取 package.json 中的版本
- 统一使用较旧但稳定的 GitHub Actions 版本以提高可靠性
2025-12-14 12:15:45 +08:00
coolxitech
fef38d40ee feat(electron): 引入 Electron 桌面应用支持
- 添加 Electron 主进程入口文件 main.ts
- 配置 Vite 插件以支持 Electron 构建
- 更新 package.json 添加 Electron 相关依赖和构建脚本
- 修改路由历史模式为 HashHistory 以兼容 Electron 环境
- 调整构建流程分离服务端与客户端打包任务
- 新增 Electron 应用图标和基础窗口配置
- 集成开发服务器 URL 加载逻辑与静态文件加载 fallback
- 更新构建日期并设置主进程入口点字段
- 添加 Windows 安装包构建目标及输出目录配置
- 优化依赖预构建列表以提升启动性能
- 分离 release 资源收集路径并增强跨平台兼容性
- 升级部分工具链版本以获得最新功能支持
2025-12-14 12:06:56 +08:00
coolxitech
9f5a873513 chore(tsconfig): 调整TypeScript编译目标和库版本
- 将编译目标从ES2023降级到ES2022
- 更新库定义版本从ES2023升级到ES2024
2025-12-14 12:06:32 +08:00
coolxitech
95b4f23268 docs(readme): 更新 README 文档以支持 Go 语言环境
- 在 README 中添加 Go 语言版本徽章
- 更新依赖环境列表,新增 Go 1.21+ 的安装要求
- 补充多平台二进制可执行文件下载链接
- 说明使用 Golang 构建跨平台兼容程序的功能
- 添加 Windows、Linux 和 MacOS 平台的最新构建版本下载地址
- 修改构建工具描述,加入对 Golang 支持的说明
- 调整文档结构以便更好地展示项目技术栈和快速启动指南
2025-12-14 12:06:20 +08:00
coolxitech
24efe3da2d docs(readme): 更新 README 文档内容
- 在构建工具描述中增加对 Golang 的说明
- 添加各平台下载链接至快速开始部分
- 补充 Windows、Linux 和 MacOS 的二进制文件下载地址
2025-12-13 17:25:50 +08:00
coolxitech
790c1b5840 chore(ci): 优化 GitHub Actions 构建流程
- 强制指定使用 bash shell,解决 Windows 环境下的执行错误
- 在构建前运行 go mod tidy,确保依赖整洁
- 保留编译过程中的控制台输出,便于调试追踪
2025-12-13 17:06:31 +08:00
coolxitech
67012cb273 feat(go): 初始化 Go 模块配置
- 创建 go.mod 文件
- 设置模块名为 ogame
- 指定 Go 版本为 1.25.4
2025-12-13 17:02:15 +08:00
coolxitech
9c4cfa02d8 ci(workflow): 更新构建工作流以支持多架构编译
- 添加对 Linux ARM64 和 macOS Apple Silicon 的支持
- 重命名可执行文件以明确平台和架构
- 更新构建步骤注释和顺序
- 修改上传构件名称以匹配可执行文件
- 调整发布流程以包含新增的架构文件
- 移除冗余的 Go 模块初始化逻辑
- 优化构建脚本中的条件判断结构
2025-12-13 17:00:24 +08:00
coolxitech
1cabf329d3 refactor(utils): 简化数据加密函数实现
- 移除不必要的变量赋值
- 直接返回加密结果
- 保持错误处理逻辑不变
2025-12-13 16:59:48 +08:00
coolxitech
1cc1f8f009 删除构建文件 2025-12-13 16:53:11 +08:00
coolxitech
dc40dace28 refactor(server): 移除 Express 服务器实现
- 删除了基于 Express 的服务器配置
- 移除了静态资源服务逻辑
- 删除了局域网 IP 获取和 URL 自动打开功能
- 移除了 SPA fallback 处理
- 清理了相关依赖导入和变量声明
2025-12-13 16:38:48 +08:00
coolxitech
b15f13f25b feat(server): 支持命令行指定端口和改进静态资源服务
- 新增 -port 命令行参数,支持指定运行端口
- 改进静态资源处理逻辑,增强 SPA 路由兼容性
- 优化端口监听失败时的错误提示和程序退出机制
- 增强启动信息展示,包括运行模式和时间戳
- 自动打开浏览器功能保持后台运行不阻塞主服务
- 添加详细的实时访问日志提示信息
2025-12-13 16:18:53 +08:00
coolxitech
e4f7b20882 refactor(server): 将后端从 Node.js 迁移至 Go
- 移除对 Express 和相关中间件的依赖
- 新增 Go 编写的 HTTP 服务,支持嵌入前端资源
- 更新构建流程以使用 Go 编译跨平台可执行文件
- 配置 GitHub Actions 工作流以适应新的构建方式
- 实现自动打开浏览器和显示局域网访问地址功能
- 清理 package.json 中不再需要的脚本和依赖项
- 更新 pnpm-lock.yaml 文件以反映依赖变化
2025-12-13 15:50:41 +08:00
coolxitech
061d1f0152 feat(server): 优化静态资源服务与构建配置
- 添加 docs 目录到 .gitignore 忽略列表
- 修复统计脚本 URL 协议为 HTTPS
- 更新构建时间戳并新增 Windows 可执行文件构建脚本
- 重构服务端静态资源处理逻辑,支持 Bun 自动嵌入
- 改进 SPA 路由 fallback 机制
- 优化局域网 IP 获取函数变量声明
- 完善 Content-Type 响应头设置
- 移除冗余代码注释,提升可读性
2025-12-13 14:55:08 +08:00
coolxitech
b758c6e84d fix(server): 修复静态资源拦截器路径匹配问题
- 修改路由参数匹配模式,支持更灵活的路径处理
- 确保默认路径正确映射到 index.html
- 优化路径解析逻辑,提高静态资源访问准确性
2025-12-13 14:19:10 +08:00
coolxitech
fc481507f0 fix(server): 修复静态资源拦截器路径匹配问题
- 将路由从 '*' 更改为 '/*' 以正确处理所有路径
- 确保默认路径 '/' 正确映射到 '/index.html'
- 优化路径处理逻辑以增强单文件嵌入功能
2025-12-13 14:13:36 +08:00
coolxitech
cd14e88cc0 feat(server): 实现跨平台自动打开浏览器功能
- 移除对 'open' 包的依赖,改用 Node.js 内置模块实现自动打开浏览器
- 新增 openUrl 函数,支持 macOS、Windows 和 Linux 系统
- 更新网络接口遍历逻辑中的变量命名以提高可读性
- 静态资源处理中间件改为使用 Bun.file API 并内嵌到可执行文件中
- 优化控制台输出信息,增强用户体验和提示清晰度
- 调整服务器监听地址为 0.0.0.0,并移除 trust proxy 设置
- 修改获取局域网 IP 的函数名称和注释结构使其更加明确
- 删除 package.json 和 lock 文件中不再使用的依赖项及相关条目
- 更新 GitHub Actions 工作流配置以适配新的编译和打包方式
- 在 CI 流程中启用代码压缩选项以减小最终二进制文件体积
2025-12-13 14:08:12 +08:00
coolxitech
20dc6bd086 feat(server): 更新静态资源目录路径
- 将静态资源目录从 'dist' 更改为 'docs'
- 确保服务器能正确指向新的构建输出目录
- 适配 Vue 项目文档部署需求
2025-12-13 13:57:12 +08:00
coolxitech
c0b405ae98 refactor(server): 动态导入open模块以优化启动性能
- 将open模块的引入方式从同步改为动态导入
- 避免在服务器启动时立即加载不必要的依赖
- 提升应用初始化速度和资源利用率
- 确保浏览器自动打开功能正常运行
- 添加错误处理以应对模块加载失败情况
2025-12-13 13:53:53 +08:00
coolxitech
1b2718246f refactor(server): 重构浏览器自动打开功能
- 将导入的 open 模块重命名为 openUrl 以避免命名冲突
- 更新调用 openUrl 函数来打开指定 URL
- 保持错误处理逻辑不变,确保异常情况下的日志记录
2025-12-13 13:47:34 +08:00
coolxitech
7307791314 chore(build): 更新打包脚本包含文档目录
- 将 Windows 打包命令中的 dist 目录替换为 docs 目录
- 将 Linux/macOS 打包命令中的 dist/ 目录替换为 docs/ 目录
- 确保所有平台的打包流程统一使用 docs 目录
- 保持构建产物的一致性和完整性
- 避免因目录变更导致的打包遗漏问题
2025-12-13 13:41:57 +08:00
coolxitech
268c88a89c ci(workflow): 优化构建与发布流程
- 移除手动触发工作流配置
- 从 package.json 动态读取应用版本号
- 更新资源打包路径为 dist 目录
- 实现跨平台压缩命令统一处理
- 自动传递版本号至 Release 任务
- 启用自动生成 Release Notes 功能
- 确保构建产物正确上传与归档
2025-12-13 13:40:56 +08:00
coolxitech
56d98018e6 build(docker): 更新构建命令使用pnpm build
- 将vite build替换为pnpm build以优化构建流程
- 确保构建过程与项目依赖管理工具一致
2025-12-13 13:30:57 +08:00
coolxitech
d88296fd96 chore(ci): 更新构建工作流的标签触发规则
- 将标签匹配模式从 'v*' 更改为 'v*.*'
- 移除冗余的标签数组嵌套结构
- 优化工作流触发条件配置
2025-12-13 13:24:36 +08:00
coolxitech
85c90fed50 build(workflow): 更新打包路径为 docs 目录
- 修改 Windows 平台压缩命令,将 dist 替换为 docs
- 修改 Linux/macOS 平台打包命令,将 dist/ 替换为 docs/
2025-12-13 13:18:48 +08:00
coolxitech
b77ae14d5c chore(deps): 添加 express 和 open 依赖项
- 在 package.json 中添加 express 版本 5.2.1
- 在 package.json 中添加 open 版本 11.0.0
- 更新 pnpm-lock.yaml 文件以包含新的依赖项及其子依赖项
- 添加与新依赖项相关的中间件和工具库
- 确保所有新增依赖项的版本兼容性
2025-12-13 13:16:11 +08:00
coolxitech
7e937330bb ci(workflow): 添加多平台构建与发布工作流
- 新增 GitHub Actions 工作流文件
- 支持 Windows、Linux 和 macOS 平台构建
- 配置 Bun 环境并安装依赖
- 构建 Vue 前端资源
- 编译后端为可执行文件
- 打包静态资源与可执行程序
- 上传构建产物并创建 GitHub Release
2025-12-13 13:12:37 +08:00
coolxitech
cfbbb95ddb chore(ci): 修复Docker Hub登录变量引用
- 将DOCKERHUB_USERNAME从secrets改为vars引用
- 统一使用vars中的用户名进行Docker Hub认证
- 保持密码仍从secrets中读取以确保安全性
2025-12-13 12:28:44 +08:00
coolxitech
c1f7043690 fix(workflow): 修复Docker Hub登录检查条件
- 将登录检查条件从 vars.DOCKERHUB_USERNAME 修改为 secrets.DOCKERHUB_USERNAME
- 更新username输入变量引用从 vars.DOCKERHUB_USERNAME 到 secrets.DOCKERHUB_USERNAME
- 保持密码token引用为 secrets.DOCKERHUB_TOKEN 不变
- 确保只有在配置了Docker Hub凭据时才执行登录步骤
2025-12-13 12:26:45 +08:00
coolxitech
70b74509b3 Merge remote-tracking branch 'origin/main'
# Conflicts:
#	Dockerfile
2025-12-13 12:15:01 +08:00
coolxitech
da3215bcc1 chore(docker): 移除pnpm安装时的--shamefully-hoist参数
- 删除了Dockerfile中pnpm install命令的--shamefully-hoist选项
- 简化了依赖安装流程
- 保持构建过程的一致性
2025-12-13 12:14:41 +08:00
coolxitech
3ed03b5e37 build(docker): 更新pnpm安装命令以解决依赖问题
- 在pnpm install命令中添加--shamefully-hoist参数
- 保持vite构建步骤不变
- 维持nginx基础镜像配置
2025-12-13 12:08:55 +08:00
coolxitech
90f18952ec refactor(docker): 优化Docker构建流程
- 简化多阶段构建结构
- 移除不必要的注释和空行
- 更新基础镜像为node:latest
- 调整工作目录创建方式
- 合并git克隆和依赖安装步骤
- 修改构建命令执行顺序
- 清理nginx html目录内容
- 调整文件复制路径逻辑
2025-12-13 12:02:43 +08:00
coolxitech
9986a05d44 Merge remote-tracking branch 'origin/main'
# Conflicts:
#	src/stores/gameStore.ts
2025-12-13 12:02:08 +08:00
谦君
731d79673b feat: 新增战报弹窗与舰队模拟器,重构UI组件
新增 BattleReportDialog、SpyReportDialog、NumberWithTooltip 等组件,完善舰队模拟器功能。重构并引入 Sheet、Sidebar、Tooltip、Skeleton 等 UI 组件,优化界面结构。实现 battle.worker 支持战斗计算,增加 universeStore、fleetStorageLogic 等核心逻辑,完善多语言与类型定义。
2025-12-13 11:14:23 +08:00
coolxitech
cf5a62ed21 chore(deps): 更新依赖并移除冗余包
- 移除了 pnpm-lock.yaml 中的 esbuild 相关依赖项
- 清理了多个平台特定的 esbuild 子依赖
- 更新了 @tailwindcss/vite 和 @vitejs/plugin-vue 的依赖版本
- 标记多个工具包为可选依赖以优化安装体积
- 精简了 rolldown-vite 的依赖树结构
2025-12-13 10:35:15 +08:00
coolxitech
533c36b962 build(docker): 优化 Docker 构建流程
- 调整 pnpm 安装方式以提高构建稳定性
- 修改依赖安装顺序以更好利用缓存
- 更新注释内容以准确反映构建步骤
- 移除冗余指令以简化 Dockerfile 结构
2025-12-13 10:33:11 +08:00
coolxitech
b49e5f667c chore(ci): 优化 Docker 登录和镜像标签逻辑
- 调整 GHCR 登录注释,明确其始终执行
- 修改 Docker Hub 登录条件,仅检查 vars.DOCKERHUB_USERNAME 是否存在
- 更新 Docker Hub 镜像标签格式,添加 docker.io 前缀以确保唯一性
- 移除关于 GITHUB_TOKEN 的注释冗余内容
- 统一镜像推送逻辑中的标签生成方式
2025-12-13 10:30:54 +08:00
coolxitech
1e9c3ad37b ci(docker): 重构多架构镜像构建流程
- 合并原有分离的 amd64 和 arm64 构建任务为统一的多架构构建任务
- 使用 docker/setup-qemu-action 和 docker/setup-buildx-action 支持多架构构建
- 更新 GitHub Actions 的依赖版本至最新(checkout@v4、login-action@v3、build-push-action@v6)
- 修改平台配置为 linux/amd64,linux/arm64 实现一键双架构构建
- 改用 GITHUB_TOKEN 进行 GHCR 认证,提高安全性
- 优化 Docker Hub 登录逻辑,仅在配置凭据时执行
- 移除手动创建 manifest 步骤,由 build-push-action 自动处理多架构标签
- 增加对 git tag 触发的支持,实现版本化镜像推送
- 添加构建缓存支持以提升后续构建速度
- 更新镜像标签策略,同时推送 latest 和 commit SHA 标签到 GHCR 与 Docker Hub
2025-12-13 10:28:57 +08:00
coolxitech
190455a1bd chore(ci): 添加手动触发工作流的支持
- 在 GitHub Actions 工作流中启用 workflow_dispatch 触发器
- 允许通过 GitHub UI 手动启动 ogame-vue-ts 构建任务
- 保留现有的 push 到 main 分支的自动触发机制
2025-12-13 10:23:55 +08:00
coolxitech
67d71ece0c chore: 更新.gitignore文件
- 添加 pnpm-lock.yaml 到忽略列表
- 保持编辑器相关目录和文件的忽略规则不变
2025-12-13 10:20:54 +08:00
coolxitech
0520609f61 chore(pnpm): 配置仅构建依赖项并更新包管理器版本
- 添加 vue-demi 到 onlyBuiltDependencies 配置
- 更新 pnpm 包管理器到版本 10.13.1
- 升级 vite 覆盖配置为 rolldown-vite 7.2.5
2025-12-13 10:20:24 +08:00
coolxitech
ec69c77956 fix(gameStore): 修正侧边栏折叠逻辑
- 调整侧边栏折叠条件以适配大屏设备
- 移除小屏设备上的错误折叠状态
- 确保默认状态下侧边栏在宽屏上展开
2025-12-13 10:20:09 +08:00
coolxitech
469c5a0170 feat(docker): 优化Docker构建流程并支持生产环境部署
- 引入多阶段构建,分离构建与运行时环境
- 使用node:20-alpine作为构建基础镜像,减小体积
- 添加pnpm包管理器并优化依赖安装流程
- 利用缓存机制提升构建效率
- 新增nginx.conf配置文件解决Vue Router历史模式404问题
- 设置静态资源缓存策略提升性能
- 更改默认启动命令为Nginx服务方式运行应用
- 移除开发服务器相关指令,适配生产部署需求
2025-12-13 10:19:58 +08:00
141 changed files with 9912 additions and 1894 deletions

142
.github/workflows/build.yml vendored Normal file
View File

@@ -0,0 +1,142 @@
name: 构建多平台程序 (Go Server & Electron Client)
on:
push:
branches:
- main
jobs:
# 1. 构建 Go 服务端
build-server:
name: Build Server (${{ matrix.goos }}-${{ matrix.goarch }})
runs-on: ubuntu-latest
strategy:
matrix:
include:
- goos: windows
goarch: amd64
executable: ogame-server-win.exe
- goos: linux
goarch: amd64
executable: ogame-server-linux
- goos: linux
goarch: arm64
executable: ogame-server-linux-arm64
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v3
with:
version: 8
- name: Setup Node & Go
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'
- uses: actions/setup-go@v5
with:
go-version: '1.25'
- name: Build Frontend & Server
run: |
pnpm install
pnpm run build
go mod tidy
GOOS=${{ matrix.goos }} GOARCH=${{ matrix.goarch }} go build -ldflags="-s -w" -o ${{ matrix.executable }} main.go
- name: Upload Server Binaries
uses: actions/upload-artifact@v4
with:
name: server-${{ matrix.goos }}-${{ matrix.goarch }}
path: ${{ matrix.executable }}
# 2. 构建 Electron 客户端
build-electron:
name: Build Electron (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: windows-latest
platform: win
- os: macos-latest
platform: mac
- os: ubuntu-latest
platform: linux
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v3
with:
version: 8
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'
- name: Build Electron
run: |
pnpm install
pnpm run build
pnpm run build:electron --${{ matrix.platform }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# 【关键点】这里只上传安装包后缀,不上传文件夹
- name: Upload Electron Installers
uses: actions/upload-artifact@v4
with:
name: electron-${{ matrix.platform }}
path: |
pkg/*.exe
pkg/*.dmg
pkg/*.AppImage
# 3. 发布 Release
release:
needs: [ build-server, build-electron ]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- name: Get Version
id: get_version
run: echo "VERSION=v$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT
# 1. 下载时,不使用 merge-multiple防止覆盖冲突
- name: Download Artifacts
uses: actions/download-artifact@v4
with:
path: ./raw-assets
# 2. 核心步骤:手动移动文件到一个扁平目录,并强制重命名
- name: Flatten and Rename Assets
run: |
mkdir -p ./final-release
# 移动 Server 文件并确保名字唯一
# 注意根据你之前的附件Artifact 名字是 server-windows-amd64
cp ./raw-assets/server-windows-amd64/ogame-server-win.exe ./final-release/ogame-server-win.exe || cp ./raw-assets/server-windows-amd64/server-windows-amd64.exe ./final-release/ogame-server-win.exe || true
cp ./raw-assets/server-linux-amd64/ogame-server-linux ./final-release/ogame-server-linux || true
cp ./raw-assets/server-linux-arm64/ogame-server-linux-arm64 ./final-release/ogame-server-linux-arm64 || true
# 移动 Electron 安装包 (排除 unpacked 目录)
find ./raw-assets/electron-* -type f \( -name "*.exe" -o -name "*.dmg" -o -name "*.AppImage" -o -name "*.zip" \) -exec cp {} ./final-release/ \;
# 检查结果
echo "Final assets to upload:"
ls -R ./final-release
# 3. 一次性上传,禁止重复匹配
- name: Create GitHub Release
uses: softprops/action-gh-release@v1
with:
tag_name: ${{ steps.get_version.outputs.VERSION }}
name: Release ${{ steps.get_version.outputs.VERSION }}
# 重点:只上传这个干净目录下的所有文件,不要再写具体的通配符防止重复
files: ./final-release/*
generate_release_notes: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,105 +1,59 @@
name: 自动化创建Docker镜像 name: Docker 多架构构建并发布
on: on:
push: push:
branches: branches: [ main ]
- main tags: [ 'v*.*.*' ] # 打 tag 时也触发
workflow_dispatch:
permissions:
contents: read
packages: write
jobs: jobs:
build-amd64: build-and-push:
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps: steps:
- name: 代码 - name: 代码
uses: actions/checkout@v2 uses: actions/checkout@v4
with:
fetch-depth: 0
# QEMU 用于支持多架构构建(必须)
- name: 设置 QEMU
uses: docker/setup-qemu-action@v3
# Buildx 是目前官方唯一推荐的多架构构建方式
- name: 设置 Docker Buildx
uses: docker/setup-buildx-action@v3
# 登录 GHCR始终执行
- name: 登录 GitHub Container Registry - name: 登录 GitHub Container Registry
uses: docker/login-action@v2 uses: docker/login-action@v3
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.actor }} username: ${{ github.actor }}
password: ${{ secrets.GHCR_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
# 登录 Docker Hub只在用户名存在时执行
- name: 登录 Docker Hub - name: 登录 Docker Hub
uses: docker/login-action@v2 if: vars.DOCKERHUB_USERNAME != '' # 只检查 vars忽略 secrets
uses: docker/login-action@v3
with: with:
username: ${{ secrets.DOCKERHUB_USERNAME }} username: ${{ vars.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }} password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: 构建并推送 amd64 Docker镜像 # 真正一键构建 + 推送多架构镜像amd64 + arm64
uses: docker/build-push-action@v3 - name: 构建并推送多架构镜像
uses: docker/build-push-action@v6
with: with:
context: . context: .
platforms: linux/amd64 platforms: linux/amd64,linux/arm64
push: true push: true
tags: | tags: |
ghcr.io/${{ github.repository_owner }}/ogame-vue-ts:amd64 ghcr.io/${{ github.repository_owner }}/ogame-vue-ts:latest
${{ secrets.DOCKERHUB_USERNAME }}/ogame-vue-ts:amd64 ghcr.io/${{ github.repository_owner }}/ogame-vue-ts:${{ github.sha }}
${{ vars.DOCKERHUB_USERNAME != '' && format('docker.io/{0}/ogame-vue-ts:latest', vars.DOCKERHUB_USERNAME) || '' }}
build-arm64: ${{ vars.DOCKERHUB_USERNAME != '' && format('docker.io/{0}/ogame-vue-ts:{1}', vars.DOCKERHUB_USERNAME, github.sha) || '' }}
runs-on: ubuntu-22.04-arm cache-from: type=gha
permissions: cache-to: type=gha,mode=max
contents: read
packages: write
steps:
- name: 检查代码
uses: actions/checkout@v2
- name: 登录 GitHub Container Registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GHCR_TOKEN }}
- name: 登录 Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: 构建并推送 arm64 Docker镜像
uses: docker/build-push-action@v3
with:
context: .
platforms: linux/arm64
push: true
tags: |
ghcr.io/${{ github.repository_owner }}/ogame-vue-ts:arm64
${{ secrets.DOCKERHUB_USERNAME }}/ogame-vue-ts:arm64
create-manifest:
needs: [build-amd64, build-arm64]
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: 登录 GitHub Container Registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GHCR_TOKEN }}
- name: 登录 Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: 创建并推送多架构清单
run: |
# GitHub Container Registry
docker manifest create ghcr.io/${{ github.repository_owner }}/ogame-vue-ts:latest \
ghcr.io/${{ github.repository_owner }}/ogame-vue-ts:amd64 \
ghcr.io/${{ github.repository_owner }}/ogame-vue-ts:arm64
docker manifest push ghcr.io/${{ github.repository_owner }}/ogame-vue-ts:latest
# Docker Hub
docker manifest create ${{ secrets.DOCKERHUB_USERNAME }}/ogame-vue-ts:latest \
${{ secrets.DOCKERHUB_USERNAME }}/ogame-vue-ts:amd64 \
${{ secrets.DOCKERHUB_USERNAME }}/ogame-vue-ts:arm64
docker manifest push ${{ secrets.DOCKERHUB_USERNAME }}/ogame-vue-ts:latest

1
.gitignore vendored
View File

@@ -12,6 +12,7 @@ node_modules
dist dist
dist-ssr dist-ssr
*.local *.local
docs
# Editor directories and files # Editor directories and files
.claude/* .claude/*

View File

@@ -1,17 +1,21 @@
FROM node:latest FROM node:latest AS builder
RUN mkdir -p /workspace RUN mkdir -p /workspace
WORKDIR /workspace WORKDIR /workspace
RUN npm config set registry https://registry.npmmirror.com RUN npm config set registry https://registry.npmmirror.com
RUN cd /workspace
RUN git clone https://github.com/setube/ogame-vue-ts.git RUN git clone https://github.com/setube/ogame-vue-ts.git
RUN mv ./ogame-vue-ts/* . ; rm -rf ./ogame-vue-ts/ RUN mv ./ogame-vue-ts/* . ; rm -rf ./ogame-vue-ts/
RUN npm install -g pnpm ; pnpm install ; npx vite build RUN npm install -g pnpm ; pnpm install;
RUN pnpm build
CMD ["npx", "vite", "preview", "--host", "0.0.0.0", "--port", "25121"] # --- 第二阶段Nginx ---
FROM nginx:alpine
COPY nginx.conf /etc/nginx/conf.d/default.conf
RUN rm -rf /usr/share/nginx/html/*
COPY --from=builder /workspace/docs /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

View File

@@ -9,6 +9,8 @@
[![Vue 3](https://img.shields.io/badge/Vue-3.5-brightgreen.svg)](https://vuejs.org/) [![Vue 3](https://img.shields.io/badge/Vue-3.5-brightgreen.svg)](https://vuejs.org/)
[![TypeScript](https://img.shields.io/badge/TypeScript-5.9-blue.svg)](https://www.typescriptlang.org/) [![TypeScript](https://img.shields.io/badge/TypeScript-5.9-blue.svg)](https://www.typescriptlang.org/)
[![Vite](https://img.shields.io/badge/Vite-7.2-646CFF.svg)](https://vitejs.dev/) [![Vite](https://img.shields.io/badge/Vite-7.2-646CFF.svg)](https://vitejs.dev/)
[![Go](https://img.shields.io/badge/Go-1.25-79D4FD.svg)](https://golang.org/)
[简体中文](README.md) | English [简体中文](README.md) | English
</div> </div>
@@ -36,7 +38,7 @@ OGame Vue TS is a single-player, browser-based space strategy game inspired by t
- **Frontend Framework:** [Vue 3](https://vuejs.org/) with Composition API (`<script setup>`) - **Frontend Framework:** [Vue 3](https://vuejs.org/) with Composition API (`<script setup>`)
- **Language:** [TypeScript](https://www.typescriptlang.org/) with strict type checking - **Language:** [TypeScript](https://www.typescriptlang.org/) with strict type checking
- **Build Tool:** [Vite](https://vitejs.dev/) (Custom Rolldown-Vite 7.2.5) - **Build Tool:** [Vite](https://vitejs.dev/) (Custom Rolldown-Vite 7.2.5)、[Golang](https://golang.org/)(Building cross-platform Web server.)、[Electron](https://www.electronjs.org/)(Building cross-platform visual interfaces)
- **State Management:** [Pinia](https://pinia.vuejs.org/) with persisted state plugin - **State Management:** [Pinia](https://pinia.vuejs.org/) with persisted state plugin
- **Routing:** [Vue Router 4](https://router.vuejs.org/) - **Routing:** [Vue Router 4](https://router.vuejs.org/)
- **UI Components:** [shadcn-vue](https://www.shadcn-vue.com/) (New York style) - **UI Components:** [shadcn-vue](https://www.shadcn-vue.com/) (New York style)
@@ -47,10 +49,33 @@ OGame Vue TS is a single-player, browser-based space strategy game inspired by t
## Quick Start ## Quick Start
### Download Build Product
#### Server version
[Windows](https://github.com/coolxitech/ogame-vue-ts/releases/latest/download/ogame-windows-amd64.exe)
[Linux amd64](https://github.com/coolxitech/ogame-vue-ts/releases/latest/download/ogame-linux-amd64)
[Linux arm64](https://github.com/coolxitech/ogame-vue-ts/releases/latest/download/ogame-linux-arm64)
[MacOS Intel](https://github.com/coolxitech/ogame-vue-ts/releases/latest/download/ogame-macos-amd64)
[MacOS](https://github.com/coolxitech/ogame-vue-ts/releases/latest/download/ogame-macos-arm64)
#### Desktop version
[Windows](https://github.com/coolxitech/ogame-vue-ts/releases/latest/download/OGame.Setup.exe)
[Ubuntu](https://github.com/coolxitech/ogame-vue-ts/releases/latest/download/OGame.AppImage)
[MacOS](https://github.com/coolxitech/ogame-vue-ts/releases/latest/download/OGame-mac.dmg)
### Prerequisites ### Prerequisites
- [Node.js](https://nodejs.org/) (version 18 or higher recommended) - [Node.js](https://nodejs.org/) (version 18 or higher recommended)
- [pnpm](https://pnpm.io/) (version 10.13.1 or higher) - [pnpm](https://pnpm.io/) (version 10.13.1 or higher)
- [Go](https://golang.org/) (version 1.21 or higher recommended) (optional for binary builds)
### Installation ### Installation

View File

@@ -9,6 +9,7 @@
[![Vue 3](https://img.shields.io/badge/Vue-3.5-brightgreen.svg)](https://vuejs.org/) [![Vue 3](https://img.shields.io/badge/Vue-3.5-brightgreen.svg)](https://vuejs.org/)
[![TypeScript](https://img.shields.io/badge/TypeScript-5.9-blue.svg)](https://www.typescriptlang.org/) [![TypeScript](https://img.shields.io/badge/TypeScript-5.9-blue.svg)](https://www.typescriptlang.org/)
[![Vite](https://img.shields.io/badge/Vite-7.2-646CFF.svg)](https://vitejs.dev/) [![Vite](https://img.shields.io/badge/Vite-7.2-646CFF.svg)](https://vitejs.dev/)
[![Go](https://img.shields.io/badge/Go-1.25-79D4FD.svg)](https://golang.org/)
[English](README-EN.md) | 简体中文 [English](README-EN.md) | 简体中文
@@ -37,7 +38,7 @@ OGame Vue TS 是一款受经典 OGame 游戏启发的单机版、基于浏览器
- **前端框架:** [Vue 3](https://vuejs.org/) + Composition API (`<script setup>` 语法) - **前端框架:** [Vue 3](https://vuejs.org/) + Composition API (`<script setup>` 语法)
- **开发语言:** [TypeScript](https://www.typescriptlang.org/) (启用严格类型检查) - **开发语言:** [TypeScript](https://www.typescriptlang.org/) (启用严格类型检查)
- **构建工具:** [Vite](https://vitejs.dev/) (自定义 Rolldown-Vite 7.2.5) - **构建工具:** [Vite](https://vitejs.dev/) (自定义 Rolldown-Vite 7.2.5)、[Golang](https://golang.org/)(构建跨平台的Web服务端)、[Electron](https://www.electronjs.org/)(构建跨平台可视化界面)
- **状态管理:** [Pinia](https://pinia.vuejs.org/) + 持久化插件 - **状态管理:** [Pinia](https://pinia.vuejs.org/) + 持久化插件
- **路由管理:** [Vue Router 4](https://router.vuejs.org/) - **路由管理:** [Vue Router 4](https://router.vuejs.org/)
- **UI 组件:** [shadcn-vue](https://www.shadcn-vue.com/) (New York 风格) - **UI 组件:** [shadcn-vue](https://www.shadcn-vue.com/) (New York 风格)
@@ -48,10 +49,33 @@ OGame Vue TS 是一款受经典 OGame 游戏启发的单机版、基于浏览器
## 快速开始 ## 快速开始
### 下载构建版本
#### 服务端
[Windows](https://github.com/coolxitech/ogame-vue-ts/releases/latest/download/ogame-windows-amd64.exe)
[Linux amd64](https://github.com/coolxitech/ogame-vue-ts/releases/latest/download/ogame-linux-amd64)
[Linux arm64](https://github.com/coolxitech/ogame-vue-ts/releases/latest/download/ogame-linux-arm64)
[MacOS Intel](https://github.com/coolxitech/ogame-vue-ts/releases/latest/download/ogame-macos-amd64)
[MacOS](https://github.com/coolxitech/ogame-vue-ts/releases/latest/download/ogame-macos-arm64)
#### 桌面版
[Windows](https://github.com/coolxitech/ogame-vue-ts/releases/latest/download/OGame.Setup.exe)
[Ubuntu](https://github.com/coolxitech/ogame-vue-ts/releases/latest/download/OGame.AppImage)
[MacOS](https://github.com/coolxitech/ogame-vue-ts/releases/latest/download/OGame-mac.dmg)
### 环境要求 ### 环境要求
- [Node.js](https://nodejs.org/) (推荐 18 或更高版本) - [Node.js](https://nodejs.org/) (推荐 18 或更高版本)
- [pnpm](https://pnpm.io/) (版本 10.13.1 或更高) - [pnpm](https://pnpm.io/) (版本 10.13.1 或更高)
- [Go](https://golang.org/) (版本 1.21 或更高版本)(可选)
### 安装 ### 安装

View File

@@ -1 +0,0 @@
import{Dt as e,G as t,J as n,K as r,St as i,U as a,X as o,Y as s,Z as c,jt as l,pt as u,q as d,st as f}from"./vendor-ui-DBxeWLyT.js";import{Bt as p,Rt as m}from"./index-Cch-Ig40.js";var h={key:0,class:`fixed inset-0 z-50 flex items-center justify-center`},g={class:`relative bg-card border rounded-lg shadow-lg p-6 max-w-md w-full mx-4 z-10`},_={class:`text-lg font-semibold mb-2`},v={class:`text-sm text-muted-foreground mb-6 whitespace-pre-line`},y={class:`flex justify-end gap-2`},b=c({__name:`AlertDialog`,setup(c,{expose:b}){let{t:x}=p(),S=i(!1),C=i(null),w=e=>{C.value=e,S.value=!0},T=()=>{C.value?.onConfirm&&C.value.onConfirm(),S.value=!1},E=()=>{S.value=!1};return b({show:w}),(i,c)=>(f(),r(a,{to:`body`},[S.value?(f(),n(`div`,h,[t(`div`,{class:`fixed inset-0 bg-black/50`,onClick:E}),t(`div`,g,[t(`h2`,_,l(C.value?.title),1),t(`p`,v,l(C.value?.message),1),t(`div`,y,[C.value?.onConfirm?(f(),r(e(m),{key:0,onClick:E,variant:`outline`},{default:u(()=>[s(l(e(x)(`common.cancel`)),1)]),_:1})):d(``,!0),o(e(m),{onClick:T,variant:`default`},{default:u(()=>[s(l(e(x)(`common.confirm`)),1)]),_:1})])])])):d(``,!0)]))}});export{b as t};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
import{Dt as e,J as t,Ot as n,Z as r,st as i,ut as a}from"./vendor-ui-DBxeWLyT.js";import{zt as o}from"./index-Cch-Ig40.js";var s=r({__name:`CardDescription`,props:{class:{}},setup(r){let s=r;return(r,c)=>(i(),t(`p`,{"data-slot":`card-description`,class:n(e(o)(`text-muted-foreground text-sm`,s.class))},[a(r.$slots,`default`)],2))}});export{s as t};

View File

@@ -1,2 +0,0 @@
import{Dt as e,G as t,J as n,St as r,W as i,X as a,Y as o,Z as s,jt as c,pt as l,q as u,st as d}from"./vendor-ui-DBxeWLyT.js";import{n as f}from"./UnlockRequirement-BdFx1RC0.js";import{Bt as p,Rt as m,Vt as h,ct as g,rt as _,w as v}from"./index-Cch-Ig40.js";import{t as y}from"./useGameConfig-D2EZdt1x.js";import{t as b}from"./AlertDialog-_72FqRCT.js";var x={key:0,class:`absolute inset-0 z-10 bg-background/70 backdrop-blur-[2px] rounded-lg flex items-center justify-center`},S={class:`text-center p-4 space-y-2`},C={class:`flex justify-center`},w={class:`rounded-full bg-muted p-2`},T={class:`text-xs font-medium text-muted-foreground`},E=s({__name:`CardUnlockOverlay`,props:{requirements:{}},setup(s){let E=s,D=h(),{t:O}=p(),{BUILDINGS:k,TECHNOLOGIES:A}=y(),j=r(null),M=i(()=>!E.requirements||!D.currentPlanet?!0:v(D.currentPlanet,D.player.technologies,E.requirements)),N=()=>{if(!E.requirements||!D.currentPlanet)return``;let e=[];for(let[t,n]of Object.entries(E.requirements))if(Object.values(_).includes(t)){let r=t,i=D.currentPlanet.buildings[r]||0,a=k.value[r]?.name||r,o=i>=n?``:``;e.push(`${o} ${a}: Lv ${n} (${O(`common.current`)}: Lv ${i})`)}else if(Object.values(g).includes(t)){let r=t,i=D.player.technologies[r]||0,a=A.value[r]?.name||r,o=i>=n?``:``;e.push(`${o} ${a}: Lv ${n} (${O(`common.current`)}: Lv ${i})`)}return e.join(`
`)},P=()=>{j.value?.show({title:O(`common.requirementsNotMet`),message:N()})};return(r,i)=>M.value?u(``,!0):(d(),n(`div`,x,[t(`div`,S,[t(`div`,C,[t(`div`,w,[a(e(f),{size:20,class:`text-muted-foreground`})])]),t(`p`,T,c(e(O)(`common.locked`)),1),a(e(m),{variant:`outline`,size:`sm`,onClick:P,class:`text-xs`},{default:l(()=>[o(c(e(O)(`common.viewRequirements`)),1)]),_:1})]),a(b,{ref_key:`requirementsDialog`,ref:j},null,512)]))}});export{E as t};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
import{Dt as e,G as t,H as n,J as r,K as i,Ot as a,W as o,X as s,Y as c,Z as l,jt as u,lt as d,pt as f,q as p,st as m}from"./vendor-ui-DBxeWLyT.js";import"./vendor-vue-Bqq1sBNf.js";import{t as h}from"./CardDescription-CRV0m8La.js";import{Bt as g,D as ee,E as te,F as _,It as v,M as y,Pt as b,Rt as x,U as S,V as C,Vt as w,_t as T,dt as E,ft as D,gt as O,ht as k,j as A,lt as j,mt as M,pt as N,ut as P,vt as F}from"./index-Cch-Ig40.js";import{t as I}from"./useGameConfig-D2EZdt1x.js";var L={key:0,class:`container mx-auto p-4 sm:p-6 space-y-4 sm:space-y-6`},R={class:`text-center`},z={class:`text-2xl sm:text-3xl font-bold mb-1 sm:mb-2 flex items-center justify-center gap-2`},B={class:`text-xs sm:text-sm text-muted-foreground`},V={key:0,class:`mt-2`},H={key:1,class:`mt-2`},U={class:`flex items-center gap-2`},W={class:`grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-3 sm:gap-4`},G={class:`text-xs sm:text-sm text-muted-foreground`},K={class:`text-lg sm:text-xl font-bold`},q=l({__name:`OverviewView`,setup(l){let q=w(),{t:J}=g(),{SHIPS:Y}=I(),X=o(()=>q.currentPlanet),Z=o(()=>X.value?ee(X.value,q.player.officers):null),Q=o(()=>X.value?te(X.value,q.player.officers):null),ne=o(()=>{if(!X.value)return 0;let e=_(q.player.officers,Date.now());return y(X.value,{energyProductionBonus:e.energyProductionBonus})}),re=o(()=>X.value?A(X.value):0),ie=[{key:`metal`},{key:`crystal`},{key:`deuterium`},{key:`darkMatter`},{key:`energy`}],$=o(()=>!X.value||X.value.isMoon?null:ae(X.value.id)),ae=e=>q.player.planets.find(t=>t.isMoon&&t.parentPlanetId===e)||null,oe=()=>{$.value&&(q.currentPlanetId=$.value.id)},se=()=>{X.value?.parentPlanetId&&(q.currentPlanetId=X.value.parentPlanetId)};return(o,l)=>X.value?(m(),r(`div`,L,[t(`div`,R,[t(`h1`,z,[c(u(X.value.name)+` `,1),X.value.isMoon?(m(),i(e(v),{key:0,variant:`secondary`},{default:f(()=>[c(u(e(J)(`planet.moon`)),1)]),_:1})):p(``,!0)]),t(`p`,B,u(e(J)(`planet.position`))+`: [`+u(X.value.position.galaxy)+`:`+u(X.value.position.system)+`:`+u(X.value.position.position)+`] `,1),!X.value.isMoon&&$.value?(m(),r(`div`,V,[s(e(x),{onClick:oe,variant:`outline`,size:`sm`},{default:f(()=>[l[0]||=t(`span`,{class:`mr-2`},`🌙`,-1),c(` `+u(e(J)(`planet.switchToMoon`)),1)]),_:1})])):p(``,!0),X.value.isMoon?(m(),r(`div`,H,[s(e(x),{onClick:se,variant:`outline`,size:`sm`},{default:f(()=>[c(u(e(J)(`planet.backToPlanet`)),1)]),_:1})])):p(``,!0)]),s(e(D),null,{default:f(()=>[s(e(P),null,{default:f(()=>[s(e(j),null,{default:f(()=>[c(u(e(J)(`overview.resourceOverview`)),1)]),_:1})]),_:1}),s(e(E),null,{default:f(()=>[s(e(F),null,{default:f(()=>[s(e(N),null,{default:f(()=>[s(e(k),null,{default:f(()=>[s(e(M),null,{default:f(()=>[c(u(e(J)(`common.resourceType`)),1)]),_:1}),s(e(M),{class:`text-right`},{default:f(()=>[c(u(e(J)(`resources.current`)),1)]),_:1}),s(e(M),{class:`text-right`},{default:f(()=>[c(u(e(J)(`resources.max`)),1)]),_:1}),s(e(M),{class:`text-right`},{default:f(()=>[c(u(e(J)(`resources.production`))+u(e(J)(`resources.perHour`)),1)]),_:1})]),_:1})]),_:1}),s(e(T),null,{default:f(()=>[(m(),r(n,null,d(ie,i=>s(e(k),{key:i.key},{default:f(()=>[s(e(O),{class:`font-medium`},{default:f(()=>[t(`div`,U,[s(b,{type:i.key,size:`sm`},null,8,[`type`]),c(` `+u(e(J)(`resources.${i.key}`)),1)])]),_:2},1024),i.key===`energy`?(m(),r(n,{key:0},[s(e(O),{class:a([`text-right`,X.value.resources[i.key]>=0?`text-green-600 dark:text-green-400`:`text-red-600 dark:text-red-400`])},{default:f(()=>[c(u(e(C)(X.value.resources[i.key])),1)]),_:2},1032,[`class`]),s(e(O),{class:`text-right text-muted-foreground`},{default:f(()=>[...l[1]||=[c(`-`,-1)]]),_:1}),s(e(O),{class:`text-right text-muted-foreground`},{default:f(()=>[c(u(e(C)(ne.value))+` / `+u(e(C)(re.value)),1)]),_:1})],64)):(m(),r(n,{key:1},[s(e(O),{class:a([`text-right`,e(S)(X.value.resources[i.key],Q.value?.[i.key]||1/0)])},{default:f(()=>[c(u(e(C)(X.value.resources[i.key])),1)]),_:2},1032,[`class`]),s(e(O),{class:`text-right text-muted-foreground`},{default:f(()=>[c(u(e(C)(Q.value?.[i.key]||0)),1)]),_:2},1024),s(e(O),{class:`text-right text-muted-foreground`},{default:f(()=>[c(u(e(C)(Z.value?.[i.key]||0)),1)]),_:2},1024)],64))]),_:2},1024)),64))]),_:1})]),_:1})]),_:1})]),_:1}),s(e(D),null,{default:f(()=>[s(e(P),null,{default:f(()=>[s(e(j),null,{default:f(()=>[c(u(e(J)(`overview.fleetInfo`)),1)]),_:1}),s(e(h),null,{default:f(()=>[c(u(e(J)(`overview.currentShips`)),1)]),_:1})]),_:1}),s(e(E),null,{default:f(()=>[t(`div`,W,[(m(!0),r(n,null,d(X.value.fleet,(n,i)=>(m(),r(`div`,{key:i},[t(`p`,G,u(e(Y)[i].name),1),t(`p`,K,u(n),1)]))),128))])]),_:1})]),_:1})])):p(``,!0)}});export{q as default};

View File

@@ -1 +0,0 @@
import{Dt as e,G as t,H as n,J as r,K as ee,Ot as i,St as te,W as a,X as o,Y as s,Z as c,jt as l,lt as u,pt as d,q as ne,st as f}from"./vendor-ui-DBxeWLyT.js";import"./vendor-vue-Bqq1sBNf.js";import{t as re}from"./UnlockRequirement-BdFx1RC0.js";import{t as ie}from"./CardDescription-CRV0m8La.js";import{Bt as ae,It as p,Pt as m,Rt as h,V as g,Vt as oe,W as _,Z as v,ct as y,dt as b,ft as x,lt as S,rt as C,ut as w,v as T,w as E,y as D,yt as O}from"./index-Cch-Ig40.js";import{t as k}from"./useGameConfig-D2EZdt1x.js";import{t as A}from"./AlertDialog-_72FqRCT.js";import{t as j}from"./CardUnlockOverlay-SeY-L1Ut.js";var M={key:0,class:`container mx-auto p-4 sm:p-6`},N={class:`text-2xl sm:text-3xl font-bold mb-4 sm:mb-6`},P={class:`grid grid-cols-2 lg:grid-cols-3 gap-3 sm:gap-4`},F={class:`flex justify-between items-start gap-2`},se={class:`min-w-0 flex-1`},I={class:`space-y-2.5 sm:space-y-3`},L={class:`text-xs sm:text-sm space-y-1.5 sm:space-y-2`},R={class:`text-muted-foreground mb-1 sm:mb-2`},z={class:`space-y-1 sm:space-y-1.5`},B={class:`flex items-center gap-1.5 sm:gap-2`},V={class:`text-xs`},H={class:`flex items-center gap-1.5 sm:gap-2`},U={class:`text-xs`},W={class:`flex items-center gap-1.5 sm:gap-2`},G={class:`text-xs`},K=c({__name:`ResearchView`,setup(c){let K=oe(),ce=O(),{t:q}=ae(),{TECHNOLOGIES:J}=k(),Y=a(()=>K.currentPlanet),X=a(()=>K.player),Z=te(null),le=e=>{if(!K.currentPlanet||!D(K.currentPlanet,e,K.player.technologies,K.player.researchQueue).valid)return!1;let t=K.player.technologies[e]||0,{queueItem:n}=T(K.currentPlanet,e,t,K.player.officers);return K.player.researchQueue.push(n),!0},ue=e=>{le(e)||Z.value?.show({title:q(`researchView.researchFailed`),message:q(`researchView.researchFailedMessage`)})},Q=e=>X.value.technologies[e]||0,de=e=>{if(!Y.value||X.value.researchQueue.length>0)return!1;let t=J.value[e],n=$(e,Q(e)+1);return E(Y.value,K.player.technologies,t.requirements)&&Y.value.resources.metal>=n.metal&&Y.value.resources.crystal>=n.crystal&&Y.value.resources.deuterium>=n.deuterium},$=(e,t)=>v(e,t);return(te,a)=>Y.value?(f(),r(`div`,M,[o(re,{"required-building":e(C).ResearchLab,"required-level":1},null,8,[`required-building`]),t(`h1`,N,l(e(q)(`researchView.title`)),1),t(`div`,P,[(f(!0),r(n,null,u(Object.values(e(y)),n=>(f(),ee(e(x),{key:n,class:`relative`},{default:d(()=>[o(j,{requirements:e(J)[n].requirements},null,8,[`requirements`]),o(e(w),null,{default:d(()=>[t(`div`,F,[t(`div`,se,[o(e(S),{class:`text-base sm:text-lg cursor-pointer hover:text-primary transition-colors`,onClick:t=>e(ce).openTechnology(n,Q(n))},{default:d(()=>[s(l(e(J)[n].name),1)]),_:2},1032,[`onClick`]),o(e(ie),{class:`text-xs sm:text-sm`},{default:d(()=>[s(l(e(J)[n].description),1)]),_:2},1024)]),o(e(p),{variant:`secondary`,class:`text-xs whitespace-nowrap flex-shrink-0`},{default:d(()=>[s(`Lv `+l(Q(n)),1)]),_:2},1024)])]),_:2},1024),o(e(b),null,{default:d(()=>[t(`div`,I,[t(`div`,L,[t(`p`,R,l(e(q)(`researchView.researchCost`))+`:`,1),t(`div`,z,[t(`div`,B,[o(m,{type:`metal`,size:`sm`}),t(`span`,V,l(e(q)(`resources.metal`))+`:`,1),t(`span`,{class:i([`font-medium text-xs sm:text-sm`,e(_)(Y.value.resources.metal,$(n,Q(n)+1).metal)])},l(e(g)($(n,Q(n)+1).metal)),3)]),t(`div`,H,[o(m,{type:`crystal`,size:`sm`}),t(`span`,U,l(e(q)(`resources.crystal`))+`:`,1),t(`span`,{class:i([`font-medium text-xs sm:text-sm`,e(_)(Y.value.resources.crystal,$(n,Q(n)+1).crystal)])},l(e(g)($(n,Q(n)+1).crystal)),3)]),t(`div`,W,[o(m,{type:`deuterium`,size:`sm`}),t(`span`,G,l(e(q)(`resources.deuterium`))+`:`,1),t(`span`,{class:i([`font-medium text-xs sm:text-sm`,e(_)(Y.value.resources.deuterium,$(n,Q(n)+1).deuterium)])},l(e(g)($(n,Q(n)+1).deuterium)),3)])])]),o(e(h),{onClick:e=>ue(n),disabled:!de(n),class:`w-full`},{default:d(()=>[s(l(e(q)(`researchView.research`)),1)]),_:1},8,[`onClick`,`disabled`])])]),_:2},1024)]),_:2},1024))),128))]),o(A,{ref_key:`alertDialog`,ref:Z},null,512)])):ne(``,!0)}});export{K as default};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
import{Dt as e,G as t,J as n,W as r,X as i,Y as a,Z as o,jt as s,pt as c,q as l,st as u}from"./vendor-ui-DBxeWLyT.js";import{s as d}from"./vendor-vue-Bqq1sBNf.js";import{t as f}from"./CardDescription-CRV0m8La.js";import{At as p,Bt as m,It as h,Rt as g,Vt as _,dt as v,ft as y,jt as b,lt as x,ut as S}from"./index-Cch-Ig40.js";import{t as C}from"./useGameConfig-D2EZdt1x.js";var w=b(`lock`,[[`rect`,{width:`18`,height:`11`,x:`3`,y:`11`,rx:`2`,ry:`2`,key:`1w4ew1`}],[`path`,{d:`M7 11V7a5 5 0 0 1 10 0v4`,key:`fwvmzm`}]]),T={key:0,class:`fixed inset-0 z-50 bg-background/80 backdrop-blur-sm flex items-center justify-center p-4`},E={class:`flex justify-center mb-4`},D={class:`rounded-full bg-muted p-4`},O={class:`p-4 bg-muted rounded-lg space-y-2`},k={class:`text-sm font-medium text-center`},A={class:`flex items-center justify-center gap-2`},j={class:`text-base sm:text-lg font-bold`},M={key:0,class:`text-xs text-center text-muted-foreground`},N={class:`flex gap-2`},P=o({__name:`UnlockRequirement`,props:{requiredBuilding:{},requiredLevel:{}},setup(o){let b=o,P=d(),F=_(),{t:I}=m(),{BUILDINGS:L}=C(),R=r(()=>L.value[b.requiredBuilding]?.name||b.requiredBuilding),z=r(()=>F.currentPlanet&&F.currentPlanet.buildings[b.requiredBuilding]||0),B=r(()=>z.value>=b.requiredLevel),V=()=>{P.push(`/buildings`)};return(r,d)=>B.value?l(``,!0):(u(),n(`div`,T,[i(e(y),{class:`max-w-md w-full`},{default:c(()=>[i(e(S),{class:`text-center`},{default:c(()=>[t(`div`,E,[t(`div`,D,[i(e(w),{size:48,class:`text-muted-foreground`})])]),i(e(x),{class:`text-xl sm:text-2xl`},{default:c(()=>[a(s(e(I)(`common.featureLocked`)),1)]),_:1}),i(e(f),{class:`text-sm sm:text-base`},{default:c(()=>[a(s(e(I)(`common.unlockRequired`)),1)]),_:1})]),_:1}),i(e(v),{class:`space-y-4`},{default:c(()=>[t(`div`,O,[t(`p`,k,s(e(I)(`common.requiredBuilding`))+`:`,1),t(`div`,A,[t(`span`,j,s(R.value),1),i(e(h),{variant:`default`},{default:c(()=>[a(`Lv `+s(o.requiredLevel),1)]),_:1})]),z.value===void 0?l(``,!0):(u(),n(`p`,M,s(e(I)(`common.currentLevel`))+`: Lv `+s(z.value),1))]),t(`div`,N,[i(e(g),{onClick:V,class:`flex-1`},{default:c(()=>[i(e(p),{size:16,class:`mr-2`}),a(` `+s(e(I)(`common.goToBuildings`)),1)]),_:1})])]),_:1})]),_:1})]))}});export{w as n,P as t};

View File

@@ -1 +0,0 @@
import{jt as e}from"./index-Cch-Ig40.js";var t=e(`eye`,[[`path`,{d:`M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0`,key:`1nclc0`}],[`circle`,{cx:`12`,cy:`12`,r:`3`,key:`1v7zrd`}]]);export{t};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -1 +0,0 @@
var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),s=e=>{let n={};for(var r in e)t(n,r,{get:e[r],enumerable:!0});return n},c=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},l=(n,r,a)=>(a=n==null?{}:e(i(n)),c(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n)),u=(e=>typeof require<`u`?require:typeof Proxy<`u`?new Proxy(e,{get:(e,t)=>(typeof require<`u`?require:e)[t]}):e)(function(e){if(typeof require<`u`)return require.apply(this,arguments);throw Error('Calling `require` for "'+e+"\" in an environment that doesn't expose the `require` function.")});export{l as i,s as n,u as r,o as t};

View File

@@ -1 +0,0 @@
import{F as e,N as t,P as n,T as r,a as i,c as a,d as o,f as s,l as c,n as l,o as u,p as d,r as f,s as p,t as m,u as h}from"./index-Cch-Ig40.js";const g=(e,n,r,i)=>{let a=u(n,r);return h(n,e.buildings,i)?t(e.resources,a)?{valid:!0}:{valid:!1,reason:`errors.insufficientResources`}:{valid:!1,reason:`errors.requirementsNotMet`}},_=(t,r,a,o)=>{let c=u(r,a),l=i(r,a,e(o,Date.now()).buildingSpeedBonus);return n(t.resources,c),s(r,a,l)},v=(e,n,r,i)=>{let a=l(n,r);return p(n,e.buildings,i)?t(e.resources,a)?c(n,e.defense,r)?{valid:!0}:{valid:!1,reason:`errors.shieldDomeLimit`}:{valid:!1,reason:`errors.insufficientResources`}:{valid:!1,reason:`errors.requirementsNotMet`}},y=(t,r,i,a)=>{let s=l(r,i),c=m(r,i,e(a,Date.now()).buildingSpeedBonus);return n(t.resources,s),o(r,i,c)},b=(t,n,i,o,s=0)=>{let c=e(o,Date.now());if(s>=r(c.additionalFleetSlots))return{valid:!1,reason:`errors.fleetMissionsFull`};if(!a(t.fleet,n))return{valid:!1,reason:`errors.insufficientFleet`};let l=f(n,c.fuelConsumptionReduction,i);return t.resources.deuterium<l?{valid:!1,reason:`errors.insufficientFuel`,fuelNeeded:l}:{valid:!0,fuelNeeded:l}},x=(e,t,r,i,a)=>{d(e.fleet,t),e.resources.deuterium-=r,i&&n(e.resources,a)};export{b as a,v as i,x as n,g as o,_ as r,y as t};

View File

@@ -1 +0,0 @@
import{W as e}from"./vendor-ui-DBxeWLyT.js";import{$ as t,Bt as n,Q as r,ct as i,et as a,it as o,nt as s,ot as c,rt as l,st as u,tt as d}from"./index-Cch-Ig40.js";const f=()=>{let{t:f}=n(),p={[l.MetalMine]:`metalMine`,[l.CrystalMine]:`crystalMine`,[l.DeuteriumSynthesizer]:`deuteriumSynthesizer`,[l.SolarPlant]:`solarPlant`,[l.RoboticsFactory]:`roboticsFactory`,[l.NaniteFactory]:`naniteFactory`,[l.Shipyard]:`shipyard`,[l.ResearchLab]:`researchLab`,[l.MetalStorage]:`metalStorage`,[l.CrystalStorage]:`crystalStorage`,[l.DeuteriumTank]:`deuteriumTank`,[l.DarkMatterCollector]:`darkMatterCollector`,[l.LunarBase]:`lunarBase`,[l.SensorPhalanx]:`sensorPhalanx`,[l.JumpGate]:`jumpGate`},m={[u.LightFighter]:`lightFighter`,[u.HeavyFighter]:`heavyFighter`,[u.Cruiser]:`cruiser`,[u.Battleship]:`battleship`,[u.SmallCargo]:`smallCargo`,[u.LargeCargo]:`largeCargo`,[u.ColonyShip]:`colonyShip`,[u.Recycler]:`recycler`,[u.EspionageProbe]:`espionageProbe`,[u.DarkMatterHarvester]:`darkMatterHarvester`},h={[o.RocketLauncher]:`rocketLauncher`,[o.LightLaser]:`lightLaser`,[o.HeavyLaser]:`heavyLaser`,[o.GaussCannon]:`gaussCannon`,[o.IonCannon]:`ionCannon`,[o.PlasmaTurret]:`plasmaTurret`,[o.SmallShieldDome]:`smallShieldDome`,[o.LargeShieldDome]:`largeShieldDome`},g={[i.EnergyTechnology]:`energyTechnology`,[i.LaserTechnology]:`laserTechnology`,[i.IonTechnology]:`ionTechnology`,[i.HyperspaceTechnology]:`hyperspaceTechnology`,[i.PlasmaTechnology]:`plasmaTechnology`,[i.ComputerTechnology]:`computerTechnology`,[i.CombustionDrive]:`combustionDrive`,[i.ImpulseDrive]:`impulseDrive`,[i.HyperspaceDrive]:`hyperspaceDrive`,[i.DarkMatterTechnology]:`darkMatterTechnology`},_={[c.Commander]:`commander`,[c.Admiral]:`admiral`,[c.Engineer]:`engineer`,[c.Geologist]:`geologist`,[c.Technocrat]:`technocrat`,[c.DarkMatterSpecialist]:`darkMatterSpecialist`};return{BUILDINGS:e(()=>{let e={};for(let[t,n]of Object.entries(r)){let r=t,i=p[r];e[r]={...n,name:f(`buildings.${i}`),description:f(`buildingDescriptions.${i}`)}}return e}),SHIPS:e(()=>{let e={};for(let[t,n]of Object.entries(d)){let r=t,i=m[r];e[r]={...n,name:f(`ships.${i}`),description:f(`shipDescriptions.${i}`)}}return e}),DEFENSES:e(()=>{let e={};for(let[n,r]of Object.entries(t)){let t=n,i=h[t];e[t]={...r,name:f(`defenses.${i}`),description:f(`defenseDescriptions.${i}`)}}return e}),TECHNOLOGIES:e(()=>{let e={};for(let[t,n]of Object.entries(s)){let r=t,i=g[r];e[r]={...n,name:f(`technologies.${i}`),description:f(`technologyDescriptions.${i}`)}}return e}),OFFICERS:e(()=>{let e={};for(let[t,n]of Object.entries(a)){let r=t,i=_[r];e[r]={...n,name:f(`officers.${i}`),description:f(`officerDescriptions.${i}`)}}return e})}};export{f as t};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,24 +0,0 @@
<!DOCTYPE html>
<html lang="zh-cmn-Hans">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, viewport-fit=cover" />
<link rel="icon" type="image/svg+xml" href="./logo.svg" />
<title>OGame-Vue-Ts</title>
<script type="module" crossorigin src="./assets/index-Cch-Ig40.js"></script>
<link rel="modulepreload" crossorigin href="./assets/rolldown-runtime-CIDIeb-o.js">
<link rel="modulepreload" crossorigin href="./assets/vendor-ui-DBxeWLyT.js">
<link rel="modulepreload" crossorigin href="./assets/vendor-vue-Bqq1sBNf.js">
<link rel="stylesheet" crossorigin href="./assets/index-B25uYV3W.css">
</head>
<body>
<div id="app"></div>
<!-- 统计勿删 -->
<script charset="UTF-8" id="LA_COLLECT" src="//sdk.51.la/js-sdk-pro.min.js"></script>
<script>LA.init({ id: "L298GYqn6JhAO0VU", ck: "L298GYqn6JhAO0VU", autoTrack: true, hashMode: true })</script>
</body>
</html>

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 12 KiB

26
electron/main.ts Normal file
View File

@@ -0,0 +1,26 @@
import { app, BrowserWindow } from 'electron'
// @ts-ignore
import path from "node:path";
import { fileURLToPath } from 'node:url'
import { dirname } from 'node:path'
app.whenReady().then(() => {
// @ts-ignore
const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
const win = new BrowserWindow({
title: 'OGame',
icon: path.join(__dirname, '../public/favicon.ico'),
width: 1200,
height: 800,
})
win.setMenu(null);
// You can use `process.env.VITE_DEV_SERVER_URL` when the vite command is called `serve`
if (process.env.VITE_DEV_SERVER_URL) {
win.loadURL(process.env.VITE_DEV_SERVER_URL)
} else {
// Load your file
win.loadFile('docs/index.html');
}
})

3
go.mod Normal file
View File

@@ -0,0 +1,3 @@
module ogame
go 1.25.4

View File

@@ -13,7 +13,7 @@
<div id="app"></div> <div id="app"></div>
<script type="module" src="/src/main.ts"></script> <script type="module" src="/src/main.ts"></script>
<!-- 统计勿删 --> <!-- 统计勿删 -->
<script charset="UTF-8" id="LA_COLLECT" src="//sdk.51.la/js-sdk-pro.min.js"></script> <script charset="UTF-8" id="LA_COLLECT" src="https://sdk.51.la/js-sdk-pro.min.js"></script>
<script>LA.init({ id: "L298GYqn6JhAO0VU", ck: "L298GYqn6JhAO0VU", autoTrack: true, hashMode: true })</script> <script>LA.init({ id: "L298GYqn6JhAO0VU", ck: "L298GYqn6JhAO0VU", autoTrack: true, hashMode: true })</script>
</body> </body>

134
main.go Normal file
View File

@@ -0,0 +1,134 @@
package main
import (
"embed"
"flag"
"fmt"
"io/fs"
"net"
"net/http"
"os"
"os/exec"
"runtime"
"strings"
"time"
)
// 使用 go:embed 强制将 docs 文件夹及其所有内容打包进二进制文件
//go:embed docs/*
var content embed.FS
func main() {
// --- 1. 命令行参数配置 ---
// 定义 -port 参数,默认为 0自动分配
portPtr := flag.Int("port", 0, "指定运行端口 (例如: 8080),不指定则自动分配可用端口")
flag.Parse()
// --- 2. 静态资源处理 ---
// 获取 docs 子目录的文件系统句柄
distFS, err := fs.Sub(content, "docs")
if err != nil {
fmt.Printf("❌ 错误: 无法访问嵌入的 docs 目录: %v\n", err)
return
}
fileServer := http.FileServer(http.FS(distFS))
// 自定义路由处理:支持静态文件和 SPA (单页应用) 回退
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
// 移除路径前缀的斜杠
path := strings.TrimPrefix(r.URL.Path, "/")
// 尝试打开文件
f, err := distFS.Open(path)
if err != nil {
// 如果文件不存在(或者是访问根目录),则回退到 index.html
// 这是为了支持 Vue Router 的 History 模式
indexData, err := fs.ReadFile(distFS, "index.html")
if err != nil {
http.Error(w, "Index.html not found in embedded docs", http.StatusNotFound)
return
}
w.Header().Set("Content-Type", "text/html; charset=utf-8")
http.ServeContent(w, r, "index.html", time.Now(), strings.NewReader(string(indexData)))
return
}
f.Close()
// 如果文件存在,使用标准文件服务器响应
fileServer.ServeHTTP(w, r)
})
// --- 3. 端口监听逻辑 ---
addr := fmt.Sprintf("0.0.0.0:%d", *portPtr)
listener, err := net.Listen("tcp", addr)
if err != nil {
fmt.Printf("❌ 错误: 端口 %d 已被占用或监听失败: %v\n", *portPtr, err)
// 停留 5 秒让用户看到错误信息
time.Sleep(5 * time.Second)
os.Exit(1)
}
actualPort := listener.Addr().(*net.TCPAddr).Port
localUrl := fmt.Sprintf("http://localhost:%d", actualPort)
lanUrl := fmt.Sprintf("http://%s:%d", getLocalIp(), actualPort)
// --- 4. 控制台信息展示 ---
fmt.Println("=======================================")
fmt.Printf("🚀 OGame 服务启动成功!\n")
fmt.Printf("📅 启动时间: %s\n", time.Now().Format("2006-01-02 15:04:05"))
fmt.Printf("🔗 本地访问: %s\n", localUrl)
fmt.Printf("🌐 局域网访问: %s\n", lanUrl)
if *portPtr != 0 {
fmt.Printf("📌 运行模式: 固定端口 (%d)\n", *portPtr)
} else {
fmt.Printf("🎲 运行模式: 自动分配端口\n")
}
fmt.Println("=======================================")
fmt.Println("💡 提示: 请勿关闭此控制台窗口,否则服务将停止。")
fmt.Println("--- 实时访问日志 ---")
// --- 5. 自动打开浏览器并启动服务 ---
go openBrowser(localUrl)
err = http.Serve(listener, nil)
if err != nil {
fmt.Printf("❌ 服务运行异常: %v\n", err)
}
}
// 获取本机局域网 IP
func getLocalIp() string {
addrs, err := net.InterfaceAddrs()
if err != nil {
return "localhost"
}
for _, address := range addrs {
if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
if ipnet.IP.To4() != nil {
return ipnet.IP.String()
}
}
}
return "localhost"
}
// 根据不同操作系统自动打开默认浏览器
func openBrowser(url string) {
var cmd string
var args []string
switch runtime.GOOS {
case "windows":
cmd = "cmd"
args = []string{"/c", "start", url}
case "darwin":
cmd = "open"
args = []string{url}
default: // linux
cmd = "xdg-open"
args = []string{url}
}
_ = exec.Command(cmd, args...).Start()
}

17
nginx.conf Normal file
View File

@@ -0,0 +1,17 @@
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html index.htm;
location / {
try_files $uri $uri/ /index.html;
}
# 可选:缓存静态资源
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2?|ttf|eot) {
expires 1y;
add_header Cache-Control "public, immutable";
}
}

View File

@@ -3,14 +3,21 @@
"title": "OGame-Vue-Ts", "title": "OGame-Vue-Ts",
"qq": "920930589", "qq": "920930589",
"id": "2zBlHPUA6E", "id": "2zBlHPUA6E",
"author": "setube", "author": {
"name": "setube",
"email": "1962257451@qq.com"
},
"private": true, "private": true,
"version": "1.0.0", "version": "1.1.0",
"buildDate": "2025/12/14 13:13:07",
"main": "dist-electron/main.js",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite --port 25121", "dev": "vite --port 25121",
"build": "vue-tsc -b && vite build", "build": "vue-tsc -b && vite build && node update-build-date.js",
"preview": "vite preview" "preview": "vite preview",
"build:server": "pnpm run build && go build",
"build:electron": "pnpm run build && electron-builder"
}, },
"dependencies": { "dependencies": {
"@tailwindcss/vite": "^4.1.17", "@tailwindcss/vite": "^4.1.17",
@@ -20,10 +27,12 @@
"clsx": "^2.1.1", "clsx": "^2.1.1",
"crypto-js": "^4.2.0", "crypto-js": "^4.2.0",
"file-saver": "^2.0.5", "file-saver": "^2.0.5",
"finalhandler": "^2.1.1",
"lucide-vue-next": "^0.556.0", "lucide-vue-next": "^0.556.0",
"pinia": "^3.0.4", "pinia": "^3.0.4",
"pinia-plugin-persistedstate": "^4.7.1", "pinia-plugin-persistedstate": "^4.7.1",
"reka-ui": "^2.6.1", "reka-ui": "^2.6.1",
"serve-static": "^2.2.0",
"tailwind-merge": "^3.4.0", "tailwind-merge": "^3.4.0",
"tailwindcss": "^4.1.17", "tailwindcss": "^4.1.17",
"vue": "^3.5.24", "vue": "^3.5.24",
@@ -36,15 +45,46 @@
"@types/node": "^24.10.2", "@types/node": "^24.10.2",
"@vitejs/plugin-vue": "^6.0.1", "@vitejs/plugin-vue": "^6.0.1",
"@vue/tsconfig": "^0.8.1", "@vue/tsconfig": "^0.8.1",
"electron": "^39.2.7",
"electron-builder": "^26.0.12",
"electron-vite": "^5.0.0",
"tw-animate-css": "^1.4.0", "tw-animate-css": "^1.4.0",
"typescript": "~5.9.3", "typescript": "~5.9.3",
"vite": "npm:rolldown-vite@7.2.5", "vite": "npm:rolldown-vite@7.2.5",
"vite-plugin-electron": "^0.29.0",
"vite-plugin-electron-renderer": "^0.14.6",
"vue-tsc": "^3.1.4" "vue-tsc": "^3.1.4"
}, },
"pnpm": { "pnpm": {
"overrides": { "overrides": {
"vite": "npm:rolldown-vite@7.2.5" "vite": "npm:rolldown-vite@7.2.5"
} },
"onlyBuiltDependencies": [
"electron-winstaller",
"esbuild",
"vue-demi"
]
}, },
"packageManager": "pnpm@10.13.1+sha512.37ebf1a5c7a30d5fabe0c5df44ee8da4c965ca0c5af3dbab28c3a1681b70a256218d05c81c9c0dcf767ef6b8551eb5b960042b9ed4300c59242336377e01cfad" "packageManager": "pnpm@10.13.1+sha512.37ebf1a5c7a30d5fabe0c5df44ee8da4c965ca0c5af3dbab28c3a1681b70a256218d05c81c9c0dcf767ef6b8551eb5b960042b9ed4300c59242336377e01cfad",
"build": {
"appId": "games.wenzi.ogame",
"productName": "OGame",
"directories": {
"output": "pkg"
},
"win": {
"target": "nsis",
"icon": "public/favicon.ico",
"verifyUpdateCodeSignature": false,
"artifactName": "${productName}-Setup.${ext}"
},
"mac": {
"target": ["dmg", "zip"],
"artifactName": "${productName}-mac.${ext}"
},
"linux": {
"target": ["AppImage", "deb"],
"artifactName": "${productName}-linux.${ext}"
}
}
} }

3390
pnpm-lock.yaml generated
View File

@@ -13,7 +13,7 @@ importers:
dependencies: dependencies:
'@tailwindcss/vite': '@tailwindcss/vite':
specifier: ^4.1.17 specifier: ^4.1.17
version: 4.1.17(rolldown-vite@7.2.5(@types/node@24.10.2)(esbuild@0.27.1)(jiti@2.6.1)(terser@5.44.1)) version: 4.1.17(rolldown-vite@7.2.5(@types/node@24.10.2)(esbuild@0.25.12)(jiti@2.6.1)(terser@5.44.1))
'@tanstack/vue-table': '@tanstack/vue-table':
specifier: ^8.21.3 specifier: ^8.21.3
version: 8.21.3(vue@3.5.25(typescript@5.9.3)) version: 8.21.3(vue@3.5.25(typescript@5.9.3))
@@ -32,6 +32,9 @@ importers:
file-saver: file-saver:
specifier: ^2.0.5 specifier: ^2.0.5
version: 2.0.5 version: 2.0.5
finalhandler:
specifier: ^2.1.1
version: 2.1.1
lucide-vue-next: lucide-vue-next:
specifier: ^0.556.0 specifier: ^0.556.0
version: 0.556.0(vue@3.5.25(typescript@5.9.3)) version: 0.556.0(vue@3.5.25(typescript@5.9.3))
@@ -44,6 +47,9 @@ importers:
reka-ui: reka-ui:
specifier: ^2.6.1 specifier: ^2.6.1
version: 2.6.1(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3)) version: 2.6.1(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3))
serve-static:
specifier: ^2.2.0
version: 2.2.0
tailwind-merge: tailwind-merge:
specifier: ^3.4.0 specifier: ^3.4.0
version: 3.4.0 version: 3.4.0
@@ -71,16 +77,19 @@ importers:
version: 24.10.2 version: 24.10.2
'@vitejs/plugin-vue': '@vitejs/plugin-vue':
specifier: ^6.0.1 specifier: ^6.0.1
version: 6.0.2(rolldown-vite@7.2.5(@types/node@24.10.2)(esbuild@0.27.1)(jiti@2.6.1)(terser@5.44.1))(vue@3.5.25(typescript@5.9.3)) version: 6.0.2(rolldown-vite@7.2.5(@types/node@24.10.2)(esbuild@0.25.12)(jiti@2.6.1)(terser@5.44.1))(vue@3.5.25(typescript@5.9.3))
'@vue/tsconfig': '@vue/tsconfig':
specifier: ^0.8.1 specifier: ^0.8.1
version: 0.8.1(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3)) version: 0.8.1(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3))
esbuild: electron:
specifier: ^0.27.1 specifier: ^39.2.7
version: 0.27.1 version: 39.2.7
terser: electron-builder:
specifier: ^5.44.1 specifier: ^26.0.12
version: 5.44.1 version: 26.0.12(electron-builder-squirrel-windows@26.0.12)
electron-vite:
specifier: ^5.0.0
version: 5.0.0(rolldown-vite@7.2.5(@types/node@24.10.2)(esbuild@0.25.12)(jiti@2.6.1)(terser@5.44.1))
tw-animate-css: tw-animate-css:
specifier: ^1.4.0 specifier: ^1.4.0
version: 1.4.0 version: 1.4.0
@@ -89,13 +98,60 @@ importers:
version: 5.9.3 version: 5.9.3
vite: vite:
specifier: npm:rolldown-vite@7.2.5 specifier: npm:rolldown-vite@7.2.5
version: rolldown-vite@7.2.5(@types/node@24.10.2)(esbuild@0.27.1)(jiti@2.6.1)(terser@5.44.1) version: rolldown-vite@7.2.5(@types/node@24.10.2)(esbuild@0.25.12)(jiti@2.6.1)(terser@5.44.1)
vite-plugin-electron:
specifier: ^0.29.0
version: 0.29.0(vite-plugin-electron-renderer@0.14.6)
vite-plugin-electron-renderer:
specifier: ^0.14.6
version: 0.14.6
vue-tsc: vue-tsc:
specifier: ^3.1.4 specifier: ^3.1.4
version: 3.1.8(typescript@5.9.3) version: 3.1.8(typescript@5.9.3)
packages: packages:
7zip-bin@5.2.0:
resolution: {integrity: sha512-ukTPVhqG4jNzMro2qA9HSCSSVJN3aN7tlb+hfqYCt3ER0yWroeA2VR38MNrOHLQ/cVj+DaIMad0kFCtWWowh/A==}
'@babel/code-frame@7.27.1':
resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==}
engines: {node: '>=6.9.0'}
'@babel/compat-data@7.28.5':
resolution: {integrity: sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==}
engines: {node: '>=6.9.0'}
'@babel/core@7.28.5':
resolution: {integrity: sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==}
engines: {node: '>=6.9.0'}
'@babel/generator@7.28.5':
resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==}
engines: {node: '>=6.9.0'}
'@babel/helper-compilation-targets@7.27.2':
resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==}
engines: {node: '>=6.9.0'}
'@babel/helper-globals@7.28.0':
resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==}
engines: {node: '>=6.9.0'}
'@babel/helper-module-imports@7.27.1':
resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==}
engines: {node: '>=6.9.0'}
'@babel/helper-module-transforms@7.28.3':
resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0
'@babel/helper-plugin-utils@7.27.1':
resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==}
engines: {node: '>=6.9.0'}
'@babel/helper-string-parser@7.27.1': '@babel/helper-string-parser@7.27.1':
resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
@@ -104,15 +160,88 @@ packages:
resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
'@babel/helper-validator-option@7.27.1':
resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==}
engines: {node: '>=6.9.0'}
'@babel/helpers@7.28.4':
resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==}
engines: {node: '>=6.9.0'}
'@babel/parser@7.28.5': '@babel/parser@7.28.5':
resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==}
engines: {node: '>=6.0.0'} engines: {node: '>=6.0.0'}
hasBin: true hasBin: true
'@babel/plugin-transform-arrow-functions@7.27.1':
resolution: {integrity: sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
'@babel/template@7.27.2':
resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==}
engines: {node: '>=6.9.0'}
'@babel/traverse@7.28.5':
resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==}
engines: {node: '>=6.9.0'}
'@babel/types@7.28.5': '@babel/types@7.28.5':
resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
'@develar/schema-utils@2.6.5':
resolution: {integrity: sha512-0cp4PsWQ/9avqTVMCtZ+GirikIA36ikvjtHweU4/j8yLtgObI0+JUPhYFScgwlteveGB1rt3Cm8UhN04XayDig==}
engines: {node: '>= 8.9.0'}
'@electron/asar@3.2.18':
resolution: {integrity: sha512-2XyvMe3N3Nrs8cV39IKELRHTYUWFKrmqqSY1U+GMlc0jvqjIVnoxhNd2H4JolWQncbJi1DCvb5TNxZuI2fEjWg==}
engines: {node: '>=10.12.0'}
hasBin: true
'@electron/asar@3.4.1':
resolution: {integrity: sha512-i4/rNPRS84t0vSRa2HorerGRXWyF4vThfHesw0dmcWHp+cspK743UanA0suA5Q5y8kzY2y6YKrvbIUn69BCAiA==}
engines: {node: '>=10.12.0'}
hasBin: true
'@electron/fuses@1.8.0':
resolution: {integrity: sha512-zx0EIq78WlY/lBb1uXlziZmDZI4ubcCXIMJ4uGjXzZW0nS19TjSPeXPAjzzTmKQlJUZm0SbmZhPKP7tuQ1SsEw==}
hasBin: true
'@electron/get@2.0.3':
resolution: {integrity: sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==}
engines: {node: '>=12'}
'@electron/node-gyp@https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2':
resolution: {tarball: https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2}
version: 10.2.0-electron.1
engines: {node: '>=12.13.0'}
hasBin: true
'@electron/notarize@2.5.0':
resolution: {integrity: sha512-jNT8nwH1f9X5GEITXaQ8IF/KdskvIkOFfB2CvwumsveVidzpSc+mvhhTMdAGSYF3O+Nq49lJ7y+ssODRXu06+A==}
engines: {node: '>= 10.0.0'}
'@electron/osx-sign@1.3.1':
resolution: {integrity: sha512-BAfviURMHpmb1Yb50YbCxnOY0wfwaLXH5KJ4+80zS0gUkzDX3ec23naTlEqKsN+PwYn+a1cCzM7BJ4Wcd3sGzw==}
engines: {node: '>=12.0.0'}
hasBin: true
'@electron/rebuild@3.7.0':
resolution: {integrity: sha512-VW++CNSlZwMYP7MyXEbrKjpzEwhB5kDNbzGtiPEjwYysqyTCF+YbNJ210Dj3AjWsGSV4iEEwNkmJN9yGZmVvmw==}
engines: {node: '>=12.13.0'}
hasBin: true
'@electron/universal@2.0.1':
resolution: {integrity: sha512-fKpv9kg4SPmt+hY7SVBnIYULE9QJl8L3sCfcBsnqbJwwBwAeTLokJ9TRt9y7bK0JAzIW2y78TVVjvnQEms/yyA==}
engines: {node: '>=16.4'}
'@electron/windows-sign@1.2.2':
resolution: {integrity: sha512-dfZeox66AvdPtb2lD8OsIIQh12Tp0GNCRUDfBHIKGpbmopZto2/A8nSpYYLoedPIHpqkeblZ/k8OV0Gy7PYuyQ==}
engines: {node: '>=14.14'}
hasBin: true
'@emnapi/core@1.7.1': '@emnapi/core@1.7.1':
resolution: {integrity: sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==} resolution: {integrity: sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==}
@@ -122,158 +251,158 @@ packages:
'@emnapi/wasi-threads@1.1.0': '@emnapi/wasi-threads@1.1.0':
resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==}
'@esbuild/aix-ppc64@0.27.1': '@esbuild/aix-ppc64@0.25.12':
resolution: {integrity: sha512-HHB50pdsBX6k47S4u5g/CaLjqS3qwaOVE5ILsq64jyzgMhLuCuZ8rGzM9yhsAjfjkbgUPMzZEPa7DAp7yz6vuA==} resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==}
engines: {node: '>=18'} engines: {node: '>=18'}
cpu: [ppc64] cpu: [ppc64]
os: [aix] os: [aix]
'@esbuild/android-arm64@0.27.1': '@esbuild/android-arm64@0.25.12':
resolution: {integrity: sha512-45fuKmAJpxnQWixOGCrS+ro4Uvb4Re9+UTieUY2f8AEc+t7d4AaZ6eUJ3Hva7dtrxAAWHtlEFsXFMAgNnGU9uQ==} resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==}
engines: {node: '>=18'} engines: {node: '>=18'}
cpu: [arm64] cpu: [arm64]
os: [android] os: [android]
'@esbuild/android-arm@0.27.1': '@esbuild/android-arm@0.25.12':
resolution: {integrity: sha512-kFqa6/UcaTbGm/NncN9kzVOODjhZW8e+FRdSeypWe6j33gzclHtwlANs26JrupOntlcWmB0u8+8HZo8s7thHvg==} resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==}
engines: {node: '>=18'} engines: {node: '>=18'}
cpu: [arm] cpu: [arm]
os: [android] os: [android]
'@esbuild/android-x64@0.27.1': '@esbuild/android-x64@0.25.12':
resolution: {integrity: sha512-LBEpOz0BsgMEeHgenf5aqmn/lLNTFXVfoWMUox8CtWWYK9X4jmQzWjoGoNb8lmAYml/tQ/Ysvm8q7szu7BoxRQ==} resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==}
engines: {node: '>=18'} engines: {node: '>=18'}
cpu: [x64] cpu: [x64]
os: [android] os: [android]
'@esbuild/darwin-arm64@0.27.1': '@esbuild/darwin-arm64@0.25.12':
resolution: {integrity: sha512-veg7fL8eMSCVKL7IW4pxb54QERtedFDfY/ASrumK/SbFsXnRazxY4YykN/THYqFnFwJ0aVjiUrVG2PwcdAEqQQ==} resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==}
engines: {node: '>=18'} engines: {node: '>=18'}
cpu: [arm64] cpu: [arm64]
os: [darwin] os: [darwin]
'@esbuild/darwin-x64@0.27.1': '@esbuild/darwin-x64@0.25.12':
resolution: {integrity: sha512-+3ELd+nTzhfWb07Vol7EZ+5PTbJ/u74nC6iv4/lwIU99Ip5uuY6QoIf0Hn4m2HoV0qcnRivN3KSqc+FyCHjoVQ==} resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==}
engines: {node: '>=18'} engines: {node: '>=18'}
cpu: [x64] cpu: [x64]
os: [darwin] os: [darwin]
'@esbuild/freebsd-arm64@0.27.1': '@esbuild/freebsd-arm64@0.25.12':
resolution: {integrity: sha512-/8Rfgns4XD9XOSXlzUDepG8PX+AVWHliYlUkFI3K3GB6tqbdjYqdhcb4BKRd7C0BhZSoaCxhv8kTcBrcZWP+xg==} resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==}
engines: {node: '>=18'} engines: {node: '>=18'}
cpu: [arm64] cpu: [arm64]
os: [freebsd] os: [freebsd]
'@esbuild/freebsd-x64@0.27.1': '@esbuild/freebsd-x64@0.25.12':
resolution: {integrity: sha512-GITpD8dK9C+r+5yRT/UKVT36h/DQLOHdwGVwwoHidlnA168oD3uxA878XloXebK4Ul3gDBBIvEdL7go9gCUFzQ==} resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==}
engines: {node: '>=18'} engines: {node: '>=18'}
cpu: [x64] cpu: [x64]
os: [freebsd] os: [freebsd]
'@esbuild/linux-arm64@0.27.1': '@esbuild/linux-arm64@0.25.12':
resolution: {integrity: sha512-W9//kCrh/6in9rWIBdKaMtuTTzNj6jSeG/haWBADqLLa9P8O5YSRDzgD5y9QBok4AYlzS6ARHifAb75V6G670Q==} resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==}
engines: {node: '>=18'} engines: {node: '>=18'}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
'@esbuild/linux-arm@0.27.1': '@esbuild/linux-arm@0.25.12':
resolution: {integrity: sha512-ieMID0JRZY/ZeCrsFQ3Y3NlHNCqIhTprJfDgSB3/lv5jJZ8FX3hqPyXWhe+gvS5ARMBJ242PM+VNz/ctNj//eA==} resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==}
engines: {node: '>=18'} engines: {node: '>=18'}
cpu: [arm] cpu: [arm]
os: [linux] os: [linux]
'@esbuild/linux-ia32@0.27.1': '@esbuild/linux-ia32@0.25.12':
resolution: {integrity: sha512-VIUV4z8GD8rtSVMfAj1aXFahsi/+tcoXXNYmXgzISL+KB381vbSTNdeZHHHIYqFyXcoEhu9n5cT+05tRv13rlw==} resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==}
engines: {node: '>=18'} engines: {node: '>=18'}
cpu: [ia32] cpu: [ia32]
os: [linux] os: [linux]
'@esbuild/linux-loong64@0.27.1': '@esbuild/linux-loong64@0.25.12':
resolution: {integrity: sha512-l4rfiiJRN7sTNI//ff65zJ9z8U+k6zcCg0LALU5iEWzY+a1mVZ8iWC1k5EsNKThZ7XCQ6YWtsZ8EWYm7r1UEsg==} resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==}
engines: {node: '>=18'} engines: {node: '>=18'}
cpu: [loong64] cpu: [loong64]
os: [linux] os: [linux]
'@esbuild/linux-mips64el@0.27.1': '@esbuild/linux-mips64el@0.25.12':
resolution: {integrity: sha512-U0bEuAOLvO/DWFdygTHWY8C067FXz+UbzKgxYhXC0fDieFa0kDIra1FAhsAARRJbvEyso8aAqvPdNxzWuStBnA==} resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==}
engines: {node: '>=18'} engines: {node: '>=18'}
cpu: [mips64el] cpu: [mips64el]
os: [linux] os: [linux]
'@esbuild/linux-ppc64@0.27.1': '@esbuild/linux-ppc64@0.25.12':
resolution: {integrity: sha512-NzdQ/Xwu6vPSf/GkdmRNsOfIeSGnh7muundsWItmBsVpMoNPVpM61qNzAVY3pZ1glzzAxLR40UyYM23eaDDbYQ==} resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==}
engines: {node: '>=18'} engines: {node: '>=18'}
cpu: [ppc64] cpu: [ppc64]
os: [linux] os: [linux]
'@esbuild/linux-riscv64@0.27.1': '@esbuild/linux-riscv64@0.25.12':
resolution: {integrity: sha512-7zlw8p3IApcsN7mFw0O1Z1PyEk6PlKMu18roImfl3iQHTnr/yAfYv6s4hXPidbDoI2Q0pW+5xeoM4eTCC0UdrQ==} resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==}
engines: {node: '>=18'} engines: {node: '>=18'}
cpu: [riscv64] cpu: [riscv64]
os: [linux] os: [linux]
'@esbuild/linux-s390x@0.27.1': '@esbuild/linux-s390x@0.25.12':
resolution: {integrity: sha512-cGj5wli+G+nkVQdZo3+7FDKC25Uh4ZVwOAK6A06Hsvgr8WqBBuOy/1s+PUEd/6Je+vjfm6stX0kmib5b/O2Ykw==} resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==}
engines: {node: '>=18'} engines: {node: '>=18'}
cpu: [s390x] cpu: [s390x]
os: [linux] os: [linux]
'@esbuild/linux-x64@0.27.1': '@esbuild/linux-x64@0.25.12':
resolution: {integrity: sha512-z3H/HYI9MM0HTv3hQZ81f+AKb+yEoCRlUby1F80vbQ5XdzEMyY/9iNlAmhqiBKw4MJXwfgsh7ERGEOhrM1niMA==} resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==}
engines: {node: '>=18'} engines: {node: '>=18'}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
'@esbuild/netbsd-arm64@0.27.1': '@esbuild/netbsd-arm64@0.25.12':
resolution: {integrity: sha512-wzC24DxAvk8Em01YmVXyjl96Mr+ecTPyOuADAvjGg+fyBpGmxmcr2E5ttf7Im8D0sXZihpxzO1isus8MdjMCXQ==} resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==}
engines: {node: '>=18'} engines: {node: '>=18'}
cpu: [arm64] cpu: [arm64]
os: [netbsd] os: [netbsd]
'@esbuild/netbsd-x64@0.27.1': '@esbuild/netbsd-x64@0.25.12':
resolution: {integrity: sha512-1YQ8ybGi2yIXswu6eNzJsrYIGFpnlzEWRl6iR5gMgmsrR0FcNoV1m9k9sc3PuP5rUBLshOZylc9nqSgymI+TYg==} resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==}
engines: {node: '>=18'} engines: {node: '>=18'}
cpu: [x64] cpu: [x64]
os: [netbsd] os: [netbsd]
'@esbuild/openbsd-arm64@0.27.1': '@esbuild/openbsd-arm64@0.25.12':
resolution: {integrity: sha512-5Z+DzLCrq5wmU7RDaMDe2DVXMRm2tTDvX2KU14JJVBN2CT/qov7XVix85QoJqHltpvAOZUAc3ndU56HSMWrv8g==} resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==}
engines: {node: '>=18'} engines: {node: '>=18'}
cpu: [arm64] cpu: [arm64]
os: [openbsd] os: [openbsd]
'@esbuild/openbsd-x64@0.27.1': '@esbuild/openbsd-x64@0.25.12':
resolution: {integrity: sha512-Q73ENzIdPF5jap4wqLtsfh8YbYSZ8Q0wnxplOlZUOyZy7B4ZKW8DXGWgTCZmF8VWD7Tciwv5F4NsRf6vYlZtqg==} resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==}
engines: {node: '>=18'} engines: {node: '>=18'}
cpu: [x64] cpu: [x64]
os: [openbsd] os: [openbsd]
'@esbuild/openharmony-arm64@0.27.1': '@esbuild/openharmony-arm64@0.25.12':
resolution: {integrity: sha512-ajbHrGM/XiK+sXM0JzEbJAen+0E+JMQZ2l4RR4VFwvV9JEERx+oxtgkpoKv1SevhjavK2z2ReHk32pjzktWbGg==} resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==}
engines: {node: '>=18'} engines: {node: '>=18'}
cpu: [arm64] cpu: [arm64]
os: [openharmony] os: [openharmony]
'@esbuild/sunos-x64@0.27.1': '@esbuild/sunos-x64@0.25.12':
resolution: {integrity: sha512-IPUW+y4VIjuDVn+OMzHc5FV4GubIwPnsz6ubkvN8cuhEqH81NovB53IUlrlBkPMEPxvNnf79MGBoz8rZ2iW8HA==} resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==}
engines: {node: '>=18'} engines: {node: '>=18'}
cpu: [x64] cpu: [x64]
os: [sunos] os: [sunos]
'@esbuild/win32-arm64@0.27.1': '@esbuild/win32-arm64@0.25.12':
resolution: {integrity: sha512-RIVRWiljWA6CdVu8zkWcRmGP7iRRIIwvhDKem8UMBjPql2TXM5PkDVvvrzMtj1V+WFPB4K7zkIGM7VzRtFkjdg==} resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==}
engines: {node: '>=18'} engines: {node: '>=18'}
cpu: [arm64] cpu: [arm64]
os: [win32] os: [win32]
'@esbuild/win32-ia32@0.27.1': '@esbuild/win32-ia32@0.25.12':
resolution: {integrity: sha512-2BR5M8CPbptC1AK5JbJT1fWrHLvejwZidKx3UMSF0ecHMa+smhi16drIrCEggkgviBwLYd5nwrFLSl5Kho96RQ==} resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==}
engines: {node: '>=18'} engines: {node: '>=18'}
cpu: [ia32] cpu: [ia32]
os: [win32] os: [win32]
'@esbuild/win32-x64@0.27.1': '@esbuild/win32-x64@0.25.12':
resolution: {integrity: sha512-d5X6RMYv6taIymSk8JBP+nxv8DQAMY6A51GPgusqLdK9wBz5wWIXy1KjTck6HnjE9hqJzJRdk+1p/t5soSbCtw==} resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==}
engines: {node: '>=18'} engines: {node: '>=18'}
cpu: [x64] cpu: [x64]
os: [win32] os: [win32]
@@ -290,12 +419,27 @@ packages:
'@floating-ui/vue@1.1.9': '@floating-ui/vue@1.1.9':
resolution: {integrity: sha512-BfNqNW6KA83Nexspgb9DZuz578R7HT8MZw1CfK9I6Ah4QReNWEJsXWHN+SdmOVLNGmTPDi+fDT535Df5PzMLbQ==} resolution: {integrity: sha512-BfNqNW6KA83Nexspgb9DZuz578R7HT8MZw1CfK9I6Ah4QReNWEJsXWHN+SdmOVLNGmTPDi+fDT535Df5PzMLbQ==}
'@gar/promisify@1.1.3':
resolution: {integrity: sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==}
'@internationalized/date@3.10.0': '@internationalized/date@3.10.0':
resolution: {integrity: sha512-oxDR/NTEJ1k+UFVQElaNIk65E/Z83HK1z1WI3lQyhTtnNg4R5oVXaPzK3jcpKG8UHKDVuDQHzn+wsxSz8RP3aw==} resolution: {integrity: sha512-oxDR/NTEJ1k+UFVQElaNIk65E/Z83HK1z1WI3lQyhTtnNg4R5oVXaPzK3jcpKG8UHKDVuDQHzn+wsxSz8RP3aw==}
'@internationalized/number@3.6.5': '@internationalized/number@3.6.5':
resolution: {integrity: sha512-6hY4Kl4HPBvtfS62asS/R22JzNNy8vi/Ssev7x6EobfCp+9QIB2hKvI2EtbdJ0VSQacxVNtqhE/NmF/NZ0gm6g==} resolution: {integrity: sha512-6hY4Kl4HPBvtfS62asS/R22JzNNy8vi/Ssev7x6EobfCp+9QIB2hKvI2EtbdJ0VSQacxVNtqhE/NmF/NZ0gm6g==}
'@isaacs/balanced-match@4.0.1':
resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==}
engines: {node: 20 || >=22}
'@isaacs/brace-expansion@5.0.0':
resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==}
engines: {node: 20 || >=22}
'@isaacs/cliui@8.0.2':
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
engines: {node: '>=12'}
'@jridgewell/gen-mapping@0.3.13': '@jridgewell/gen-mapping@0.3.13':
resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
@@ -315,9 +459,26 @@ packages:
'@jridgewell/trace-mapping@0.3.31': '@jridgewell/trace-mapping@0.3.31':
resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
'@malept/cross-spawn-promise@2.0.0':
resolution: {integrity: sha512-1DpKU0Z5ThltBwjNySMC14g0CkbyhCaz9FkhxqNsZI6uAPJXFS8cMXlBKo26FJ8ZuW6S9GCMcR9IO5k2X5/9Fg==}
engines: {node: '>= 12.13.0'}
'@malept/flatpak-bundler@0.4.0':
resolution: {integrity: sha512-9QOtNffcOF/c1seMCDnjckb3R9WHcG34tky+FHpNKKCW0wc/scYLwMtO+ptyGUfMW0/b/n4qRiALlaFHc9Oj7Q==}
engines: {node: '>= 10.0.0'}
'@napi-rs/wasm-runtime@1.1.0': '@napi-rs/wasm-runtime@1.1.0':
resolution: {integrity: sha512-Fq6DJW+Bb5jaWE69/qOE0D1TUN9+6uWhCeZpdnSBk14pjLcCWR7Q8n49PTSPHazM37JqrsdpEthXy2xn6jWWiA==} resolution: {integrity: sha512-Fq6DJW+Bb5jaWE69/qOE0D1TUN9+6uWhCeZpdnSBk14pjLcCWR7Q8n49PTSPHazM37JqrsdpEthXy2xn6jWWiA==}
'@npmcli/fs@2.1.2':
resolution: {integrity: sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==}
engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
'@npmcli/move-file@2.0.1':
resolution: {integrity: sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==}
engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
deprecated: This functionality has been moved to @npmcli/fs
'@oxc-project/runtime@0.97.0': '@oxc-project/runtime@0.97.0':
resolution: {integrity: sha512-yH0zw7z+jEws4dZ4IUKoix5Lh3yhqIJWF9Dc8PWvhpo7U7O+lJrv7ZZL4BeRO0la8LBQFwcCewtLBnVV7hPe/w==} resolution: {integrity: sha512-yH0zw7z+jEws4dZ4IUKoix5Lh3yhqIJWF9Dc8PWvhpo7U7O+lJrv7ZZL4BeRO0la8LBQFwcCewtLBnVV7hPe/w==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
@@ -325,6 +486,10 @@ packages:
'@oxc-project/types@0.97.0': '@oxc-project/types@0.97.0':
resolution: {integrity: sha512-lxmZK4xFrdvU0yZiDwgVQTCvh2gHWBJCBk5ALsrtsBWhs0uDIi+FTOnXRQeQfs304imdvTdaakT/lqwQ8hkOXQ==} resolution: {integrity: sha512-lxmZK4xFrdvU0yZiDwgVQTCvh2gHWBJCBk5ALsrtsBWhs0uDIi+FTOnXRQeQfs304imdvTdaakT/lqwQ8hkOXQ==}
'@pkgjs/parseargs@0.11.0':
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
engines: {node: '>=14'}
'@rolldown/binding-android-arm64@1.0.0-beta.50': '@rolldown/binding-android-arm64@1.0.0-beta.50':
resolution: {integrity: sha512-XlEkrOIHLyGT3avOgzfTFSjG+f+dZMw+/qd+Y3HLN86wlndrB/gSimrJCk4gOhr1XtRtEKfszpadI3Md4Z4/Ag==} resolution: {integrity: sha512-XlEkrOIHLyGT3avOgzfTFSjG+f+dZMw+/qd+Y3HLN86wlndrB/gSimrJCk4gOhr1XtRtEKfszpadI3Md4Z4/Ag==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
@@ -415,9 +580,17 @@ packages:
'@rolldown/pluginutils@1.0.0-beta.50': '@rolldown/pluginutils@1.0.0-beta.50':
resolution: {integrity: sha512-5e76wQiQVeL1ICOZVUg4LSOVYg9jyhGCin+icYozhsUzM+fHE7kddi1bdiE0jwVqTfkjba3jUFbEkoC9WkdvyA==} resolution: {integrity: sha512-5e76wQiQVeL1ICOZVUg4LSOVYg9jyhGCin+icYozhsUzM+fHE7kddi1bdiE0jwVqTfkjba3jUFbEkoC9WkdvyA==}
'@sindresorhus/is@4.6.0':
resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==}
engines: {node: '>=10'}
'@swc/helpers@0.5.17': '@swc/helpers@0.5.17':
resolution: {integrity: sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==} resolution: {integrity: sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==}
'@szmarczak/http-timer@4.0.6':
resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==}
engines: {node: '>=10'}
'@tailwindcss/node@4.1.17': '@tailwindcss/node@4.1.17':
resolution: {integrity: sha512-csIkHIgLb3JisEFQ0vxr2Y57GUNYh447C8xzwj89U/8fdW8LhProdxvnVH6U8M2Y73QKiTIH+LWbK3V2BBZsAg==} resolution: {integrity: sha512-csIkHIgLb3JisEFQ0vxr2Y57GUNYh447C8xzwj89U/8fdW8LhProdxvnVH6U8M2Y73QKiTIH+LWbK3V2BBZsAg==}
@@ -530,21 +703,58 @@ packages:
peerDependencies: peerDependencies:
vue: ^2.7.0 || ^3.0.0 vue: ^2.7.0 || ^3.0.0
'@tootallnate/once@2.0.0':
resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==}
engines: {node: '>= 10'}
'@tybys/wasm-util@0.10.1': '@tybys/wasm-util@0.10.1':
resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==}
'@types/cacheable-request@6.0.3':
resolution: {integrity: sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==}
'@types/crypto-js@4.2.2': '@types/crypto-js@4.2.2':
resolution: {integrity: sha512-sDOLlVbHhXpAUAL0YHDUUwDZf3iN4Bwi4W6a0W0b+QcAezUbRtH4FVb+9J4h+XFPW7l/gQ9F8qC7P+Ec4k8QVQ==} resolution: {integrity: sha512-sDOLlVbHhXpAUAL0YHDUUwDZf3iN4Bwi4W6a0W0b+QcAezUbRtH4FVb+9J4h+XFPW7l/gQ9F8qC7P+Ec4k8QVQ==}
'@types/debug@4.1.12':
resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==}
'@types/file-saver@2.0.7': '@types/file-saver@2.0.7':
resolution: {integrity: sha512-dNKVfHd/jk0SkR/exKGj2ggkB45MAkzvWCaqLUUgkyjITkGNzH8H+yUwr+BLJUBjZOe9w8X3wgmXhZDRg1ED6A==} resolution: {integrity: sha512-dNKVfHd/jk0SkR/exKGj2ggkB45MAkzvWCaqLUUgkyjITkGNzH8H+yUwr+BLJUBjZOe9w8X3wgmXhZDRg1ED6A==}
'@types/fs-extra@9.0.13':
resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==}
'@types/http-cache-semantics@4.0.4':
resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==}
'@types/keyv@3.1.4':
resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==}
'@types/ms@2.1.0':
resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==}
'@types/node@22.19.3':
resolution: {integrity: sha512-1N9SBnWYOJTrNZCdh/yJE+t910Y128BoyY+zBLWhL3r0TYzlTmFdXrPwHL9DyFZmlEXNQQolTZh3KHV31QDhyA==}
'@types/node@24.10.2': '@types/node@24.10.2':
resolution: {integrity: sha512-WOhQTZ4G8xZ1tjJTvKOpyEVSGgOTvJAfDK3FNFgELyaTpzhdgHVHeqW8V+UJvzF5BT+/B54T/1S2K6gd9c7bbA==} resolution: {integrity: sha512-WOhQTZ4G8xZ1tjJTvKOpyEVSGgOTvJAfDK3FNFgELyaTpzhdgHVHeqW8V+UJvzF5BT+/B54T/1S2K6gd9c7bbA==}
'@types/plist@3.0.5':
resolution: {integrity: sha512-E6OCaRmAe4WDmWNsL/9RMqdkkzDCY1etutkflWk4c+AcjDU07Pcz1fQwTX0TQz+Pxqn9i4L1TU3UFpjnrcDgxA==}
'@types/responselike@1.0.3':
resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==}
'@types/verror@1.10.11':
resolution: {integrity: sha512-RlDm9K7+o5stv0Co8i8ZRGxDbrTxhJtgjqjFyVh/tXQyl/rYtTKlnTvZ88oSTeYREWurwx20Js4kTuKCsFkUtg==}
'@types/web-bluetooth@0.0.21': '@types/web-bluetooth@0.0.21':
resolution: {integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==} resolution: {integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==}
'@types/yauzl@2.10.3':
resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==}
'@vitejs/plugin-vue@6.0.2': '@vitejs/plugin-vue@6.0.2':
resolution: {integrity: sha512-iHmwV3QcVGGvSC1BG5bZ4z6iwa1SOpAPWmnjOErd4Ske+lZua5K9TtAVdx0gMBClJ28DViCbSmZitjWZsWO3LA==} resolution: {integrity: sha512-iHmwV3QcVGGvSC1BG5bZ4z6iwa1SOpAPWmnjOErd4Ske+lZua5K9TtAVdx0gMBClJ28DViCbSmZitjWZsWO3LA==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
@@ -643,51 +853,408 @@ packages:
peerDependencies: peerDependencies:
vue: ^3.5.0 vue: ^3.5.0
'@xmldom/xmldom@0.8.11':
resolution: {integrity: sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==}
engines: {node: '>=10.0.0'}
abbrev@1.1.1:
resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==}
acorn@8.15.0: acorn@8.15.0:
resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==}
engines: {node: '>=0.4.0'} engines: {node: '>=0.4.0'}
hasBin: true hasBin: true
agent-base@6.0.2:
resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}
engines: {node: '>= 6.0.0'}
agent-base@7.1.4:
resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==}
engines: {node: '>= 14'}
agentkeepalive@4.6.0:
resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==}
engines: {node: '>= 8.0.0'}
aggregate-error@3.1.0:
resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==}
engines: {node: '>=8'}
ajv-keywords@3.5.2:
resolution: {integrity: sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==}
peerDependencies:
ajv: ^6.9.1
ajv@6.12.6:
resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
alien-signals@3.1.1: alien-signals@3.1.1:
resolution: {integrity: sha512-ogkIWbVrLwKtHY6oOAXaYkAxP+cTH7V5FZ5+Tm4NZFd8VDZ6uNMDrfzqctTZ42eTMCSR3ne3otpcxmqSnFfPYA==} resolution: {integrity: sha512-ogkIWbVrLwKtHY6oOAXaYkAxP+cTH7V5FZ5+Tm4NZFd8VDZ6uNMDrfzqctTZ42eTMCSR3ne3otpcxmqSnFfPYA==}
ansi-regex@5.0.1:
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
engines: {node: '>=8'}
ansi-regex@6.2.2:
resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==}
engines: {node: '>=12'}
ansi-styles@4.3.0:
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
engines: {node: '>=8'}
ansi-styles@6.2.3:
resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==}
engines: {node: '>=12'}
app-builder-bin@5.0.0-alpha.12:
resolution: {integrity: sha512-j87o0j6LqPL3QRr8yid6c+Tt5gC7xNfYo6uQIQkorAC6MpeayVMZrEDzKmJJ/Hlv7EnOQpaRm53k6ktDYZyB6w==}
app-builder-lib@26.0.12:
resolution: {integrity: sha512-+/CEPH1fVKf6HowBUs6LcAIoRcjeqgvAeoSE+cl7Y7LndyQ9ViGPYibNk7wmhMHzNgHIuIbw4nWADPO+4mjgWw==}
engines: {node: '>=14.0.0'}
peerDependencies:
dmg-builder: 26.0.12
electron-builder-squirrel-windows: 26.0.12
argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
aria-hidden@1.2.6: aria-hidden@1.2.6:
resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==}
engines: {node: '>=10'} engines: {node: '>=10'}
assert-plus@1.0.0:
resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==}
engines: {node: '>=0.8'}
astral-regex@2.0.0:
resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==}
engines: {node: '>=8'}
async-exit-hook@2.0.1:
resolution: {integrity: sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==}
engines: {node: '>=0.12.0'}
async@3.2.6:
resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==}
asynckit@0.4.0:
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
at-least-node@1.0.0:
resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==}
engines: {node: '>= 4.0.0'}
balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
base64-js@1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
baseline-browser-mapping@2.9.7:
resolution: {integrity: sha512-k9xFKplee6KIio3IDbwj+uaCLpqzOwakOgmqzPezM0sFJlFKcg30vk2wOiAJtkTSfx0SSQDSe8q+mWA/fSH5Zg==}
hasBin: true
birpc@2.9.0: birpc@2.9.0:
resolution: {integrity: sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==} resolution: {integrity: sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==}
bl@4.1.0:
resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==}
boolean@3.2.0:
resolution: {integrity: sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==}
deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.
brace-expansion@1.1.12:
resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==}
brace-expansion@2.0.2:
resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==}
browserslist@4.28.1:
resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==}
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
hasBin: true
buffer-crc32@0.2.13:
resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==}
buffer-from@1.1.2: buffer-from@1.1.2:
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
buffer@5.7.1:
resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
builder-util-runtime@9.3.1:
resolution: {integrity: sha512-2/egrNDDnRaxVwK3A+cJq6UOlqOdedGA7JPqCeJjN2Zjk1/QB/6QUi3b714ScIGS7HafFXTyzJEOr5b44I3kvQ==}
engines: {node: '>=12.0.0'}
builder-util@26.0.11:
resolution: {integrity: sha512-xNjXfsldUEe153h1DraD0XvDOpqGR0L5eKFkdReB7eFW5HqysDZFfly4rckda6y9dF39N3pkPlOblcfHKGw+uA==}
cac@6.7.14:
resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
engines: {node: '>=8'}
cacache@16.1.3:
resolution: {integrity: sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==}
engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
cacheable-lookup@5.0.4:
resolution: {integrity: sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==}
engines: {node: '>=10.6.0'}
cacheable-request@7.0.4:
resolution: {integrity: sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==}
engines: {node: '>=8'}
call-bind-apply-helpers@1.0.2:
resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
engines: {node: '>= 0.4'}
caniuse-lite@1.0.30001760:
resolution: {integrity: sha512-7AAMPcueWELt1p3mi13HR/LHH0TJLT11cnwDJEs3xA4+CK/PLKeO9Kl1oru24htkyUKtkGCvAx4ohB0Ttry8Dw==}
chalk@4.1.2:
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
engines: {node: '>=10'}
chownr@2.0.0:
resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==}
engines: {node: '>=10'}
chromium-pickle-js@0.2.0:
resolution: {integrity: sha512-1R5Fho+jBq0DDydt+/vHWj5KJNJCKdARKOCwZUen84I5BreWoLqRLANH1U87eJy1tiASPtMnGqJJq0ZsLoRPOw==}
ci-info@3.9.0:
resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==}
engines: {node: '>=8'}
class-variance-authority@0.7.1: class-variance-authority@0.7.1:
resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==}
clean-stack@2.2.0:
resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==}
engines: {node: '>=6'}
cli-cursor@3.1.0:
resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==}
engines: {node: '>=8'}
cli-spinners@2.9.2:
resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==}
engines: {node: '>=6'}
cli-truncate@2.1.0:
resolution: {integrity: sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==}
engines: {node: '>=8'}
cliui@8.0.1:
resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
engines: {node: '>=12'}
clone-response@1.0.3:
resolution: {integrity: sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==}
clone@1.0.4:
resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==}
engines: {node: '>=0.8'}
clsx@2.1.1: clsx@2.1.1:
resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==}
engines: {node: '>=6'} engines: {node: '>=6'}
color-convert@2.0.1:
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
engines: {node: '>=7.0.0'}
color-name@1.1.4:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
combined-stream@1.0.8:
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
engines: {node: '>= 0.8'}
commander@2.20.3: commander@2.20.3:
resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
commander@5.1.0:
resolution: {integrity: sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==}
engines: {node: '>= 6'}
commander@9.5.0:
resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==}
engines: {node: ^12.20.0 || >=14}
compare-version@0.1.2:
resolution: {integrity: sha512-pJDh5/4wrEnXX/VWRZvruAGHkzKdr46z11OlTPN+VrATlWWhSKewNCJ1futCO5C7eJB3nPMFZA1LeYtcFboZ2A==}
engines: {node: '>=0.10.0'}
concat-map@0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
config-file-ts@0.2.8-rc1:
resolution: {integrity: sha512-GtNECbVI82bT4RiDIzBSVuTKoSHufnU7Ce7/42bkWZJZFLjmDF2WBpVsvRkhKCfKBnTBb3qZrBwPpFBU/Myvhg==}
convert-source-map@2.0.0:
resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
copy-anything@4.0.5: copy-anything@4.0.5:
resolution: {integrity: sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==} resolution: {integrity: sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==}
engines: {node: '>=18'} engines: {node: '>=18'}
core-util-is@1.0.2:
resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==}
crc@3.8.0:
resolution: {integrity: sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==}
cross-dirname@0.1.0:
resolution: {integrity: sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q==}
cross-spawn@7.0.6:
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
engines: {node: '>= 8'}
crypto-js@4.2.0: crypto-js@4.2.0:
resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==} resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==}
csstype@3.2.3: csstype@3.2.3:
resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
debug@4.4.3:
resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
engines: {node: '>=6.0'}
peerDependencies:
supports-color: '*'
peerDependenciesMeta:
supports-color:
optional: true
decompress-response@6.0.0:
resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==}
engines: {node: '>=10'}
defaults@1.0.4:
resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==}
defer-to-connect@2.0.1:
resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==}
engines: {node: '>=10'}
define-data-property@1.1.4:
resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==}
engines: {node: '>= 0.4'}
define-properties@1.2.1:
resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==}
engines: {node: '>= 0.4'}
defu@6.1.4: defu@6.1.4:
resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==}
delayed-stream@1.0.0:
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
engines: {node: '>=0.4.0'}
depd@2.0.0:
resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
engines: {node: '>= 0.8'}
detect-libc@2.1.2: detect-libc@2.1.2:
resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
engines: {node: '>=8'} engines: {node: '>=8'}
detect-node@2.1.0:
resolution: {integrity: sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==}
dir-compare@4.2.0:
resolution: {integrity: sha512-2xMCmOoMrdQIPHdsTawECdNPwlVFB9zGcz3kuhmBO6U3oU+UQjsue0i8ayLKpgBcm+hcXPMVSGUN9d+pvJ6+VQ==}
dmg-builder@26.0.12:
resolution: {integrity: sha512-59CAAjAhTaIMCN8y9kD573vDkxbs1uhDcrFLHSgutYdPcGOU35Rf95725snvzEOy4BFB7+eLJ8djCNPmGwG67w==}
dmg-license@1.0.11:
resolution: {integrity: sha512-ZdzmqwKmECOWJpqefloC5OJy1+WZBBse5+MR88z9g9Zn4VY+WYUkAyojmhzJckH5YbbZGcYIuGAkY5/Ys5OM2Q==}
engines: {node: '>=8'}
os: [darwin]
hasBin: true
dotenv-expand@11.0.7:
resolution: {integrity: sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA==}
engines: {node: '>=12'}
dotenv@16.6.1:
resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==}
engines: {node: '>=12'}
dunder-proto@1.0.1:
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
engines: {node: '>= 0.4'}
eastasianwidth@0.2.0:
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
ee-first@1.1.1:
resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
ejs@3.1.10:
resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==}
engines: {node: '>=0.10.0'}
hasBin: true
electron-builder-squirrel-windows@26.0.12:
resolution: {integrity: sha512-kpwXM7c/ayRUbYVErQbsZ0nQZX4aLHQrPEG9C4h9vuJCXylwFH8a7Jgi2VpKIObzCXO7LKHiCw4KdioFLFOgqA==}
electron-builder@26.0.12:
resolution: {integrity: sha512-cD1kz5g2sgPTMFHjLxfMjUK5JABq3//J4jPswi93tOPFz6btzXYtK5NrDt717NRbukCUDOrrvmYVOWERlqoiXA==}
engines: {node: '>=14.0.0'}
hasBin: true
electron-publish@26.0.11:
resolution: {integrity: sha512-a8QRH0rAPIWH9WyyS5LbNvW9Ark6qe63/LqDB7vu2JXYpi0Gma5Q60Dh4tmTqhOBQt0xsrzD8qE7C+D7j+B24A==}
electron-to-chromium@1.5.267:
resolution: {integrity: sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==}
electron-vite@5.0.0:
resolution: {integrity: sha512-OHp/vjdlubNlhNkPkL/+3JD34ii5ov7M0GpuXEVdQeqdQ3ulvVR7Dg/rNBLfS5XPIFwgoBLDf9sjjrL+CuDyRQ==}
engines: {node: ^20.19.0 || >=22.12.0}
hasBin: true
peerDependencies:
'@swc/core': ^1.0.0
vite: ^5.0.0 || ^6.0.0 || ^7.0.0
peerDependenciesMeta:
'@swc/core':
optional: true
electron-winstaller@5.4.0:
resolution: {integrity: sha512-bO3y10YikuUwUuDUQRM4KfwNkKhnpVO7IPdbsrejwN9/AABJzzTQ4GeHwyzNSrVO+tEH3/Np255a3sVZpZDjvg==}
engines: {node: '>=8.0.0'}
electron@39.2.7:
resolution: {integrity: sha512-KU0uFS6LSTh4aOIC3miolcbizOFP7N1M46VTYVfqIgFiuA2ilfNaOHLDS9tCMvwwHRowAsvqBrh9NgMXcTOHCQ==}
engines: {node: '>= 12.20.55'}
hasBin: true
emoji-regex@8.0.0:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
emoji-regex@9.2.2:
resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
encodeurl@2.0.0:
resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==}
engines: {node: '>= 0.8'}
encoding@0.1.13:
resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==}
end-of-stream@1.4.5:
resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==}
enhanced-resolve@5.18.3: enhanced-resolve@5.18.3:
resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==} resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==}
engines: {node: '>=10.13.0'} engines: {node: '>=10.13.0'}
@@ -696,14 +1263,76 @@ packages:
resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
engines: {node: '>=0.12'} engines: {node: '>=0.12'}
esbuild@0.27.1: env-paths@2.2.1:
resolution: {integrity: sha512-yY35KZckJJuVVPXpvjgxiCuVEJT67F6zDeVTv4rizyPrfGBUpZQsvmxnN+C371c2esD/hNMjj4tpBhuueLN7aA==} resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==}
engines: {node: '>=6'}
err-code@2.0.3:
resolution: {integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==}
es-define-property@1.0.1:
resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
engines: {node: '>= 0.4'}
es-errors@1.3.0:
resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
engines: {node: '>= 0.4'}
es-object-atoms@1.1.1:
resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
engines: {node: '>= 0.4'}
es-set-tostringtag@2.1.0:
resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==}
engines: {node: '>= 0.4'}
es6-error@4.1.1:
resolution: {integrity: sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==}
esbuild@0.25.12:
resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==}
engines: {node: '>=18'} engines: {node: '>=18'}
hasBin: true hasBin: true
escalade@3.2.0:
resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
engines: {node: '>=6'}
escape-html@1.0.3:
resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==}
escape-string-regexp@4.0.0:
resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
engines: {node: '>=10'}
estree-walker@2.0.2: estree-walker@2.0.2:
resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
etag@1.8.1:
resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==}
engines: {node: '>= 0.6'}
exponential-backoff@3.1.3:
resolution: {integrity: sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==}
extract-zip@2.0.1:
resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==}
engines: {node: '>= 10.17.0'}
hasBin: true
extsprintf@1.4.1:
resolution: {integrity: sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==}
engines: {'0': node >=0.6.0}
fast-deep-equal@3.1.3:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
fast-json-stable-stringify@2.1.0:
resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
fd-slicer@1.1.0:
resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==}
fdir@6.5.0: fdir@6.5.0:
resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
engines: {node: '>=12.0.0'} engines: {node: '>=12.0.0'}
@@ -716,25 +1345,286 @@ packages:
file-saver@2.0.5: file-saver@2.0.5:
resolution: {integrity: sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==} resolution: {integrity: sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==}
filelist@1.0.4:
resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==}
finalhandler@2.1.1:
resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==}
engines: {node: '>= 18.0.0'}
foreground-child@3.3.1:
resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==}
engines: {node: '>=14'}
form-data@4.0.5:
resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==}
engines: {node: '>= 6'}
fresh@2.0.0:
resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==}
engines: {node: '>= 0.8'}
fs-extra@10.1.0:
resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==}
engines: {node: '>=12'}
fs-extra@11.3.2:
resolution: {integrity: sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A==}
engines: {node: '>=14.14'}
fs-extra@7.0.1:
resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==}
engines: {node: '>=6 <7 || >=8'}
fs-extra@8.1.0:
resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==}
engines: {node: '>=6 <7 || >=8'}
fs-extra@9.1.0:
resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==}
engines: {node: '>=10'}
fs-minipass@2.1.0:
resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==}
engines: {node: '>= 8'}
fs.realpath@1.0.0:
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
fsevents@2.3.3: fsevents@2.3.3:
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin] os: [darwin]
function-bind@1.1.2:
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
gensync@1.0.0-beta.2:
resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
engines: {node: '>=6.9.0'}
get-caller-file@2.0.5:
resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
engines: {node: 6.* || 8.* || >= 10.*}
get-intrinsic@1.3.0:
resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
engines: {node: '>= 0.4'}
get-proto@1.0.1:
resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==}
engines: {node: '>= 0.4'}
get-stream@5.2.0:
resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==}
engines: {node: '>=8'}
glob@10.5.0:
resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==}
hasBin: true
glob@7.2.3:
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
deprecated: Glob versions prior to v9 are no longer supported
glob@8.1.0:
resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==}
engines: {node: '>=12'}
deprecated: Glob versions prior to v9 are no longer supported
global-agent@3.0.0:
resolution: {integrity: sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==}
engines: {node: '>=10.0'}
globalthis@1.0.4:
resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==}
engines: {node: '>= 0.4'}
gopd@1.2.0:
resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
engines: {node: '>= 0.4'}
got@11.8.6:
resolution: {integrity: sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==}
engines: {node: '>=10.19.0'}
graceful-fs@4.2.11: graceful-fs@4.2.11:
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
has-flag@4.0.0:
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
engines: {node: '>=8'}
has-property-descriptors@1.0.2:
resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==}
has-symbols@1.1.0:
resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==}
engines: {node: '>= 0.4'}
has-tostringtag@1.0.2:
resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==}
engines: {node: '>= 0.4'}
hasown@2.0.2:
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
engines: {node: '>= 0.4'}
hookable@5.5.3: hookable@5.5.3:
resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==}
hosted-git-info@4.1.0:
resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==}
engines: {node: '>=10'}
http-cache-semantics@4.2.0:
resolution: {integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==}
http-errors@2.0.1:
resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==}
engines: {node: '>= 0.8'}
http-proxy-agent@5.0.0:
resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==}
engines: {node: '>= 6'}
http-proxy-agent@7.0.2:
resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==}
engines: {node: '>= 14'}
http2-wrapper@1.0.3:
resolution: {integrity: sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==}
engines: {node: '>=10.19.0'}
https-proxy-agent@5.0.1:
resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==}
engines: {node: '>= 6'}
https-proxy-agent@7.0.6:
resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==}
engines: {node: '>= 14'}
humanize-ms@1.2.1:
resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==}
iconv-corefoundation@1.1.7:
resolution: {integrity: sha512-T10qvkw0zz4wnm560lOEg0PovVqUXuOFhhHAkixw8/sycy7TJt7v/RrkEKEQnAw2viPSJu6iAkErxnzR0g8PpQ==}
engines: {node: ^8.11.2 || >=10}
os: [darwin]
iconv-lite@0.6.3:
resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
engines: {node: '>=0.10.0'}
ieee754@1.2.1:
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
imurmurhash@0.1.4:
resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
engines: {node: '>=0.8.19'}
indent-string@4.0.0:
resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==}
engines: {node: '>=8'}
infer-owner@1.0.4:
resolution: {integrity: sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==}
inflight@1.0.6:
resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
inherits@2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
ip-address@10.1.0:
resolution: {integrity: sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==}
engines: {node: '>= 12'}
is-ci@3.0.1:
resolution: {integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==}
hasBin: true
is-fullwidth-code-point@3.0.0:
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
engines: {node: '>=8'}
is-interactive@1.0.0:
resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==}
engines: {node: '>=8'}
is-lambda@1.0.1:
resolution: {integrity: sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==}
is-unicode-supported@0.1.0:
resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==}
engines: {node: '>=10'}
is-what@5.5.0: is-what@5.5.0:
resolution: {integrity: sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==} resolution: {integrity: sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==}
engines: {node: '>=18'} engines: {node: '>=18'}
isbinaryfile@4.0.10:
resolution: {integrity: sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==}
engines: {node: '>= 8.0.0'}
isbinaryfile@5.0.7:
resolution: {integrity: sha512-gnWD14Jh3FzS3CPhF0AxNOJ8CxqeblPTADzI38r0wt8ZyQl5edpy75myt08EG2oKvpyiqSqsx+Wkz9vtkbTqYQ==}
engines: {node: '>= 18.0.0'}
isexe@2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
jackspeak@3.4.3:
resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==}
jake@10.9.4:
resolution: {integrity: sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==}
engines: {node: '>=10'}
hasBin: true
jiti@2.6.1: jiti@2.6.1:
resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==}
hasBin: true hasBin: true
js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
js-yaml@4.1.1:
resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==}
hasBin: true
jsesc@3.1.0:
resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==}
engines: {node: '>=6'}
hasBin: true
json-buffer@3.0.1:
resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
json-schema-traverse@0.4.1:
resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
json-stringify-safe@5.0.1:
resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==}
json5@2.2.3:
resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
engines: {node: '>=6'}
hasBin: true
jsonfile@4.0.0:
resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==}
jsonfile@6.2.0:
resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==}
keyv@4.5.4:
resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
lazy-val@1.0.5:
resolution: {integrity: sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q==}
lightningcss-android-arm64@1.30.2: lightningcss-android-arm64@1.30.2:
resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==} resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==}
engines: {node: '>= 12.0.0'} engines: {node: '>= 12.0.0'}
@@ -809,6 +1699,31 @@ packages:
resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==} resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==}
engines: {node: '>= 12.0.0'} engines: {node: '>= 12.0.0'}
lodash@4.17.21:
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
log-symbols@4.1.0:
resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==}
engines: {node: '>=10'}
lowercase-keys@2.0.0:
resolution: {integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==}
engines: {node: '>=8'}
lru-cache@10.4.3:
resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
lru-cache@5.1.1:
resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
lru-cache@6.0.0:
resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
engines: {node: '>=10'}
lru-cache@7.18.3:
resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==}
engines: {node: '>=12'}
lucide-vue-next@0.556.0: lucide-vue-next@0.556.0:
resolution: {integrity: sha512-JvdCM2smkWrMDhkfD/FpZiWekkbWD6MZLstIFx/FOVZgULrnMr5hegCB9LlTdgllEFnQYQs8hhHC1WYcAV9HTA==} resolution: {integrity: sha512-JvdCM2smkWrMDhkfD/FpZiWekkbWD6MZLstIFx/FOVZgULrnMr5hegCB9LlTdgllEFnQYQs8hhHC1WYcAV9HTA==}
peerDependencies: peerDependencies:
@@ -817,9 +1732,120 @@ packages:
magic-string@0.30.21: magic-string@0.30.21:
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
make-fetch-happen@10.2.1:
resolution: {integrity: sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==}
engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
matcher@3.0.0:
resolution: {integrity: sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==}
engines: {node: '>=10'}
math-intrinsics@1.1.0:
resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
engines: {node: '>= 0.4'}
mime-db@1.52.0:
resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
engines: {node: '>= 0.6'}
mime-db@1.54.0:
resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==}
engines: {node: '>= 0.6'}
mime-types@2.1.35:
resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
engines: {node: '>= 0.6'}
mime-types@3.0.2:
resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==}
engines: {node: '>=18'}
mime@2.6.0:
resolution: {integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==}
engines: {node: '>=4.0.0'}
hasBin: true
mimic-fn@2.1.0:
resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
engines: {node: '>=6'}
mimic-response@1.0.1:
resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==}
engines: {node: '>=4'}
mimic-response@3.1.0:
resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==}
engines: {node: '>=10'}
minimatch@10.1.1:
resolution: {integrity: sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==}
engines: {node: 20 || >=22}
minimatch@3.1.2:
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
minimatch@5.1.6:
resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==}
engines: {node: '>=10'}
minimatch@9.0.5:
resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
engines: {node: '>=16 || 14 >=14.17'}
minimist@1.2.8:
resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
minipass-collect@1.0.2:
resolution: {integrity: sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==}
engines: {node: '>= 8'}
minipass-fetch@2.1.2:
resolution: {integrity: sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==}
engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
minipass-flush@1.0.5:
resolution: {integrity: sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==}
engines: {node: '>= 8'}
minipass-pipeline@1.2.4:
resolution: {integrity: sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==}
engines: {node: '>=8'}
minipass-sized@1.0.3:
resolution: {integrity: sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==}
engines: {node: '>=8'}
minipass@3.3.6:
resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==}
engines: {node: '>=8'}
minipass@5.0.0:
resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==}
engines: {node: '>=8'}
minipass@7.1.2:
resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==}
engines: {node: '>=16 || 14 >=14.17'}
minizlib@2.1.2:
resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==}
engines: {node: '>= 8'}
mitt@3.0.1: mitt@3.0.1:
resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==}
mkdirp@0.5.6:
resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==}
hasBin: true
mkdirp@1.0.4:
resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==}
engines: {node: '>=10'}
hasBin: true
ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
muggle-string@0.4.1: muggle-string@0.4.1:
resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==}
@@ -828,12 +1854,95 @@ packages:
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true hasBin: true
negotiator@0.6.4:
resolution: {integrity: sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==}
engines: {node: '>= 0.6'}
node-abi@3.85.0:
resolution: {integrity: sha512-zsFhmbkAzwhTft6nd3VxcG0cvJsT70rL+BIGHWVq5fi6MwGrHwzqKaxXE+Hl2GmnGItnDKPPkO5/LQqjVkIdFg==}
engines: {node: '>=10'}
node-addon-api@1.7.2:
resolution: {integrity: sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==}
node-api-version@0.2.1:
resolution: {integrity: sha512-2xP/IGGMmmSQpI1+O/k72jF/ykvZ89JeuKX3TLJAYPDVLUalrshrLHkeVcCCZqG/eEa635cr8IBYzgnDvM2O8Q==}
node-releases@2.0.27:
resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==}
nopt@6.0.0:
resolution: {integrity: sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==}
engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
hasBin: true
normalize-url@6.1.0:
resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==}
engines: {node: '>=10'}
object-keys@1.1.1:
resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==}
engines: {node: '>= 0.4'}
ohash@2.0.11: ohash@2.0.11:
resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==}
on-finished@2.4.1:
resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==}
engines: {node: '>= 0.8'}
once@1.4.0:
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
onetime@5.1.2:
resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
engines: {node: '>=6'}
ora@5.4.1:
resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==}
engines: {node: '>=10'}
p-cancelable@2.1.1:
resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==}
engines: {node: '>=8'}
p-limit@3.1.0:
resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
engines: {node: '>=10'}
p-map@4.0.0:
resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==}
engines: {node: '>=10'}
package-json-from-dist@1.0.1:
resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==}
parseurl@1.3.3:
resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
engines: {node: '>= 0.8'}
path-browserify@1.0.1: path-browserify@1.0.1:
resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==}
path-is-absolute@1.0.1:
resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
engines: {node: '>=0.10.0'}
path-key@3.1.1:
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
engines: {node: '>=8'}
path-scurry@1.11.1:
resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==}
engines: {node: '>=16 || 14 >=14.18'}
pe-library@0.4.1:
resolution: {integrity: sha512-eRWB5LBz7PpDu4PUlwT0PhnQfTQJlDDdPa35urV4Osrm0t0AqQFGn+UIkU3klZvwJ8KPO3VbBFsXquA6p6kqZw==}
engines: {node: '>=12', npm: '>=6'}
pend@1.2.0:
resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==}
perfect-debounce@1.0.0: perfect-debounce@1.0.0:
resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==}
@@ -867,18 +1976,106 @@ packages:
typescript: typescript:
optional: true optional: true
plist@3.1.0:
resolution: {integrity: sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==}
engines: {node: '>=10.4.0'}
postcss@8.5.6: postcss@8.5.6:
resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
engines: {node: ^10 || ^12 || >=14} engines: {node: ^10 || ^12 || >=14}
postject@1.0.0-alpha.6:
resolution: {integrity: sha512-b9Eb8h2eVqNE8edvKdwqkrY6O7kAwmI8kcnBv1NScolYJbo59XUF0noFq+lxbC1yN20bmC0WBEbDC5H/7ASb0A==}
engines: {node: '>=14.0.0'}
hasBin: true
proc-log@2.0.1:
resolution: {integrity: sha512-Kcmo2FhfDTXdcbfDH76N7uBYHINxc/8GW7UAVuVP9I+Va3uHSerrnKV6dLooga/gh7GlgzuCCr/eoldnL1muGw==}
engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
progress@2.0.3:
resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==}
engines: {node: '>=0.4.0'}
promise-inflight@1.0.1:
resolution: {integrity: sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==}
peerDependencies:
bluebird: '*'
peerDependenciesMeta:
bluebird:
optional: true
promise-retry@2.0.1:
resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==}
engines: {node: '>=10'}
pump@3.0.3:
resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==}
punycode@2.3.1:
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
engines: {node: '>=6'}
quick-lru@5.1.1:
resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==}
engines: {node: '>=10'}
range-parser@1.2.1:
resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}
engines: {node: '>= 0.6'}
read-binary-file-arch@1.0.6:
resolution: {integrity: sha512-BNg9EN3DD3GsDXX7Aa8O4p92sryjkmzYYgmgTAc6CA4uGLEDzFfxOxugu21akOxpcXHiEgsYkC6nPsQvLLLmEg==}
hasBin: true
readable-stream@3.6.2:
resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}
engines: {node: '>= 6'}
reka-ui@2.6.1: reka-ui@2.6.1:
resolution: {integrity: sha512-XK7cJDQoNuGXfCNzBBo/81Yg/OgjPwvbabnlzXG2VsdSgNsT6iIkuPBPr+C0Shs+3bb0x0lbPvgQAhMSCKm5Ww==} resolution: {integrity: sha512-XK7cJDQoNuGXfCNzBBo/81Yg/OgjPwvbabnlzXG2VsdSgNsT6iIkuPBPr+C0Shs+3bb0x0lbPvgQAhMSCKm5Ww==}
peerDependencies: peerDependencies:
vue: '>= 3.2.0' vue: '>= 3.2.0'
require-directory@2.1.1:
resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
engines: {node: '>=0.10.0'}
resedit@1.7.2:
resolution: {integrity: sha512-vHjcY2MlAITJhC0eRD/Vv8Vlgmu9Sd3LX9zZvtGzU5ZImdTN3+d6e/4mnTyV8vEbyf1sgNIrWxhWlrys52OkEA==}
engines: {node: '>=12', npm: '>=6'}
resolve-alpn@1.2.1:
resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==}
responselike@2.0.1:
resolution: {integrity: sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==}
restore-cursor@3.1.0:
resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==}
engines: {node: '>=8'}
retry@0.12.0:
resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==}
engines: {node: '>= 4'}
rfdc@1.4.1: rfdc@1.4.1:
resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==}
rimraf@2.6.3:
resolution: {integrity: sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==}
deprecated: Rimraf versions prior to v4 are no longer supported
hasBin: true
rimraf@3.0.2:
resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
deprecated: Rimraf versions prior to v4 are no longer supported
hasBin: true
roarr@2.15.4:
resolution: {integrity: sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==}
engines: {node: '>=8.0'}
rolldown-vite@7.2.5: rolldown-vite@7.2.5:
resolution: {integrity: sha512-u09tdk/huMiN8xwoiBbig197jKdCamQTtOruSalOzbqGje3jdHiV0njQlAW0YvzoahkirFePNQ4RYlfnRQpXZA==} resolution: {integrity: sha512-u09tdk/huMiN8xwoiBbig197jKdCamQTtOruSalOzbqGje3jdHiV0njQlAW0YvzoahkirFePNQ4RYlfnRQpXZA==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
@@ -924,6 +2121,84 @@ packages:
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
hasBin: true hasBin: true
safe-buffer@5.2.1:
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
safer-buffer@2.1.2:
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
sanitize-filename@1.6.3:
resolution: {integrity: sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==}
sax@1.4.3:
resolution: {integrity: sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ==}
semver-compare@1.0.0:
resolution: {integrity: sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==}
semver@5.7.2:
resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==}
hasBin: true
semver@6.3.1:
resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
hasBin: true
semver@7.7.3:
resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==}
engines: {node: '>=10'}
hasBin: true
send@1.2.0:
resolution: {integrity: sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==}
engines: {node: '>= 18'}
serialize-error@7.0.1:
resolution: {integrity: sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==}
engines: {node: '>=10'}
serve-static@2.2.0:
resolution: {integrity: sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==}
engines: {node: '>= 18'}
setprototypeof@1.2.0:
resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
shebang-command@2.0.0:
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
engines: {node: '>=8'}
shebang-regex@3.0.0:
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
engines: {node: '>=8'}
signal-exit@3.0.7:
resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
signal-exit@4.1.0:
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
engines: {node: '>=14'}
simple-update-notifier@2.0.0:
resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==}
engines: {node: '>=10'}
slice-ansi@3.0.0:
resolution: {integrity: sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==}
engines: {node: '>=8'}
smart-buffer@4.2.0:
resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==}
engines: {node: '>= 6.0.0', npm: '>= 3.0.0'}
socks-proxy-agent@7.0.0:
resolution: {integrity: sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==}
engines: {node: '>= 10'}
socks@2.8.7:
resolution: {integrity: sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==}
engines: {node: '>= 10.0.0', npm: '>= 3.0.0'}
source-map-js@1.2.1: source-map-js@1.2.1:
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
@@ -939,10 +2214,52 @@ packages:
resolution: {integrity: sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==} resolution: {integrity: sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
sprintf-js@1.1.3:
resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==}
ssri@9.0.1:
resolution: {integrity: sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==}
engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
stat-mode@1.0.0:
resolution: {integrity: sha512-jH9EhtKIjuXZ2cWxmXS8ZP80XyC3iasQxMDV8jzhNJpfDb7VbQLVW4Wvsxz9QZvzV+G4YoSfBUVKDOyxLzi/sg==}
engines: {node: '>= 6'}
statuses@2.0.2:
resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==}
engines: {node: '>= 0.8'}
string-width@4.2.3:
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
engines: {node: '>=8'}
string-width@5.1.2:
resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
engines: {node: '>=12'}
string_decoder@1.3.0:
resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
strip-ansi@6.0.1:
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
engines: {node: '>=8'}
strip-ansi@7.1.2:
resolution: {integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==}
engines: {node: '>=12'}
sumchecker@3.0.1:
resolution: {integrity: sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==}
engines: {node: '>= 8.0'}
superjson@2.2.6: superjson@2.2.6:
resolution: {integrity: sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA==} resolution: {integrity: sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA==}
engines: {node: '>=16'} engines: {node: '>=16'}
supports-color@7.2.0:
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
engines: {node: '>=8'}
tailwind-merge@3.4.0: tailwind-merge@3.4.0:
resolution: {integrity: sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==} resolution: {integrity: sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==}
@@ -953,29 +2270,110 @@ packages:
resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==}
engines: {node: '>=6'} engines: {node: '>=6'}
tar@6.2.1:
resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==}
engines: {node: '>=10'}
temp-file@3.4.0:
resolution: {integrity: sha512-C5tjlC/HCtVUOi3KWVokd4vHVViOmGjtLwIh4MuzPo/nMYTV/p1urt3RnMz2IWXDdKEGJH3k5+KPxtqRsUYGtg==}
temp@0.9.4:
resolution: {integrity: sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==}
engines: {node: '>=6.0.0'}
terser@5.44.1: terser@5.44.1:
resolution: {integrity: sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw==} resolution: {integrity: sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw==}
engines: {node: '>=10'} engines: {node: '>=10'}
hasBin: true hasBin: true
tiny-async-pool@1.3.0:
resolution: {integrity: sha512-01EAw5EDrcVrdgyCLgoSPvqznC0sVxDSVeiOz09FUpjh71G79VCqneOr+xvt7T1r76CF6ZZfPjHorN2+d+3mqA==}
tinyglobby@0.2.15: tinyglobby@0.2.15:
resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==}
engines: {node: '>=12.0.0'} engines: {node: '>=12.0.0'}
tmp-promise@3.0.3:
resolution: {integrity: sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==}
tmp@0.2.5:
resolution: {integrity: sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==}
engines: {node: '>=14.14'}
toidentifier@1.0.1:
resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
engines: {node: '>=0.6'}
truncate-utf8-bytes@1.0.2:
resolution: {integrity: sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==}
tslib@2.8.1: tslib@2.8.1:
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
tw-animate-css@1.4.0: tw-animate-css@1.4.0:
resolution: {integrity: sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==} resolution: {integrity: sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==}
type-fest@0.13.1:
resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==}
engines: {node: '>=10'}
typescript@5.9.3: typescript@5.9.3:
resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
engines: {node: '>=14.17'} engines: {node: '>=14.17'}
hasBin: true hasBin: true
undici-types@6.21.0:
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
undici-types@7.16.0: undici-types@7.16.0:
resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==}
unique-filename@2.0.1:
resolution: {integrity: sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==}
engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
unique-slug@3.0.0:
resolution: {integrity: sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==}
engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
universalify@0.1.2:
resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==}
engines: {node: '>= 4.0.0'}
universalify@2.0.1:
resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==}
engines: {node: '>= 10.0.0'}
update-browserslist-db@1.2.2:
resolution: {integrity: sha512-E85pfNzMQ9jpKkA7+TJAi4TJN+tBCuWh5rUcS/sv6cFi+1q9LYDwDI5dpUL0u/73EElyQ8d3TEaeW4sPedBqYA==}
hasBin: true
peerDependencies:
browserslist: '>= 4.21.0'
uri-js@4.4.1:
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
utf8-byte-length@1.0.5:
resolution: {integrity: sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA==}
util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
verror@1.10.1:
resolution: {integrity: sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg==}
engines: {node: '>=0.6.0'}
vite-plugin-electron-renderer@0.14.6:
resolution: {integrity: sha512-oqkWFa7kQIkvHXG7+Mnl1RTroA4sP0yesKatmAy0gjZC4VwUqlvF9IvOpHd1fpLWsqYX/eZlVxlhULNtaQ78Jw==}
vite-plugin-electron@0.29.0:
resolution: {integrity: sha512-HP0DI9Shg41hzt55IKYVnbrChWXHX95QtsEQfM+szQBpWjVhVGMlqRjVco6ebfQjWNr+Ga+PeoBjMIl8zMaufw==}
peerDependencies:
vite-plugin-electron-renderer: '*'
peerDependenciesMeta:
vite-plugin-electron-renderer:
optional: true
vscode-uri@3.1.0: vscode-uri@3.1.0:
resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==} resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==}
@@ -1023,21 +2421,280 @@ packages:
typescript: typescript:
optional: true optional: true
wcwidth@1.0.1:
resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==}
which@2.0.2:
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
engines: {node: '>= 8'}
hasBin: true
wrap-ansi@7.0.0:
resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
engines: {node: '>=10'}
wrap-ansi@8.1.0:
resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==}
engines: {node: '>=12'}
wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
xmlbuilder@15.1.1:
resolution: {integrity: sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==}
engines: {node: '>=8.0'}
y18n@5.0.8:
resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
engines: {node: '>=10'}
yallist@3.1.1:
resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
yallist@4.0.0:
resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
yargs-parser@21.1.1:
resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
engines: {node: '>=12'}
yargs@17.7.2:
resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==}
engines: {node: '>=12'}
yauzl@2.10.0:
resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==}
yocto-queue@0.1.0:
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'}
snapshots: snapshots:
7zip-bin@5.2.0: {}
'@babel/code-frame@7.27.1':
dependencies:
'@babel/helper-validator-identifier': 7.28.5
js-tokens: 4.0.0
picocolors: 1.1.1
'@babel/compat-data@7.28.5': {}
'@babel/core@7.28.5':
dependencies:
'@babel/code-frame': 7.27.1
'@babel/generator': 7.28.5
'@babel/helper-compilation-targets': 7.27.2
'@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5)
'@babel/helpers': 7.28.4
'@babel/parser': 7.28.5
'@babel/template': 7.27.2
'@babel/traverse': 7.28.5
'@babel/types': 7.28.5
'@jridgewell/remapping': 2.3.5
convert-source-map: 2.0.0
debug: 4.4.3
gensync: 1.0.0-beta.2
json5: 2.2.3
semver: 6.3.1
transitivePeerDependencies:
- supports-color
'@babel/generator@7.28.5':
dependencies:
'@babel/parser': 7.28.5
'@babel/types': 7.28.5
'@jridgewell/gen-mapping': 0.3.13
'@jridgewell/trace-mapping': 0.3.31
jsesc: 3.1.0
'@babel/helper-compilation-targets@7.27.2':
dependencies:
'@babel/compat-data': 7.28.5
'@babel/helper-validator-option': 7.27.1
browserslist: 4.28.1
lru-cache: 5.1.1
semver: 6.3.1
'@babel/helper-globals@7.28.0': {}
'@babel/helper-module-imports@7.27.1':
dependencies:
'@babel/traverse': 7.28.5
'@babel/types': 7.28.5
transitivePeerDependencies:
- supports-color
'@babel/helper-module-transforms@7.28.3(@babel/core@7.28.5)':
dependencies:
'@babel/core': 7.28.5
'@babel/helper-module-imports': 7.27.1
'@babel/helper-validator-identifier': 7.28.5
'@babel/traverse': 7.28.5
transitivePeerDependencies:
- supports-color
'@babel/helper-plugin-utils@7.27.1': {}
'@babel/helper-string-parser@7.27.1': {} '@babel/helper-string-parser@7.27.1': {}
'@babel/helper-validator-identifier@7.28.5': {} '@babel/helper-validator-identifier@7.28.5': {}
'@babel/helper-validator-option@7.27.1': {}
'@babel/helpers@7.28.4':
dependencies:
'@babel/template': 7.27.2
'@babel/types': 7.28.5
'@babel/parser@7.28.5': '@babel/parser@7.28.5':
dependencies: dependencies:
'@babel/types': 7.28.5 '@babel/types': 7.28.5
'@babel/plugin-transform-arrow-functions@7.27.1(@babel/core@7.28.5)':
dependencies:
'@babel/core': 7.28.5
'@babel/helper-plugin-utils': 7.27.1
'@babel/template@7.27.2':
dependencies:
'@babel/code-frame': 7.27.1
'@babel/parser': 7.28.5
'@babel/types': 7.28.5
'@babel/traverse@7.28.5':
dependencies:
'@babel/code-frame': 7.27.1
'@babel/generator': 7.28.5
'@babel/helper-globals': 7.28.0
'@babel/parser': 7.28.5
'@babel/template': 7.27.2
'@babel/types': 7.28.5
debug: 4.4.3
transitivePeerDependencies:
- supports-color
'@babel/types@7.28.5': '@babel/types@7.28.5':
dependencies: dependencies:
'@babel/helper-string-parser': 7.27.1 '@babel/helper-string-parser': 7.27.1
'@babel/helper-validator-identifier': 7.28.5 '@babel/helper-validator-identifier': 7.28.5
'@develar/schema-utils@2.6.5':
dependencies:
ajv: 6.12.6
ajv-keywords: 3.5.2(ajv@6.12.6)
'@electron/asar@3.2.18':
dependencies:
commander: 5.1.0
glob: 7.2.3
minimatch: 3.1.2
'@electron/asar@3.4.1':
dependencies:
commander: 5.1.0
glob: 7.2.3
minimatch: 3.1.2
'@electron/fuses@1.8.0':
dependencies:
chalk: 4.1.2
fs-extra: 9.1.0
minimist: 1.2.8
'@electron/get@2.0.3':
dependencies:
debug: 4.4.3
env-paths: 2.2.1
fs-extra: 8.1.0
got: 11.8.6
progress: 2.0.3
semver: 6.3.1
sumchecker: 3.0.1
optionalDependencies:
global-agent: 3.0.0
transitivePeerDependencies:
- supports-color
'@electron/node-gyp@https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2':
dependencies:
env-paths: 2.2.1
exponential-backoff: 3.1.3
glob: 8.1.0
graceful-fs: 4.2.11
make-fetch-happen: 10.2.1
nopt: 6.0.0
proc-log: 2.0.1
semver: 7.7.3
tar: 6.2.1
which: 2.0.2
transitivePeerDependencies:
- bluebird
- supports-color
'@electron/notarize@2.5.0':
dependencies:
debug: 4.4.3
fs-extra: 9.1.0
promise-retry: 2.0.1
transitivePeerDependencies:
- supports-color
'@electron/osx-sign@1.3.1':
dependencies:
compare-version: 0.1.2
debug: 4.4.3
fs-extra: 10.1.0
isbinaryfile: 4.0.10
minimist: 1.2.8
plist: 3.1.0
transitivePeerDependencies:
- supports-color
'@electron/rebuild@3.7.0':
dependencies:
'@electron/node-gyp': https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2
'@malept/cross-spawn-promise': 2.0.0
chalk: 4.1.2
debug: 4.4.3
detect-libc: 2.1.2
fs-extra: 10.1.0
got: 11.8.6
node-abi: 3.85.0
node-api-version: 0.2.1
ora: 5.4.1
read-binary-file-arch: 1.0.6
semver: 7.7.3
tar: 6.2.1
yargs: 17.7.2
transitivePeerDependencies:
- bluebird
- supports-color
'@electron/universal@2.0.1':
dependencies:
'@electron/asar': 3.2.18
'@malept/cross-spawn-promise': 2.0.0
debug: 4.4.3
dir-compare: 4.2.0
fs-extra: 11.3.2
minimatch: 9.0.5
plist: 3.1.0
transitivePeerDependencies:
- supports-color
'@electron/windows-sign@1.2.2':
dependencies:
cross-dirname: 0.1.0
debug: 4.4.3
fs-extra: 11.3.2
minimist: 1.2.8
postject: 1.0.0-alpha.6
transitivePeerDependencies:
- supports-color
optional: true
'@emnapi/core@1.7.1': '@emnapi/core@1.7.1':
dependencies: dependencies:
'@emnapi/wasi-threads': 1.1.0 '@emnapi/wasi-threads': 1.1.0
@@ -1054,82 +2711,82 @@ snapshots:
tslib: 2.8.1 tslib: 2.8.1
optional: true optional: true
'@esbuild/aix-ppc64@0.27.1': '@esbuild/aix-ppc64@0.25.12':
optional: true optional: true
'@esbuild/android-arm64@0.27.1': '@esbuild/android-arm64@0.25.12':
optional: true optional: true
'@esbuild/android-arm@0.27.1': '@esbuild/android-arm@0.25.12':
optional: true optional: true
'@esbuild/android-x64@0.27.1': '@esbuild/android-x64@0.25.12':
optional: true optional: true
'@esbuild/darwin-arm64@0.27.1': '@esbuild/darwin-arm64@0.25.12':
optional: true optional: true
'@esbuild/darwin-x64@0.27.1': '@esbuild/darwin-x64@0.25.12':
optional: true optional: true
'@esbuild/freebsd-arm64@0.27.1': '@esbuild/freebsd-arm64@0.25.12':
optional: true optional: true
'@esbuild/freebsd-x64@0.27.1': '@esbuild/freebsd-x64@0.25.12':
optional: true optional: true
'@esbuild/linux-arm64@0.27.1': '@esbuild/linux-arm64@0.25.12':
optional: true optional: true
'@esbuild/linux-arm@0.27.1': '@esbuild/linux-arm@0.25.12':
optional: true optional: true
'@esbuild/linux-ia32@0.27.1': '@esbuild/linux-ia32@0.25.12':
optional: true optional: true
'@esbuild/linux-loong64@0.27.1': '@esbuild/linux-loong64@0.25.12':
optional: true optional: true
'@esbuild/linux-mips64el@0.27.1': '@esbuild/linux-mips64el@0.25.12':
optional: true optional: true
'@esbuild/linux-ppc64@0.27.1': '@esbuild/linux-ppc64@0.25.12':
optional: true optional: true
'@esbuild/linux-riscv64@0.27.1': '@esbuild/linux-riscv64@0.25.12':
optional: true optional: true
'@esbuild/linux-s390x@0.27.1': '@esbuild/linux-s390x@0.25.12':
optional: true optional: true
'@esbuild/linux-x64@0.27.1': '@esbuild/linux-x64@0.25.12':
optional: true optional: true
'@esbuild/netbsd-arm64@0.27.1': '@esbuild/netbsd-arm64@0.25.12':
optional: true optional: true
'@esbuild/netbsd-x64@0.27.1': '@esbuild/netbsd-x64@0.25.12':
optional: true optional: true
'@esbuild/openbsd-arm64@0.27.1': '@esbuild/openbsd-arm64@0.25.12':
optional: true optional: true
'@esbuild/openbsd-x64@0.27.1': '@esbuild/openbsd-x64@0.25.12':
optional: true optional: true
'@esbuild/openharmony-arm64@0.27.1': '@esbuild/openharmony-arm64@0.25.12':
optional: true optional: true
'@esbuild/sunos-x64@0.27.1': '@esbuild/sunos-x64@0.25.12':
optional: true optional: true
'@esbuild/win32-arm64@0.27.1': '@esbuild/win32-arm64@0.25.12':
optional: true optional: true
'@esbuild/win32-ia32@0.27.1': '@esbuild/win32-ia32@0.25.12':
optional: true optional: true
'@esbuild/win32-x64@0.27.1': '@esbuild/win32-x64@0.25.12':
optional: true optional: true
'@floating-ui/core@1.7.3': '@floating-ui/core@1.7.3':
@@ -1152,6 +2809,8 @@ snapshots:
- '@vue/composition-api' - '@vue/composition-api'
- vue - vue
'@gar/promisify@1.1.3': {}
'@internationalized/date@3.10.0': '@internationalized/date@3.10.0':
dependencies: dependencies:
'@swc/helpers': 0.5.17 '@swc/helpers': 0.5.17
@@ -1160,6 +2819,21 @@ snapshots:
dependencies: dependencies:
'@swc/helpers': 0.5.17 '@swc/helpers': 0.5.17
'@isaacs/balanced-match@4.0.1': {}
'@isaacs/brace-expansion@5.0.0':
dependencies:
'@isaacs/balanced-match': 4.0.1
'@isaacs/cliui@8.0.2':
dependencies:
string-width: 5.1.2
string-width-cjs: string-width@4.2.3
strip-ansi: 7.1.2
strip-ansi-cjs: strip-ansi@6.0.1
wrap-ansi: 8.1.0
wrap-ansi-cjs: wrap-ansi@7.0.0
'@jridgewell/gen-mapping@0.3.13': '@jridgewell/gen-mapping@0.3.13':
dependencies: dependencies:
'@jridgewell/sourcemap-codec': 1.5.5 '@jridgewell/sourcemap-codec': 1.5.5
@@ -1176,6 +2850,7 @@ snapshots:
dependencies: dependencies:
'@jridgewell/gen-mapping': 0.3.13 '@jridgewell/gen-mapping': 0.3.13
'@jridgewell/trace-mapping': 0.3.31 '@jridgewell/trace-mapping': 0.3.31
optional: true
'@jridgewell/sourcemap-codec@1.5.5': {} '@jridgewell/sourcemap-codec@1.5.5': {}
@@ -1184,6 +2859,19 @@ snapshots:
'@jridgewell/resolve-uri': 3.1.2 '@jridgewell/resolve-uri': 3.1.2
'@jridgewell/sourcemap-codec': 1.5.5 '@jridgewell/sourcemap-codec': 1.5.5
'@malept/cross-spawn-promise@2.0.0':
dependencies:
cross-spawn: 7.0.6
'@malept/flatpak-bundler@0.4.0':
dependencies:
debug: 4.4.3
fs-extra: 9.1.0
lodash: 4.17.21
tmp-promise: 3.0.3
transitivePeerDependencies:
- supports-color
'@napi-rs/wasm-runtime@1.1.0': '@napi-rs/wasm-runtime@1.1.0':
dependencies: dependencies:
'@emnapi/core': 1.7.1 '@emnapi/core': 1.7.1
@@ -1191,10 +2879,23 @@ snapshots:
'@tybys/wasm-util': 0.10.1 '@tybys/wasm-util': 0.10.1
optional: true optional: true
'@npmcli/fs@2.1.2':
dependencies:
'@gar/promisify': 1.1.3
semver: 7.7.3
'@npmcli/move-file@2.0.1':
dependencies:
mkdirp: 1.0.4
rimraf: 3.0.2
'@oxc-project/runtime@0.97.0': {} '@oxc-project/runtime@0.97.0': {}
'@oxc-project/types@0.97.0': {} '@oxc-project/types@0.97.0': {}
'@pkgjs/parseargs@0.11.0':
optional: true
'@rolldown/binding-android-arm64@1.0.0-beta.50': '@rolldown/binding-android-arm64@1.0.0-beta.50':
optional: true optional: true
@@ -1241,10 +2942,16 @@ snapshots:
'@rolldown/pluginutils@1.0.0-beta.50': {} '@rolldown/pluginutils@1.0.0-beta.50': {}
'@sindresorhus/is@4.6.0': {}
'@swc/helpers@0.5.17': '@swc/helpers@0.5.17':
dependencies: dependencies:
tslib: 2.8.1 tslib: 2.8.1
'@szmarczak/http-timer@4.0.6':
dependencies:
defer-to-connect: 2.0.1
'@tailwindcss/node@4.1.17': '@tailwindcss/node@4.1.17':
dependencies: dependencies:
'@jridgewell/remapping': 2.3.5 '@jridgewell/remapping': 2.3.5
@@ -1306,12 +3013,12 @@ snapshots:
'@tailwindcss/oxide-win32-arm64-msvc': 4.1.17 '@tailwindcss/oxide-win32-arm64-msvc': 4.1.17
'@tailwindcss/oxide-win32-x64-msvc': 4.1.17 '@tailwindcss/oxide-win32-x64-msvc': 4.1.17
'@tailwindcss/vite@4.1.17(rolldown-vite@7.2.5(@types/node@24.10.2)(esbuild@0.27.1)(jiti@2.6.1)(terser@5.44.1))': '@tailwindcss/vite@4.1.17(rolldown-vite@7.2.5(@types/node@24.10.2)(esbuild@0.25.12)(jiti@2.6.1)(terser@5.44.1))':
dependencies: dependencies:
'@tailwindcss/node': 4.1.17 '@tailwindcss/node': 4.1.17
'@tailwindcss/oxide': 4.1.17 '@tailwindcss/oxide': 4.1.17
tailwindcss: 4.1.17 tailwindcss: 4.1.17
vite: rolldown-vite@7.2.5(@types/node@24.10.2)(esbuild@0.27.1)(jiti@2.6.1)(terser@5.44.1) vite: rolldown-vite@7.2.5(@types/node@24.10.2)(esbuild@0.25.12)(jiti@2.6.1)(terser@5.44.1)
'@tanstack/table-core@8.21.3': {} '@tanstack/table-core@8.21.3': {}
@@ -1327,25 +3034,72 @@ snapshots:
'@tanstack/virtual-core': 3.13.13 '@tanstack/virtual-core': 3.13.13
vue: 3.5.25(typescript@5.9.3) vue: 3.5.25(typescript@5.9.3)
'@tootallnate/once@2.0.0': {}
'@tybys/wasm-util@0.10.1': '@tybys/wasm-util@0.10.1':
dependencies: dependencies:
tslib: 2.8.1 tslib: 2.8.1
optional: true optional: true
'@types/cacheable-request@6.0.3':
dependencies:
'@types/http-cache-semantics': 4.0.4
'@types/keyv': 3.1.4
'@types/node': 24.10.2
'@types/responselike': 1.0.3
'@types/crypto-js@4.2.2': {} '@types/crypto-js@4.2.2': {}
'@types/debug@4.1.12':
dependencies:
'@types/ms': 2.1.0
'@types/file-saver@2.0.7': {} '@types/file-saver@2.0.7': {}
'@types/fs-extra@9.0.13':
dependencies:
'@types/node': 24.10.2
'@types/http-cache-semantics@4.0.4': {}
'@types/keyv@3.1.4':
dependencies:
'@types/node': 24.10.2
'@types/ms@2.1.0': {}
'@types/node@22.19.3':
dependencies:
undici-types: 6.21.0
'@types/node@24.10.2': '@types/node@24.10.2':
dependencies: dependencies:
undici-types: 7.16.0 undici-types: 7.16.0
'@types/plist@3.0.5':
dependencies:
'@types/node': 24.10.2
xmlbuilder: 15.1.1
optional: true
'@types/responselike@1.0.3':
dependencies:
'@types/node': 24.10.2
'@types/verror@1.10.11':
optional: true
'@types/web-bluetooth@0.0.21': {} '@types/web-bluetooth@0.0.21': {}
'@vitejs/plugin-vue@6.0.2(rolldown-vite@7.2.5(@types/node@24.10.2)(esbuild@0.27.1)(jiti@2.6.1)(terser@5.44.1))(vue@3.5.25(typescript@5.9.3))': '@types/yauzl@2.10.3':
dependencies:
'@types/node': 24.10.2
optional: true
'@vitejs/plugin-vue@6.0.2(rolldown-vite@7.2.5(@types/node@24.10.2)(esbuild@0.25.12)(jiti@2.6.1)(terser@5.44.1))(vue@3.5.25(typescript@5.9.3))':
dependencies: dependencies:
'@rolldown/pluginutils': 1.0.0-beta.50 '@rolldown/pluginutils': 1.0.0-beta.50
vite: rolldown-vite@7.2.5(@types/node@24.10.2)(esbuild@0.27.1)(jiti@2.6.1)(terser@5.44.1) vite: rolldown-vite@7.2.5(@types/node@24.10.2)(esbuild@0.25.12)(jiti@2.6.1)(terser@5.44.1)
vue: 3.5.25(typescript@5.9.3) vue: 3.5.25(typescript@5.9.3)
'@volar/language-core@2.4.26': '@volar/language-core@2.4.26':
@@ -1481,38 +3235,509 @@ snapshots:
dependencies: dependencies:
vue: 3.5.25(typescript@5.9.3) vue: 3.5.25(typescript@5.9.3)
acorn@8.15.0: {} '@xmldom/xmldom@0.8.11': {}
abbrev@1.1.1: {}
acorn@8.15.0:
optional: true
agent-base@6.0.2:
dependencies:
debug: 4.4.3
transitivePeerDependencies:
- supports-color
agent-base@7.1.4: {}
agentkeepalive@4.6.0:
dependencies:
humanize-ms: 1.2.1
aggregate-error@3.1.0:
dependencies:
clean-stack: 2.2.0
indent-string: 4.0.0
ajv-keywords@3.5.2(ajv@6.12.6):
dependencies:
ajv: 6.12.6
ajv@6.12.6:
dependencies:
fast-deep-equal: 3.1.3
fast-json-stable-stringify: 2.1.0
json-schema-traverse: 0.4.1
uri-js: 4.4.1
alien-signals@3.1.1: {} alien-signals@3.1.1: {}
ansi-regex@5.0.1: {}
ansi-regex@6.2.2: {}
ansi-styles@4.3.0:
dependencies:
color-convert: 2.0.1
ansi-styles@6.2.3: {}
app-builder-bin@5.0.0-alpha.12: {}
app-builder-lib@26.0.12(dmg-builder@26.0.12)(electron-builder-squirrel-windows@26.0.12):
dependencies:
'@develar/schema-utils': 2.6.5
'@electron/asar': 3.2.18
'@electron/fuses': 1.8.0
'@electron/notarize': 2.5.0
'@electron/osx-sign': 1.3.1
'@electron/rebuild': 3.7.0
'@electron/universal': 2.0.1
'@malept/flatpak-bundler': 0.4.0
'@types/fs-extra': 9.0.13
async-exit-hook: 2.0.1
builder-util: 26.0.11
builder-util-runtime: 9.3.1
chromium-pickle-js: 0.2.0
config-file-ts: 0.2.8-rc1
debug: 4.4.3
dmg-builder: 26.0.12(electron-builder-squirrel-windows@26.0.12)
dotenv: 16.6.1
dotenv-expand: 11.0.7
ejs: 3.1.10
electron-builder-squirrel-windows: 26.0.12(dmg-builder@26.0.12)
electron-publish: 26.0.11
fs-extra: 10.1.0
hosted-git-info: 4.1.0
is-ci: 3.0.1
isbinaryfile: 5.0.7
js-yaml: 4.1.1
json5: 2.2.3
lazy-val: 1.0.5
minimatch: 10.1.1
plist: 3.1.0
resedit: 1.7.2
semver: 7.7.3
tar: 6.2.1
temp-file: 3.4.0
tiny-async-pool: 1.3.0
transitivePeerDependencies:
- bluebird
- supports-color
argparse@2.0.1: {}
aria-hidden@1.2.6: aria-hidden@1.2.6:
dependencies: dependencies:
tslib: 2.8.1 tslib: 2.8.1
assert-plus@1.0.0:
optional: true
astral-regex@2.0.0:
optional: true
async-exit-hook@2.0.1: {}
async@3.2.6: {}
asynckit@0.4.0: {}
at-least-node@1.0.0: {}
balanced-match@1.0.2: {}
base64-js@1.5.1: {}
baseline-browser-mapping@2.9.7: {}
birpc@2.9.0: {} birpc@2.9.0: {}
bl@4.1.0:
dependencies:
buffer: 5.7.1
inherits: 2.0.4
readable-stream: 3.6.2
boolean@3.2.0:
optional: true
brace-expansion@1.1.12:
dependencies:
balanced-match: 1.0.2
concat-map: 0.0.1
brace-expansion@2.0.2:
dependencies:
balanced-match: 1.0.2
browserslist@4.28.1:
dependencies:
baseline-browser-mapping: 2.9.7
caniuse-lite: 1.0.30001760
electron-to-chromium: 1.5.267
node-releases: 2.0.27
update-browserslist-db: 1.2.2(browserslist@4.28.1)
buffer-crc32@0.2.13: {}
buffer-from@1.1.2: {} buffer-from@1.1.2: {}
buffer@5.7.1:
dependencies:
base64-js: 1.5.1
ieee754: 1.2.1
builder-util-runtime@9.3.1:
dependencies:
debug: 4.4.3
sax: 1.4.3
transitivePeerDependencies:
- supports-color
builder-util@26.0.11:
dependencies:
7zip-bin: 5.2.0
'@types/debug': 4.1.12
app-builder-bin: 5.0.0-alpha.12
builder-util-runtime: 9.3.1
chalk: 4.1.2
cross-spawn: 7.0.6
debug: 4.4.3
fs-extra: 10.1.0
http-proxy-agent: 7.0.2
https-proxy-agent: 7.0.6
is-ci: 3.0.1
js-yaml: 4.1.1
sanitize-filename: 1.6.3
source-map-support: 0.5.21
stat-mode: 1.0.0
temp-file: 3.4.0
tiny-async-pool: 1.3.0
transitivePeerDependencies:
- supports-color
cac@6.7.14: {}
cacache@16.1.3:
dependencies:
'@npmcli/fs': 2.1.2
'@npmcli/move-file': 2.0.1
chownr: 2.0.0
fs-minipass: 2.1.0
glob: 8.1.0
infer-owner: 1.0.4
lru-cache: 7.18.3
minipass: 3.3.6
minipass-collect: 1.0.2
minipass-flush: 1.0.5
minipass-pipeline: 1.2.4
mkdirp: 1.0.4
p-map: 4.0.0
promise-inflight: 1.0.1
rimraf: 3.0.2
ssri: 9.0.1
tar: 6.2.1
unique-filename: 2.0.1
transitivePeerDependencies:
- bluebird
cacheable-lookup@5.0.4: {}
cacheable-request@7.0.4:
dependencies:
clone-response: 1.0.3
get-stream: 5.2.0
http-cache-semantics: 4.2.0
keyv: 4.5.4
lowercase-keys: 2.0.0
normalize-url: 6.1.0
responselike: 2.0.1
call-bind-apply-helpers@1.0.2:
dependencies:
es-errors: 1.3.0
function-bind: 1.1.2
caniuse-lite@1.0.30001760: {}
chalk@4.1.2:
dependencies:
ansi-styles: 4.3.0
supports-color: 7.2.0
chownr@2.0.0: {}
chromium-pickle-js@0.2.0: {}
ci-info@3.9.0: {}
class-variance-authority@0.7.1: class-variance-authority@0.7.1:
dependencies: dependencies:
clsx: 2.1.1 clsx: 2.1.1
clean-stack@2.2.0: {}
cli-cursor@3.1.0:
dependencies:
restore-cursor: 3.1.0
cli-spinners@2.9.2: {}
cli-truncate@2.1.0:
dependencies:
slice-ansi: 3.0.0
string-width: 4.2.3
optional: true
cliui@8.0.1:
dependencies:
string-width: 4.2.3
strip-ansi: 6.0.1
wrap-ansi: 7.0.0
clone-response@1.0.3:
dependencies:
mimic-response: 1.0.1
clone@1.0.4: {}
clsx@2.1.1: {} clsx@2.1.1: {}
commander@2.20.3: {} color-convert@2.0.1:
dependencies:
color-name: 1.1.4
color-name@1.1.4: {}
combined-stream@1.0.8:
dependencies:
delayed-stream: 1.0.0
commander@2.20.3:
optional: true
commander@5.1.0: {}
commander@9.5.0:
optional: true
compare-version@0.1.2: {}
concat-map@0.0.1: {}
config-file-ts@0.2.8-rc1:
dependencies:
glob: 10.5.0
typescript: 5.9.3
convert-source-map@2.0.0: {}
copy-anything@4.0.5: copy-anything@4.0.5:
dependencies: dependencies:
is-what: 5.5.0 is-what: 5.5.0
core-util-is@1.0.2:
optional: true
crc@3.8.0:
dependencies:
buffer: 5.7.1
optional: true
cross-dirname@0.1.0:
optional: true
cross-spawn@7.0.6:
dependencies:
path-key: 3.1.1
shebang-command: 2.0.0
which: 2.0.2
crypto-js@4.2.0: {} crypto-js@4.2.0: {}
csstype@3.2.3: {} csstype@3.2.3: {}
debug@4.4.3:
dependencies:
ms: 2.1.3
decompress-response@6.0.0:
dependencies:
mimic-response: 3.1.0
defaults@1.0.4:
dependencies:
clone: 1.0.4
defer-to-connect@2.0.1: {}
define-data-property@1.1.4:
dependencies:
es-define-property: 1.0.1
es-errors: 1.3.0
gopd: 1.2.0
optional: true
define-properties@1.2.1:
dependencies:
define-data-property: 1.1.4
has-property-descriptors: 1.0.2
object-keys: 1.1.1
optional: true
defu@6.1.4: {} defu@6.1.4: {}
delayed-stream@1.0.0: {}
depd@2.0.0: {}
detect-libc@2.1.2: {} detect-libc@2.1.2: {}
detect-node@2.1.0:
optional: true
dir-compare@4.2.0:
dependencies:
minimatch: 3.1.2
p-limit: 3.1.0
dmg-builder@26.0.12(electron-builder-squirrel-windows@26.0.12):
dependencies:
app-builder-lib: 26.0.12(dmg-builder@26.0.12)(electron-builder-squirrel-windows@26.0.12)
builder-util: 26.0.11
builder-util-runtime: 9.3.1
fs-extra: 10.1.0
iconv-lite: 0.6.3
js-yaml: 4.1.1
optionalDependencies:
dmg-license: 1.0.11
transitivePeerDependencies:
- bluebird
- electron-builder-squirrel-windows
- supports-color
dmg-license@1.0.11:
dependencies:
'@types/plist': 3.0.5
'@types/verror': 1.10.11
ajv: 6.12.6
crc: 3.8.0
iconv-corefoundation: 1.1.7
plist: 3.1.0
smart-buffer: 4.2.0
verror: 1.10.1
optional: true
dotenv-expand@11.0.7:
dependencies:
dotenv: 16.6.1
dotenv@16.6.1: {}
dunder-proto@1.0.1:
dependencies:
call-bind-apply-helpers: 1.0.2
es-errors: 1.3.0
gopd: 1.2.0
eastasianwidth@0.2.0: {}
ee-first@1.1.1: {}
ejs@3.1.10:
dependencies:
jake: 10.9.4
electron-builder-squirrel-windows@26.0.12(dmg-builder@26.0.12):
dependencies:
app-builder-lib: 26.0.12(dmg-builder@26.0.12)(electron-builder-squirrel-windows@26.0.12)
builder-util: 26.0.11
electron-winstaller: 5.4.0
transitivePeerDependencies:
- bluebird
- dmg-builder
- supports-color
electron-builder@26.0.12(electron-builder-squirrel-windows@26.0.12):
dependencies:
app-builder-lib: 26.0.12(dmg-builder@26.0.12)(electron-builder-squirrel-windows@26.0.12)
builder-util: 26.0.11
builder-util-runtime: 9.3.1
chalk: 4.1.2
dmg-builder: 26.0.12(electron-builder-squirrel-windows@26.0.12)
fs-extra: 10.1.0
is-ci: 3.0.1
lazy-val: 1.0.5
simple-update-notifier: 2.0.0
yargs: 17.7.2
transitivePeerDependencies:
- bluebird
- electron-builder-squirrel-windows
- supports-color
electron-publish@26.0.11:
dependencies:
'@types/fs-extra': 9.0.13
builder-util: 26.0.11
builder-util-runtime: 9.3.1
chalk: 4.1.2
form-data: 4.0.5
fs-extra: 10.1.0
lazy-val: 1.0.5
mime: 2.6.0
transitivePeerDependencies:
- supports-color
electron-to-chromium@1.5.267: {}
electron-vite@5.0.0(rolldown-vite@7.2.5(@types/node@24.10.2)(esbuild@0.25.12)(jiti@2.6.1)(terser@5.44.1)):
dependencies:
'@babel/core': 7.28.5
'@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.28.5)
cac: 6.7.14
esbuild: 0.25.12
magic-string: 0.30.21
picocolors: 1.1.1
vite: rolldown-vite@7.2.5(@types/node@24.10.2)(esbuild@0.25.12)(jiti@2.6.1)(terser@5.44.1)
transitivePeerDependencies:
- supports-color
electron-winstaller@5.4.0:
dependencies:
'@electron/asar': 3.4.1
debug: 4.4.3
fs-extra: 7.0.1
lodash: 4.17.21
temp: 0.9.4
optionalDependencies:
'@electron/windows-sign': 1.2.2
transitivePeerDependencies:
- supports-color
electron@39.2.7:
dependencies:
'@electron/get': 2.0.3
'@types/node': 22.19.3
extract-zip: 2.0.1
transitivePeerDependencies:
- supports-color
emoji-regex@8.0.0: {}
emoji-regex@9.2.2: {}
encodeurl@2.0.0: {}
encoding@0.1.13:
dependencies:
iconv-lite: 0.6.3
optional: true
end-of-stream@1.4.5:
dependencies:
once: 1.4.0
enhanced-resolve@5.18.3: enhanced-resolve@5.18.3:
dependencies: dependencies:
graceful-fs: 4.2.11 graceful-fs: 4.2.11
@@ -1520,54 +3745,420 @@ snapshots:
entities@4.5.0: {} entities@4.5.0: {}
esbuild@0.27.1: env-paths@2.2.1: {}
err-code@2.0.3: {}
es-define-property@1.0.1: {}
es-errors@1.3.0: {}
es-object-atoms@1.1.1:
dependencies:
es-errors: 1.3.0
es-set-tostringtag@2.1.0:
dependencies:
es-errors: 1.3.0
get-intrinsic: 1.3.0
has-tostringtag: 1.0.2
hasown: 2.0.2
es6-error@4.1.1:
optional: true
esbuild@0.25.12:
optionalDependencies: optionalDependencies:
'@esbuild/aix-ppc64': 0.27.1 '@esbuild/aix-ppc64': 0.25.12
'@esbuild/android-arm': 0.27.1 '@esbuild/android-arm': 0.25.12
'@esbuild/android-arm64': 0.27.1 '@esbuild/android-arm64': 0.25.12
'@esbuild/android-x64': 0.27.1 '@esbuild/android-x64': 0.25.12
'@esbuild/darwin-arm64': 0.27.1 '@esbuild/darwin-arm64': 0.25.12
'@esbuild/darwin-x64': 0.27.1 '@esbuild/darwin-x64': 0.25.12
'@esbuild/freebsd-arm64': 0.27.1 '@esbuild/freebsd-arm64': 0.25.12
'@esbuild/freebsd-x64': 0.27.1 '@esbuild/freebsd-x64': 0.25.12
'@esbuild/linux-arm': 0.27.1 '@esbuild/linux-arm': 0.25.12
'@esbuild/linux-arm64': 0.27.1 '@esbuild/linux-arm64': 0.25.12
'@esbuild/linux-ia32': 0.27.1 '@esbuild/linux-ia32': 0.25.12
'@esbuild/linux-loong64': 0.27.1 '@esbuild/linux-loong64': 0.25.12
'@esbuild/linux-mips64el': 0.27.1 '@esbuild/linux-mips64el': 0.25.12
'@esbuild/linux-ppc64': 0.27.1 '@esbuild/linux-ppc64': 0.25.12
'@esbuild/linux-riscv64': 0.27.1 '@esbuild/linux-riscv64': 0.25.12
'@esbuild/linux-s390x': 0.27.1 '@esbuild/linux-s390x': 0.25.12
'@esbuild/linux-x64': 0.27.1 '@esbuild/linux-x64': 0.25.12
'@esbuild/netbsd-arm64': 0.27.1 '@esbuild/netbsd-arm64': 0.25.12
'@esbuild/netbsd-x64': 0.27.1 '@esbuild/netbsd-x64': 0.25.12
'@esbuild/openbsd-arm64': 0.27.1 '@esbuild/openbsd-arm64': 0.25.12
'@esbuild/openbsd-x64': 0.27.1 '@esbuild/openbsd-x64': 0.25.12
'@esbuild/openharmony-arm64': 0.27.1 '@esbuild/openharmony-arm64': 0.25.12
'@esbuild/sunos-x64': 0.27.1 '@esbuild/sunos-x64': 0.25.12
'@esbuild/win32-arm64': 0.27.1 '@esbuild/win32-arm64': 0.25.12
'@esbuild/win32-ia32': 0.27.1 '@esbuild/win32-ia32': 0.25.12
'@esbuild/win32-x64': 0.27.1 '@esbuild/win32-x64': 0.25.12
escalade@3.2.0: {}
escape-html@1.0.3: {}
escape-string-regexp@4.0.0:
optional: true
estree-walker@2.0.2: {} estree-walker@2.0.2: {}
etag@1.8.1: {}
exponential-backoff@3.1.3: {}
extract-zip@2.0.1:
dependencies:
debug: 4.4.3
get-stream: 5.2.0
yauzl: 2.10.0
optionalDependencies:
'@types/yauzl': 2.10.3
transitivePeerDependencies:
- supports-color
extsprintf@1.4.1:
optional: true
fast-deep-equal@3.1.3: {}
fast-json-stable-stringify@2.1.0: {}
fd-slicer@1.1.0:
dependencies:
pend: 1.2.0
fdir@6.5.0(picomatch@4.0.3): fdir@6.5.0(picomatch@4.0.3):
optionalDependencies: optionalDependencies:
picomatch: 4.0.3 picomatch: 4.0.3
file-saver@2.0.5: {} file-saver@2.0.5: {}
filelist@1.0.4:
dependencies:
minimatch: 5.1.6
finalhandler@2.1.1:
dependencies:
debug: 4.4.3
encodeurl: 2.0.0
escape-html: 1.0.3
on-finished: 2.4.1
parseurl: 1.3.3
statuses: 2.0.2
transitivePeerDependencies:
- supports-color
foreground-child@3.3.1:
dependencies:
cross-spawn: 7.0.6
signal-exit: 4.1.0
form-data@4.0.5:
dependencies:
asynckit: 0.4.0
combined-stream: 1.0.8
es-set-tostringtag: 2.1.0
hasown: 2.0.2
mime-types: 2.1.35
fresh@2.0.0: {}
fs-extra@10.1.0:
dependencies:
graceful-fs: 4.2.11
jsonfile: 6.2.0
universalify: 2.0.1
fs-extra@11.3.2:
dependencies:
graceful-fs: 4.2.11
jsonfile: 6.2.0
universalify: 2.0.1
fs-extra@7.0.1:
dependencies:
graceful-fs: 4.2.11
jsonfile: 4.0.0
universalify: 0.1.2
fs-extra@8.1.0:
dependencies:
graceful-fs: 4.2.11
jsonfile: 4.0.0
universalify: 0.1.2
fs-extra@9.1.0:
dependencies:
at-least-node: 1.0.0
graceful-fs: 4.2.11
jsonfile: 6.2.0
universalify: 2.0.1
fs-minipass@2.1.0:
dependencies:
minipass: 3.3.6
fs.realpath@1.0.0: {}
fsevents@2.3.3: fsevents@2.3.3:
optional: true optional: true
function-bind@1.1.2: {}
gensync@1.0.0-beta.2: {}
get-caller-file@2.0.5: {}
get-intrinsic@1.3.0:
dependencies:
call-bind-apply-helpers: 1.0.2
es-define-property: 1.0.1
es-errors: 1.3.0
es-object-atoms: 1.1.1
function-bind: 1.1.2
get-proto: 1.0.1
gopd: 1.2.0
has-symbols: 1.1.0
hasown: 2.0.2
math-intrinsics: 1.1.0
get-proto@1.0.1:
dependencies:
dunder-proto: 1.0.1
es-object-atoms: 1.1.1
get-stream@5.2.0:
dependencies:
pump: 3.0.3
glob@10.5.0:
dependencies:
foreground-child: 3.3.1
jackspeak: 3.4.3
minimatch: 9.0.5
minipass: 7.1.2
package-json-from-dist: 1.0.1
path-scurry: 1.11.1
glob@7.2.3:
dependencies:
fs.realpath: 1.0.0
inflight: 1.0.6
inherits: 2.0.4
minimatch: 3.1.2
once: 1.4.0
path-is-absolute: 1.0.1
glob@8.1.0:
dependencies:
fs.realpath: 1.0.0
inflight: 1.0.6
inherits: 2.0.4
minimatch: 5.1.6
once: 1.4.0
global-agent@3.0.0:
dependencies:
boolean: 3.2.0
es6-error: 4.1.1
matcher: 3.0.0
roarr: 2.15.4
semver: 7.7.3
serialize-error: 7.0.1
optional: true
globalthis@1.0.4:
dependencies:
define-properties: 1.2.1
gopd: 1.2.0
optional: true
gopd@1.2.0: {}
got@11.8.6:
dependencies:
'@sindresorhus/is': 4.6.0
'@szmarczak/http-timer': 4.0.6
'@types/cacheable-request': 6.0.3
'@types/responselike': 1.0.3
cacheable-lookup: 5.0.4
cacheable-request: 7.0.4
decompress-response: 6.0.0
http2-wrapper: 1.0.3
lowercase-keys: 2.0.0
p-cancelable: 2.1.1
responselike: 2.0.1
graceful-fs@4.2.11: {} graceful-fs@4.2.11: {}
has-flag@4.0.0: {}
has-property-descriptors@1.0.2:
dependencies:
es-define-property: 1.0.1
optional: true
has-symbols@1.1.0: {}
has-tostringtag@1.0.2:
dependencies:
has-symbols: 1.1.0
hasown@2.0.2:
dependencies:
function-bind: 1.1.2
hookable@5.5.3: {} hookable@5.5.3: {}
hosted-git-info@4.1.0:
dependencies:
lru-cache: 6.0.0
http-cache-semantics@4.2.0: {}
http-errors@2.0.1:
dependencies:
depd: 2.0.0
inherits: 2.0.4
setprototypeof: 1.2.0
statuses: 2.0.2
toidentifier: 1.0.1
http-proxy-agent@5.0.0:
dependencies:
'@tootallnate/once': 2.0.0
agent-base: 6.0.2
debug: 4.4.3
transitivePeerDependencies:
- supports-color
http-proxy-agent@7.0.2:
dependencies:
agent-base: 7.1.4
debug: 4.4.3
transitivePeerDependencies:
- supports-color
http2-wrapper@1.0.3:
dependencies:
quick-lru: 5.1.1
resolve-alpn: 1.2.1
https-proxy-agent@5.0.1:
dependencies:
agent-base: 6.0.2
debug: 4.4.3
transitivePeerDependencies:
- supports-color
https-proxy-agent@7.0.6:
dependencies:
agent-base: 7.1.4
debug: 4.4.3
transitivePeerDependencies:
- supports-color
humanize-ms@1.2.1:
dependencies:
ms: 2.1.3
iconv-corefoundation@1.1.7:
dependencies:
cli-truncate: 2.1.0
node-addon-api: 1.7.2
optional: true
iconv-lite@0.6.3:
dependencies:
safer-buffer: 2.1.2
ieee754@1.2.1: {}
imurmurhash@0.1.4: {}
indent-string@4.0.0: {}
infer-owner@1.0.4: {}
inflight@1.0.6:
dependencies:
once: 1.4.0
wrappy: 1.0.2
inherits@2.0.4: {}
ip-address@10.1.0: {}
is-ci@3.0.1:
dependencies:
ci-info: 3.9.0
is-fullwidth-code-point@3.0.0: {}
is-interactive@1.0.0: {}
is-lambda@1.0.1: {}
is-unicode-supported@0.1.0: {}
is-what@5.5.0: {} is-what@5.5.0: {}
isbinaryfile@4.0.10: {}
isbinaryfile@5.0.7: {}
isexe@2.0.0: {}
jackspeak@3.4.3:
dependencies:
'@isaacs/cliui': 8.0.2
optionalDependencies:
'@pkgjs/parseargs': 0.11.0
jake@10.9.4:
dependencies:
async: 3.2.6
filelist: 1.0.4
picocolors: 1.1.1
jiti@2.6.1: {} jiti@2.6.1: {}
js-tokens@4.0.0: {}
js-yaml@4.1.1:
dependencies:
argparse: 2.0.1
jsesc@3.1.0: {}
json-buffer@3.0.1: {}
json-schema-traverse@0.4.1: {}
json-stringify-safe@5.0.1:
optional: true
json5@2.2.3: {}
jsonfile@4.0.0:
optionalDependencies:
graceful-fs: 4.2.11
jsonfile@6.2.0:
dependencies:
universalify: 2.0.1
optionalDependencies:
graceful-fs: 4.2.11
keyv@4.5.4:
dependencies:
json-buffer: 3.0.1
lazy-val@1.0.5: {}
lightningcss-android-arm64@1.30.2: lightningcss-android-arm64@1.30.2:
optional: true optional: true
@@ -1617,6 +4208,27 @@ snapshots:
lightningcss-win32-arm64-msvc: 1.30.2 lightningcss-win32-arm64-msvc: 1.30.2
lightningcss-win32-x64-msvc: 1.30.2 lightningcss-win32-x64-msvc: 1.30.2
lodash@4.17.21: {}
log-symbols@4.1.0:
dependencies:
chalk: 4.1.2
is-unicode-supported: 0.1.0
lowercase-keys@2.0.0: {}
lru-cache@10.4.3: {}
lru-cache@5.1.1:
dependencies:
yallist: 3.1.1
lru-cache@6.0.0:
dependencies:
yallist: 4.0.0
lru-cache@7.18.3: {}
lucide-vue-next@0.556.0(vue@3.5.25(typescript@5.9.3)): lucide-vue-next@0.556.0(vue@3.5.25(typescript@5.9.3)):
dependencies: dependencies:
vue: 3.5.25(typescript@5.9.3) vue: 3.5.25(typescript@5.9.3)
@@ -1625,16 +4237,203 @@ snapshots:
dependencies: dependencies:
'@jridgewell/sourcemap-codec': 1.5.5 '@jridgewell/sourcemap-codec': 1.5.5
make-fetch-happen@10.2.1:
dependencies:
agentkeepalive: 4.6.0
cacache: 16.1.3
http-cache-semantics: 4.2.0
http-proxy-agent: 5.0.0
https-proxy-agent: 5.0.1
is-lambda: 1.0.1
lru-cache: 7.18.3
minipass: 3.3.6
minipass-collect: 1.0.2
minipass-fetch: 2.1.2
minipass-flush: 1.0.5
minipass-pipeline: 1.2.4
negotiator: 0.6.4
promise-retry: 2.0.1
socks-proxy-agent: 7.0.0
ssri: 9.0.1
transitivePeerDependencies:
- bluebird
- supports-color
matcher@3.0.0:
dependencies:
escape-string-regexp: 4.0.0
optional: true
math-intrinsics@1.1.0: {}
mime-db@1.52.0: {}
mime-db@1.54.0: {}
mime-types@2.1.35:
dependencies:
mime-db: 1.52.0
mime-types@3.0.2:
dependencies:
mime-db: 1.54.0
mime@2.6.0: {}
mimic-fn@2.1.0: {}
mimic-response@1.0.1: {}
mimic-response@3.1.0: {}
minimatch@10.1.1:
dependencies:
'@isaacs/brace-expansion': 5.0.0
minimatch@3.1.2:
dependencies:
brace-expansion: 1.1.12
minimatch@5.1.6:
dependencies:
brace-expansion: 2.0.2
minimatch@9.0.5:
dependencies:
brace-expansion: 2.0.2
minimist@1.2.8: {}
minipass-collect@1.0.2:
dependencies:
minipass: 3.3.6
minipass-fetch@2.1.2:
dependencies:
minipass: 3.3.6
minipass-sized: 1.0.3
minizlib: 2.1.2
optionalDependencies:
encoding: 0.1.13
minipass-flush@1.0.5:
dependencies:
minipass: 3.3.6
minipass-pipeline@1.2.4:
dependencies:
minipass: 3.3.6
minipass-sized@1.0.3:
dependencies:
minipass: 3.3.6
minipass@3.3.6:
dependencies:
yallist: 4.0.0
minipass@5.0.0: {}
minipass@7.1.2: {}
minizlib@2.1.2:
dependencies:
minipass: 3.3.6
yallist: 4.0.0
mitt@3.0.1: {} mitt@3.0.1: {}
mkdirp@0.5.6:
dependencies:
minimist: 1.2.8
mkdirp@1.0.4: {}
ms@2.1.3: {}
muggle-string@0.4.1: {} muggle-string@0.4.1: {}
nanoid@3.3.11: {} nanoid@3.3.11: {}
negotiator@0.6.4: {}
node-abi@3.85.0:
dependencies:
semver: 7.7.3
node-addon-api@1.7.2:
optional: true
node-api-version@0.2.1:
dependencies:
semver: 7.7.3
node-releases@2.0.27: {}
nopt@6.0.0:
dependencies:
abbrev: 1.1.1
normalize-url@6.1.0: {}
object-keys@1.1.1:
optional: true
ohash@2.0.11: {} ohash@2.0.11: {}
on-finished@2.4.1:
dependencies:
ee-first: 1.1.1
once@1.4.0:
dependencies:
wrappy: 1.0.2
onetime@5.1.2:
dependencies:
mimic-fn: 2.1.0
ora@5.4.1:
dependencies:
bl: 4.1.0
chalk: 4.1.2
cli-cursor: 3.1.0
cli-spinners: 2.9.2
is-interactive: 1.0.0
is-unicode-supported: 0.1.0
log-symbols: 4.1.0
strip-ansi: 6.0.1
wcwidth: 1.0.1
p-cancelable@2.1.1: {}
p-limit@3.1.0:
dependencies:
yocto-queue: 0.1.0
p-map@4.0.0:
dependencies:
aggregate-error: 3.1.0
package-json-from-dist@1.0.1: {}
parseurl@1.3.3: {}
path-browserify@1.0.1: {} path-browserify@1.0.1: {}
path-is-absolute@1.0.1: {}
path-key@3.1.1: {}
path-scurry@1.11.1:
dependencies:
lru-cache: 10.4.3
minipass: 7.1.2
pe-library@0.4.1: {}
pend@1.2.0: {}
perfect-debounce@1.0.0: {} perfect-debounce@1.0.0: {}
picocolors@1.1.1: {} picocolors@1.1.1: {}
@@ -1654,12 +4453,57 @@ snapshots:
optionalDependencies: optionalDependencies:
typescript: 5.9.3 typescript: 5.9.3
plist@3.1.0:
dependencies:
'@xmldom/xmldom': 0.8.11
base64-js: 1.5.1
xmlbuilder: 15.1.1
postcss@8.5.6: postcss@8.5.6:
dependencies: dependencies:
nanoid: 3.3.11 nanoid: 3.3.11
picocolors: 1.1.1 picocolors: 1.1.1
source-map-js: 1.2.1 source-map-js: 1.2.1
postject@1.0.0-alpha.6:
dependencies:
commander: 9.5.0
optional: true
proc-log@2.0.1: {}
progress@2.0.3: {}
promise-inflight@1.0.1: {}
promise-retry@2.0.1:
dependencies:
err-code: 2.0.3
retry: 0.12.0
pump@3.0.3:
dependencies:
end-of-stream: 1.4.5
once: 1.4.0
punycode@2.3.1: {}
quick-lru@5.1.1: {}
range-parser@1.2.1: {}
read-binary-file-arch@1.0.6:
dependencies:
debug: 4.4.3
transitivePeerDependencies:
- supports-color
readable-stream@3.6.2:
dependencies:
inherits: 2.0.4
string_decoder: 1.3.0
util-deprecate: 1.0.2
reka-ui@2.6.1(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3)): reka-ui@2.6.1(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3)):
dependencies: dependencies:
'@floating-ui/dom': 1.7.4 '@floating-ui/dom': 1.7.4
@@ -1677,9 +4521,46 @@ snapshots:
- '@vue/composition-api' - '@vue/composition-api'
- typescript - typescript
require-directory@2.1.1: {}
resedit@1.7.2:
dependencies:
pe-library: 0.4.1
resolve-alpn@1.2.1: {}
responselike@2.0.1:
dependencies:
lowercase-keys: 2.0.0
restore-cursor@3.1.0:
dependencies:
onetime: 5.1.2
signal-exit: 3.0.7
retry@0.12.0: {}
rfdc@1.4.1: {} rfdc@1.4.1: {}
rolldown-vite@7.2.5(@types/node@24.10.2)(esbuild@0.27.1)(jiti@2.6.1)(terser@5.44.1): rimraf@2.6.3:
dependencies:
glob: 7.2.3
rimraf@3.0.2:
dependencies:
glob: 7.2.3
roarr@2.15.4:
dependencies:
boolean: 3.2.0
detect-node: 2.1.0
globalthis: 1.0.4
json-stringify-safe: 5.0.1
semver-compare: 1.0.0
sprintf-js: 1.1.3
optional: true
rolldown-vite@7.2.5(@types/node@24.10.2)(esbuild@0.25.12)(jiti@2.6.1)(terser@5.44.1):
dependencies: dependencies:
'@oxc-project/runtime': 0.97.0 '@oxc-project/runtime': 0.97.0
fdir: 6.5.0(picomatch@4.0.3) fdir: 6.5.0(picomatch@4.0.3)
@@ -1690,7 +4571,7 @@ snapshots:
tinyglobby: 0.2.15 tinyglobby: 0.2.15
optionalDependencies: optionalDependencies:
'@types/node': 24.10.2 '@types/node': 24.10.2
esbuild: 0.27.1 esbuild: 0.25.12
fsevents: 2.3.3 fsevents: 2.3.3
jiti: 2.6.1 jiti: 2.6.1
terser: 5.44.1 terser: 5.44.1
@@ -1715,6 +4596,93 @@ snapshots:
'@rolldown/binding-win32-ia32-msvc': 1.0.0-beta.50 '@rolldown/binding-win32-ia32-msvc': 1.0.0-beta.50
'@rolldown/binding-win32-x64-msvc': 1.0.0-beta.50 '@rolldown/binding-win32-x64-msvc': 1.0.0-beta.50
safe-buffer@5.2.1: {}
safer-buffer@2.1.2: {}
sanitize-filename@1.6.3:
dependencies:
truncate-utf8-bytes: 1.0.2
sax@1.4.3: {}
semver-compare@1.0.0:
optional: true
semver@5.7.2: {}
semver@6.3.1: {}
semver@7.7.3: {}
send@1.2.0:
dependencies:
debug: 4.4.3
encodeurl: 2.0.0
escape-html: 1.0.3
etag: 1.8.1
fresh: 2.0.0
http-errors: 2.0.1
mime-types: 3.0.2
ms: 2.1.3
on-finished: 2.4.1
range-parser: 1.2.1
statuses: 2.0.2
transitivePeerDependencies:
- supports-color
serialize-error@7.0.1:
dependencies:
type-fest: 0.13.1
optional: true
serve-static@2.2.0:
dependencies:
encodeurl: 2.0.0
escape-html: 1.0.3
parseurl: 1.3.3
send: 1.2.0
transitivePeerDependencies:
- supports-color
setprototypeof@1.2.0: {}
shebang-command@2.0.0:
dependencies:
shebang-regex: 3.0.0
shebang-regex@3.0.0: {}
signal-exit@3.0.7: {}
signal-exit@4.1.0: {}
simple-update-notifier@2.0.0:
dependencies:
semver: 7.7.3
slice-ansi@3.0.0:
dependencies:
ansi-styles: 4.3.0
astral-regex: 2.0.0
is-fullwidth-code-point: 3.0.0
optional: true
smart-buffer@4.2.0: {}
socks-proxy-agent@7.0.0:
dependencies:
agent-base: 6.0.2
debug: 4.4.3
socks: 2.8.7
transitivePeerDependencies:
- supports-color
socks@2.8.7:
dependencies:
ip-address: 10.1.0
smart-buffer: 4.2.0
source-map-js@1.2.1: {} source-map-js@1.2.1: {}
source-map-support@0.5.21: source-map-support@0.5.21:
@@ -1726,36 +4694,161 @@ snapshots:
speakingurl@14.0.1: {} speakingurl@14.0.1: {}
sprintf-js@1.1.3:
optional: true
ssri@9.0.1:
dependencies:
minipass: 3.3.6
stat-mode@1.0.0: {}
statuses@2.0.2: {}
string-width@4.2.3:
dependencies:
emoji-regex: 8.0.0
is-fullwidth-code-point: 3.0.0
strip-ansi: 6.0.1
string-width@5.1.2:
dependencies:
eastasianwidth: 0.2.0
emoji-regex: 9.2.2
strip-ansi: 7.1.2
string_decoder@1.3.0:
dependencies:
safe-buffer: 5.2.1
strip-ansi@6.0.1:
dependencies:
ansi-regex: 5.0.1
strip-ansi@7.1.2:
dependencies:
ansi-regex: 6.2.2
sumchecker@3.0.1:
dependencies:
debug: 4.4.3
transitivePeerDependencies:
- supports-color
superjson@2.2.6: superjson@2.2.6:
dependencies: dependencies:
copy-anything: 4.0.5 copy-anything: 4.0.5
supports-color@7.2.0:
dependencies:
has-flag: 4.0.0
tailwind-merge@3.4.0: {} tailwind-merge@3.4.0: {}
tailwindcss@4.1.17: {} tailwindcss@4.1.17: {}
tapable@2.3.0: {} tapable@2.3.0: {}
tar@6.2.1:
dependencies:
chownr: 2.0.0
fs-minipass: 2.1.0
minipass: 5.0.0
minizlib: 2.1.2
mkdirp: 1.0.4
yallist: 4.0.0
temp-file@3.4.0:
dependencies:
async-exit-hook: 2.0.1
fs-extra: 10.1.0
temp@0.9.4:
dependencies:
mkdirp: 0.5.6
rimraf: 2.6.3
terser@5.44.1: terser@5.44.1:
dependencies: dependencies:
'@jridgewell/source-map': 0.3.11 '@jridgewell/source-map': 0.3.11
acorn: 8.15.0 acorn: 8.15.0
commander: 2.20.3 commander: 2.20.3
source-map-support: 0.5.21 source-map-support: 0.5.21
optional: true
tiny-async-pool@1.3.0:
dependencies:
semver: 5.7.2
tinyglobby@0.2.15: tinyglobby@0.2.15:
dependencies: dependencies:
fdir: 6.5.0(picomatch@4.0.3) fdir: 6.5.0(picomatch@4.0.3)
picomatch: 4.0.3 picomatch: 4.0.3
tmp-promise@3.0.3:
dependencies:
tmp: 0.2.5
tmp@0.2.5: {}
toidentifier@1.0.1: {}
truncate-utf8-bytes@1.0.2:
dependencies:
utf8-byte-length: 1.0.5
tslib@2.8.1: {} tslib@2.8.1: {}
tw-animate-css@1.4.0: {} tw-animate-css@1.4.0: {}
type-fest@0.13.1:
optional: true
typescript@5.9.3: {} typescript@5.9.3: {}
undici-types@6.21.0: {}
undici-types@7.16.0: {} undici-types@7.16.0: {}
unique-filename@2.0.1:
dependencies:
unique-slug: 3.0.0
unique-slug@3.0.0:
dependencies:
imurmurhash: 0.1.4
universalify@0.1.2: {}
universalify@2.0.1: {}
update-browserslist-db@1.2.2(browserslist@4.28.1):
dependencies:
browserslist: 4.28.1
escalade: 3.2.0
picocolors: 1.1.1
uri-js@4.4.1:
dependencies:
punycode: 2.3.1
utf8-byte-length@1.0.5: {}
util-deprecate@1.0.2: {}
verror@1.10.1:
dependencies:
assert-plus: 1.0.0
core-util-is: 1.0.2
extsprintf: 1.4.1
optional: true
vite-plugin-electron-renderer@0.14.6: {}
vite-plugin-electron@0.29.0(vite-plugin-electron-renderer@0.14.6):
optionalDependencies:
vite-plugin-electron-renderer: 0.14.6
vscode-uri@3.1.0: {} vscode-uri@3.1.0: {}
vue-demi@0.14.10(vue@3.5.25(typescript@5.9.3)): vue-demi@0.14.10(vue@3.5.25(typescript@5.9.3)):
@@ -1784,3 +4877,52 @@ snapshots:
'@vue/shared': 3.5.25 '@vue/shared': 3.5.25
optionalDependencies: optionalDependencies:
typescript: 5.9.3 typescript: 5.9.3
wcwidth@1.0.1:
dependencies:
defaults: 1.0.4
which@2.0.2:
dependencies:
isexe: 2.0.0
wrap-ansi@7.0.0:
dependencies:
ansi-styles: 4.3.0
string-width: 4.2.3
strip-ansi: 6.0.1
wrap-ansi@8.1.0:
dependencies:
ansi-styles: 6.2.3
string-width: 5.1.2
strip-ansi: 7.1.2
wrappy@1.0.2: {}
xmlbuilder@15.1.1: {}
y18n@5.0.8: {}
yallist@3.1.1: {}
yallist@4.0.0: {}
yargs-parser@21.1.1: {}
yargs@17.7.2:
dependencies:
cliui: 8.0.1
escalade: 3.2.0
get-caller-file: 2.0.5
require-directory: 2.1.1
string-width: 4.2.3
y18n: 5.0.8
yargs-parser: 21.1.1
yauzl@2.10.0:
dependencies:
buffer-crc32: 0.2.13
fd-slicer: 1.1.0
yocto-queue@0.1.0: {}

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 KiB

View File

@@ -1,150 +1,131 @@
<template> <template>
<div class="flex h-screen bg-background overflow-hidden"> <SidebarProvider :open="sidebarOpen" @update:open="sidebarOpen = $event">
<!-- 遮罩层移动端 --> <Sidebar collapsible="icon">
<div v-if="!gameStore.sidebarCollapsed" class="fixed inset-0 bg-black/50 z-30 lg:hidden" @click="toggleSidebar" />
<!-- 侧边导航栏 -->
<aside
:class="[
'border-r bg-card flex flex-col transition-all duration-300 ease-in-out shadow-lg z-40',
'fixed lg:relative h-full',
gameStore.sidebarCollapsed ? '-translate-x-full lg:translate-x-0 lg:w-16' : 'translate-x-0 w-64'
]"
>
<!-- Logo --> <!-- Logo -->
<div class="p-4 border-b flex items-center justify-center"> <SidebarHeader class="border-b">
<h1 v-if="!gameStore.sidebarCollapsed" class="text-xl font-bold flex items-center gap-2"> <div class="flex items-center justify-center p-4 group-data-[collapsible=icon]:p-2">
<span class="text-2xl"> <img src="@/assets/logo.svg" class="w-10 group-data-[collapsible=icon]:w-8" />
<img src="@/assets/logo.svg" class="w-10" /> <h1 class="text-xl font-bold ml-2 group-data-[collapsible=icon]:hidden">{{ pkg.title }}</h1>
</span>
{{ pkg.title }}
</h1>
<span v-else class="text-2xl">
<img src="@/assets/logo.svg" class="w-10" />
</span>
</div>
<!-- 星球信息 -->
<div v-if="planet && !gameStore.sidebarCollapsed" class="p-4 border-b">
<div class="text-sm space-y-2">
<div>
<p class="font-semibold mb-1">
{{ planet.name }}
<Badge v-if="planet.isMoon" variant="secondary" class="ml-1 text-xs">{{ t('planet.moon') }}</Badge>
</p>
<p class="text-muted-foreground text-xs">
[{{ planet.position.galaxy }}:{{ planet.position.system }}:{{ planet.position.position }}]
</p>
</div>
<!-- 玩家积分显示 -->
<div class="bg-muted/50 rounded-lg p-2">
<div class="flex items-center justify-between">
<span class="text-xs text-muted-foreground">{{ t('player.points') }}</span>
<span class="text-sm font-bold text-primary">{{ formatNumber(gameStore.player.points) }}</span>
</div>
</div>
<!-- 月球切换按钮 -->
<div v-if="hasMoon || planet.isMoon" class="flex gap-1">
<Button v-if="planet.isMoon" @click="switchToParentPlanet" variant="outline" size="sm" class="w-full text-xs h-7">
{{ t('planet.backToPlanet') }}
</Button>
<Button v-else-if="moon" @click="switchToMoon" variant="outline" size="sm" class="w-full text-xs h-7">
{{ t('planet.switchToMoon') }}
</Button>
</div>
</div> </div>
</div> </SidebarHeader>
<!-- 导航菜单 --> <SidebarContent>
<nav class="flex-1 p-2 space-y-1 overflow-y-auto"> <!-- 星球信息 -->
<RouterLink v-for="item in navItems" :key="item.path" :to="item.path" v-slot="{ isActive: routeActive }"> <SidebarGroup v-if="planet" class="border-b group-data-[collapsible=icon]:hidden">
<Button <div class="px-4 py-3 space-y-2 text-sm">
:variant="routeActive ? 'secondary' : 'ghost'" <div>
:class="['w-full transition-all', gameStore.sidebarCollapsed ? 'justify-center px-0' : 'justify-start']" <p class="font-semibold mb-1">
:title="gameStore.sidebarCollapsed ? item.name.value : undefined" {{ planet.name }}
> <Badge v-if="planet.isMoon" variant="secondary" class="ml-1 text-xs">{{ t('planet.moon') }}</Badge>
<component :is="item.icon" :class="['h-4 w-4', !gameStore.sidebarCollapsed && 'mr-3']" /> </p>
<span v-if="!gameStore.sidebarCollapsed">{{ item.name.value }}</span> <p class="text-muted-foreground text-xs">
</Button> [{{ planet.position.galaxy }}:{{ planet.position.system }}:{{ planet.position.position }}]
</RouterLink> </p>
</nav> </div>
<!-- 玩家积分显示 -->
<!-- 语言切换 --> <div class="bg-muted/50 rounded-lg p-2">
<div class="p-2 border-t"> <div class="flex items-center justify-between">
<Popover> <span class="text-xs text-muted-foreground">{{ t('player.points') }}</span>
<PopoverTrigger as-child> <span class="text-sm font-bold text-primary">{{ formatNumber(gameStore.player.points) }}</span>
<Button variant="ghost" class="w-full" size="sm"> </div>
<Languages class="h-4 w-4" /> </div>
<span v-if="!gameStore.sidebarCollapsed" class="ml-2">{{ localeNames[gameStore.locale] }}</span> <!-- 月球切换按钮 -->
</Button> <div v-if="hasMoon || planet.isMoon" class="flex gap-1">
</PopoverTrigger> <Button v-if="planet.isMoon" @click="switchToParentPlanet" variant="outline" size="sm" class="w-full text-xs h-7">
<PopoverContent class="w-48 p-2" :align="gameStore.sidebarCollapsed ? 'start' : 'center'"> {{ t('planet.backToPlanet') }}
<div class="space-y-1"> </Button>
<Button <Button v-else-if="moon" @click="switchToMoon" variant="outline" size="sm" class="w-full text-xs h-7">
v-for="locale in locales" {{ t('planet.switchToMoon') }}
:key="locale"
@click="gameStore.locale = locale"
:variant="gameStore.locale === locale ? 'secondary' : 'ghost'"
class="w-full justify-start"
size="sm"
>
{{ localeNames[locale] }}
</Button> </Button>
</div> </div>
</PopoverContent> </div>
</Popover> </SidebarGroup>
</div>
<!-- 夜间模式切换 --> <!-- 导航菜单 -->
<div class="p-2 border-t"> <SidebarGroup>
<Button @click="isDark = !isDark" variant="ghost" class="w-full" size="sm"> <SidebarMenu>
<Sun v-if="isDark" class="h-4 w-4" /> <SidebarMenuItem v-for="item in navItems" :key="item.path">
<Moon v-else class="h-4 w-4" /> <SidebarMenuButton as-child :is-active="$route.path === item.path" :tooltip="item.name.value">
<span v-if="!gameStore.sidebarCollapsed" class="ml-2">{{ isDark ? t('sidebar.lightMode') : t('sidebar.darkMode') }}</span> <RouterLink :to="item.path">
</Button> <component :is="item.icon" />
</div> <span>{{ item.name.value }}</span>
<div class="p-2 border-t"> <!-- 未读消息数量 -->
<Button @click="toggleSidebar" variant="ghost" class="w-full" size="sm"> <SidebarMenuBadge v-if="item.path === '/messages' && unreadMessagesCount > 0">
<ChevronLeft v-if="!gameStore.sidebarCollapsed" class="h-4 w-4" /> {{ unreadMessagesCount }}
<ChevronRight v-else class="h-4 w-4" /> </SidebarMenuBadge>
<span v-if="!gameStore.sidebarCollapsed" class="ml-2">{{ t('sidebar.collapse') }}</span> </RouterLink>
</Button> </SidebarMenuButton>
</div> </SidebarMenuItem>
</aside> </SidebarMenu>
</SidebarGroup>
</SidebarContent>
<!-- 底部设置 -->
<SidebarFooter class="border-t">
<SidebarMenu>
<!-- 语言切换 -->
<SidebarMenuItem>
<Popover>
<PopoverTrigger as-child>
<SidebarMenuButton :tooltip="localeNames[gameStore.locale]">
<Languages />
<span>{{ localeNames[gameStore.locale] }}</span>
</SidebarMenuButton>
</PopoverTrigger>
<PopoverContent class="w-48 p-2" side="right" align="end">
<div class="space-y-1">
<Button
v-for="locale in locales"
:key="locale"
@click="gameStore.locale = locale"
:variant="gameStore.locale === locale ? 'secondary' : 'ghost'"
class="w-full justify-start"
size="sm"
>
{{ localeNames[locale] }}
</Button>
</div>
</PopoverContent>
</Popover>
</SidebarMenuItem>
<!-- 夜间模式切换 -->
<SidebarMenuItem>
<SidebarMenuButton @click="isDark = !isDark" :tooltip="isDark ? t('sidebar.lightMode') : t('sidebar.darkMode')">
<Sun v-if="isDark" />
<Moon v-else />
<span>{{ isDark ? t('sidebar.lightMode') : t('sidebar.darkMode') }}</span>
</SidebarMenuButton>
</SidebarMenuItem>
<!-- 折叠按钮 -->
<SidebarMenuItem class="hidden sm:inline">
<SidebarMenuButton @click="toggleSidebar" :tooltip="sidebarOpen ? t('sidebar.collapse') : t('sidebar.expand')">
<ChevronsLeft class="group-data-[state=collapsed]:rotate-180 transition-transform" />
<span>{{ t('sidebar.collapse') }}</span>
</SidebarMenuButton>
</SidebarMenuItem>
</SidebarMenu>
</SidebarFooter>
</Sidebar>
<!-- 主内容区 --> <!-- 主内容区 -->
<div class="flex-1 flex flex-col overflow-hidden"> <SidebarInset>
<!-- 顶部资源栏 --> <div class="flex flex-col h-full overflow-hidden">
<header v-if="planet" class="bg-card border-b px-4 sm:px-6 py-4.5 shadow-md"> <!-- 顶部资源栏 -->
<div class="flex items-center justify-between gap-3 sm:gap-6"> <header v-if="planet" class="bg-card border-b px-4 sm:px-6 py-6.5 shadow-md">
<!-- 汉堡菜单移动端- 左侧占位 --> <div class="flex items-center justify-between gap-3 sm:gap-6">
<div class="lg:flex-1"> <!-- 汉堡菜单移动端- 左侧占位 -->
<Button @click="toggleSidebar" variant="ghost" size="icon" class="lg:hidden h-8 w-8"> <div class="lg:flex-1">
<component :is="gameStore.sidebarCollapsed ? Menu : X" class="h-5 w-5" /> <SidebarTrigger class="lg:hidden" />
</Button> </div>
</div>
<!-- 资源显示 - PC端居中 --> <!-- 资源显示 - PC端居中 -->
<div class="flex items-center gap-3 sm:gap-6 flex-1 lg:flex-none overflow-x-auto lg:justify-center"> <div class="flex items-center gap-3 sm:gap-6 flex-1 lg:flex-none overflow-x-auto lg:justify-center">
<div v-for="resourceType in resourceTypes" :key="resourceType.key" class="flex items-center gap-1.5 sm:gap-2 flex-shrink-0"> <div v-for="resourceType in resourceTypes" :key="resourceType.key" class="flex items-center gap-1.5 sm:gap-2 flex-shrink-0">
<ResourceIcon :type="resourceType.key" size="md" /> <ResourceIcon :type="resourceType.key" size="md" />
<div class="min-w-0"> <div class="min-w-0">
<!-- 电量显示 --> <!-- 所有资源统一显示当前值/容量 -->
<template v-if="resourceType.key === 'energy'">
<p
class="text-xs sm:text-sm font-medium truncate"
:class="
planet.resources[resourceType.key] >= 0 ? 'text-green-600 dark:text-green-400' : 'text-red-600 dark:text-red-400'
"
>
{{ formatNumber(planet.resources[resourceType.key]) }}
</p>
<p class="text-[10px] sm:text-xs text-muted-foreground truncate">
{{ formatNumber(energyProduction || 0) }} / {{ formatNumber(energyConsumption || 0) }}
</p>
</template>
<!-- 其他资源显示 -->
<template v-else>
<p <p
class="text-xs sm:text-sm font-medium truncate" class="text-xs sm:text-sm font-medium truncate"
:class="getResourceColor(planet.resources[resourceType.key], capacity?.[resourceType.key] || Infinity)" :class="getResourceColor(planet.resources[resourceType.key], capacity?.[resourceType.key] || Infinity)"
@@ -152,105 +133,116 @@
{{ formatNumber(planet.resources[resourceType.key]) }} / {{ formatNumber(capacity?.[resourceType.key] || 0) }} {{ formatNumber(planet.resources[resourceType.key]) }} / {{ formatNumber(capacity?.[resourceType.key] || 0) }}
</p> </p>
<p class="text-[10px] sm:text-xs text-muted-foreground truncate"> <p class="text-[10px] sm:text-xs text-muted-foreground truncate">
+{{ formatNumber(production?.[resourceType.key] || 0) }}/{{ t('resources.perHour') }} +{{ formatNumber(Math.round((production?.[resourceType.key] || 0) / 60)) }}/{{ t('resources.perMinute') }}
</p> </p>
</template> </div>
</div>
</div>
<!-- 右侧状态 - 右侧占位 -->
<div class="flex items-center gap-2 sm:gap-4 flex-shrink-0 lg:flex-1 lg:justify-end">
<!-- 建造队列状态 -->
<div v-if="planet.buildQueue.length > 0" class="flex items-center gap-1.5 sm:gap-2 text-xs sm:text-sm">
<div class="h-2 w-2 rounded-full bg-green-500 animate-pulse" />
<span class="text-muted-foreground hidden sm:inline">{{ t('queue.building') }}</span>
</div>
<div v-if="gameStore.player.researchQueue.length > 0" class="flex items-center gap-1.5 sm:gap-2 text-xs sm:text-sm">
<div class="h-2 w-2 rounded-full bg-blue-500 animate-pulse" />
<span class="text-muted-foreground hidden sm:inline">{{ t('queue.researching') }}</span>
</div> </div>
</div> </div>
</div> </div>
</header>
<!-- 右侧状态 - 右侧占位 --> <!-- 建造队列 -->
<div class="flex items-center gap-2 sm:gap-4 flex-shrink-0 lg:flex-1 lg:justify-end"> <div
<!-- 建造队列状态 --> v-if="planet && (planet.buildQueue.length > 0 || gameStore.player.researchQueue.length > 0)"
<div v-if="planet.buildQueue.length > 0" class="flex items-center gap-1.5 sm:gap-2 text-xs sm:text-sm"> class="bg-card border-b px-4 sm:px-6 py-4.5"
<div class="h-2 w-2 rounded-full bg-green-500 animate-pulse" /> >
<span class="text-muted-foreground hidden sm:inline">{{ t('queue.building') }}</span> <div class="space-y-3">
<!-- 建造队列 -->
<div v-for="item in planet.buildQueue" :key="item.id" class="space-y-1.5">
<div class="flex items-center justify-between text-xs sm:text-sm gap-2">
<div class="flex items-center gap-1.5 sm:gap-2 min-w-0 flex-1">
<div class="h-2 w-2 rounded-full bg-green-500 animate-pulse flex-shrink-0" />
<span class="font-medium truncate">{{ getItemName(item) }}</span>
<span class="text-muted-foreground hidden sm:inline flex-shrink-0 text-[10px] sm:text-xs">
<template v-if="item.type === 'ship' || item.type === 'defense'">
{{ t('queue.quantity') }} {{ item.quantity }}
</template>
<template v-else> {{ t('queue.level') }} {{ item.targetLevel }}</template>
</span>
</div>
<div class="flex items-center gap-2 sm:gap-3 flex-shrink-0">
<span class="text-muted-foreground text-[10px] sm:text-xs whitespace-nowrap">
{{ formatTime(getRemainingTime(item)) }}
</span>
<Button
@click="handleCancelBuild(item.id)"
variant="ghost"
size="sm"
class="h-5 sm:h-6 px-1.5 sm:px-2 text-[10px] sm:text-xs"
>
{{ t('queue.cancel') }}
</Button>
</div>
</div>
<Progress :model-value="getQueueProgress(item)" class="h-1.5" />
</div> </div>
<div v-if="gameStore.player.researchQueue.length > 0" class="flex items-center gap-1.5 sm:gap-2 text-xs sm:text-sm"> <!-- 研究队列 -->
<div class="h-2 w-2 rounded-full bg-blue-500 animate-pulse" /> <div v-for="item in gameStore.player.researchQueue" :key="item.id" class="space-y-1.5">
<span class="text-muted-foreground hidden sm:inline">{{ t('queue.researching') }}</span> <div class="flex items-center justify-between text-xs sm:text-sm gap-2">
<div class="flex items-center gap-1.5 sm:gap-2 min-w-0 flex-1">
<div class="h-2 w-2 rounded-full bg-blue-500 animate-pulse flex-shrink-0" />
<span class="font-medium truncate">{{ getItemName(item) }}</span>
<span class="text-muted-foreground hidden sm:inline flex-shrink-0 text-[10px] sm:text-xs">
{{ t('queue.level') }} {{ item.targetLevel }}
</span>
</div>
<div class="flex items-center gap-2 sm:gap-3 flex-shrink-0">
<span class="text-muted-foreground text-[10px] sm:text-xs whitespace-nowrap">
{{ formatTime(getRemainingTime(item)) }}
</span>
<Button
@click="handleCancelResearch(item.id)"
variant="ghost"
size="sm"
class="h-5 sm:h-6 px-1.5 sm:px-2 text-[10px] sm:text-xs"
>
{{ t('queue.cancel') }}
</Button>
</div>
</div>
<Progress :model-value="getQueueProgress(item)" class="h-1.5" />
</div> </div>
</div> </div>
</div> </div>
</header>
<!-- 建造队列 --> <!-- 内容区域 -->
<div <main class="flex-1 overflow-y-auto">
v-if="planet && (planet.buildQueue.length > 0 || gameStore.player.researchQueue.length > 0)" <div class="animate-fade-in">
class="bg-card border-b px-4 sm:px-6 py-4.5" <RouterView />
>
<div class="space-y-3">
<!-- 建造队列 -->
<div v-for="item in planet.buildQueue" :key="item.id" class="space-y-1.5">
<div class="flex items-center justify-between text-xs sm:text-sm gap-2">
<div class="flex items-center gap-1.5 sm:gap-2 min-w-0 flex-1">
<div class="h-2 w-2 rounded-full bg-green-500 animate-pulse flex-shrink-0" />
<span class="font-medium truncate">{{ getItemName(item) }}</span>
<span class="text-muted-foreground hidden sm:inline flex-shrink-0 text-[10px] sm:text-xs">
{{ t('queue.level') }} {{ item.targetLevel }}
</span>
</div>
<div class="flex items-center gap-2 sm:gap-3 flex-shrink-0">
<span class="text-muted-foreground text-[10px] sm:text-xs whitespace-nowrap">{{ formatTime(getRemainingTime(item)) }}</span>
<Button
@click="handleCancelBuild(item.id)"
variant="ghost"
size="sm"
class="h-5 sm:h-6 px-1.5 sm:px-2 text-[10px] sm:text-xs"
>
{{ t('queue.cancel') }}
</Button>
</div>
</div>
<Progress :model-value="getQueueProgress(item)" class="h-1.5" />
</div> </div>
<!-- 研究队列 --> </main>
<div v-for="item in gameStore.player.researchQueue" :key="item.id" class="space-y-1.5">
<div class="flex items-center justify-between text-xs sm:text-sm gap-2">
<div class="flex items-center gap-1.5 sm:gap-2 min-w-0 flex-1">
<div class="h-2 w-2 rounded-full bg-blue-500 animate-pulse flex-shrink-0" />
<span class="font-medium truncate">{{ getItemName(item) }}</span>
<span class="text-muted-foreground hidden sm:inline flex-shrink-0 text-[10px] sm:text-xs">
{{ t('queue.level') }} {{ item.targetLevel }}
</span>
</div>
<div class="flex items-center gap-2 sm:gap-3 flex-shrink-0">
<span class="text-muted-foreground text-[10px] sm:text-xs whitespace-nowrap">{{ formatTime(getRemainingTime(item)) }}</span>
<Button
@click="handleCancelResearch(item.id)"
variant="ghost"
size="sm"
class="h-5 sm:h-6 px-1.5 sm:px-2 text-[10px] sm:text-xs"
>
{{ t('queue.cancel') }}
</Button>
</div>
</div>
<Progress :model-value="getQueueProgress(item)" class="h-1.5" />
</div>
</div>
</div> </div>
</SidebarInset>
<!-- 内容区域 -->
<main class="flex-1 overflow-y-auto">
<div class="animate-fade-in">
<RouterView />
</div>
</main>
</div>
<!-- 确认对话框 --> <!-- 确认对话框 -->
<ConfirmDialog ref="confirmDialog" /> <ConfirmDialog ref="confirmDialog" />
<!-- 详情弹窗 --> <!-- 详情弹窗 -->
<DetailDialog /> <DetailDialog />
</div>
<!-- Toast 通知 -->
<Sonner position="top-center" />
</SidebarProvider>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { onMounted, onUnmounted, computed, ref } from 'vue' import { onMounted, onUnmounted, computed, ref } from 'vue'
import { RouterView, RouterLink } from 'vue-router' import { RouterView, RouterLink } from 'vue-router'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { useUniverseStore } from '@/stores/universeStore'
import { useTheme } from '@/composables/useTheme' import { useTheme } from '@/composables/useTheme'
import { useI18n } from '@/composables/useI18n' import { useI18n } from '@/composables/useI18n'
import { localeNames, detectBrowserLocale, type Locale } from '@/locales' import { localeNames, detectBrowserLocale, type Locale } from '@/locales'
@@ -258,12 +250,26 @@
import { Badge } from '@/components/ui/badge' import { Badge } from '@/components/ui/badge'
import { Progress } from '@/components/ui/progress' import { Progress } from '@/components/ui/progress'
import { Popover, PopoverTrigger, PopoverContent } from '@/components/ui/popover' import { Popover, PopoverTrigger, PopoverContent } from '@/components/ui/popover'
import {
Sidebar,
SidebarContent,
SidebarFooter,
SidebarGroup,
SidebarHeader,
SidebarInset,
SidebarMenu,
SidebarMenuBadge,
SidebarMenuButton,
SidebarMenuItem,
SidebarProvider,
SidebarTrigger
} from '@/components/ui/sidebar'
import ResourceIcon from '@/components/ResourceIcon.vue' import ResourceIcon from '@/components/ResourceIcon.vue'
import ConfirmDialog from '@/components/ConfirmDialog.vue' import ConfirmDialog from '@/components/ConfirmDialog.vue'
import DetailDialog from '@/components/DetailDialog.vue' import DetailDialog from '@/components/DetailDialog.vue'
import { BuildingType, TechnologyType, ShipType, DefenseType, MissionType } from '@/types/game' import Sonner from '@/components/ui/sonner/Sonner.vue'
import { MissionType } from '@/types/game'
import type { BuildQueueItem, FleetMission } from '@/types/game' import type { BuildQueueItem, FleetMission } from '@/types/game'
import { BUILDINGS, TECHNOLOGIES, SHIPS, DEFENSES } from '@/config/gameConfig'
import { formatNumber, formatTime, getResourceColor } from '@/utils/format' import { formatNumber, formatTime, getResourceColor } from '@/utils/format'
import { import {
Moon, Moon,
@@ -276,18 +282,15 @@
Shield, Shield,
Mail, Mail,
Globe, Globe,
ChevronLeft,
ChevronRight,
Menu,
X,
Users, Users,
Swords, Swords,
Languages, Languages,
Settings Settings,
Wrench,
ChevronsLeft
} from 'lucide-vue-next' } from 'lucide-vue-next'
import * as gameLogic from '@/logic/gameLogic' import * as gameLogic from '@/logic/gameLogic'
import * as planetLogic from '@/logic/planetLogic' import * as planetLogic from '@/logic/planetLogic'
import * as publicLogic from '@/logic/publicLogic'
import * as officerLogic from '@/logic/officerLogic' import * as officerLogic from '@/logic/officerLogic'
import * as buildingValidation from '@/logic/buildingValidation' import * as buildingValidation from '@/logic/buildingValidation'
import * as resourceLogic from '@/logic/resourceLogic' import * as resourceLogic from '@/logic/resourceLogic'
@@ -295,8 +298,13 @@
import * as fleetLogic from '@/logic/fleetLogic' import * as fleetLogic from '@/logic/fleetLogic'
import * as shipLogic from '@/logic/shipLogic' import * as shipLogic from '@/logic/shipLogic'
import pkg from '../package.json' import pkg from '../package.json'
import { migrateGameData } from '@/utils/migration'
// 执行数据迁移(在 store 初始化之前)
migrateGameData()
const gameStore = useGameStore() const gameStore = useGameStore()
const universeStore = useUniverseStore()
const { isDark } = useTheme() const { isDark } = useTheme()
const { t } = useI18n() const { t } = useI18n()
const confirmDialog = ref<InstanceType<typeof ConfirmDialog> | null>(null) const confirmDialog = ref<InstanceType<typeof ConfirmDialog> | null>(null)
@@ -304,15 +312,21 @@
// 所有可用的语言选项 // 所有可用的语言选项
const locales: Locale[] = ['zh-CN', 'zh-TW', 'en', 'de', 'ru', 'ko', 'ja'] const locales: Locale[] = ['zh-CN', 'zh-TW', 'en', 'de', 'ru', 'ko', 'ja']
const initGame = () => { // 侧边栏状态(不持久化,根据屏幕尺寸初始化)
// PC端≥1024px默认打开移动端默认关闭
const sidebarOpen = ref(window.innerWidth >= 1024)
const initGame = async () => {
const shouldInit = gameLogic.shouldInitializeGame(gameStore.player.planets) const shouldInit = gameLogic.shouldInitializeGame(gameStore.player.planets)
if (!shouldInit) { if (!shouldInit) {
const now = Date.now() const now = Date.now()
gameLogic.updatePlanetsLastUpdate(gameStore.player.planets, now)
// 计算离线收益(直接同步计算)
const bonuses = officerLogic.calculateActiveBonuses(gameStore.player.officers, now)
gameStore.player.planets.forEach(planet => { gameStore.player.planets.forEach(planet => {
const key = gameLogic.generatePositionKey(planet.position.galaxy, planet.position.system, planet.position.position) resourceLogic.updatePlanetResources(planet, now, bonuses)
gameStore.universePlanets[key] = planet
}) })
generateNPCPlanets() generateNPCPlanets()
return return
} }
@@ -320,8 +334,6 @@
const initialPlanet = planetLogic.createInitialPlanet(gameStore.player.id, t('planet.homePlanet')) const initialPlanet = planetLogic.createInitialPlanet(gameStore.player.id, t('planet.homePlanet'))
gameStore.player.planets = [initialPlanet] gameStore.player.planets = [initialPlanet]
gameStore.currentPlanetId = initialPlanet.id gameStore.currentPlanetId = initialPlanet.id
const key = gameLogic.generatePositionKey(initialPlanet.position.galaxy, initialPlanet.position.system, initialPlanet.position.position)
gameStore.universePlanets[key] = initialPlanet
} }
const generateNPCPlanets = () => { const generateNPCPlanets = () => {
@@ -329,9 +341,9 @@
for (let i = 0; i < npcCount; i++) { for (let i = 0; i < npcCount; i++) {
const position = gameLogic.generateRandomPosition() const position = gameLogic.generateRandomPosition()
const key = gameLogic.generatePositionKey(position.galaxy, position.system, position.position) const key = gameLogic.generatePositionKey(position.galaxy, position.system, position.position)
if (gameStore.universePlanets[key]) continue if (universeStore.planets[key]) continue
const npcPlanet = planetLogic.createNPCPlanet(i, position, t('planet.planetPrefix')) const npcPlanet = planetLogic.createNPCPlanet(i, position, t('planet.planetPrefix'))
gameStore.universePlanets[key] = npcPlanet universeStore.planets[key] = npcPlanet
} }
} }
@@ -339,9 +351,12 @@
if (gameStore.isPaused) return if (gameStore.isPaused) return
const now = Date.now() const now = Date.now()
gameStore.gameTime = now gameStore.gameTime = now
// 检查军官过期
gameLogic.checkOfficersExpiration(gameStore.player.officers, now) gameLogic.checkOfficersExpiration(gameStore.player.officers, now)
// 处理游戏更新(建造队列、研究队列等)
const result = gameLogic.processGameUpdate(gameStore.player, now) const result = gameLogic.processGameUpdate(gameStore.player, now)
gameStore.player.researchQueue = result.updatedResearchQueue gameStore.player.researchQueue = result.updatedResearchQueue
// 处理舰队任务
gameStore.player.fleetMissions.forEach(mission => { gameStore.player.fleetMissions.forEach(mission => {
if (mission.status === 'outbound' && now >= mission.arrivalTime) { if (mission.status === 'outbound' && now >= mission.arrivalTime) {
processMissionArrival(mission) processMissionArrival(mission)
@@ -351,27 +366,41 @@
}) })
} }
const processMissionArrival = (mission: FleetMission) => { const processMissionArrival = async (mission: FleetMission) => {
const targetPlanet = gameStore.player.planets.find( // 从宇宙星球地图中查找目标星球
p => const targetKey = gameLogic.generatePositionKey(
p.position.galaxy === mission.targetPosition.galaxy && mission.targetPosition.galaxy,
p.position.system === mission.targetPosition.system && mission.targetPosition.system,
p.position.position === mission.targetPosition.position mission.targetPosition.position
) )
// 先从玩家星球中查找,再从宇宙地图中查找
const targetPlanet =
gameStore.player.planets.find(
p =>
p.position.galaxy === mission.targetPosition.galaxy &&
p.position.system === mission.targetPosition.system &&
p.position.position === mission.targetPosition.position
) || universeStore.planets[targetKey]
if (mission.missionType === MissionType.Transport) { if (mission.missionType === MissionType.Transport) {
fleetLogic.processTransportArrival(mission, targetPlanet) fleetLogic.processTransportArrival(mission, targetPlanet)
} else if (mission.missionType === MissionType.Attack) { } else if (mission.missionType === MissionType.Attack) {
const attackResult = fleetLogic.processAttackArrival(mission, targetPlanet, gameStore.player, null, gameStore.player.planets) const attackResult = await fleetLogic.processAttackArrival(mission, targetPlanet, gameStore.player, null, gameStore.player.planets)
if (attackResult) { if (attackResult) {
gameStore.player.battleReports.push(attackResult.battleResult) gameStore.player.battleReports.push(attackResult.battleResult)
if (attackResult.moon) { if (attackResult.moon) {
gameStore.player.planets.push(attackResult.moon) gameStore.player.planets.push(attackResult.moon)
} }
if (attackResult.debrisField) {
// 将残骸场添加到游戏状态
universeStore.debrisFields[attackResult.debrisField.id] = attackResult.debrisField
}
} }
} else if (mission.missionType === MissionType.Colonize) { } else if (mission.missionType === MissionType.Colonize) {
const newPlanet = fleetLogic.processColonizeArrival(mission, targetPlanet, gameStore.player.id, t('planet.colonyPrefix')) const newPlanet = fleetLogic.processColonizeArrival(mission, targetPlanet, gameStore.player.id, t('planet.colonyPrefix'))
if (newPlanet) gameStore.player.planets.push(newPlanet) if (newPlanet) {
gameStore.player.planets.push(newPlanet)
}
} else if (mission.missionType === MissionType.Spy) { } else if (mission.missionType === MissionType.Spy) {
const spyReport = fleetLogic.processSpyArrival(mission, targetPlanet, gameStore.player.id) const spyReport = fleetLogic.processSpyArrival(mission, targetPlanet, gameStore.player.id)
if (spyReport) gameStore.player.spyReports.push(spyReport) if (spyReport) gameStore.player.spyReports.push(spyReport)
@@ -382,6 +411,42 @@
if (missionIndex > -1) gameStore.player.fleetMissions.splice(missionIndex, 1) if (missionIndex > -1) gameStore.player.fleetMissions.splice(missionIndex, 1)
return return
} }
} else if (mission.missionType === MissionType.Recycle) {
// 处理回收任务
const debrisId = `debris_${mission.targetPosition.galaxy}_${mission.targetPosition.system}_${mission.targetPosition.position}`
const debrisField = universeStore.debrisFields[debrisId]
const recycleResult = fleetLogic.processRecycleArrival(mission, debrisField)
if (recycleResult && debrisField) {
if (recycleResult.remainingDebris && (recycleResult.remainingDebris.metal > 0 || recycleResult.remainingDebris.crystal > 0)) {
// 更新残骸场
universeStore.debrisFields[debrisId] = {
id: debrisField.id,
position: debrisField.position,
resources: recycleResult.remainingDebris,
createdAt: debrisField.createdAt,
expiresAt: debrisField.expiresAt
}
} else {
// 残骸场已被完全收集,删除
delete universeStore.debrisFields[debrisId]
}
}
} else if (mission.missionType === MissionType.Destroy) {
// 处理行星毁灭任务
const destroyResult = fleetLogic.processDestroyArrival(mission, targetPlanet, gameStore.player)
if (destroyResult && destroyResult.success && destroyResult.planetId) {
// 星球被摧毁
// 从玩家星球列表中移除(如果是玩家的星球)
const planetIndex = gameStore.player.planets.findIndex(p => p.id === destroyResult.planetId)
if (planetIndex > -1) {
gameStore.player.planets.splice(planetIndex, 1)
} else {
// 不是玩家星球,从宇宙地图中移除
delete universeStore.planets[targetKey]
}
// TODO: 可以添加战斗报告或摧毁报告来通知玩家结果
}
} }
} }
@@ -394,27 +459,31 @@
if (missionIndex > -1) gameStore.player.fleetMissions.splice(missionIndex, 1) if (missionIndex > -1) gameStore.player.fleetMissions.splice(missionIndex, 1)
} }
// 游戏循环定时器
let gameLoop: ReturnType<typeof setInterval> | null = null
// 清理定时器
onUnmounted(() => {
if (gameLoop) clearInterval(gameLoop)
})
// 初始化游戏 // 初始化游戏
onMounted(() => { onMounted(async () => {
// 如果是首次访问(没有星球数据),使用浏览器语言自动检测 // 如果是首次访问(没有星球数据),使用浏览器语言自动检测
const isFirstVisit = gameStore.player.planets.length === 0 const isFirstVisit = gameStore.player.planets.length === 0
if (isFirstVisit) { if (isFirstVisit) {
gameStore.locale = detectBrowserLocale() gameStore.locale = detectBrowserLocale()
} }
await initGame()
initGame()
// 启动游戏循环 // 启动游戏循环
const gameLoop = setInterval(() => { gameLoop = setInterval(() => {
updateGame() updateGame()
}, 1000) // 每秒更新一次 }, 1000) // 每1秒更新一次
// 清理定时器
onUnmounted(() => {
clearInterval(gameLoop)
})
}) })
// 定义 planet computed需要在 watch 之前定义)
const planet = computed(() => gameStore.currentPlanet)
const navItems = [ const navItems = [
{ name: computed(() => t('nav.overview')), path: '/', icon: Home }, { name: computed(() => t('nav.overview')), path: '/', icon: Home },
{ name: computed(() => t('nav.buildings')), path: '/buildings', icon: Building2 }, { name: computed(() => t('nav.buildings')), path: '/buildings', icon: Building2 },
@@ -426,23 +495,35 @@
{ name: computed(() => t('nav.simulator')), path: '/battle-simulator', icon: Swords }, { name: computed(() => t('nav.simulator')), path: '/battle-simulator', icon: Swords },
{ name: computed(() => t('nav.galaxy')), path: '/galaxy', icon: Globe }, { name: computed(() => t('nav.galaxy')), path: '/galaxy', icon: Globe },
{ name: computed(() => t('nav.messages')), path: '/messages', icon: Mail }, { name: computed(() => t('nav.messages')), path: '/messages', icon: Mail },
{ name: computed(() => t('nav.settings')), path: '/settings', icon: Settings } { name: computed(() => t('nav.settings')), path: '/settings', icon: Settings },
// GM菜单仅在开发模式下显示
...(import.meta.env.DEV ? [{ name: computed(() => t('nav.gm')), path: '/gm', icon: Wrench }] : [])
] ]
const planet = computed(() => gameStore.currentPlanet) // 使用直接计算,不再缓存
const production = computed(() => (planet.value ? publicLogic.getResourceProduction(planet.value, gameStore.player.officers) : null)) const production = computed(() => {
const capacity = computed(() => (planet.value ? publicLogic.getResourceCapacity(planet.value, gameStore.player.officers) : null)) if (!planet.value) return null
const now = Date.now()
// 电量产出和消耗 const bonuses = officerLogic.calculateActiveBonuses(gameStore.player.officers, now)
const energyProduction = computed(() => { return resourceLogic.calculateResourceProduction(planet.value, {
if (!planet.value) return 0 resourceProductionBonus: bonuses.resourceProductionBonus,
const bonuses = officerLogic.calculateActiveBonuses(gameStore.player.officers, Date.now()) darkMatterProductionBonus: bonuses.darkMatterProductionBonus,
return resourceLogic.calculateEnergyProduction(planet.value, { energyProductionBonus: bonuses.energyProductionBonus }) energyProductionBonus: bonuses.energyProductionBonus
})
}) })
const energyConsumption = computed(() => { const capacity = computed(() => {
if (!planet.value) return 0 if (!planet.value) return null
return resourceLogic.calculateEnergyConsumption(planet.value) const now = Date.now()
const bonuses = officerLogic.calculateActiveBonuses(gameStore.player.officers, now)
return resourceLogic.calculateResourceCapacity(planet.value, bonuses.storageCapacityBonus)
})
// 未读消息数量
const unreadMessagesCount = computed(() => {
const unreadBattles = gameStore.player.battleReports.filter(r => !r.read).length
const unreadSpies = gameStore.player.spyReports.filter(r => !r.read).length
return unreadBattles + unreadSpies
}) })
// 资源类型配置 // 资源类型配置
@@ -477,20 +558,20 @@
// 切换侧边栏 // 切换侧边栏
const toggleSidebar = () => { const toggleSidebar = () => {
gameStore.sidebarCollapsed = !gameStore.sidebarCollapsed sidebarOpen.value = !sidebarOpen.value
} }
// 获取队列项的名称 // 获取队列项的名称
const getItemName = (item: BuildQueueItem): string => { const getItemName = (item: BuildQueueItem): string => {
if (item.type === 'building' || item.type === 'demolish') { if (item.type === 'building' || item.type === 'demolish') {
const buildingName = BUILDINGS[item.itemType as BuildingType]?.name || item.itemType const buildingName = t(`buildings.${item.itemType}`)
return item.type === 'demolish' ? `${t('buildingsView.demolish')} - ${buildingName}` : buildingName return item.type === 'demolish' ? `${t('buildingsView.demolish')} - ${buildingName}` : buildingName
} else if (item.type === 'technology') { } else if (item.type === 'technology') {
return TECHNOLOGIES[item.itemType as TechnologyType]?.name || item.itemType return t(`technologies.${item.itemType}`)
} else if (item.type === 'ship') { } else if (item.type === 'ship') {
return SHIPS[item.itemType as ShipType]?.name || item.itemType return t(`ships.${item.itemType}`)
} else if (item.type === 'defense') { } else if (item.type === 'defense') {
return DEFENSES[item.itemType as DefenseType]?.name || item.itemType return t(`defenses.${item.itemType}`)
} }
return item.itemType return item.itemType
} }

View File

@@ -0,0 +1,334 @@
<template>
<Dialog v-model:open="isOpen">
<DialogContent class="max-w-4xl max-h-[90vh] overflow-y-auto">
<DialogHeader>
<DialogTitle class="flex items-center gap-2">
<Trophy class="h-5 w-5" />
{{ t('messagesView.battleReport') }}
</DialogTitle>
<DialogDescription v-if="report">
{{ formatDate(report.timestamp) }}
</DialogDescription>
</DialogHeader>
<div v-if="report" class="space-y-4">
<!-- 战斗双方信息 -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 text-sm">
<!-- 攻击方星球 -->
<div class="p-3 bg-blue-50 dark:bg-blue-950/20 rounded-lg">
<p class="font-medium text-blue-600 dark:text-blue-400 mb-1">{{ t('simulatorView.attacker') }}</p>
<p v-if="attackerPlanet" class="text-xs text-muted-foreground">
{{ attackerPlanet.name }} [{{ attackerPlanet.position.galaxy }}:{{ attackerPlanet.position.system }}:{{
attackerPlanet.position.position
}}]
</p>
<p v-else class="text-xs text-muted-foreground">{{ report.attackerPlanetId }}</p>
</div>
<!-- 防守方星球 -->
<div class="p-3 bg-red-50 dark:bg-red-950/20 rounded-lg">
<p class="font-medium text-red-600 dark:text-red-400 mb-1">{{ t('simulatorView.defender') }}</p>
<p v-if="defenderPlanet" class="text-xs text-muted-foreground">
{{ defenderPlanet.name }} [{{ defenderPlanet.position.galaxy }}:{{ defenderPlanet.position.system }}:{{
defenderPlanet.position.position
}}]
</p>
<p v-else class="text-xs text-muted-foreground">{{ report.defenderPlanetId }}</p>
</div>
</div>
<!-- 胜利者 -->
<div class="text-center p-4 rounded-lg" :class="getWinnerStyle(report.winner)">
<p class="text-lg font-bold">
{{
report.winner === 'attacker'
? t('messagesView.victory')
: report.winner === 'defender'
? t('messagesView.defeat')
: t('messagesView.draw')
}}
</p>
<p v-if="report.rounds" class="text-sm mt-1">{{ t('simulatorView.afterRounds').replace('{rounds}', String(report.rounds)) }}</p>
</div>
<!-- 损失对比 -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<!-- 攻击方损失 -->
<div class="space-y-2">
<p class="text-sm font-medium text-red-600 dark:text-red-400">{{ t('messagesView.attackerLosses') }}</p>
<div class="p-3 bg-muted rounded-lg space-y-1 text-xs">
<div v-for="(count, shipType) in report.attackerLosses" :key="shipType">
<span class="text-muted-foreground">{{ SHIPS[shipType].name }}:</span>
<span class="ml-2 font-medium">{{ count }}</span>
</div>
<p v-if="Object.keys(report.attackerLosses).length === 0" class="text-muted-foreground">
{{ t('messagesView.noLosses') }}
</p>
</div>
</div>
<!-- 防守方损失 -->
<div class="space-y-2">
<p class="text-sm font-medium text-red-600 dark:text-red-400">{{ t('messagesView.defenderLosses') }}</p>
<div class="p-3 bg-muted rounded-lg space-y-1 text-xs">
<div v-for="(count, shipType) in report.defenderLosses.fleet" :key="shipType">
<span class="text-muted-foreground">{{ SHIPS[shipType].name }}:</span>
<span class="ml-2 font-medium">{{ count }}</span>
</div>
<div v-for="(count, defenseType) in report.defenderLosses.defense" :key="defenseType">
<span class="text-muted-foreground">{{ DEFENSES[defenseType].name }}:</span>
<span class="ml-2 font-medium">{{ count }}</span>
</div>
<p
v-if="Object.keys(report.defenderLosses.fleet).length === 0 && Object.keys(report.defenderLosses.defense).length === 0"
class="text-muted-foreground"
>
{{ t('messagesView.noLosses') }}
</p>
</div>
</div>
</div>
<!-- 剩余单位 -->
<div v-if="report.attackerRemaining || report.defenderRemaining" class="grid grid-cols-1 md:grid-cols-2 gap-4">
<!-- 攻击方剩余 -->
<div v-if="report.attackerRemaining && Object.keys(report.attackerRemaining).length > 0" class="space-y-2">
<p class="text-sm font-medium text-blue-600 dark:text-blue-400">{{ t('messagesView.attackerRemaining') }}</p>
<div class="p-3 bg-muted rounded-lg space-y-1 text-xs">
<div v-for="(count, shipType) in report.attackerRemaining" :key="shipType">
<span class="text-muted-foreground">{{ SHIPS[shipType].name }}:</span>
<span class="ml-2 font-medium">{{ count }}</span>
</div>
</div>
</div>
<!-- 防守方剩余 -->
<div
v-if="
report.defenderRemaining &&
(Object.keys(report.defenderRemaining.fleet || {}).length > 0 ||
Object.keys(report.defenderRemaining.defense || {}).length > 0)
"
class="space-y-2"
>
<p class="text-sm font-medium text-blue-600 dark:text-blue-400">{{ t('messagesView.defenderRemaining') }}</p>
<div class="p-3 bg-muted rounded-lg space-y-1 text-xs">
<div v-for="(count, shipType) in report.defenderRemaining.fleet" :key="shipType">
<span class="text-muted-foreground">{{ SHIPS[shipType].name }}:</span>
<span class="ml-2 font-medium">{{ count }}</span>
</div>
<div v-for="(count, defenseType) in report.defenderRemaining.defense" :key="defenseType">
<span class="text-muted-foreground">{{ DEFENSES[defenseType].name }}:</span>
<span class="ml-2 font-medium">{{ count }}</span>
</div>
</div>
</div>
</div>
<!-- 战利品和残骸 -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<!-- 掠夺资源 -->
<div
v-if="report.plunder && (report.plunder.metal > 0 || report.plunder.crystal > 0 || report.plunder.deuterium > 0)"
class="p-3 bg-green-50 dark:bg-green-950 rounded-lg"
>
<p class="text-sm font-medium mb-2 text-green-600 dark:text-green-400">{{ t('messagesView.plunder') }}</p>
<div class="flex flex-wrap gap-3 text-xs">
<span v-if="report.plunder.metal > 0" class="flex items-center gap-1">
<ResourceIcon type="metal" size="sm" />
{{ formatNumber(report.plunder.metal) }}
</span>
<span v-if="report.plunder.crystal > 0" class="flex items-center gap-1">
<ResourceIcon type="crystal" size="sm" />
{{ formatNumber(report.plunder.crystal) }}
</span>
<span v-if="report.plunder.deuterium > 0" class="flex items-center gap-1">
<ResourceIcon type="deuterium" size="sm" />
{{ formatNumber(report.plunder.deuterium) }}
</span>
</div>
</div>
<!-- 残骸场 -->
<div
v-if="report.debrisField && (report.debrisField.metal > 0 || report.debrisField.crystal > 0)"
class="p-3 bg-muted rounded-lg"
>
<p class="text-sm font-medium mb-2">{{ t('messagesView.debrisField') }}</p>
<div class="flex flex-wrap gap-3 text-xs">
<span v-if="report.debrisField.metal > 0" class="flex items-center gap-1">
<ResourceIcon type="metal" size="sm" />
{{ formatNumber(report.debrisField.metal) }}
</span>
<span v-if="report.debrisField.crystal > 0" class="flex items-center gap-1">
<ResourceIcon type="crystal" size="sm" />
{{ formatNumber(report.debrisField.crystal) }}
</span>
</div>
<!-- 月球生成概率 -->
<p v-if="report.moonChance && report.moonChance > 0" class="text-xs text-muted-foreground mt-2">
{{ t('messagesView.moonChance') }}: {{ (report.moonChance * 100).toFixed(1) }}%
</p>
</div>
</div>
<!-- 回合详情 -->
<div v-if="report.roundDetails && report.roundDetails.length > 0" class="space-y-2">
<Button @click="showRoundDetails = !showRoundDetails" variant="outline" size="sm" class="w-full">
{{ showRoundDetails ? t('messagesView.hideRoundDetails') : t('messagesView.showRoundDetails') }}
</Button>
<div v-if="showRoundDetails" class="relative pl-6 space-y-4">
<!-- 时间线 -->
<div class="absolute left-2 top-0 bottom-0 w-0.5 bg-border" />
<div v-for="detail in report.roundDetails" :key="detail.round" class="relative">
<!-- 时间线节点 -->
<div class="absolute -left-6 top-3 w-4 h-4 rounded-full bg-primary border-2 border-background" />
<!-- 回合内容卡片 -->
<div class="border rounded-lg p-3 bg-card hover:shadow-md transition-shadow">
<div class="flex items-center justify-between mb-3">
<p class="text-sm font-semibold">{{ t('messagesView.round').replace('{round}', String(detail.round)) }}</p>
<TooltipProvider :delay-duration="300">
<div class="flex gap-3 text-xs text-muted-foreground">
<Tooltip>
<TooltipTrigger as-child>
<span class="flex items-center gap-1">
<Sword class="h-3 w-3" />
{{ formatNumber(detail.attackerRemainingPower) }}
</span>
</TooltipTrigger>
<TooltipContent>
<p>{{ t('messagesView.attackerRemainingPower') }}</p>
</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger as-child>
<span class="flex items-center gap-1">
<Shield class="h-3 w-3" />
{{ formatNumber(detail.defenderRemainingPower) }}
</span>
</TooltipTrigger>
<TooltipContent>
<p>{{ t('messagesView.defenderRemainingPower') }}</p>
</TooltipContent>
</Tooltip>
</div>
</TooltipProvider>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-3">
<!-- 攻击方本回合损失 -->
<div class="bg-red-50 dark:bg-red-950/20 rounded p-2">
<p class="text-xs font-medium text-red-600 dark:text-red-400 mb-1.5">{{ t('messagesView.attackerLosses') }}</p>
<div class="text-xs space-y-0.5">
<div v-for="(count, shipType) in detail.attackerLosses" :key="shipType" class="flex justify-between">
<span class="text-muted-foreground">{{ SHIPS[shipType].name }}</span>
<span class="font-medium">-{{ count }}</span>
</div>
<p v-if="Object.keys(detail.attackerLosses).length === 0" class="text-muted-foreground italic">
{{ t('messagesView.noLosses') }}
</p>
</div>
</div>
<!-- 防守方本回合损失 -->
<div class="bg-blue-50 dark:bg-blue-950/20 rounded p-2">
<p class="text-xs font-medium text-blue-600 dark:text-blue-400 mb-1.5">{{ t('messagesView.defenderLosses') }}</p>
<div class="text-xs space-y-0.5">
<div v-for="(count, shipType) in detail.defenderLosses.fleet" :key="shipType" class="flex justify-between">
<span class="text-muted-foreground">{{ SHIPS[shipType].name }}</span>
<span class="font-medium">-{{ count }}</span>
</div>
<div v-for="(count, defenseType) in detail.defenderLosses.defense" :key="defenseType" class="flex justify-between">
<span class="text-muted-foreground">{{ DEFENSES[defenseType].name }}</span>
<span class="font-medium">-{{ count }}</span>
</div>
<p
v-if="
Object.keys(detail.defenderLosses.fleet).length === 0 && Object.keys(detail.defenderLosses.defense).length === 0
"
class="text-muted-foreground italic"
>
{{ t('messagesView.noLosses') }}
</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</DialogContent>
</Dialog>
</template>
<script setup lang="ts">
import { ref, watch, computed } from 'vue'
import { useGameStore } from '@/stores/gameStore'
import { useUniverseStore } from '@/stores/universeStore'
import { useI18n } from '@/composables/useI18n'
import { useGameConfig } from '@/composables/useGameConfig'
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '@/components/ui/dialog'
import { Button } from '@/components/ui/button'
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'
import ResourceIcon from '@/components/ResourceIcon.vue'
import { formatNumber, formatDate } from '@/utils/format'
import { Trophy, Sword, Shield } from 'lucide-vue-next'
import type { BattleResult } from '@/types/game'
const props = defineProps<{
report: BattleResult | null
open: boolean
}>()
const emit = defineEmits<{
(e: 'update:open', value: boolean): void
}>()
const gameStore = useGameStore()
const universeStore = useUniverseStore()
const { t } = useI18n()
const { SHIPS, DEFENSES } = useGameConfig()
const isOpen = ref(props.open)
const showRoundDetails = ref(false)
// 获取攻击方星球信息
const attackerPlanet = computed(() => {
if (!props.report) return null
return gameStore.player.planets.find(p => p.id === props.report!.attackerPlanetId)
})
// 获取防守方星球信息
const defenderPlanet = computed(() => {
if (!props.report) return null
// 先从玩家星球中查找
const playerPlanet = gameStore.player.planets.find(p => p.id === props.report!.defenderPlanetId)
if (playerPlanet) return playerPlanet
// 再从宇宙星球地图中查找
return Object.values(universeStore.planets).find(p => p.id === props.report!.defenderPlanetId)
})
watch(
() => props.open,
newValue => {
isOpen.value = newValue
if (newValue) {
showRoundDetails.value = false
}
}
)
watch(isOpen, newValue => {
emit('update:open', newValue)
})
// 获取胜利者样式
const getWinnerStyle = (winner: string) => {
if (winner === 'attacker') return 'bg-green-50 dark:bg-green-950 text-green-700 dark:text-green-300'
if (winner === 'defender') return 'bg-red-50 dark:bg-red-950 text-red-700 dark:text-red-300'
return 'bg-gray-50 dark:bg-gray-950 text-gray-700 dark:text-gray-300'
}
</script>

View File

@@ -30,6 +30,7 @@
interface Props { interface Props {
requirements?: Partial<Record<BuildingType | TechnologyType, number>> requirements?: Partial<Record<BuildingType | TechnologyType, number>>
currentLevel?: number // 当前建筑/科技等级,用于判断是否已解锁
} }
const props = defineProps<Props>() const props = defineProps<Props>()
@@ -39,6 +40,8 @@
const requirementsDialog = ref<InstanceType<typeof AlertDialog> | null>(null) const requirementsDialog = ref<InstanceType<typeof AlertDialog> | null>(null)
const isUnlocked = computed(() => { const isUnlocked = computed(() => {
// 如果已经建造过level > 0则认为已解锁不显示遮罩
if (props.currentLevel !== undefined && props.currentLevel > 0) return true
if (!props.requirements || !gameStore.currentPlanet) return true if (!props.requirements || !gameStore.currentPlanet) return true
return publicLogic.checkRequirements(gameStore.currentPlanet, gameStore.player.technologies, props.requirements) return publicLogic.checkRequirements(gameStore.currentPlanet, gameStore.player.technologies, props.requirements)
}) })

View File

@@ -0,0 +1,50 @@
<template>
<Popover>
<PopoverTrigger as-child>
<span class="cursor-pointer underline decoration-dotted underline-offset-4 touch-manipulation">{{ abbreviatedValue }}</span>
</PopoverTrigger>
<PopoverContent class="w-auto p-2" side="top" align="center">
<p class="font-mono text-sm">{{ formattedValue }}</p>
</PopoverContent>
</Popover>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'
const props = defineProps<{
value: number
}>()
// 完整格式化的数字(带千位分隔符)
const formattedValue = computed(() => {
return props.value.toLocaleString()
})
// 缩写格式的数字
const abbreviatedValue = computed(() => {
const num = props.value
// 小于1000直接显示
if (num < 1000) {
return num.toString()
}
// 1000 - 999,999: 使用 K (千)
if (num < 1000000) {
const k = num / 1000
return k % 1 === 0 ? `${k}K` : `${k.toFixed(1)}K`
}
// 1,000,000 - 999,999,999: 使用 M (百万)
if (num < 1000000000) {
const m = num / 1000000
return m % 1 === 0 ? `${m}M` : `${m.toFixed(1)}M`
}
// 1,000,000,000+: 使用 B (十亿)
const b = num / 1000000000
return b % 1 === 0 ? `${b}B` : `${b.toFixed(1)}B`
})
</script>

View File

@@ -0,0 +1,141 @@
<template>
<Dialog v-model:open="isOpen">
<DialogContent class="max-w-2xl max-h-[90vh] overflow-y-auto">
<DialogHeader>
<DialogTitle class="flex items-center gap-2">
<Eye class="h-5 w-5" />
{{ t('messagesView.spyReport') }}
</DialogTitle>
<DialogDescription v-if="report">
{{ formatDate(report.timestamp) }}
</DialogDescription>
</DialogHeader>
<div v-if="report" class="space-y-4">
<!-- 目标星球信息 -->
<div class="p-3 bg-muted rounded-lg">
<p class="text-sm font-medium mb-2">{{ t('messagesView.targetPlanet') }}</p>
<p v-if="targetPlanet" class="text-xs text-muted-foreground">
{{ targetPlanet.name }} [{{ targetPlanet.position.galaxy }}:{{ targetPlanet.position.system }}:{{
targetPlanet.position.position
}}]
</p>
<p v-else class="text-xs text-muted-foreground">{{ report.targetPlanetId }}</p>
</div>
<!-- 资源 -->
<div>
<p class="text-sm font-medium mb-2">{{ t('messagesView.resources') }}:</p>
<div class="flex flex-wrap gap-3 text-xs sm:text-sm">
<span class="flex items-center gap-1">
<ResourceIcon type="metal" size="sm" />
{{ formatNumber(report.resources.metal) }}
</span>
<span class="flex items-center gap-1">
<ResourceIcon type="crystal" size="sm" />
{{ formatNumber(report.resources.crystal) }}
</span>
<span class="flex items-center gap-1">
<ResourceIcon type="deuterium" size="sm" />
{{ formatNumber(report.resources.deuterium) }}
</span>
<span class="flex items-center gap-1">
<ResourceIcon type="darkMatter" size="sm" />
{{ formatNumber(report.resources.darkMatter) }}
</span>
</div>
</div>
<!-- 舰队如果有 -->
<div v-if="report.fleet && Object.keys(report.fleet).length > 0">
<p class="text-sm font-medium mb-2">{{ t('messagesView.fleet') }}:</p>
<div class="grid grid-cols-2 sm:grid-cols-3 gap-2 text-xs sm:text-sm">
<div v-for="(count, shipType) in report.fleet" :key="shipType">
<span class="text-muted-foreground">{{ SHIPS[shipType].name }}:</span>
<span class="ml-1 font-medium">{{ count }}</span>
</div>
</div>
</div>
<!-- 防御设施如果有 -->
<div v-if="report.defense && hasDefense(report.defense)">
<p class="text-sm font-medium mb-2">{{ t('messagesView.defense') }}:</p>
<div class="grid grid-cols-2 sm:grid-cols-3 gap-2 text-xs sm:text-sm">
<div v-for="(count, defenseType) in report.defense" :key="defenseType">
<span v-if="count && count > 0" class="block">
<span class="text-muted-foreground">{{ DEFENSES[defenseType].name }}:</span>
<span class="ml-1 font-medium">{{ count }}</span>
</span>
</div>
</div>
</div>
<!-- 建筑如果有 -->
<div v-if="report.buildings && Object.keys(report.buildings).length > 0">
<p class="text-sm font-medium mb-2">{{ t('messagesView.buildings') }}:</p>
<div class="grid grid-cols-2 sm:grid-cols-3 gap-2 text-xs sm:text-sm">
<div v-for="(level, buildingType) in report.buildings" :key="buildingType">
<span class="text-muted-foreground">{{ BUILDINGS[buildingType].name }}:</span>
<span class="ml-1 font-medium">Lv.{{ level }}</span>
</div>
</div>
</div>
</div>
</DialogContent>
</Dialog>
</template>
<script setup lang="ts">
import { ref, watch, computed } from 'vue'
import { useGameStore } from '@/stores/gameStore'
import { useUniverseStore } from '@/stores/universeStore'
import { useI18n } from '@/composables/useI18n'
import { useGameConfig } from '@/composables/useGameConfig'
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '@/components/ui/dialog'
import ResourceIcon from '@/components/ResourceIcon.vue'
import { formatNumber, formatDate } from '@/utils/format'
import { Eye } from 'lucide-vue-next'
import type { SpyReport } from '@/types/game'
const props = defineProps<{
report: SpyReport | null
open: boolean
}>()
const emit = defineEmits<{
(e: 'update:open', value: boolean): void
}>()
const gameStore = useGameStore()
const universeStore = useUniverseStore()
const { t } = useI18n()
const { SHIPS, DEFENSES, BUILDINGS } = useGameConfig()
const isOpen = ref(props.open)
// 获取目标星球信息
const targetPlanet = computed(() => {
if (!props.report) return null
// 先从玩家星球中查找
const playerPlanet = gameStore.player.planets.find(p => p.id === props.report!.targetPlanetId)
if (playerPlanet) return playerPlanet
// 再从宇宙星球地图中查找
return Object.values(universeStore.planets).find(p => p.id === props.report!.targetPlanetId)
})
watch(
() => props.open,
newValue => {
isOpen.value = newValue
}
)
watch(isOpen, newValue => {
emit('update:open', newValue)
})
// 检查是否有防御设施
const hasDefense = (defense: any): boolean => {
if (!defense) return false
return Object.values(defense).some((count: any) => count > 0)
}
</script>

View File

@@ -21,24 +21,36 @@
<Badge v-if="level === currentLevel" variant="default">{{ level }}</Badge> <Badge v-if="level === currentLevel" variant="default">{{ level }}</Badge>
<span v-else>{{ level }}</span> <span v-else>{{ level }}</span>
</TableCell> </TableCell>
<TableCell class="text-center text-sm">{{ formatNumber(getLevelData(level).cost.metal) }}</TableCell> <TableCell class="text-center text-sm">
<TableCell class="text-center text-sm">{{ formatNumber(getLevelData(level).cost.crystal) }}</TableCell> <NumberWithTooltip :value="getLevelData(level).cost.metal" />
<TableCell class="text-center text-sm">{{ formatNumber(getLevelData(level).cost.deuterium) }}</TableCell> </TableCell>
<TableCell class="text-center text-sm">
<NumberWithTooltip :value="getLevelData(level).cost.crystal" />
</TableCell>
<TableCell class="text-center text-sm">
<NumberWithTooltip :value="getLevelData(level).cost.deuterium" />
</TableCell>
<TableCell class="text-center text-sm">{{ formatTime(getLevelData(level).buildTime) }}</TableCell> <TableCell class="text-center text-sm">{{ formatTime(getLevelData(level).buildTime) }}</TableCell>
<TableCell class="text-center text-sm"> <TableCell class="text-center text-sm">
<span v-if="getLevelData(level).production > 0" class="text-green-600 dark:text-green-400"> <span v-if="getLevelData(level).production > 0" class="text-green-600 dark:text-green-400">
+{{ formatNumber(getLevelData(level).production) }}/{{ t('resources.perHour') }} +
<NumberWithTooltip :value="getLevelData(level).production" />
/{{ t('resources.perHour') }}
</span> </span>
<span v-else>-</span> <span v-else>-</span>
</TableCell> </TableCell>
<TableCell class="text-center text-sm"> <TableCell class="text-center text-sm">
<span v-if="getLevelData(level).consumption > 0" class="text-red-600 dark:text-red-400"> <span v-if="getLevelData(level).consumption > 0" class="text-red-600 dark:text-red-400">
-{{ formatNumber(getLevelData(level).consumption) }} -
<NumberWithTooltip :value="getLevelData(level).consumption" />
</span> </span>
<span v-else>-</span> <span v-else>-</span>
</TableCell> </TableCell>
<TableCell class="text-center text-sm"> <TableCell class="text-center text-sm">
<span class="text-primary font-medium">+{{ getLevelData(level).points }}</span> <span class="text-primary font-medium">
+
<NumberWithTooltip :value="getLevelData(level).points" />
</span>
</TableCell> </TableCell>
</TableRow> </TableRow>
</TableBody> </TableBody>
@@ -54,15 +66,21 @@
<CardContent class="space-y-2"> <CardContent class="space-y-2">
<div class="flex items-center justify-between text-sm"> <div class="flex items-center justify-between text-sm">
<span class="text-muted-foreground">{{ t('resources.metal') }}:</span> <span class="text-muted-foreground">{{ t('resources.metal') }}:</span>
<span class="font-medium">{{ formatNumber(totalStats.metal) }}</span> <span class="font-medium">
<NumberWithTooltip :value="totalStats.metal" />
</span>
</div> </div>
<div class="flex items-center justify-between text-sm"> <div class="flex items-center justify-between text-sm">
<span class="text-muted-foreground">{{ t('resources.crystal') }}:</span> <span class="text-muted-foreground">{{ t('resources.crystal') }}:</span>
<span class="font-medium">{{ formatNumber(totalStats.crystal) }}</span> <span class="font-medium">
<NumberWithTooltip :value="totalStats.crystal" />
</span>
</div> </div>
<div class="flex items-center justify-between text-sm"> <div class="flex items-center justify-between text-sm">
<span class="text-muted-foreground">{{ t('resources.deuterium') }}:</span> <span class="text-muted-foreground">{{ t('resources.deuterium') }}:</span>
<span class="font-medium">{{ formatNumber(totalStats.deuterium) }}</span> <span class="font-medium">
<NumberWithTooltip :value="totalStats.deuterium" />
</span>
</div> </div>
</CardContent> </CardContent>
</Card> </Card>
@@ -72,7 +90,9 @@
<CardTitle class="text-sm">{{ t('buildings.totalPoints') }}</CardTitle> <CardTitle class="text-sm">{{ t('buildings.totalPoints') }}</CardTitle>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div class="text-3xl font-bold text-primary">{{ formatNumber(totalStats.points) }}</div> <div class="text-3xl font-bold text-primary">
<NumberWithTooltip :value="totalStats.points" />
</div>
<p class="text-xs text-muted-foreground mt-1"> <p class="text-xs text-muted-foreground mt-1">
{{ t('buildings.levelRange') }}: {{ Math.max(0, currentLevel - 10) }} - {{ Math.min(currentLevel + 10, currentLevel + 10) }} {{ t('buildings.levelRange') }}: {{ Math.max(0, currentLevel - 10) }} - {{ Math.min(currentLevel + 10, currentLevel + 10) }}
</p> </p>
@@ -89,8 +109,10 @@
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table' import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
import { Badge } from '@/components/ui/badge' import { Badge } from '@/components/ui/badge'
import NumberWithTooltip from '@/components/NumberWithTooltip.vue'
import * as buildingLogic from '@/logic/buildingLogic' import * as buildingLogic from '@/logic/buildingLogic'
import * as pointsLogic from '@/logic/pointsLogic' import * as pointsLogic from '@/logic/pointsLogic'
import { formatTime } from '@/utils/format'
const { t } = useI18n() const { t } = useI18n()
@@ -99,12 +121,11 @@
currentLevel: number currentLevel: number
}>() }>()
// 等级范围:当前等级 ±10 // 等级范围:当前等级 +10
const levelRange = computed(() => { const levelRange = computed(() => {
const start = Math.max(0, props.currentLevel - 10)
const end = props.currentLevel + 10 const end = props.currentLevel + 10
const levels = [] const levels = []
for (let i = start; i <= end; i++) { for (let i = props.currentLevel; i <= end; i++) {
levels.push(i) levels.push(i)
} }
return levels return levels
@@ -129,18 +150,18 @@
let production = 0 let production = 0
let consumption = 0 let consumption = 0
// 资源矿产量 // 资源矿产量(与 resourceLogic.ts 保持一致)
if (props.buildingType === 'metalMine') { if (props.buildingType === 'metalMine') {
production = Math.floor(30 * level * Math.pow(1.1, level)) production = Math.floor(1500 * level * Math.pow(1.5, level))
} else if (props.buildingType === 'crystalMine') { } else if (props.buildingType === 'crystalMine') {
production = Math.floor(20 * level * Math.pow(1.1, level)) production = Math.floor(1000 * level * Math.pow(1.5, level))
} else if (props.buildingType === 'deuteriumSynthesizer') { } else if (props.buildingType === 'deuteriumSynthesizer') {
production = Math.floor(10 * level * Math.pow(1.1, level)) production = Math.floor(500 * level * Math.pow(1.5, level))
} }
// 能量产出 // 能量产出(与 resourceLogic.ts 保持一致)
if (props.buildingType === 'solarPlant') { if (props.buildingType === 'solarPlant') {
production = Math.floor(20 * level * Math.pow(1.1, level)) production = Math.floor(50 * level * Math.pow(1.1, level))
} }
// 能量消耗(矿场和合成器) // 能量消耗(矿场和合成器)
@@ -178,18 +199,4 @@
return { metal, crystal, deuterium, points } return { metal, crystal, deuterium, points }
}) })
const formatNumber = (num: number): string => {
return num.toLocaleString()
}
const formatTime = (seconds: number): string => {
if (seconds < 60) return `${seconds}${t('common.timeSecond')}`
const minutes = Math.floor(seconds / 60)
const secs = seconds % 60
if (minutes < 60) return `${minutes}${t('common.timeMinute')}${secs}${t('common.timeSecond')}`
const hours = Math.floor(minutes / 60)
const mins = minutes % 60
return `${hours}${t('common.timeHour')}${mins}${t('common.timeMinute')}`
}
</script> </script>

View File

@@ -10,7 +10,9 @@
</CardTitle> </CardTitle>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div class="text-2xl font-bold">{{ formatNumber(config.attack) }}</div> <div class="text-2xl font-bold">
<NumberWithTooltip :value="config.attack" />
</div>
</CardContent> </CardContent>
</Card> </Card>
@@ -22,7 +24,9 @@
</CardTitle> </CardTitle>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div class="text-2xl font-bold">{{ formatNumber(config.shield) }}</div> <div class="text-2xl font-bold">
<NumberWithTooltip :value="config.shield" />
</div>
</CardContent> </CardContent>
</Card> </Card>
@@ -34,7 +38,9 @@
</CardTitle> </CardTitle>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div class="text-2xl font-bold">{{ formatNumber(config.armor) }}</div> <div class="text-2xl font-bold">
<NumberWithTooltip :value="config.armor" />
</div>
</CardContent> </CardContent>
</Card> </Card>
</div> </div>
@@ -48,19 +54,27 @@
<CardContent class="space-y-2"> <CardContent class="space-y-2">
<div v-if="config.cost.metal > 0" class="flex items-center justify-between text-sm"> <div v-if="config.cost.metal > 0" class="flex items-center justify-between text-sm">
<span class="text-muted-foreground">{{ t('resources.metal') }}:</span> <span class="text-muted-foreground">{{ t('resources.metal') }}:</span>
<span class="font-medium">{{ formatNumber(config.cost.metal) }}</span> <span class="font-medium">
<NumberWithTooltip :value="config.cost.metal" />
</span>
</div> </div>
<div v-if="config.cost.crystal > 0" class="flex items-center justify-between text-sm"> <div v-if="config.cost.crystal > 0" class="flex items-center justify-between text-sm">
<span class="text-muted-foreground">{{ t('resources.crystal') }}:</span> <span class="text-muted-foreground">{{ t('resources.crystal') }}:</span>
<span class="font-medium">{{ formatNumber(config.cost.crystal) }}</span> <span class="font-medium">
<NumberWithTooltip :value="config.cost.crystal" />
</span>
</div> </div>
<div v-if="config.cost.deuterium > 0" class="flex items-center justify-between text-sm"> <div v-if="config.cost.deuterium > 0" class="flex items-center justify-between text-sm">
<span class="text-muted-foreground">{{ t('resources.deuterium') }}:</span> <span class="text-muted-foreground">{{ t('resources.deuterium') }}:</span>
<span class="font-medium">{{ formatNumber(config.cost.deuterium) }}</span> <span class="font-medium">
<NumberWithTooltip :value="config.cost.deuterium" />
</span>
</div> </div>
<div class="flex items-center justify-between text-sm pt-2 border-t"> <div class="flex items-center justify-between text-sm pt-2 border-t">
<span class="text-muted-foreground">{{ t('player.points') }}:</span> <span class="text-muted-foreground">{{ t('player.points') }}:</span>
<span class="font-bold text-primary">{{ pointsPerUnit }}</span> <span class="font-bold text-primary">
<NumberWithTooltip :value="pointsPerUnit" />
</span>
</div> </div>
</CardContent> </CardContent>
</Card> </Card>
@@ -92,22 +106,31 @@
<div class="space-y-1 text-sm"> <div class="space-y-1 text-sm">
<div class="flex justify-between"> <div class="flex justify-between">
<span>{{ t('resources.metal') }}:</span> <span>{{ t('resources.metal') }}:</span>
<span class="font-medium">{{ formatNumber(batchCost.metal) }}</span> <span class="font-medium">
<NumberWithTooltip :value="batchCost.metal" />
</span>
</div> </div>
<div class="flex justify-between"> <div class="flex justify-between">
<span>{{ t('resources.crystal') }}:</span> <span>{{ t('resources.crystal') }}:</span>
<span class="font-medium">{{ formatNumber(batchCost.crystal) }}</span> <span class="font-medium">
<NumberWithTooltip :value="batchCost.crystal" />
</span>
</div> </div>
<div class="flex justify-between"> <div class="flex justify-between">
<span>{{ t('resources.deuterium') }}:</span> <span>{{ t('resources.deuterium') }}:</span>
<span class="font-medium">{{ formatNumber(batchCost.deuterium) }}</span> <span class="font-medium">
<NumberWithTooltip :value="batchCost.deuterium" />
</span>
</div> </div>
</div> </div>
</div> </div>
<div class="space-y-2"> <div class="space-y-2">
<p class="text-sm text-muted-foreground">{{ t('defense.totalTime') }}:</p> <p class="text-sm text-muted-foreground">{{ t('defense.totalTime') }}:</p>
<div class="text-xl font-bold">{{ formatTime(config.buildTime * quantity) }}</div> <div class="text-xl font-bold">{{ formatTime(config.buildTime * quantity) }}</div>
<p class="text-xs text-muted-foreground">{{ t('player.points') }}: +{{ formatNumber(batchPoints) }}</p> <p class="text-xs text-muted-foreground">
{{ t('player.points') }}: +
<NumberWithTooltip :value="batchPoints" />
</p>
</div> </div>
</div> </div>
</CardContent> </CardContent>
@@ -122,9 +145,11 @@
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
import { Input } from '@/components/ui/input' import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label' import { Label } from '@/components/ui/label'
import NumberWithTooltip from '@/components/NumberWithTooltip.vue'
import { Sword, Shield, ShieldCheck } from 'lucide-vue-next' import { Sword, Shield, ShieldCheck } from 'lucide-vue-next'
import * as pointsLogic from '@/logic/pointsLogic' import * as pointsLogic from '@/logic/pointsLogic'
import { DEFENSES } from '@/config/gameConfig' import { DEFENSES } from '@/config/gameConfig'
import { formatTime } from '@/utils/format'
const { t } = useI18n() const { t } = useI18n()
@@ -151,18 +176,4 @@
const batchPoints = computed(() => { const batchPoints = computed(() => {
return pointsLogic.calculateDefensePoints(props.defenseType, quantity.value) return pointsLogic.calculateDefensePoints(props.defenseType, quantity.value)
}) })
const formatNumber = (num: number): string => {
return num.toLocaleString()
}
const formatTime = (seconds: number): string => {
if (seconds < 60) return `${seconds}${t('common.timeSecond')}`
const minutes = Math.floor(seconds / 60)
const secs = seconds % 60
if (minutes < 60) return `${minutes}${t('common.timeMinute')}${secs}${t('common.timeSecond')}`
const hours = Math.floor(minutes / 60)
const mins = minutes % 60
return `${hours}${t('common.timeHour')}${mins}${t('common.timeMinute')}`
}
</script> </script>

View File

@@ -10,7 +10,9 @@
</CardTitle> </CardTitle>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div class="text-2xl font-bold">{{ formatNumber(config.attack) }}</div> <div class="text-2xl font-bold">
<NumberWithTooltip :value="config.attack" />
</div>
</CardContent> </CardContent>
</Card> </Card>
@@ -22,7 +24,9 @@
</CardTitle> </CardTitle>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div class="text-2xl font-bold">{{ formatNumber(config.shield) }}</div> <div class="text-2xl font-bold">
<NumberWithTooltip :value="config.shield" />
</div>
</CardContent> </CardContent>
</Card> </Card>
@@ -34,7 +38,9 @@
</CardTitle> </CardTitle>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div class="text-2xl font-bold">{{ formatNumber(config.armor) }}</div> <div class="text-2xl font-bold">
<NumberWithTooltip :value="config.armor" />
</div>
</CardContent> </CardContent>
</Card> </Card>
@@ -46,7 +52,9 @@
</CardTitle> </CardTitle>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div class="text-2xl font-bold">{{ formatNumber(config.speed) }}</div> <div class="text-2xl font-bold">
<NumberWithTooltip :value="config.speed" />
</div>
</CardContent> </CardContent>
</Card> </Card>
@@ -58,7 +66,9 @@
</CardTitle> </CardTitle>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div class="text-2xl font-bold">{{ formatNumber(config.cargoCapacity) }}</div> <div class="text-2xl font-bold">
<NumberWithTooltip :value="config.cargoCapacity" />
</div>
</CardContent> </CardContent>
</Card> </Card>
@@ -70,7 +80,9 @@
</CardTitle> </CardTitle>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div class="text-2xl font-bold">{{ formatNumber(config.fuelConsumption) }}</div> <div class="text-2xl font-bold">
<NumberWithTooltip :value="config.fuelConsumption" />
</div>
</CardContent> </CardContent>
</Card> </Card>
</div> </div>
@@ -84,19 +96,27 @@
<CardContent class="space-y-2"> <CardContent class="space-y-2">
<div v-if="config.cost.metal > 0" class="flex items-center justify-between text-sm"> <div v-if="config.cost.metal > 0" class="flex items-center justify-between text-sm">
<span class="text-muted-foreground">{{ t('resources.metal') }}:</span> <span class="text-muted-foreground">{{ t('resources.metal') }}:</span>
<span class="font-medium">{{ formatNumber(config.cost.metal) }}</span> <span class="font-medium">
<NumberWithTooltip :value="config.cost.metal" />
</span>
</div> </div>
<div v-if="config.cost.crystal > 0" class="flex items-center justify-between text-sm"> <div v-if="config.cost.crystal > 0" class="flex items-center justify-between text-sm">
<span class="text-muted-foreground">{{ t('resources.crystal') }}:</span> <span class="text-muted-foreground">{{ t('resources.crystal') }}:</span>
<span class="font-medium">{{ formatNumber(config.cost.crystal) }}</span> <span class="font-medium">
<NumberWithTooltip :value="config.cost.crystal" />
</span>
</div> </div>
<div v-if="config.cost.deuterium > 0" class="flex items-center justify-between text-sm"> <div v-if="config.cost.deuterium > 0" class="flex items-center justify-between text-sm">
<span class="text-muted-foreground">{{ t('resources.deuterium') }}:</span> <span class="text-muted-foreground">{{ t('resources.deuterium') }}:</span>
<span class="font-medium">{{ formatNumber(config.cost.deuterium) }}</span> <span class="font-medium">
<NumberWithTooltip :value="config.cost.deuterium" />
</span>
</div> </div>
<div class="flex items-center justify-between text-sm pt-2 border-t"> <div class="flex items-center justify-between text-sm pt-2 border-t">
<span class="text-muted-foreground">{{ t('player.points') }}:</span> <span class="text-muted-foreground">{{ t('player.points') }}:</span>
<span class="font-bold text-primary">{{ pointsPerUnit }}</span> <span class="font-bold text-primary">
<NumberWithTooltip :value="pointsPerUnit" />
</span>
</div> </div>
</CardContent> </CardContent>
</Card> </Card>
@@ -128,22 +148,31 @@
<div class="space-y-1 text-sm"> <div class="space-y-1 text-sm">
<div class="flex justify-between"> <div class="flex justify-between">
<span>{{ t('resources.metal') }}:</span> <span>{{ t('resources.metal') }}:</span>
<span class="font-medium">{{ formatNumber(batchCost.metal) }}</span> <span class="font-medium">
<NumberWithTooltip :value="batchCost.metal" />
</span>
</div> </div>
<div class="flex justify-between"> <div class="flex justify-between">
<span>{{ t('resources.crystal') }}:</span> <span>{{ t('resources.crystal') }}:</span>
<span class="font-medium">{{ formatNumber(batchCost.crystal) }}</span> <span class="font-medium">
<NumberWithTooltip :value="batchCost.crystal" />
</span>
</div> </div>
<div class="flex justify-between"> <div class="flex justify-between">
<span>{{ t('resources.deuterium') }}:</span> <span>{{ t('resources.deuterium') }}:</span>
<span class="font-medium">{{ formatNumber(batchCost.deuterium) }}</span> <span class="font-medium">
<NumberWithTooltip :value="batchCost.deuterium" />
</span>
</div> </div>
</div> </div>
</div> </div>
<div class="space-y-2"> <div class="space-y-2">
<p class="text-sm text-muted-foreground">{{ t('shipyard.totalTime') }}:</p> <p class="text-sm text-muted-foreground">{{ t('shipyard.totalTime') }}:</p>
<div class="text-xl font-bold">{{ formatTime(config.buildTime * quantity) }}</div> <div class="text-xl font-bold">{{ formatTime(config.buildTime * quantity) }}</div>
<p class="text-xs text-muted-foreground">{{ t('player.points') }}: +{{ formatNumber(batchPoints) }}</p> <p class="text-xs text-muted-foreground">
{{ t('player.points') }}: +
<NumberWithTooltip :value="batchPoints" />
</p>
</div> </div>
</div> </div>
</CardContent> </CardContent>
@@ -158,9 +187,11 @@
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
import { Input } from '@/components/ui/input' import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label' import { Label } from '@/components/ui/label'
import NumberWithTooltip from '@/components/NumberWithTooltip.vue'
import { Sword, Shield, ShieldCheck, Zap, Package, Fuel } from 'lucide-vue-next' import { Sword, Shield, ShieldCheck, Zap, Package, Fuel } from 'lucide-vue-next'
import * as pointsLogic from '@/logic/pointsLogic' import * as pointsLogic from '@/logic/pointsLogic'
import { SHIPS } from '@/config/gameConfig' import { SHIPS } from '@/config/gameConfig'
import { formatTime } from '@/utils/format'
const { t } = useI18n() const { t } = useI18n()
@@ -187,18 +218,4 @@
const batchPoints = computed(() => { const batchPoints = computed(() => {
return pointsLogic.calculateShipPoints(props.shipType, quantity.value) return pointsLogic.calculateShipPoints(props.shipType, quantity.value)
}) })
const formatNumber = (num: number): string => {
return num.toLocaleString()
}
const formatTime = (seconds: number): string => {
if (seconds < 60) return `${seconds}${t('common.timeSecond')}`
const minutes = Math.floor(seconds / 60)
const secs = seconds % 60
if (minutes < 60) return `${minutes}${t('common.timeMinute')}${secs}${t('common.timeSecond')}`
const hours = Math.floor(minutes / 60)
const mins = minutes % 60
return `${hours}${t('common.timeHour')}${mins}${t('common.timeMinute')}`
}
</script> </script>

View File

@@ -19,12 +19,21 @@
<Badge v-if="level === currentLevel" variant="default">{{ level }}</Badge> <Badge v-if="level === currentLevel" variant="default">{{ level }}</Badge>
<span v-else>{{ level }}</span> <span v-else>{{ level }}</span>
</TableCell> </TableCell>
<TableCell class="text-center text-sm">{{ formatNumber(getLevelData(level).cost.metal) }}</TableCell> <TableCell class="text-center text-sm">
<TableCell class="text-center text-sm">{{ formatNumber(getLevelData(level).cost.crystal) }}</TableCell> <NumberWithTooltip :value="getLevelData(level).cost.metal" />
<TableCell class="text-center text-sm">{{ formatNumber(getLevelData(level).cost.deuterium) }}</TableCell> </TableCell>
<TableCell class="text-center text-sm">
<NumberWithTooltip :value="getLevelData(level).cost.crystal" />
</TableCell>
<TableCell class="text-center text-sm">
<NumberWithTooltip :value="getLevelData(level).cost.deuterium" />
</TableCell>
<TableCell class="text-center text-sm">{{ formatTime(getLevelData(level).researchTime) }}</TableCell> <TableCell class="text-center text-sm">{{ formatTime(getLevelData(level).researchTime) }}</TableCell>
<TableCell class="text-center text-sm"> <TableCell class="text-center text-sm">
<span class="text-primary font-medium">+{{ getLevelData(level).points }}</span> <span class="text-primary font-medium">
+
<NumberWithTooltip :value="getLevelData(level).points" />
</span>
</TableCell> </TableCell>
</TableRow> </TableRow>
</TableBody> </TableBody>
@@ -40,15 +49,21 @@
<CardContent class="space-y-2"> <CardContent class="space-y-2">
<div class="flex items-center justify-between text-sm"> <div class="flex items-center justify-between text-sm">
<span class="text-muted-foreground">{{ t('resources.metal') }}:</span> <span class="text-muted-foreground">{{ t('resources.metal') }}:</span>
<span class="font-medium">{{ formatNumber(totalStats.metal) }}</span> <span class="font-medium">
<NumberWithTooltip :value="totalStats.metal" />
</span>
</div> </div>
<div class="flex items-center justify-between text-sm"> <div class="flex items-center justify-between text-sm">
<span class="text-muted-foreground">{{ t('resources.crystal') }}:</span> <span class="text-muted-foreground">{{ t('resources.crystal') }}:</span>
<span class="font-medium">{{ formatNumber(totalStats.crystal) }}</span> <span class="font-medium">
<NumberWithTooltip :value="totalStats.crystal" />
</span>
</div> </div>
<div class="flex items-center justify-between text-sm"> <div class="flex items-center justify-between text-sm">
<span class="text-muted-foreground">{{ t('resources.deuterium') }}:</span> <span class="text-muted-foreground">{{ t('resources.deuterium') }}:</span>
<span class="font-medium">{{ formatNumber(totalStats.deuterium) }}</span> <span class="font-medium">
<NumberWithTooltip :value="totalStats.deuterium" />
</span>
</div> </div>
</CardContent> </CardContent>
</Card> </Card>
@@ -58,7 +73,9 @@
<CardTitle class="text-sm">{{ t('research.totalPoints') }}</CardTitle> <CardTitle class="text-sm">{{ t('research.totalPoints') }}</CardTitle>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div class="text-3xl font-bold text-primary">{{ formatNumber(totalStats.points) }}</div> <div class="text-3xl font-bold text-primary">
<NumberWithTooltip :value="totalStats.points" />
</div>
<p class="text-xs text-muted-foreground mt-1"> <p class="text-xs text-muted-foreground mt-1">
{{ t('research.levelRange') }}: {{ Math.max(0, currentLevel - 10) }} - {{ Math.min(currentLevel + 10, currentLevel + 10) }} {{ t('research.levelRange') }}: {{ Math.max(0, currentLevel - 10) }} - {{ Math.min(currentLevel + 10, currentLevel + 10) }}
</p> </p>
@@ -75,8 +92,10 @@
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table' import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
import { Badge } from '@/components/ui/badge' import { Badge } from '@/components/ui/badge'
import NumberWithTooltip from '@/components/NumberWithTooltip.vue'
import * as researchLogic from '@/logic/researchLogic' import * as researchLogic from '@/logic/researchLogic'
import * as pointsLogic from '@/logic/pointsLogic' import * as pointsLogic from '@/logic/pointsLogic'
import { formatTime } from '@/utils/format'
const { t } = useI18n() const { t } = useI18n()
@@ -85,12 +104,11 @@
currentLevel: number currentLevel: number
}>() }>()
// 等级范围:当前等级 ±10 // 等级范围:当前等级 +10
const levelRange = computed(() => { const levelRange = computed(() => {
const start = Math.max(0, props.currentLevel - 10)
const end = props.currentLevel + 10 const end = props.currentLevel + 10
const levels = [] const levels = []
for (let i = start; i <= end; i++) { for (let i = props.currentLevel; i <= end; i++) {
levels.push(i) levels.push(i)
} }
return levels return levels
@@ -137,18 +155,4 @@
return { metal, crystal, deuterium, points } return { metal, crystal, deuterium, points }
}) })
const formatNumber = (num: number): string => {
return num.toLocaleString()
}
const formatTime = (seconds: number): string => {
if (seconds < 60) return `${seconds}${t('common.timeSecond')}`
const minutes = Math.floor(seconds / 60)
const secs = seconds % 60
if (minutes < 60) return `${minutes}${t('common.timeMinute')}${secs}${t('common.timeSecond')}`
const hours = Math.floor(minutes / 60)
const mins = minutes % 60
return `${hours}${t('common.timeHour')}${mins}${t('common.timeMinute')}`
}
</script> </script>

View File

@@ -14,22 +14,22 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import type { HTMLAttributes } from 'vue' import type { HTMLAttributes } from 'vue'
import { useVModel } from '@vueuse/core' import { useVModel } from '@vueuse/core'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
const props = defineProps<{ const props = defineProps<{
defaultValue?: string | number defaultValue?: string | number
modelValue?: string | number modelValue?: string | number
class?: HTMLAttributes['class'] class?: HTMLAttributes['class']
}>() }>()
const emits = defineEmits<{ const emits = defineEmits<{
(e: 'update:modelValue', payload: string | number): void (e: 'update:modelValue', payload: string | number): void
}>() }>()
const modelValue = useVModel(props, 'modelValue', emits, { const modelValue = useVModel(props, 'modelValue', emits, {
passive: true, passive: true,
defaultValue: props.defaultValue defaultValue: props.defaultValue
}) })
</script> </script>

View File

@@ -0,0 +1,29 @@
<script setup lang="ts">
import type { SeparatorProps } from "reka-ui"
import type { HTMLAttributes } from "vue"
import { reactiveOmit } from "@vueuse/core"
import { Separator } from "reka-ui"
import { cn } from "@/lib/utils"
const props = withDefaults(defineProps<
SeparatorProps & { class?: HTMLAttributes["class"] }
>(), {
orientation: "horizontal",
decorative: true,
})
const delegatedProps = reactiveOmit(props, "class")
</script>
<template>
<Separator
data-slot="separator"
v-bind="delegatedProps"
:class="
cn(
'bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px',
props.class,
)
"
/>
</template>

View File

@@ -0,0 +1 @@
export { default as Separator } from "./Separator.vue"

View File

@@ -0,0 +1,19 @@
<script setup lang="ts">
import type { DialogRootEmits, DialogRootProps } from "reka-ui"
import { DialogRoot, useForwardPropsEmits } from "reka-ui"
const props = defineProps<DialogRootProps>()
const emits = defineEmits<DialogRootEmits>()
const forwarded = useForwardPropsEmits(props, emits)
</script>
<template>
<DialogRoot
v-slot="slotProps"
data-slot="sheet"
v-bind="forwarded"
>
<slot v-bind="slotProps" />
</DialogRoot>
</template>

View File

@@ -0,0 +1,15 @@
<script setup lang="ts">
import type { DialogCloseProps } from "reka-ui"
import { DialogClose } from "reka-ui"
const props = defineProps<DialogCloseProps>()
</script>
<template>
<DialogClose
data-slot="sheet-close"
v-bind="props"
>
<slot />
</DialogClose>
</template>

View File

@@ -0,0 +1,62 @@
<script setup lang="ts">
import type { DialogContentEmits, DialogContentProps } from "reka-ui"
import type { HTMLAttributes } from "vue"
import { reactiveOmit } from "@vueuse/core"
import { X } from "lucide-vue-next"
import {
DialogClose,
DialogContent,
DialogPortal,
useForwardPropsEmits,
} from "reka-ui"
import { cn } from "@/lib/utils"
import SheetOverlay from "./SheetOverlay.vue"
interface SheetContentProps extends DialogContentProps {
class?: HTMLAttributes["class"]
side?: "top" | "right" | "bottom" | "left"
}
defineOptions({
inheritAttrs: false,
})
const props = withDefaults(defineProps<SheetContentProps>(), {
side: "right",
})
const emits = defineEmits<DialogContentEmits>()
const delegatedProps = reactiveOmit(props, "class", "side")
const forwarded = useForwardPropsEmits(delegatedProps, emits)
</script>
<template>
<DialogPortal>
<SheetOverlay />
<DialogContent
data-slot="sheet-content"
:class="cn(
'bg-background data-[state=open]:animate-in data-[state=closed]:animate-out fixed z-50 flex flex-col gap-4 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500',
side === 'right'
&& 'data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right inset-y-0 right-0 h-full w-3/4 border-l sm:max-w-sm',
side === 'left'
&& 'data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left inset-y-0 left-0 h-full w-3/4 border-r sm:max-w-sm',
side === 'top'
&& 'data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top inset-x-0 top-0 h-auto border-b',
side === 'bottom'
&& 'data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom inset-x-0 bottom-0 h-auto border-t',
props.class)"
v-bind="{ ...$attrs, ...forwarded }"
>
<slot />
<DialogClose
class="ring-offset-background focus:ring-ring data-[state=open]:bg-secondary absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none"
>
<X class="size-4" />
<span class="sr-only">Close</span>
</DialogClose>
</DialogContent>
</DialogPortal>
</template>

View File

@@ -0,0 +1,21 @@
<script setup lang="ts">
import type { DialogDescriptionProps } from "reka-ui"
import type { HTMLAttributes } from "vue"
import { reactiveOmit } from "@vueuse/core"
import { DialogDescription } from "reka-ui"
import { cn } from "@/lib/utils"
const props = defineProps<DialogDescriptionProps & { class?: HTMLAttributes["class"] }>()
const delegatedProps = reactiveOmit(props, "class")
</script>
<template>
<DialogDescription
data-slot="sheet-description"
:class="cn('text-muted-foreground text-sm', props.class)"
v-bind="delegatedProps"
>
<slot />
</DialogDescription>
</template>

View File

@@ -0,0 +1,16 @@
<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { cn } from "@/lib/utils"
const props = defineProps<{ class?: HTMLAttributes["class"] }>()
</script>
<template>
<div
data-slot="sheet-footer"
:class="cn('mt-auto flex flex-col gap-2 p-4', props.class)
"
>
<slot />
</div>
</template>

View File

@@ -0,0 +1,15 @@
<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { cn } from "@/lib/utils"
const props = defineProps<{ class?: HTMLAttributes["class"] }>()
</script>
<template>
<div
data-slot="sheet-header"
:class="cn('flex flex-col gap-1.5 p-4', props.class)"
>
<slot />
</div>
</template>

View File

@@ -0,0 +1,21 @@
<script setup lang="ts">
import type { DialogOverlayProps } from "reka-ui"
import type { HTMLAttributes } from "vue"
import { reactiveOmit } from "@vueuse/core"
import { DialogOverlay } from "reka-ui"
import { cn } from "@/lib/utils"
const props = defineProps<DialogOverlayProps & { class?: HTMLAttributes["class"] }>()
const delegatedProps = reactiveOmit(props, "class")
</script>
<template>
<DialogOverlay
data-slot="sheet-overlay"
:class="cn('data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/80', props.class)"
v-bind="delegatedProps"
>
<slot />
</DialogOverlay>
</template>

View File

@@ -0,0 +1,21 @@
<script setup lang="ts">
import type { DialogTitleProps } from "reka-ui"
import type { HTMLAttributes } from "vue"
import { reactiveOmit } from "@vueuse/core"
import { DialogTitle } from "reka-ui"
import { cn } from "@/lib/utils"
const props = defineProps<DialogTitleProps & { class?: HTMLAttributes["class"] }>()
const delegatedProps = reactiveOmit(props, "class")
</script>
<template>
<DialogTitle
data-slot="sheet-title"
:class="cn('text-foreground font-semibold', props.class)"
v-bind="delegatedProps"
>
<slot />
</DialogTitle>
</template>

View File

@@ -0,0 +1,15 @@
<script setup lang="ts">
import type { DialogTriggerProps } from "reka-ui"
import { DialogTrigger } from "reka-ui"
const props = defineProps<DialogTriggerProps>()
</script>
<template>
<DialogTrigger
data-slot="sheet-trigger"
v-bind="props"
>
<slot />
</DialogTrigger>
</template>

View File

@@ -0,0 +1,8 @@
export { default as Sheet } from "./Sheet.vue"
export { default as SheetClose } from "./SheetClose.vue"
export { default as SheetContent } from "./SheetContent.vue"
export { default as SheetDescription } from "./SheetDescription.vue"
export { default as SheetFooter } from "./SheetFooter.vue"
export { default as SheetHeader } from "./SheetHeader.vue"
export { default as SheetTitle } from "./SheetTitle.vue"
export { default as SheetTrigger } from "./SheetTrigger.vue"

View File

@@ -0,0 +1,100 @@
<template>
<div
v-if="collapsible === 'none'"
data-slot="sidebar"
:class="cn('bg-sidebar text-sidebar-foreground flex h-full w-(--sidebar-width) flex-col', props.class)"
v-bind="$attrs"
>
<slot />
</div>
<Sheet v-else-if="isMobile" :open="openMobile" v-bind="$attrs" @update:open="setOpenMobile">
<SheetContent
data-sidebar="sidebar"
data-slot="sidebar"
data-mobile="true"
:side="side"
class="bg-sidebar text-sidebar-foreground w-(--sidebar-width) p-0 [&>button]:hidden"
:style="{
'--sidebar-width': SIDEBAR_WIDTH_MOBILE
}"
>
<SheetHeader class="sr-only">
<SheetTitle>Sidebar</SheetTitle>
<SheetDescription>Displays the mobile sidebar.</SheetDescription>
</SheetHeader>
<div class="flex h-full w-full flex-col">
<slot />
</div>
</SheetContent>
</Sheet>
<div
v-else
class="group peer text-sidebar-foreground hidden md:block"
data-slot="sidebar"
:data-state="state"
:data-collapsible="state === 'collapsed' ? collapsible : ''"
:data-variant="variant"
:data-side="side"
>
<!-- This is what handles the sidebar gap on desktop -->
<div
:class="
cn(
'relative w-(--sidebar-width) bg-transparent transition-[width] duration-200 ease-linear',
'group-data-[collapsible=offcanvas]:w-0',
'group-data-[side=right]:rotate-180',
variant === 'floating' || variant === 'inset'
? 'group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4)))]'
: 'group-data-[collapsible=icon]:w-(--sidebar-width-icon)'
)
"
/>
<div
:class="
cn(
'fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear md:flex',
side === 'left'
? 'left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]'
: 'right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]',
// Adjust the padding for floating and inset variants.
variant === 'floating' || variant === 'inset'
? 'p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]'
: 'group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[side=left]:border-r group-data-[side=right]:border-l',
props.class
)
"
v-bind="$attrs"
>
<div
data-sidebar="sidebar"
class="bg-sidebar group-data-[variant=floating]:border-sidebar-border flex h-full w-full flex-col group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:shadow-sm"
>
<slot />
</div>
</div>
</div>
</template>
<script setup lang="ts">
import type { SidebarProps } from '.'
import { cn } from '@/lib/utils'
import { Sheet, SheetContent } from '@/components/ui/sheet'
import SheetDescription from '@/components/ui/sheet/SheetDescription.vue'
import SheetHeader from '@/components/ui/sheet/SheetHeader.vue'
import SheetTitle from '@/components/ui/sheet/SheetTitle.vue'
import { SIDEBAR_WIDTH_MOBILE, useSidebar } from './utils'
defineOptions({
inheritAttrs: false
})
const props = withDefaults(defineProps<SidebarProps>(), {
side: 'left',
variant: 'sidebar',
collapsible: 'offcanvas'
})
const { isMobile, state, openMobile, setOpenMobile } = useSidebar()
</script>

View File

@@ -0,0 +1,18 @@
<template>
<div
data-slot="sidebar-content"
data-sidebar="content"
:class="cn('flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]:overflow-hidden', props.class)"
>
<slot />
</div>
</template>
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
const props = defineProps<{
class?: HTMLAttributes['class']
}>()
</script>

View File

@@ -0,0 +1,14 @@
<template>
<div data-slot="sidebar-footer" data-sidebar="footer" :class="cn('flex flex-col gap-2 p-2', props.class)">
<slot />
</div>
</template>
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
const props = defineProps<{
class?: HTMLAttributes['class']
}>()
</script>

View File

@@ -0,0 +1,14 @@
<template>
<div data-slot="sidebar-group" data-sidebar="group" :class="cn('relative flex w-full min-w-0 flex-col p-2', props.class)">
<slot />
</div>
</template>
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
const props = defineProps<{
class?: HTMLAttributes['class']
}>()
</script>

View File

@@ -0,0 +1,31 @@
<template>
<Primitive
data-slot="sidebar-group-action"
data-sidebar="group-action"
:as="as"
:as-child="asChild"
:class="
cn(
'text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground absolute top-3.5 right-3 flex aspect-square w-5 items-center justify-center rounded-md p-0 outline-hidden transition-transform focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0',
'after:absolute after:-inset-2 md:after:hidden',
'group-data-[collapsible=icon]:hidden',
props.class
)
"
>
<slot />
</Primitive>
</template>
<script setup lang="ts">
import type { PrimitiveProps } from 'reka-ui'
import type { HTMLAttributes } from 'vue'
import { Primitive } from 'reka-ui'
import { cn } from '@/lib/utils'
const props = defineProps<
PrimitiveProps & {
class?: HTMLAttributes['class']
}
>()
</script>

View File

@@ -0,0 +1,14 @@
<template>
<div data-slot="sidebar-group-content" data-sidebar="group-content" :class="cn('w-full text-sm', props.class)">
<slot />
</div>
</template>
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
const props = defineProps<{
class?: HTMLAttributes['class']
}>()
</script>

View File

@@ -0,0 +1,30 @@
<template>
<Primitive
data-slot="sidebar-group-label"
data-sidebar="group-label"
:as="as"
:as-child="asChild"
:class="
cn(
'text-sidebar-foreground/70 ring-sidebar-ring flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium outline-hidden transition-[margin,opacity] duration-200 ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0',
'group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0',
props.class
)
"
>
<slot />
</Primitive>
</template>
<script setup lang="ts">
import type { PrimitiveProps } from 'reka-ui'
import type { HTMLAttributes } from 'vue'
import { Primitive } from 'reka-ui'
import { cn } from '@/lib/utils'
const props = defineProps<
PrimitiveProps & {
class?: HTMLAttributes['class']
}
>()
</script>

View File

@@ -0,0 +1,14 @@
<template>
<div data-slot="sidebar-header" data-sidebar="header" :class="cn('flex flex-col gap-2 p-2', props.class)">
<slot />
</div>
</template>
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
const props = defineProps<{
class?: HTMLAttributes['class']
}>()
</script>

View File

@@ -0,0 +1,15 @@
<template>
<Input data-slot="sidebar-input" data-sidebar="input" :class="cn('bg-background h-8 w-full shadow-none', props.class)">
<slot />
</Input>
</template>
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
import { Input } from '@/components/ui/input'
const props = defineProps<{
class?: HTMLAttributes['class']
}>()
</script>

View File

@@ -0,0 +1,23 @@
<template>
<main
data-slot="sidebar-inset"
:class="
cn(
'bg-background relative flex w-full flex-1 flex-col',
'md:peer-data-[variant=inset]:m-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow-sm md:peer-data-[variant=inset]:peer-data-[state=collapsed]:ml-2',
props.class
)
"
>
<slot />
</main>
</template>
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
const props = defineProps<{
class?: HTMLAttributes['class']
}>()
</script>

View File

@@ -0,0 +1,14 @@
<template>
<ul data-slot="sidebar-menu" data-sidebar="menu" :class="cn('flex w-full min-w-0 flex-col gap-1', props.class)">
<slot />
</ul>
</template>
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
const props = defineProps<{
class?: HTMLAttributes['class']
}>()
</script>

View File

@@ -0,0 +1,41 @@
<template>
<Primitive
data-slot="sidebar-menu-action"
data-sidebar="menu-action"
:class="
cn(
'text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground peer-hover/menu-button:text-sidebar-accent-foreground absolute top-1.5 right-1 flex aspect-square w-5 items-center justify-center rounded-md p-0 outline-hidden transition-transform focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0',
'after:absolute after:-inset-2 md:after:hidden',
'peer-data-[size=sm]/menu-button:top-1',
'peer-data-[size=default]/menu-button:top-1.5',
'peer-data-[size=lg]/menu-button:top-2.5',
'group-data-[collapsible=icon]:hidden',
showOnHover &&
'peer-data-[active=true]/menu-button:text-sidebar-accent-foreground group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 data-[state=open]:opacity-100 md:opacity-0',
props.class
)
"
:as="as"
:as-child="asChild"
>
<slot />
</Primitive>
</template>
<script setup lang="ts">
import type { PrimitiveProps } from 'reka-ui'
import type { HTMLAttributes } from 'vue'
import { Primitive } from 'reka-ui'
import { cn } from '@/lib/utils'
const props = withDefaults(
defineProps<
PrimitiveProps & {
showOnHover?: boolean
class?: HTMLAttributes['class']
}
>(),
{
as: 'button'
}
)
</script>

View File

@@ -0,0 +1,28 @@
<template>
<div
data-slot="sidebar-menu-badge"
data-sidebar="menu-badge"
:class="
cn(
'text-sidebar-foreground pointer-events-none absolute right-1 flex h-5 min-w-5 items-center justify-center rounded-md px-1 text-xs font-medium tabular-nums select-none',
'peer-hover/menu-button:text-sidebar-accent-foreground peer-data-[active=true]/menu-button:text-sidebar-accent-foreground',
'peer-data-[size=sm]/menu-button:top-1',
'peer-data-[size=default]/menu-button:top-1.5',
'peer-data-[size=lg]/menu-button:top-2.5',
'group-data-[collapsible=icon]:hidden',
props.class
)
"
>
<slot />
</div>
</template>
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
const props = defineProps<{
class?: HTMLAttributes['class']
}>()
</script>

View File

@@ -0,0 +1,49 @@
<template>
<SidebarMenuButtonChild v-if="!tooltip" v-bind="{ ...delegatedProps, ...$attrs }">
<slot />
</SidebarMenuButtonChild>
<Tooltip v-else>
<TooltipTrigger as-child>
<SidebarMenuButtonChild v-bind="{ ...delegatedProps, ...$attrs }">
<slot />
</SidebarMenuButtonChild>
</TooltipTrigger>
<TooltipContent side="right" align="center" :hidden="state !== 'collapsed' || isMobile">
<template v-if="typeof tooltip === 'string'">
{{ tooltip }}
</template>
<component :is="tooltip" v-else />
</TooltipContent>
</Tooltip>
</template>
<script setup lang="ts">
import type { Component } from 'vue'
import type { SidebarMenuButtonProps } from './SidebarMenuButtonChild.vue'
import { reactiveOmit } from '@vueuse/core'
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'
import SidebarMenuButtonChild from './SidebarMenuButtonChild.vue'
import { useSidebar } from './utils'
defineOptions({
inheritAttrs: false
})
const props = withDefaults(
defineProps<
SidebarMenuButtonProps & {
tooltip?: string | Component
}
>(),
{
as: 'button',
variant: 'default',
size: 'default'
}
)
const { isMobile, state } = useSidebar()
const delegatedProps = reactiveOmit(props, 'tooltip')
</script>

View File

@@ -0,0 +1,36 @@
<template>
<Primitive
data-slot="sidebar-menu-button"
data-sidebar="menu-button"
:data-size="size"
:data-active="isActive"
:class="cn(sidebarMenuButtonVariants({ variant, size }), props.class)"
:as="as"
:as-child="asChild"
v-bind="$attrs"
>
<slot />
</Primitive>
</template>
<script setup lang="ts">
import type { PrimitiveProps } from 'reka-ui'
import type { HTMLAttributes } from 'vue'
import type { SidebarMenuButtonVariants } from '.'
import { Primitive } from 'reka-ui'
import { cn } from '@/lib/utils'
import { sidebarMenuButtonVariants } from '.'
export interface SidebarMenuButtonProps extends PrimitiveProps {
variant?: SidebarMenuButtonVariants['variant']
size?: SidebarMenuButtonVariants['size']
isActive?: boolean
class?: HTMLAttributes['class']
}
const props = withDefaults(defineProps<SidebarMenuButtonProps>(), {
as: 'button',
variant: 'default',
size: 'default'
})
</script>

View File

@@ -0,0 +1,14 @@
<template>
<li data-slot="sidebar-menu-item" data-sidebar="menu-item" :class="cn('group/menu-item relative', props.class)">
<slot />
</li>
</template>
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
const props = defineProps<{
class?: HTMLAttributes['class']
}>()
</script>

View File

@@ -0,0 +1,27 @@
<template>
<div
data-slot="sidebar-menu-skeleton"
data-sidebar="menu-skeleton"
:class="cn('flex h-8 items-center gap-2 rounded-md px-2', props.class)"
>
<Skeleton v-if="showIcon" class="size-4 rounded-md" data-sidebar="menu-skeleton-icon" />
<Skeleton class="h-4 max-w-(--skeleton-width) flex-1" data-sidebar="menu-skeleton-text" :style="{ '--skeleton-width': width }" />
</div>
</template>
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { computed } from 'vue'
import { cn } from '@/lib/utils'
import { Skeleton } from '@/components/ui/skeleton'
const props = defineProps<{
showIcon?: boolean
class?: HTMLAttributes['class']
}>()
const width = computed(() => {
return `${Math.floor(Math.random() * 40) + 50}%`
})
</script>

View File

@@ -0,0 +1,24 @@
<template>
<ul
data-slot="sidebar-menu-sub"
data-sidebar="menu-badge"
:class="
cn(
'border-sidebar-border mx-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-l px-2.5 py-0.5',
'group-data-[collapsible=icon]:hidden',
props.class
)
"
>
<slot />
</ul>
</template>
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
const props = defineProps<{
class?: HTMLAttributes['class']
}>()
</script>

View File

@@ -0,0 +1,43 @@
<template>
<Primitive
data-slot="sidebar-menu-sub-button"
data-sidebar="menu-sub-button"
:as="as"
:as-child="asChild"
:data-size="size"
:data-active="isActive"
:class="
cn(
'text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground active:bg-sidebar-accent active:text-sidebar-accent-foreground [&>svg]:text-sidebar-accent-foreground flex h-7 min-w-0 -translate-x-px items-center gap-2 overflow-hidden rounded-md px-2 outline-hidden focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0',
'data-[active=true]:bg-sidebar-accent data-[active=true]:text-sidebar-accent-foreground',
size === 'sm' && 'text-xs',
size === 'md' && 'text-sm',
'group-data-[collapsible=icon]:hidden',
props.class
)
"
>
<slot />
</Primitive>
</template>
<script setup lang="ts">
import type { PrimitiveProps } from 'reka-ui'
import type { HTMLAttributes } from 'vue'
import { Primitive } from 'reka-ui'
import { cn } from '@/lib/utils'
const props = withDefaults(
defineProps<
PrimitiveProps & {
size?: 'sm' | 'md'
isActive?: boolean
class?: HTMLAttributes['class']
}
>(),
{
as: 'a',
size: 'md'
}
)
</script>

View File

@@ -0,0 +1,14 @@
<template>
<li data-slot="sidebar-menu-sub-item" data-sidebar="menu-sub-item" :class="cn('group/menu-sub-item relative', props.class)">
<slot />
</li>
</template>
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
const props = defineProps<{
class?: HTMLAttributes['class']
}>()
</script>

View File

@@ -0,0 +1,92 @@
<template>
<TooltipProvider :delay-duration="0">
<div
data-slot="sidebar-wrapper"
:style="{
'--sidebar-width': SIDEBAR_WIDTH,
'--sidebar-width-icon': SIDEBAR_WIDTH_ICON
}"
:class="cn('group/sidebar-wrapper has-data-[variant=inset]:bg-sidebar flex min-h-svh w-full', props.class)"
v-bind="$attrs"
>
<slot />
</div>
</TooltipProvider>
</template>
<script setup lang="ts">
import type { HTMLAttributes, Ref } from 'vue'
import { defaultDocument, useEventListener, useMediaQuery, useVModel } from '@vueuse/core'
import { TooltipProvider } from 'reka-ui'
import { computed, ref } from 'vue'
import { cn } from '@/lib/utils'
import {
provideSidebarContext,
SIDEBAR_COOKIE_MAX_AGE,
SIDEBAR_COOKIE_NAME,
SIDEBAR_KEYBOARD_SHORTCUT,
SIDEBAR_WIDTH,
SIDEBAR_WIDTH_ICON
} from './utils'
const props = withDefaults(
defineProps<{
defaultOpen?: boolean
open?: boolean
class?: HTMLAttributes['class']
}>(),
{
defaultOpen: !defaultDocument?.cookie.includes(`${SIDEBAR_COOKIE_NAME}=false`),
open: undefined
}
)
const emits = defineEmits<{
'update:open': [open: boolean]
}>()
const isMobile = useMediaQuery('(max-width: 768px)')
const openMobile = ref(false)
const open = useVModel(props, 'open', emits, {
defaultValue: props.defaultOpen ?? false,
passive: (props.open === undefined) as false
}) as Ref<boolean>
function setOpen(value: boolean) {
open.value = value // emits('update:open', value)
// This sets the cookie to keep the sidebar state.
document.cookie = `${SIDEBAR_COOKIE_NAME}=${open.value}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`
}
function setOpenMobile(value: boolean) {
openMobile.value = value
}
// Helper to toggle the sidebar.
function toggleSidebar() {
return isMobile.value ? setOpenMobile(!openMobile.value) : setOpen(!open.value)
}
useEventListener('keydown', (event: KeyboardEvent) => {
if (event.key === SIDEBAR_KEYBOARD_SHORTCUT && (event.metaKey || event.ctrlKey)) {
event.preventDefault()
toggleSidebar()
}
})
// We add a state so that we can do data-state="expanded" or "collapsed".
// This makes it easier to style the sidebar with Tailwind classes.
const state = computed(() => (open.value ? 'expanded' : 'collapsed'))
provideSidebarContext({
state,
open,
setOpen,
isMobile,
openMobile,
setOpenMobile,
toggleSidebar
})
</script>

View File

@@ -0,0 +1,35 @@
<template>
<button
data-sidebar="rail"
data-slot="sidebar-rail"
aria-label="Toggle Sidebar"
:tabindex="-1"
title="Toggle Sidebar"
:class="
cn(
'hover:after:bg-sidebar-border absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all ease-linear group-data-[side=left]:-right-4 group-data-[side=right]:left-0 after:absolute after:inset-y-0 after:left-1/2 after:w-[2px] sm:flex',
'in-data-[side=left]:cursor-w-resize in-data-[side=right]:cursor-e-resize',
'[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize',
'hover:group-data-[collapsible=offcanvas]:bg-sidebar group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full',
'[[data-side=left][data-collapsible=offcanvas]_&]:-right-2',
'[[data-side=right][data-collapsible=offcanvas]_&]:-left-2',
props.class
)
"
@click="toggleSidebar"
>
<slot />
</button>
</template>
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
import { useSidebar } from './utils'
const props = defineProps<{
class?: HTMLAttributes['class']
}>()
const { toggleSidebar } = useSidebar()
</script>

View File

@@ -0,0 +1,15 @@
<template>
<Separator data-slot="sidebar-separator" data-sidebar="separator" :class="cn('bg-sidebar-border mx-2 w-auto', props.class)">
<slot />
</Separator>
</template>
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
import { Separator } from '@/components/ui/separator'
const props = defineProps<{
class?: HTMLAttributes['class']
}>()
</script>

View File

@@ -0,0 +1,27 @@
<template>
<Button
data-sidebar="trigger"
data-slot="sidebar-trigger"
variant="ghost"
size="icon"
:class="cn('h-7 w-7', props.class)"
@click="toggleSidebar"
>
<PanelLeft />
<span class="sr-only">Toggle Sidebar</span>
</Button>
</template>
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { PanelLeft } from 'lucide-vue-next'
import { cn } from '@/lib/utils'
import { Button } from '@/components/ui/button'
import { useSidebar } from './utils'
const props = defineProps<{
class?: HTMLAttributes['class']
}>()
const { toggleSidebar } = useSidebar()
</script>

View File

@@ -0,0 +1,60 @@
import type { VariantProps } from 'class-variance-authority'
import type { HTMLAttributes } from 'vue'
import { cva } from 'class-variance-authority'
export interface SidebarProps {
side?: 'left' | 'right'
variant?: 'sidebar' | 'floating' | 'inset'
collapsible?: 'offcanvas' | 'icon' | 'none'
class?: HTMLAttributes['class']
}
export { default as Sidebar } from './Sidebar.vue'
export { default as SidebarContent } from './SidebarContent.vue'
export { default as SidebarFooter } from './SidebarFooter.vue'
export { default as SidebarGroup } from './SidebarGroup.vue'
export { default as SidebarGroupAction } from './SidebarGroupAction.vue'
export { default as SidebarGroupContent } from './SidebarGroupContent.vue'
export { default as SidebarGroupLabel } from './SidebarGroupLabel.vue'
export { default as SidebarHeader } from './SidebarHeader.vue'
export { default as SidebarInput } from './SidebarInput.vue'
export { default as SidebarInset } from './SidebarInset.vue'
export { default as SidebarMenu } from './SidebarMenu.vue'
export { default as SidebarMenuAction } from './SidebarMenuAction.vue'
export { default as SidebarMenuBadge } from './SidebarMenuBadge.vue'
export { default as SidebarMenuButton } from './SidebarMenuButton.vue'
export { default as SidebarMenuItem } from './SidebarMenuItem.vue'
export { default as SidebarMenuSkeleton } from './SidebarMenuSkeleton.vue'
export { default as SidebarMenuSub } from './SidebarMenuSub.vue'
export { default as SidebarMenuSubButton } from './SidebarMenuSubButton.vue'
export { default as SidebarMenuSubItem } from './SidebarMenuSubItem.vue'
export { default as SidebarProvider } from './SidebarProvider.vue'
export { default as SidebarRail } from './SidebarRail.vue'
export { default as SidebarSeparator } from './SidebarSeparator.vue'
export { default as SidebarTrigger } from './SidebarTrigger.vue'
export { useSidebar } from './utils'
export const sidebarMenuButtonVariants = cva(
'peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-hidden ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-data-[sidebar=menu-action]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0',
{
variants: {
variant: {
default: 'hover:bg-sidebar-accent hover:text-sidebar-accent-foreground',
outline:
'bg-background shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]'
},
size: {
default: 'h-8 text-sm',
sm: 'h-7 text-xs',
lg: 'h-12 text-sm group-data-[collapsible=icon]:p-0!'
}
},
defaultVariants: {
variant: 'default',
size: 'default'
}
}
)
export type SidebarMenuButtonVariants = VariantProps<typeof sidebarMenuButtonVariants>

View File

@@ -0,0 +1,19 @@
import type { ComputedRef, Ref } from 'vue'
import { createContext } from 'reka-ui'
export const SIDEBAR_COOKIE_NAME = 'sidebar_state'
export const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7
export const SIDEBAR_WIDTH = '16rem'
export const SIDEBAR_WIDTH_MOBILE = '18rem'
export const SIDEBAR_WIDTH_ICON = '3rem'
export const SIDEBAR_KEYBOARD_SHORTCUT = 'b'
export const [useSidebar, provideSidebarContext] = createContext<{
state: ComputedRef<'expanded' | 'collapsed'>
open: Ref<boolean>
setOpen: (value: boolean) => void
isMobile: Ref<boolean>
openMobile: Ref<boolean>
setOpenMobile: (value: boolean) => void
toggleSidebar: () => void
}>('Sidebar')

View File

@@ -0,0 +1,17 @@
<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { cn } from "@/lib/utils"
interface SkeletonProps {
class?: HTMLAttributes["class"]
}
const props = defineProps<SkeletonProps>()
</script>
<template>
<div
data-slot="skeleton"
:class="cn('animate-pulse rounded-md bg-primary/10', props.class)"
/>
</template>

View File

@@ -0,0 +1 @@
export { default as Skeleton } from "./Skeleton.vue"

View File

@@ -1,12 +1,3 @@
<script lang="ts" setup>
import type { ToasterProps } from "vue-sonner"
import { CircleCheckIcon, InfoIcon, Loader2Icon, OctagonXIcon, TriangleAlertIcon, XIcon } from "lucide-vue-next"
import { Toaster as Sonner } from "vue-sonner"
import { cn } from "@/lib/utils"
const props = defineProps<ToasterProps>()
</script>
<template> <template>
<Sonner <Sonner
:class="cn('toaster group', props.class)" :class="cn('toaster group', props.class)"
@@ -14,7 +5,7 @@ const props = defineProps<ToasterProps>()
'--normal-bg': 'var(--popover)', '--normal-bg': 'var(--popover)',
'--normal-text': 'var(--popover-foreground)', '--normal-text': 'var(--popover-foreground)',
'--normal-border': 'var(--border)', '--normal-border': 'var(--border)',
'--border-radius': 'var(--radius)', '--border-radius': 'var(--radius)'
}" }"
v-bind="props" v-bind="props"
> >
@@ -40,3 +31,12 @@ const props = defineProps<ToasterProps>()
</template> </template>
</Sonner> </Sonner>
</template> </template>
<script lang="ts" setup>
import type { ToasterProps } from 'vue-sonner'
import { CircleCheckIcon, InfoIcon, Loader2Icon, OctagonXIcon, TriangleAlertIcon, XIcon } from 'lucide-vue-next'
import { Toaster as Sonner } from 'vue-sonner'
import { cn } from '@/lib/utils'
const props = defineProps<ToasterProps>()
</script>

View File

@@ -1 +1 @@
export { default as Toaster } from "./Sonner.vue" export { default as Toaster } from './Sonner.vue'

View File

@@ -0,0 +1,15 @@
<template>
<TooltipRoot v-slot="slotProps" data-slot="tooltip" v-bind="forwarded">
<slot v-bind="slotProps" />
</TooltipRoot>
</template>
<script setup lang="ts">
import type { TooltipRootEmits, TooltipRootProps } from 'reka-ui'
import { TooltipRoot, useForwardPropsEmits } from 'reka-ui'
const props = defineProps<TooltipRootProps>()
const emits = defineEmits<TooltipRootEmits>()
const forwarded = useForwardPropsEmits(props, emits)
</script>

View File

@@ -0,0 +1,39 @@
<template>
<TooltipPortal>
<TooltipContent
data-slot="tooltip-content"
v-bind="{ ...forwarded, ...$attrs }"
:class="
cn(
'bg-foreground text-background animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit rounded-md px-3 py-1.5 text-xs text-balance',
props.class
)
"
>
<slot />
<TooltipArrow class="bg-foreground fill-foreground z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]" />
</TooltipContent>
</TooltipPortal>
</template>
<script setup lang="ts">
import type { TooltipContentEmits, TooltipContentProps } from 'reka-ui'
import type { HTMLAttributes } from 'vue'
import { reactiveOmit } from '@vueuse/core'
import { TooltipArrow, TooltipContent, TooltipPortal, useForwardPropsEmits } from 'reka-ui'
import { cn } from '@/lib/utils'
defineOptions({
inheritAttrs: false
})
const props = withDefaults(defineProps<TooltipContentProps & { class?: HTMLAttributes['class'] }>(), {
sideOffset: 4
})
const emits = defineEmits<TooltipContentEmits>()
const delegatedProps = reactiveOmit(props, 'class')
const forwarded = useForwardPropsEmits(delegatedProps, emits)
</script>

View File

@@ -0,0 +1,14 @@
<template>
<TooltipProvider v-bind="props">
<slot />
</TooltipProvider>
</template>
<script setup lang="ts">
import type { TooltipProviderProps } from 'reka-ui'
import { TooltipProvider } from 'reka-ui'
const props = withDefaults(defineProps<TooltipProviderProps>(), {
delayDuration: 0
})
</script>

View File

@@ -0,0 +1,12 @@
<template>
<TooltipTrigger data-slot="tooltip-trigger" v-bind="props">
<slot />
</TooltipTrigger>
</template>
<script setup lang="ts">
import type { TooltipTriggerProps } from 'reka-ui'
import { TooltipTrigger } from 'reka-ui'
const props = defineProps<TooltipTriggerProps>()
</script>

View File

@@ -0,0 +1,4 @@
export { default as Tooltip } from './Tooltip.vue'
export { default as TooltipContent } from './TooltipContent.vue'
export { default as TooltipProvider } from './TooltipProvider.vue'
export { default as TooltipTrigger } from './TooltipTrigger.vue'

View File

@@ -33,9 +33,11 @@ export const useGameConfig = () => {
[BuildingType.CrystalStorage]: 'crystalStorage', [BuildingType.CrystalStorage]: 'crystalStorage',
[BuildingType.DeuteriumTank]: 'deuteriumTank', [BuildingType.DeuteriumTank]: 'deuteriumTank',
[BuildingType.DarkMatterCollector]: 'darkMatterCollector', [BuildingType.DarkMatterCollector]: 'darkMatterCollector',
[BuildingType.Terraformer]: 'terraformer',
[BuildingType.LunarBase]: 'lunarBase', [BuildingType.LunarBase]: 'lunarBase',
[BuildingType.SensorPhalanx]: 'sensorPhalanx', [BuildingType.SensorPhalanx]: 'sensorPhalanx',
[BuildingType.JumpGate]: 'jumpGate' [BuildingType.JumpGate]: 'jumpGate',
[BuildingType.PlanetDestroyerFactory]: 'planetDestroyerFactory'
} }
// 舰船类型枚举值到翻译键的映射 // 舰船类型枚举值到翻译键的映射
@@ -49,7 +51,8 @@ export const useGameConfig = () => {
[ShipType.ColonyShip]: 'colonyShip', [ShipType.ColonyShip]: 'colonyShip',
[ShipType.Recycler]: 'recycler', [ShipType.Recycler]: 'recycler',
[ShipType.EspionageProbe]: 'espionageProbe', [ShipType.EspionageProbe]: 'espionageProbe',
[ShipType.DarkMatterHarvester]: 'darkMatterHarvester' [ShipType.DarkMatterHarvester]: 'darkMatterHarvester',
[ShipType.Deathstar]: 'deathstar'
} }
// 防御设施类型枚举值到翻译键的映射 // 防御设施类型枚举值到翻译键的映射
@@ -61,7 +64,8 @@ export const useGameConfig = () => {
[DefenseType.IonCannon]: 'ionCannon', [DefenseType.IonCannon]: 'ionCannon',
[DefenseType.PlasmaTurret]: 'plasmaTurret', [DefenseType.PlasmaTurret]: 'plasmaTurret',
[DefenseType.SmallShieldDome]: 'smallShieldDome', [DefenseType.SmallShieldDome]: 'smallShieldDome',
[DefenseType.LargeShieldDome]: 'largeShieldDome' [DefenseType.LargeShieldDome]: 'largeShieldDome',
[DefenseType.PlanetaryShield]: 'planetaryShield'
} }
// 科技类型枚举值到翻译键的映射 // 科技类型枚举值到翻译键的映射
@@ -75,7 +79,9 @@ export const useGameConfig = () => {
[TechnologyType.CombustionDrive]: 'combustionDrive', [TechnologyType.CombustionDrive]: 'combustionDrive',
[TechnologyType.ImpulseDrive]: 'impulseDrive', [TechnologyType.ImpulseDrive]: 'impulseDrive',
[TechnologyType.HyperspaceDrive]: 'hyperspaceDrive', [TechnologyType.HyperspaceDrive]: 'hyperspaceDrive',
[TechnologyType.DarkMatterTechnology]: 'darkMatterTechnology' [TechnologyType.DarkMatterTechnology]: 'darkMatterTechnology',
[TechnologyType.TerraformingTechnology]: 'terraformingTechnology',
[TechnologyType.PlanetDestructionTech]: 'planetDestructionTech'
} }
// 军官类型枚举值到翻译键的映射 // 军官类型枚举值到翻译键的映射

View File

@@ -10,8 +10,14 @@ export const BUILDINGS: Record<BuildingType, BuildingConfig> = {
baseCost: { metal: 60, crystal: 15, deuterium: 0, darkMatter: 0, energy: 0 }, baseCost: { metal: 60, crystal: 15, deuterium: 0, darkMatter: 0, energy: 0 },
baseTime: 15, // 减少建造时间30→15秒 baseTime: 15, // 减少建造时间30→15秒
costMultiplier: 1.5, costMultiplier: 1.5,
spaceUsage: 3, spaceUsage: 1,
planetOnly: true planetOnly: true,
requirements: { [BuildingType.SolarPlant]: 1 },
levelRequirements: {
10: { [BuildingType.RoboticsFactory]: 2 },
20: { [BuildingType.RoboticsFactory]: 5, [BuildingType.ResearchLab]: 3 },
30: { [BuildingType.NaniteFactory]: 1, [BuildingType.ResearchLab]: 8 }
}
}, },
[BuildingType.CrystalMine]: { [BuildingType.CrystalMine]: {
id: BuildingType.CrystalMine, id: BuildingType.CrystalMine,
@@ -20,8 +26,14 @@ export const BUILDINGS: Record<BuildingType, BuildingConfig> = {
baseCost: { metal: 48, crystal: 24, deuterium: 0, darkMatter: 0, energy: 0 }, baseCost: { metal: 48, crystal: 24, deuterium: 0, darkMatter: 0, energy: 0 },
baseTime: 15, // 减少建造时间30→15秒 baseTime: 15, // 减少建造时间30→15秒
costMultiplier: 1.6, costMultiplier: 1.6,
spaceUsage: 3, spaceUsage: 1,
planetOnly: true planetOnly: true,
requirements: { [BuildingType.SolarPlant]: 1 },
levelRequirements: {
10: { [BuildingType.RoboticsFactory]: 2 },
20: { [BuildingType.RoboticsFactory]: 5, [BuildingType.ResearchLab]: 3 },
30: { [BuildingType.NaniteFactory]: 1, [BuildingType.ResearchLab]: 8 }
}
}, },
[BuildingType.DeuteriumSynthesizer]: { [BuildingType.DeuteriumSynthesizer]: {
id: BuildingType.DeuteriumSynthesizer, id: BuildingType.DeuteriumSynthesizer,
@@ -30,8 +42,14 @@ export const BUILDINGS: Record<BuildingType, BuildingConfig> = {
baseCost: { metal: 225, crystal: 75, deuterium: 0, darkMatter: 0, energy: 0 }, baseCost: { metal: 225, crystal: 75, deuterium: 0, darkMatter: 0, energy: 0 },
baseTime: 20, // 减少建造时间30→20秒 baseTime: 20, // 减少建造时间30→20秒
costMultiplier: 1.5, costMultiplier: 1.5,
spaceUsage: 4, spaceUsage: 2,
planetOnly: true planetOnly: true,
requirements: { [BuildingType.SolarPlant]: 1 },
levelRequirements: {
10: { [BuildingType.RoboticsFactory]: 2 },
20: { [BuildingType.RoboticsFactory]: 5, [BuildingType.ResearchLab]: 3 },
30: { [BuildingType.NaniteFactory]: 1, [BuildingType.ResearchLab]: 8 }
}
}, },
[BuildingType.SolarPlant]: { [BuildingType.SolarPlant]: {
id: BuildingType.SolarPlant, id: BuildingType.SolarPlant,
@@ -40,7 +58,12 @@ export const BUILDINGS: Record<BuildingType, BuildingConfig> = {
baseCost: { metal: 75, crystal: 30, deuterium: 0, darkMatter: 0, energy: 0 }, baseCost: { metal: 75, crystal: 30, deuterium: 0, darkMatter: 0, energy: 0 },
baseTime: 15, // 减少建造时间30→15秒 baseTime: 15, // 减少建造时间30→15秒
costMultiplier: 1.5, costMultiplier: 1.5,
spaceUsage: 5 spaceUsage: 2,
levelRequirements: {
15: { [BuildingType.RoboticsFactory]: 3 },
25: { [BuildingType.RoboticsFactory]: 6, [BuildingType.ResearchLab]: 5 },
35: { [BuildingType.NaniteFactory]: 1, [BuildingType.ResearchLab]: 10 }
}
}, },
[BuildingType.RoboticsFactory]: { [BuildingType.RoboticsFactory]: {
id: BuildingType.RoboticsFactory, id: BuildingType.RoboticsFactory,
@@ -49,7 +72,17 @@ export const BUILDINGS: Record<BuildingType, BuildingConfig> = {
baseCost: { metal: 400, crystal: 120, deuterium: 200, darkMatter: 0, energy: 0 }, baseCost: { metal: 400, crystal: 120, deuterium: 200, darkMatter: 0, energy: 0 },
baseTime: 40, // 减少建造时间60→40秒 baseTime: 40, // 减少建造时间60→40秒
costMultiplier: 2, costMultiplier: 2,
spaceUsage: 6 spaceUsage: 4,
requirements: {
[BuildingType.MetalMine]: 2,
[BuildingType.CrystalMine]: 2,
[BuildingType.DeuteriumSynthesizer]: 2
},
levelRequirements: {
5: { [BuildingType.ResearchLab]: 3, [BuildingType.SolarPlant]: 8 },
8: { [BuildingType.ResearchLab]: 6, [BuildingType.SolarPlant]: 12, [BuildingType.MetalMine]: 12, [BuildingType.CrystalMine]: 12 },
10: { [BuildingType.ResearchLab]: 8, [BuildingType.NaniteFactory]: 1 }
}
}, },
[BuildingType.NaniteFactory]: { [BuildingType.NaniteFactory]: {
id: BuildingType.NaniteFactory, id: BuildingType.NaniteFactory,
@@ -58,8 +91,13 @@ export const BUILDINGS: Record<BuildingType, BuildingConfig> = {
baseCost: { metal: 1000000, crystal: 500000, deuterium: 100000, darkMatter: 0, energy: 0 }, baseCost: { metal: 1000000, crystal: 500000, deuterium: 100000, darkMatter: 0, energy: 0 },
baseTime: 240, // 减少建造时间300→240秒 baseTime: 240, // 减少建造时间300→240秒
costMultiplier: 2, costMultiplier: 2,
spaceUsage: 15, spaceUsage: 8,
requirements: { [BuildingType.RoboticsFactory]: 10 } maxLevel: 10, // 最多10级最多11个建造队列
requirements: { [BuildingType.RoboticsFactory]: 10 },
levelRequirements: {
3: { [BuildingType.ResearchLab]: 10, [BuildingType.Shipyard]: 8, [TechnologyType.ComputerTechnology]: 8 },
5: { [BuildingType.ResearchLab]: 12, [BuildingType.Shipyard]: 10, [TechnologyType.ComputerTechnology]: 10 }
}
}, },
[BuildingType.Shipyard]: { [BuildingType.Shipyard]: {
id: BuildingType.Shipyard, id: BuildingType.Shipyard,
@@ -68,7 +106,13 @@ export const BUILDINGS: Record<BuildingType, BuildingConfig> = {
baseCost: { metal: 400, crystal: 200, deuterium: 100, darkMatter: 0, energy: 0 }, baseCost: { metal: 400, crystal: 200, deuterium: 100, darkMatter: 0, energy: 0 },
baseTime: 30, // 减少建造时间60→30秒 baseTime: 30, // 减少建造时间60→30秒
costMultiplier: 2, costMultiplier: 2,
spaceUsage: 8 spaceUsage: 5,
fleetStorageBonus: 1000, // 每级增加100舰队仓储
requirements: { [BuildingType.RoboticsFactory]: 2 },
levelRequirements: {
8: { [BuildingType.RoboticsFactory]: 5, [BuildingType.ResearchLab]: 5 },
12: { [BuildingType.RoboticsFactory]: 8, [BuildingType.ResearchLab]: 8, [BuildingType.NaniteFactory]: 2 }
}
}, },
[BuildingType.ResearchLab]: { [BuildingType.ResearchLab]: {
id: BuildingType.ResearchLab, id: BuildingType.ResearchLab,
@@ -77,7 +121,21 @@ export const BUILDINGS: Record<BuildingType, BuildingConfig> = {
baseCost: { metal: 200, crystal: 400, deuterium: 200, darkMatter: 0, energy: 0 }, baseCost: { metal: 200, crystal: 400, deuterium: 200, darkMatter: 0, energy: 0 },
baseTime: 30, // 减少建造时间60→30秒 baseTime: 30, // 减少建造时间60→30秒
costMultiplier: 2, costMultiplier: 2,
spaceUsage: 5 spaceUsage: 3,
requirements: {
[BuildingType.MetalMine]: 3,
[BuildingType.CrystalMine]: 3,
[BuildingType.DeuteriumSynthesizer]: 3
},
levelRequirements: {
8: {
[BuildingType.RoboticsFactory]: 5,
[BuildingType.MetalMine]: 10,
[BuildingType.CrystalMine]: 10,
[BuildingType.DeuteriumSynthesizer]: 10
},
12: { [BuildingType.RoboticsFactory]: 8, [BuildingType.NaniteFactory]: 1, [TechnologyType.EnergyTechnology]: 5 }
}
}, },
[BuildingType.MetalStorage]: { [BuildingType.MetalStorage]: {
id: BuildingType.MetalStorage, id: BuildingType.MetalStorage,
@@ -86,7 +144,12 @@ export const BUILDINGS: Record<BuildingType, BuildingConfig> = {
baseCost: { metal: 1000, crystal: 0, deuterium: 0, darkMatter: 0, energy: 0 }, baseCost: { metal: 1000, crystal: 0, deuterium: 0, darkMatter: 0, energy: 0 },
baseTime: 15, // 减少建造时间30→15秒 baseTime: 15, // 减少建造时间30→15秒
costMultiplier: 2, costMultiplier: 2,
spaceUsage: 2 spaceUsage: 1,
requirements: { [BuildingType.MetalMine]: 2 },
levelRequirements: {
8: { [BuildingType.MetalMine]: 15, [BuildingType.RoboticsFactory]: 3 },
12: { [BuildingType.MetalMine]: 25, [BuildingType.RoboticsFactory]: 6 }
}
}, },
[BuildingType.CrystalStorage]: { [BuildingType.CrystalStorage]: {
id: BuildingType.CrystalStorage, id: BuildingType.CrystalStorage,
@@ -95,7 +158,12 @@ export const BUILDINGS: Record<BuildingType, BuildingConfig> = {
baseCost: { metal: 1000, crystal: 500, deuterium: 0, darkMatter: 0, energy: 0 }, baseCost: { metal: 1000, crystal: 500, deuterium: 0, darkMatter: 0, energy: 0 },
baseTime: 15, // 减少建造时间30→15秒 baseTime: 15, // 减少建造时间30→15秒
costMultiplier: 2, costMultiplier: 2,
spaceUsage: 2 spaceUsage: 1,
requirements: { [BuildingType.CrystalMine]: 2 },
levelRequirements: {
8: { [BuildingType.CrystalMine]: 15, [BuildingType.RoboticsFactory]: 3 },
12: { [BuildingType.CrystalMine]: 25, [BuildingType.RoboticsFactory]: 6 }
}
}, },
[BuildingType.DeuteriumTank]: { [BuildingType.DeuteriumTank]: {
id: BuildingType.DeuteriumTank, id: BuildingType.DeuteriumTank,
@@ -104,7 +172,12 @@ export const BUILDINGS: Record<BuildingType, BuildingConfig> = {
baseCost: { metal: 1000, crystal: 1000, deuterium: 0, darkMatter: 0, energy: 0 }, baseCost: { metal: 1000, crystal: 1000, deuterium: 0, darkMatter: 0, energy: 0 },
baseTime: 15, // 减少建造时间30→15秒 baseTime: 15, // 减少建造时间30→15秒
costMultiplier: 2, costMultiplier: 2,
spaceUsage: 2 spaceUsage: 1,
requirements: { [BuildingType.DeuteriumSynthesizer]: 2 },
levelRequirements: {
8: { [BuildingType.DeuteriumSynthesizer]: 15, [BuildingType.RoboticsFactory]: 3 },
12: { [BuildingType.DeuteriumSynthesizer]: 25, [BuildingType.RoboticsFactory]: 6 }
}
}, },
[BuildingType.DarkMatterCollector]: { [BuildingType.DarkMatterCollector]: {
id: BuildingType.DarkMatterCollector, id: BuildingType.DarkMatterCollector,
@@ -113,8 +186,35 @@ export const BUILDINGS: Record<BuildingType, BuildingConfig> = {
baseCost: { metal: 50000, crystal: 100000, deuterium: 50000, darkMatter: 0, energy: 0 }, baseCost: { metal: 50000, crystal: 100000, deuterium: 50000, darkMatter: 0, energy: 0 },
baseTime: 90, // 减少建造时间120→90秒 baseTime: 90, // 减少建造时间120→90秒
costMultiplier: 2, costMultiplier: 2,
spaceUsage: 10, spaceUsage: 6,
planetOnly: true planetOnly: true,
requirements: {
[BuildingType.ResearchLab]: 5,
[TechnologyType.DarkMatterTechnology]: 1
},
levelRequirements: {
5: { [BuildingType.ResearchLab]: 8, [TechnologyType.DarkMatterTechnology]: 3, [BuildingType.RoboticsFactory]: 8 },
8: { [BuildingType.ResearchLab]: 10, [TechnologyType.DarkMatterTechnology]: 5, [BuildingType.NaniteFactory]: 2 }
}
},
[BuildingType.Terraformer]: {
id: BuildingType.Terraformer,
name: '地形改造器',
description: '改造行星地形每级增加5个可用空间',
baseCost: { metal: 0, crystal: 50000, deuterium: 100000, darkMatter: 0, energy: 0 },
baseTime: 60,
costMultiplier: 2,
spaceUsage: 5,
planetOnly: true,
requirements: {
[BuildingType.ResearchLab]: 10,
[BuildingType.RoboticsFactory]: 8,
[TechnologyType.TerraformingTechnology]: 1
},
levelRequirements: {
5: { [BuildingType.ResearchLab]: 12, [TechnologyType.TerraformingTechnology]: 3, [BuildingType.NaniteFactory]: 1 },
8: { [BuildingType.ResearchLab]: 14, [TechnologyType.TerraformingTechnology]: 5, [BuildingType.NaniteFactory]: 3 }
}
}, },
// 月球专属建筑 // 月球专属建筑
[BuildingType.LunarBase]: { [BuildingType.LunarBase]: {
@@ -125,7 +225,11 @@ export const BUILDINGS: Record<BuildingType, BuildingConfig> = {
baseTime: 45, // 减少建造时间60→45秒 baseTime: 45, // 减少建造时间60→45秒
costMultiplier: 2, costMultiplier: 2,
spaceUsage: 0, // 月球基地本身不占用空间,反而增加空间 spaceUsage: 0, // 月球基地本身不占用空间,反而增加空间
moonOnly: true moonOnly: true,
levelRequirements: {
5: { [BuildingType.RoboticsFactory]: 5 },
8: { [BuildingType.RoboticsFactory]: 8, [BuildingType.NaniteFactory]: 1 }
}
}, },
[BuildingType.SensorPhalanx]: { [BuildingType.SensorPhalanx]: {
id: BuildingType.SensorPhalanx, id: BuildingType.SensorPhalanx,
@@ -134,8 +238,13 @@ export const BUILDINGS: Record<BuildingType, BuildingConfig> = {
baseCost: { metal: 20000, crystal: 40000, deuterium: 20000, darkMatter: 0, energy: 0 }, baseCost: { metal: 20000, crystal: 40000, deuterium: 20000, darkMatter: 0, energy: 0 },
baseTime: 60, // 减少建造时间90→60秒 baseTime: 60, // 减少建造时间90→60秒
costMultiplier: 2, costMultiplier: 2,
spaceUsage: 10, spaceUsage: 6,
moonOnly: true moonOnly: true,
requirements: { [BuildingType.LunarBase]: 1 },
levelRequirements: {
5: { [BuildingType.LunarBase]: 5, [TechnologyType.ComputerTechnology]: 5 },
8: { [BuildingType.LunarBase]: 8, [TechnologyType.ComputerTechnology]: 8, [BuildingType.NaniteFactory]: 2 }
}
}, },
[BuildingType.JumpGate]: { [BuildingType.JumpGate]: {
id: BuildingType.JumpGate, id: BuildingType.JumpGate,
@@ -144,8 +253,42 @@ export const BUILDINGS: Record<BuildingType, BuildingConfig> = {
baseCost: { metal: 2000000, crystal: 4000000, deuterium: 2000000, darkMatter: 0, energy: 0 }, baseCost: { metal: 2000000, crystal: 4000000, deuterium: 2000000, darkMatter: 0, energy: 0 },
baseTime: 240, // 减少建造时间300→240秒 baseTime: 240, // 减少建造时间300→240秒
costMultiplier: 2, costMultiplier: 2,
spaceUsage: 20, spaceUsage: 10,
moonOnly: true moonOnly: true,
maxLevel: 5, // 最多5级
requirements: {
[BuildingType.LunarBase]: 1,
[TechnologyType.HyperspaceTechnology]: 7
},
levelRequirements: {
3: { [BuildingType.LunarBase]: 5, [TechnologyType.HyperspaceTechnology]: 10, [BuildingType.NaniteFactory]: 3 }
}
},
// 特殊建筑
[BuildingType.PlanetDestroyerFactory]: {
id: BuildingType.PlanetDestroyerFactory,
name: '行星毁灭者工厂',
description: '建造能够摧毁行星的终极武器',
baseCost: { metal: 5000000, crystal: 4000000, deuterium: 1000000, darkMatter: 0, energy: 0 },
baseTime: 300,
costMultiplier: 2,
spaceUsage: 15,
planetOnly: true,
maxLevel: 3, // 最多3级
requirements: {
[BuildingType.Shipyard]: 12,
[BuildingType.RoboticsFactory]: 10,
[BuildingType.NaniteFactory]: 5,
[TechnologyType.PlanetDestructionTech]: 1
},
levelRequirements: {
3: {
[BuildingType.Shipyard]: 14,
[BuildingType.NaniteFactory]: 8,
[TechnologyType.PlanetDestructionTech]: 3,
[TechnologyType.HyperspaceTechnology]: 10
}
}
} }
} }
@@ -158,7 +301,12 @@ export const TECHNOLOGIES: Record<TechnologyType, TechnologyConfig> = {
baseCost: { metal: 0, crystal: 800, deuterium: 400, darkMatter: 0, energy: 0 }, baseCost: { metal: 0, crystal: 800, deuterium: 400, darkMatter: 0, energy: 0 },
baseTime: 30, // 减少研究时间60→30秒 baseTime: 30, // 减少研究时间60→30秒
costMultiplier: 2, costMultiplier: 2,
requirements: { [BuildingType.ResearchLab]: 1 } requirements: { [BuildingType.ResearchLab]: 1 },
levelRequirements: {
5: { [BuildingType.ResearchLab]: 3, [BuildingType.SolarPlant]: 10 },
8: { [BuildingType.ResearchLab]: 5, [BuildingType.SolarPlant]: 15, [BuildingType.RoboticsFactory]: 3 },
12: { [BuildingType.ResearchLab]: 8, [BuildingType.RoboticsFactory]: 6, [BuildingType.NaniteFactory]: 1 }
}
}, },
[TechnologyType.LaserTechnology]: { [TechnologyType.LaserTechnology]: {
id: TechnologyType.LaserTechnology, id: TechnologyType.LaserTechnology,
@@ -167,7 +315,11 @@ export const TECHNOLOGIES: Record<TechnologyType, TechnologyConfig> = {
baseCost: { metal: 200, crystal: 100, deuterium: 0, darkMatter: 0, energy: 0 }, baseCost: { metal: 200, crystal: 100, deuterium: 0, darkMatter: 0, energy: 0 },
baseTime: 60, baseTime: 60,
costMultiplier: 2, costMultiplier: 2,
requirements: { [BuildingType.ResearchLab]: 1, [TechnologyType.EnergyTechnology]: 2 } requirements: { [BuildingType.ResearchLab]: 1, [TechnologyType.EnergyTechnology]: 2 },
levelRequirements: {
6: { [BuildingType.ResearchLab]: 5, [TechnologyType.EnergyTechnology]: 5, [BuildingType.Shipyard]: 3 },
10: { [BuildingType.ResearchLab]: 8, [TechnologyType.EnergyTechnology]: 8, [BuildingType.Shipyard]: 6 }
}
}, },
[TechnologyType.IonTechnology]: { [TechnologyType.IonTechnology]: {
id: TechnologyType.IonTechnology, id: TechnologyType.IonTechnology,
@@ -176,7 +328,11 @@ export const TECHNOLOGIES: Record<TechnologyType, TechnologyConfig> = {
baseCost: { metal: 1000, crystal: 300, deuterium: 100, darkMatter: 0, energy: 0 }, baseCost: { metal: 1000, crystal: 300, deuterium: 100, darkMatter: 0, energy: 0 },
baseTime: 60, baseTime: 60,
costMultiplier: 2, costMultiplier: 2,
requirements: { [BuildingType.ResearchLab]: 4, [TechnologyType.LaserTechnology]: 5, [TechnologyType.EnergyTechnology]: 4 } requirements: { [BuildingType.ResearchLab]: 4, [TechnologyType.LaserTechnology]: 5, [TechnologyType.EnergyTechnology]: 4 },
levelRequirements: {
5: { [BuildingType.ResearchLab]: 8, [TechnologyType.LaserTechnology]: 10, [TechnologyType.EnergyTechnology]: 8 },
8: { [BuildingType.ResearchLab]: 10, [TechnologyType.LaserTechnology]: 12, [BuildingType.NaniteFactory]: 2 }
}
}, },
[TechnologyType.HyperspaceTechnology]: { [TechnologyType.HyperspaceTechnology]: {
id: TechnologyType.HyperspaceTechnology, id: TechnologyType.HyperspaceTechnology,
@@ -185,7 +341,11 @@ export const TECHNOLOGIES: Record<TechnologyType, TechnologyConfig> = {
baseCost: { metal: 0, crystal: 4000, deuterium: 2000, darkMatter: 0, energy: 0 }, baseCost: { metal: 0, crystal: 4000, deuterium: 2000, darkMatter: 0, energy: 0 },
baseTime: 60, baseTime: 60,
costMultiplier: 2, costMultiplier: 2,
requirements: { [BuildingType.ResearchLab]: 7, [TechnologyType.EnergyTechnology]: 5 } requirements: { [BuildingType.ResearchLab]: 7, [TechnologyType.EnergyTechnology]: 5 },
levelRequirements: {
5: { [BuildingType.ResearchLab]: 10, [TechnologyType.EnergyTechnology]: 8, [BuildingType.Shipyard]: 5 },
8: { [BuildingType.ResearchLab]: 12, [TechnologyType.EnergyTechnology]: 10, [BuildingType.NaniteFactory]: 2 }
}
}, },
[TechnologyType.PlasmaTechnology]: { [TechnologyType.PlasmaTechnology]: {
id: TechnologyType.PlasmaTechnology, id: TechnologyType.PlasmaTechnology,
@@ -199,6 +359,20 @@ export const TECHNOLOGIES: Record<TechnologyType, TechnologyConfig> = {
[TechnologyType.EnergyTechnology]: 8, [TechnologyType.EnergyTechnology]: 8,
[TechnologyType.LaserTechnology]: 10, [TechnologyType.LaserTechnology]: 10,
[TechnologyType.IonTechnology]: 5 [TechnologyType.IonTechnology]: 5
},
levelRequirements: {
5: {
[BuildingType.ResearchLab]: 10,
[TechnologyType.EnergyTechnology]: 12,
[TechnologyType.IonTechnology]: 8,
[BuildingType.NaniteFactory]: 1
},
8: {
[BuildingType.ResearchLab]: 12,
[TechnologyType.EnergyTechnology]: 15,
[TechnologyType.IonTechnology]: 10,
[BuildingType.NaniteFactory]: 3
}
} }
}, },
[TechnologyType.ComputerTechnology]: { [TechnologyType.ComputerTechnology]: {
@@ -208,7 +382,14 @@ export const TECHNOLOGIES: Record<TechnologyType, TechnologyConfig> = {
baseCost: { metal: 0, crystal: 400, deuterium: 600, darkMatter: 0, energy: 0 }, baseCost: { metal: 0, crystal: 400, deuterium: 600, darkMatter: 0, energy: 0 },
baseTime: 60, baseTime: 60,
costMultiplier: 2, costMultiplier: 2,
requirements: { [BuildingType.ResearchLab]: 1 } fleetStorageBonus: 500, // 每级全局增加50舰队仓储
maxLevel: 10, // 最多10级最多11个研究队列
requirements: { [BuildingType.ResearchLab]: 1 },
levelRequirements: {
3: { [BuildingType.ResearchLab]: 5 },
5: { [BuildingType.ResearchLab]: 8, [BuildingType.RoboticsFactory]: 5 },
8: { [BuildingType.ResearchLab]: 10, [BuildingType.NaniteFactory]: 2 }
}
}, },
[TechnologyType.CombustionDrive]: { [TechnologyType.CombustionDrive]: {
id: TechnologyType.CombustionDrive, id: TechnologyType.CombustionDrive,
@@ -217,7 +398,11 @@ export const TECHNOLOGIES: Record<TechnologyType, TechnologyConfig> = {
baseCost: { metal: 400, crystal: 0, deuterium: 600, darkMatter: 0, energy: 0 }, baseCost: { metal: 400, crystal: 0, deuterium: 600, darkMatter: 0, energy: 0 },
baseTime: 60, baseTime: 60,
costMultiplier: 2, costMultiplier: 2,
requirements: { [BuildingType.ResearchLab]: 1, [TechnologyType.EnergyTechnology]: 1 } requirements: { [BuildingType.ResearchLab]: 1, [TechnologyType.EnergyTechnology]: 1 },
levelRequirements: {
5: { [BuildingType.ResearchLab]: 5, [TechnologyType.EnergyTechnology]: 3, [BuildingType.Shipyard]: 2 },
8: { [BuildingType.ResearchLab]: 8, [TechnologyType.EnergyTechnology]: 5, [BuildingType.Shipyard]: 5 }
}
}, },
[TechnologyType.ImpulseDrive]: { [TechnologyType.ImpulseDrive]: {
id: TechnologyType.ImpulseDrive, id: TechnologyType.ImpulseDrive,
@@ -226,7 +411,11 @@ export const TECHNOLOGIES: Record<TechnologyType, TechnologyConfig> = {
baseCost: { metal: 2000, crystal: 4000, deuterium: 600, darkMatter: 0, energy: 0 }, baseCost: { metal: 2000, crystal: 4000, deuterium: 600, darkMatter: 0, energy: 0 },
baseTime: 60, baseTime: 60,
costMultiplier: 2, costMultiplier: 2,
requirements: { [BuildingType.ResearchLab]: 2, [TechnologyType.EnergyTechnology]: 1 } requirements: { [BuildingType.ResearchLab]: 2, [TechnologyType.EnergyTechnology]: 1 },
levelRequirements: {
5: { [BuildingType.ResearchLab]: 6, [TechnologyType.EnergyTechnology]: 4, [BuildingType.Shipyard]: 3 },
8: { [BuildingType.ResearchLab]: 8, [TechnologyType.EnergyTechnology]: 6, [BuildingType.Shipyard]: 6 }
}
}, },
[TechnologyType.HyperspaceDrive]: { [TechnologyType.HyperspaceDrive]: {
id: TechnologyType.HyperspaceDrive, id: TechnologyType.HyperspaceDrive,
@@ -235,7 +424,11 @@ export const TECHNOLOGIES: Record<TechnologyType, TechnologyConfig> = {
baseCost: { metal: 10000, crystal: 20000, deuterium: 6000, darkMatter: 0, energy: 0 }, baseCost: { metal: 10000, crystal: 20000, deuterium: 6000, darkMatter: 0, energy: 0 },
baseTime: 60, baseTime: 60,
costMultiplier: 2, costMultiplier: 2,
requirements: { [BuildingType.ResearchLab]: 7, [TechnologyType.HyperspaceTechnology]: 3 } requirements: { [BuildingType.ResearchLab]: 7, [TechnologyType.HyperspaceTechnology]: 3 },
levelRequirements: {
5: { [BuildingType.ResearchLab]: 10, [TechnologyType.HyperspaceTechnology]: 6, [BuildingType.Shipyard]: 8 },
8: { [BuildingType.ResearchLab]: 12, [TechnologyType.HyperspaceTechnology]: 8, [BuildingType.NaniteFactory]: 3 }
}
}, },
[TechnologyType.DarkMatterTechnology]: { [TechnologyType.DarkMatterTechnology]: {
id: TechnologyType.DarkMatterTechnology, id: TechnologyType.DarkMatterTechnology,
@@ -244,7 +437,58 @@ export const TECHNOLOGIES: Record<TechnologyType, TechnologyConfig> = {
baseCost: { metal: 100000, crystal: 200000, deuterium: 100000, darkMatter: 0, energy: 0 }, baseCost: { metal: 100000, crystal: 200000, deuterium: 100000, darkMatter: 0, energy: 0 },
baseTime: 180, baseTime: 180,
costMultiplier: 2, costMultiplier: 2,
requirements: { [BuildingType.ResearchLab]: 8, [TechnologyType.HyperspaceTechnology]: 5 } requirements: { [BuildingType.ResearchLab]: 8, [TechnologyType.HyperspaceTechnology]: 5 },
levelRequirements: {
3: {
[BuildingType.ResearchLab]: 10,
[TechnologyType.HyperspaceTechnology]: 8,
[BuildingType.RoboticsFactory]: 10,
[TechnologyType.EnergyTechnology]: 10
},
5: {
[BuildingType.ResearchLab]: 12,
[TechnologyType.HyperspaceTechnology]: 10,
[BuildingType.NaniteFactory]: 2,
[TechnologyType.EnergyTechnology]: 12
}
}
},
[TechnologyType.TerraformingTechnology]: {
id: TechnologyType.TerraformingTechnology,
name: '地形改造技术',
description: '研究行星地形改造技术每级为所有行星增加5个可用空间',
baseCost: { metal: 0, crystal: 20000, deuterium: 40000, darkMatter: 0, energy: 0 },
baseTime: 90,
costMultiplier: 2,
requirements: { [BuildingType.ResearchLab]: 8, [TechnologyType.EnergyTechnology]: 6 },
levelRequirements: {
5: { [BuildingType.ResearchLab]: 12, [TechnologyType.EnergyTechnology]: 10, [BuildingType.RoboticsFactory]: 10 },
8: { [BuildingType.ResearchLab]: 14, [TechnologyType.EnergyTechnology]: 12, [BuildingType.NaniteFactory]: 3 }
}
},
[TechnologyType.PlanetDestructionTech]: {
id: TechnologyType.PlanetDestructionTech,
name: '行星毁灭技术',
description: '研究如何摧毁整个行星的恐怖技术',
baseCost: { metal: 4000000, crystal: 8000000, deuterium: 4000000, darkMatter: 0, energy: 0 },
baseTime: 300,
costMultiplier: 2,
maxLevel: 5, // 最多5级
requirements: {
[BuildingType.ResearchLab]: 12,
[TechnologyType.HyperspaceTechnology]: 8,
[TechnologyType.HyperspaceDrive]: 6,
[TechnologyType.PlasmaTechnology]: 7
},
levelRequirements: {
3: {
[BuildingType.ResearchLab]: 14,
[TechnologyType.HyperspaceTechnology]: 12,
[TechnologyType.HyperspaceDrive]: 10,
[TechnologyType.PlasmaTechnology]: 10,
[BuildingType.NaniteFactory]: 5
}
}
} }
} }
@@ -262,6 +506,7 @@ export const SHIPS: Record<ShipType, ShipConfig> = {
armor: 400, armor: 400,
speed: 12500, speed: 12500,
fuelConsumption: 20, fuelConsumption: 20,
storageUsage: 5,
requirements: { [BuildingType.Shipyard]: 1, [TechnologyType.CombustionDrive]: 1 } requirements: { [BuildingType.Shipyard]: 1, [TechnologyType.CombustionDrive]: 1 }
}, },
[ShipType.HeavyFighter]: { [ShipType.HeavyFighter]: {
@@ -276,6 +521,7 @@ export const SHIPS: Record<ShipType, ShipConfig> = {
armor: 1000, armor: 1000,
speed: 10000, speed: 10000,
fuelConsumption: 75, fuelConsumption: 75,
storageUsage: 10,
requirements: { [BuildingType.Shipyard]: 3, [TechnologyType.ImpulseDrive]: 2 } requirements: { [BuildingType.Shipyard]: 3, [TechnologyType.ImpulseDrive]: 2 }
}, },
[ShipType.Cruiser]: { [ShipType.Cruiser]: {
@@ -290,6 +536,7 @@ export const SHIPS: Record<ShipType, ShipConfig> = {
armor: 2700, armor: 2700,
speed: 15000, speed: 15000,
fuelConsumption: 300, fuelConsumption: 300,
storageUsage: 15,
requirements: { [BuildingType.Shipyard]: 5, [TechnologyType.ImpulseDrive]: 4, [TechnologyType.IonTechnology]: 2 } requirements: { [BuildingType.Shipyard]: 5, [TechnologyType.ImpulseDrive]: 4, [TechnologyType.IonTechnology]: 2 }
}, },
[ShipType.Battleship]: { [ShipType.Battleship]: {
@@ -304,6 +551,7 @@ export const SHIPS: Record<ShipType, ShipConfig> = {
armor: 6000, armor: 6000,
speed: 10000, speed: 10000,
fuelConsumption: 500, fuelConsumption: 500,
storageUsage: 25,
requirements: { [BuildingType.Shipyard]: 7, [TechnologyType.HyperspaceDrive]: 4 } requirements: { [BuildingType.Shipyard]: 7, [TechnologyType.HyperspaceDrive]: 4 }
}, },
[ShipType.SmallCargo]: { [ShipType.SmallCargo]: {
@@ -318,6 +566,7 @@ export const SHIPS: Record<ShipType, ShipConfig> = {
armor: 400, armor: 400,
speed: 5000, speed: 5000,
fuelConsumption: 10, fuelConsumption: 10,
storageUsage: 10,
requirements: { [BuildingType.Shipyard]: 2, [TechnologyType.CombustionDrive]: 2 } requirements: { [BuildingType.Shipyard]: 2, [TechnologyType.CombustionDrive]: 2 }
}, },
[ShipType.LargeCargo]: { [ShipType.LargeCargo]: {
@@ -332,6 +581,7 @@ export const SHIPS: Record<ShipType, ShipConfig> = {
armor: 1200, armor: 1200,
speed: 7500, speed: 7500,
fuelConsumption: 50, fuelConsumption: 50,
storageUsage: 20,
requirements: { [BuildingType.Shipyard]: 4, [TechnologyType.CombustionDrive]: 6 } requirements: { [BuildingType.Shipyard]: 4, [TechnologyType.CombustionDrive]: 6 }
}, },
[ShipType.ColonyShip]: { [ShipType.ColonyShip]: {
@@ -346,6 +596,7 @@ export const SHIPS: Record<ShipType, ShipConfig> = {
armor: 3000, armor: 3000,
speed: 2500, speed: 2500,
fuelConsumption: 1000, fuelConsumption: 1000,
storageUsage: 40,
requirements: { [BuildingType.Shipyard]: 4, [TechnologyType.ImpulseDrive]: 3 } requirements: { [BuildingType.Shipyard]: 4, [TechnologyType.ImpulseDrive]: 3 }
}, },
[ShipType.Recycler]: { [ShipType.Recycler]: {
@@ -360,6 +611,7 @@ export const SHIPS: Record<ShipType, ShipConfig> = {
armor: 1600, armor: 1600,
speed: 2000, speed: 2000,
fuelConsumption: 300, fuelConsumption: 300,
storageUsage: 30,
requirements: { [BuildingType.Shipyard]: 4, [TechnologyType.CombustionDrive]: 6 } requirements: { [BuildingType.Shipyard]: 4, [TechnologyType.CombustionDrive]: 6 }
}, },
[ShipType.EspionageProbe]: { [ShipType.EspionageProbe]: {
@@ -374,6 +626,7 @@ export const SHIPS: Record<ShipType, ShipConfig> = {
armor: 100, armor: 100,
speed: 100000000, speed: 100000000,
fuelConsumption: 1, fuelConsumption: 1,
storageUsage: 2,
requirements: { [BuildingType.Shipyard]: 3, [TechnologyType.CombustionDrive]: 3 } requirements: { [BuildingType.Shipyard]: 3, [TechnologyType.CombustionDrive]: 3 }
}, },
[ShipType.DarkMatterHarvester]: { [ShipType.DarkMatterHarvester]: {
@@ -388,11 +641,31 @@ export const SHIPS: Record<ShipType, ShipConfig> = {
armor: 2000, armor: 2000,
speed: 5000, speed: 5000,
fuelConsumption: 500, fuelConsumption: 500,
storageUsage: 50,
requirements: { requirements: {
[BuildingType.Shipyard]: 8, [BuildingType.Shipyard]: 8,
[TechnologyType.HyperspaceDrive]: 5, [TechnologyType.HyperspaceDrive]: 5,
[TechnologyType.DarkMatterTechnology]: 1 [TechnologyType.DarkMatterTechnology]: 1
} }
},
[ShipType.Deathstar]: {
id: ShipType.Deathstar,
name: '死星',
description: '终极武器,能够摧毁整个行星',
cost: { metal: 5000000, crystal: 4000000, deuterium: 1000000, darkMatter: 0, energy: 0 },
buildTime: 600,
cargoCapacity: 1000000,
attack: 200000,
shield: 50000,
armor: 900000,
speed: 100,
fuelConsumption: 1,
storageUsage: 100,
requirements: {
[BuildingType.PlanetDestroyerFactory]: 10,
[TechnologyType.PlanetDestructionTech]: 7,
[TechnologyType.HyperspaceDrive]: 7
}
} }
} }
@@ -485,6 +758,21 @@ export const DEFENSES: Record<DefenseType, DefenseConfig> = {
shield: 10000, shield: 10000,
armor: 10000, armor: 10000,
requirements: { [BuildingType.Shipyard]: 6, [TechnologyType.EnergyTechnology]: 6 } requirements: { [BuildingType.Shipyard]: 6, [TechnologyType.EnergyTechnology]: 6 }
},
[DefenseType.PlanetaryShield]: {
id: DefenseType.PlanetaryShield,
name: '行星护盾',
description: '保护行星免受毁灭攻击的超级护盾',
cost: { metal: 2000000, crystal: 2000000, deuterium: 1000000, darkMatter: 0, energy: 0 },
buildTime: 180,
attack: 1,
shield: 100000,
armor: 100000,
requirements: {
[BuildingType.Shipyard]: 10,
[TechnologyType.EnergyTechnology]: 10,
[TechnologyType.HyperspaceTechnology]: 8
}
} }
} }
@@ -565,6 +853,20 @@ export const MOON_CONFIG = {
baseChance: 1, // 基础1%概率 baseChance: 1, // 基础1%概率
maxChance: 20, // 最大20%概率 maxChance: 20, // 最大20%概率
chancePerDebris: 100000, // 每10万资源增加1%概率 chancePerDebris: 100000, // 每10万资源增加1%概率
baseSize: 100, // 月球基础空间 baseSize: 60, // 月球基础空间
lunarBaseSpaceBonus: 3 // 每级月球基地增加的空间 lunarBaseSpaceBonus: 5 // 每级月球基地增加的空间
}
// 行星配置
export const PLANET_CONFIG = {
baseSize: 200, // 行星基础空间
terraformerSpaceBonus: 5, // 每级地形改造器增加的空间
terraformingTechSpaceBonus: 3 // 每级地形改造技术增加的空间
}
// 舰队仓储配置
export const FLEET_STORAGE_CONFIG = {
baseStorage: 1000, // 基础舰队仓储
shipyardBonus: 1000, // 每级造船厂增加的仓储
computerTechBonus: 500 // 每级计算机技术全局增加的仓储
} }

Some files were not shown because too many files have changed in this diff Show More