diff --git a/IFLOW.md b/IFLOW.md
new file mode 100644
index 0000000..0cf42ad
--- /dev/null
+++ b/IFLOW.md
@@ -0,0 +1,94 @@
+# IFLOW 上下文文档
+
+## 项目概述
+
+这是一个基于 **Vite + Vue 3 + Electron** 的桌面应用程序开发模板,名为 **Vutron**。它提供了一个快速搭建跨平台桌面应用的环境,内置了热重载、TypeScript 支持、多语言支持、主题切换(暗黑/明亮)、全局状态管理(Pinia)等功能。
+
+项目使用 `pnpm` 作为包管理器,主要技术栈包括:
+
+- 前端框架:Vue 3 (Composition API)
+- 构建工具:Vite
+- 桌面应用框架:Electron
+- UI 库:Vuetify
+- 状态管理:Pinia
+- 国际化:vue-i18n
+- 自动更新:electron-updater
+
+## 项目结构
+
+```
+src/
+├── main/ # Electron 主进程代码
+│ ├── AutoUpdater.ts # 自动更新功能
+│ ├── IPCs.ts # IPC 通信处理
+│ ├── MainRunner.ts # 主窗口和错误窗口创建
+│ ├── index.dev.ts # 开发环境入口
+│ ├── index.ts # 生产环境入口
+│ ├── tray.ts # 系统托盘功能
+│ └── utils/
+│ └── Constants.ts # 常量定义
+├── preload/ # Electron 预加载脚本
+├── public/ # 静态资源
+└── renderer/ # 渲染进程(Vue 应用)
+ ├── App.vue # 根组件
+ ├── main.ts # Vue 应用入口
+ ├── components/ # 公共组件
+ ├── screens/ # 页面组件
+ ├── plugins/ # 插件配置(vuetify, i18n, pinia)
+ ├── router/ # 路由配置
+ ├── store/ # Pinia 状态管理
+ ├── locales/ # 语言包
+ └── utils/ # 工具函数
+
+buildAssets/ # 构建相关资源
+docs/ # 项目文档
+tests/ # 测试文件
+```
+
+## 构建和运行
+
+### 开发环境
+
+1. 安装依赖:
+
+ ```bash
+ pnpm install
+ ```
+
+2. 启动开发服务器:
+
+ ```bash
+ pnpm dev
+ ```
+
+ 这将启动 Vite 开发服务器,并在 Electron 中打开应用。
+
+3. 构建项目:
+
+ ```bash
+ pnpm build
+ ```
+
+ 构建应用到 `dist/` 目录,并使用 `electron-builder` 打包成可执行文件。
+
+4. 运行测试:
+ ```bash
+ pnpm test
+ ```
+ 运行 Playwright 自动化测试。
+
+### 生产环境
+
+构建后的应用位于 `release/` 目录下,根据不同平台生成对应的安装包。
+
+## 开发约定
+
+- 使用 TypeScript 进行开发,类型检查通过 `vue-tsc` 完成。
+- 代码风格遵循 ESLint 和 Prettier 规范。
+- 使用 Pinia 进行全局状态管理。
+- 国际化支持通过 vue-i18n 实现。
+- 主进程与渲染进程通过 IPC 进行通信。
+- 日志记录使用 `electron-log` 模块。
+- 自动更新功能通过 `electron-updater` 实现。
+
+如果有修改代码,任务结束前需要先运行 `pnpm typecheck` 检查类型错误。不要直接运行 `pnpm dev` 或 `pnpm build`。
diff --git a/QWEN.md b/QWEN.md
index 37555d8..ca54668 100644
--- a/QWEN.md
+++ b/QWEN.md
@@ -229,6 +229,6 @@ Building creates different distribution formats based on the platform:
Artifacts are named with the format `${productName} ${version}_${arch}.${ext}` and stored in the `release/${version}` directory.
-run `pnpm typecheck` before finish the task if need
+run `pnpm typecheck` before finish the task if need,don't run `pnpm dev` or `pnpm build`.
Always respond in 中文
diff --git a/package.json b/package.json
index 2417561..9b9af49 100644
--- a/package.json
+++ b/package.json
@@ -112,6 +112,7 @@
"standard-version": "^9.5.0",
"typescript": "^5.9.3",
"typescript-eslint": "^8.46.1",
+ "unplugin-auto-import": "^20.2.0",
"vite": "^7.1.10",
"vite-plugin-electron": "^0.29.0",
"vite-plugin-electron-renderer": "^0.14.6",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 394e0bc..d11cd02 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -117,6 +117,9 @@ importers:
typescript-eslint:
specifier: ^8.46.1
version: 8.46.1(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3)
+ unplugin-auto-import:
+ specifier: ^20.2.0
+ version: 20.2.0(@vueuse/core@14.0.0(vue@3.5.22(typescript@5.9.3)))
vite:
specifier: ^7.1.10
version: 7.1.10(@types/node@22.15.15)(jiti@2.6.1)
@@ -1340,6 +1343,12 @@ packages:
resolution: {integrity: sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==}
engines: {'0': node >= 6.0}
+ confbox@0.1.8:
+ resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==}
+
+ confbox@0.2.2:
+ resolution: {integrity: sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==}
+
config-file-ts@0.2.8-rc1:
resolution: {integrity: sha512-GtNECbVI82bT4RiDIzBSVuTKoSHufnU7Ce7/42bkWZJZFLjmDF2WBpVsvRkhKCfKBnTBb3qZrBwPpFBU/Myvhg==}
@@ -1697,6 +1706,10 @@ packages:
resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
engines: {node: '>=10'}
+ escape-string-regexp@5.0.0:
+ resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==}
+ engines: {node: '>=12'}
+
eslint-compat-utils@0.5.1:
resolution: {integrity: sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==}
engines: {node: '>=12'}
@@ -1824,6 +1837,9 @@ packages:
estree-walker@2.0.2:
resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
+ estree-walker@3.0.3:
+ resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==}
+
esutils@2.0.3:
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
engines: {node: '>=0.10.0'}
@@ -1831,6 +1847,9 @@ packages:
exponential-backoff@3.1.2:
resolution: {integrity: sha512-8QxYTVXUkuy7fIIoitQkPwGonB8F3Zj8eEO8Sqg9Zv/bkI7RJAzowee4gr81Hak/dUTpA2Z7VfQgoijjPNlUZA==}
+ exsolve@1.0.7:
+ resolution: {integrity: sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==}
+
extract-zip@2.0.1:
resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==}
engines: {node: '>= 10.17.0'}
@@ -2377,6 +2396,9 @@ packages:
js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
+ js-tokens@9.0.1:
+ resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==}
+
js-yaml@4.1.0:
resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
hasBin: true
@@ -2453,6 +2475,10 @@ packages:
resolution: {integrity: sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==}
engines: {node: '>=4'}
+ local-pkg@1.1.2:
+ resolution: {integrity: sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==}
+ engines: {node: '>=14'}
+
locate-path@2.0.0:
resolution: {integrity: sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==}
engines: {node: '>=4'}
@@ -2641,6 +2667,9 @@ packages:
engines: {node: '>=10'}
hasBin: true
+ mlly@1.8.0:
+ resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==}
+
modify-values@1.0.1:
resolution: {integrity: sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==}
engines: {node: '>=0.10.0'}
@@ -2833,6 +2862,9 @@ packages:
resolution: {integrity: sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==}
engines: {node: '>=4'}
+ pathe@2.0.3:
+ resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
+
pe-library@0.4.1:
resolution: {integrity: sha512-eRWB5LBz7PpDu4PUlwT0PhnQfTQJlDDdPa35urV4Osrm0t0AqQFGn+UIkU3klZvwJ8KPO3VbBFsXquA6p6kqZw==}
engines: {node: '>=12', npm: '>=6'}
@@ -2871,6 +2903,12 @@ packages:
typescript:
optional: true
+ pkg-types@1.3.1:
+ resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==}
+
+ pkg-types@2.3.0:
+ resolution: {integrity: sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==}
+
playwright-core@1.56.1:
resolution: {integrity: sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ==}
engines: {node: '>=18'}
@@ -2957,6 +2995,9 @@ packages:
resolution: {integrity: sha512-+37VW4m47xbKfh65Wn6Xr9fnYF3QvtRSgRCSh2gtEyXlUI1SzFZtUFdRKA5+7sJkZbMEVVwhy5SOYkWA3N7gLw==}
engines: {node: '>=18.0.0'}
+ quansync@0.2.11:
+ resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==}
+
queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
@@ -3102,6 +3143,9 @@ packages:
sax@1.4.1:
resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==}
+ scule@1.3.0:
+ resolution: {integrity: sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==}
+
semver-compare@1.0.0:
resolution: {integrity: sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==}
@@ -3291,6 +3335,9 @@ packages:
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
engines: {node: '>=8'}
+ strip-literal@3.1.0:
+ resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==}
+
sumchecker@3.0.1:
resolution: {integrity: sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==}
engines: {node: '>= 8.0'}
@@ -3436,6 +3483,9 @@ packages:
engines: {node: '>=14.17'}
hasBin: true
+ ufo@1.6.1:
+ resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==}
+
uglify-js@3.19.3:
resolution: {integrity: sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==}
engines: {node: '>=0.8.0'}
@@ -3448,6 +3498,10 @@ packages:
undici-types@6.21.0:
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
+ unimport@5.5.0:
+ resolution: {integrity: sha512-/JpWMG9s1nBSlXJAQ8EREFTFy3oy6USFd8T6AoBaw1q2GGcF4R9yp3ofg32UODZlYEO5VD0EWE1RpI9XDWyPYg==}
+ engines: {node: '>=18.12.0'}
+
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}
@@ -3464,6 +3518,26 @@ packages:
resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==}
engines: {node: '>= 10.0.0'}
+ unplugin-auto-import@20.2.0:
+ resolution: {integrity: sha512-vfBI/SvD9hJqYNinipVOAj5n8dS8DJXFlCKFR5iLDp2SaQwsfdnfLXgZ+34Kd3YY3YEY9omk8XQg0bwos3Q8ug==}
+ engines: {node: '>=14'}
+ peerDependencies:
+ '@nuxt/kit': ^4.0.0
+ '@vueuse/core': '*'
+ peerDependenciesMeta:
+ '@nuxt/kit':
+ optional: true
+ '@vueuse/core':
+ optional: true
+
+ unplugin-utils@0.3.1:
+ resolution: {integrity: sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog==}
+ engines: {node: '>=20.19.0'}
+
+ unplugin@2.3.10:
+ resolution: {integrity: sha512-6NCPkv1ClwH+/BGE9QeoTIl09nuiAt0gS28nn1PvYXsGKRwM2TCbFA2QiilmehPDTXIe684k4rZI1yl3A1PCUw==}
+ engines: {node: '>=18.12.0'}
+
unzip-crx-3@0.2.0:
resolution: {integrity: sha512-0+JiUq/z7faJ6oifVB5nSwt589v1KCduqIJupNVDoWSXZtWDmjDGO3RAEOvwJ07w90aoXoP4enKsR7ecMrJtWQ==}
@@ -3610,6 +3684,9 @@ packages:
wcwidth@1.0.1:
resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==}
+ webpack-virtual-modules@0.6.2:
+ resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==}
+
which-boxed-primitive@1.1.1:
resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==}
engines: {node: '>= 0.4'}
@@ -5094,6 +5171,10 @@ snapshots:
readable-stream: 3.6.2
typedarray: 0.0.6
+ confbox@0.1.8: {}
+
+ confbox@0.2.2: {}
+
config-file-ts@0.2.8-rc1:
dependencies:
glob: 10.4.5
@@ -5664,6 +5745,8 @@ snapshots:
escape-string-regexp@4.0.0: {}
+ escape-string-regexp@5.0.0: {}
+
eslint-compat-utils@0.5.1(eslint@9.37.0(jiti@2.6.1)):
dependencies:
eslint: 9.37.0(jiti@2.6.1)
@@ -5834,10 +5917,16 @@ snapshots:
estree-walker@2.0.2: {}
+ estree-walker@3.0.3:
+ dependencies:
+ '@types/estree': 1.0.8
+
esutils@2.0.3: {}
exponential-backoff@3.1.2: {}
+ exsolve@1.0.7: {}
+
extract-zip@2.0.1:
dependencies:
debug: 4.4.0
@@ -6424,6 +6513,8 @@ snapshots:
js-tokens@4.0.0: {}
+ js-tokens@9.0.1: {}
+
js-yaml@4.1.0:
dependencies:
argparse: 2.0.1
@@ -6495,6 +6586,12 @@ snapshots:
pify: 3.0.0
strip-bom: 3.0.0
+ local-pkg@1.1.2:
+ dependencies:
+ mlly: 1.8.0
+ pkg-types: 2.3.0
+ quansync: 0.2.11
+
locate-path@2.0.0:
dependencies:
p-locate: 2.0.0
@@ -6685,6 +6782,13 @@ snapshots:
mkdirp@1.0.4: {}
+ mlly@1.8.0:
+ dependencies:
+ acorn: 8.15.0
+ pathe: 2.0.3
+ pkg-types: 1.3.1
+ ufo: 1.6.1
+
modify-values@1.0.1: {}
ms@2.1.3: {}
@@ -6883,6 +6987,8 @@ snapshots:
dependencies:
pify: 3.0.0
+ pathe@2.0.3: {}
+
pe-library@0.4.1: {}
pend@1.2.0: {}
@@ -6906,6 +7012,18 @@ snapshots:
optionalDependencies:
typescript: 5.9.3
+ pkg-types@1.3.1:
+ dependencies:
+ confbox: 0.1.8
+ mlly: 1.8.0
+ pathe: 2.0.3
+
+ pkg-types@2.3.0:
+ dependencies:
+ confbox: 0.2.2
+ exsolve: 1.0.7
+ pathe: 2.0.3
+
playwright-core@1.56.1: {}
playwright@1.56.1:
@@ -6970,6 +7088,8 @@ snapshots:
qsu@1.10.2: {}
+ quansync@0.2.11: {}
+
queue-microtask@1.2.3: {}
quick-lru@4.0.1: {}
@@ -7163,6 +7283,8 @@ snapshots:
sax@1.4.1: {}
+ scule@1.3.0: {}
+
semver-compare@1.0.0:
optional: true
@@ -7389,6 +7511,10 @@ snapshots:
strip-json-comments@3.1.1: {}
+ strip-literal@3.1.0:
+ dependencies:
+ js-tokens: 9.0.1
+
sumchecker@3.0.1:
dependencies:
debug: 4.4.0
@@ -7551,6 +7677,8 @@ snapshots:
typescript@5.9.3: {}
+ ufo@1.6.1: {}
+
uglify-js@3.19.3:
optional: true
@@ -7563,6 +7691,23 @@ snapshots:
undici-types@6.21.0: {}
+ unimport@5.5.0:
+ dependencies:
+ acorn: 8.15.0
+ escape-string-regexp: 5.0.0
+ estree-walker: 3.0.3
+ local-pkg: 1.1.2
+ magic-string: 0.30.19
+ mlly: 1.8.0
+ pathe: 2.0.3
+ picomatch: 4.0.3
+ pkg-types: 2.3.0
+ scule: 1.3.0
+ strip-literal: 3.1.0
+ tinyglobby: 0.2.15
+ unplugin: 2.3.10
+ unplugin-utils: 0.3.1
+
unique-filename@2.0.1:
dependencies:
unique-slug: 3.0.0
@@ -7575,6 +7720,29 @@ snapshots:
universalify@2.0.1: {}
+ unplugin-auto-import@20.2.0(@vueuse/core@14.0.0(vue@3.5.22(typescript@5.9.3))):
+ dependencies:
+ local-pkg: 1.1.2
+ magic-string: 0.30.19
+ picomatch: 4.0.3
+ unimport: 5.5.0
+ unplugin: 2.3.10
+ unplugin-utils: 0.3.1
+ optionalDependencies:
+ '@vueuse/core': 14.0.0(vue@3.5.22(typescript@5.9.3))
+
+ unplugin-utils@0.3.1:
+ dependencies:
+ pathe: 2.0.3
+ picomatch: 4.0.3
+
+ unplugin@2.3.10:
+ dependencies:
+ '@jridgewell/remapping': 2.3.5
+ acorn: 8.15.0
+ picomatch: 4.0.3
+ webpack-virtual-modules: 0.6.2
+
unzip-crx-3@0.2.0:
dependencies:
jszip: 3.10.1
@@ -7700,6 +7868,8 @@ snapshots:
dependencies:
defaults: 1.0.4
+ webpack-virtual-modules@0.6.2: {}
+
which-boxed-primitive@1.1.1:
dependencies:
is-bigint: 1.1.0
diff --git a/src/main/IPCs.ts b/src/main/IPCs.ts
index 7cc84c3..6ae2406 100644
--- a/src/main/IPCs.ts
+++ b/src/main/IPCs.ts
@@ -2,13 +2,16 @@ import { ipcMain, shell, IpcMainEvent, dialog } from 'electron'
import Constants from './utils/Constants'
import { join, dirname } from 'path'
import {
- writeFileSync,
- readFileSync,
- existsSync,
- ensureDirSync,
- copyFileSync
+ writeFile,
+ readFile,
+ pathExists,
+ ensureDir,
+ copy,
+ readdir,
+ stat,
} from 'fs-extra'
import { autoUpdater } from 'electron-updater'
+import { Template, TreeNode } from '../types'
/*
* IPC Communications
@@ -75,7 +78,7 @@ export default class IPCs {
const filePath = dialogResult.filePaths[0];
const fs = require('fs');
const isDirectory = fs.statSync(filePath).isDirectory();
-
+
return {
canceled: false,
filePath: filePath,
@@ -86,28 +89,26 @@ export default class IPCs {
return { canceled: true }
})
-
+
// Find all files in a folder recursively
ipcMain.handle(
'msgFindFilesInFolder',
async (event: IpcMainEvent, folderPath: string) => {
try {
- const { readdirSync, statSync } = require('fs')
- const { join } = require('path')
const foundFiles: string[] = []
- const searchFiles = (dir: string) => {
- const items = readdirSync(dir)
+ const searchFiles = async (dir: string) => {
+ const items = await readdir(dir)
for (const item of items) {
const fullPath = join(dir, item)
- const stats = statSync(fullPath)
+ const stats = await stat(fullPath)
if (stats.isDirectory()) {
// Recursively search in subdirectories
- searchFiles(fullPath)
+ await searchFiles(fullPath)
} else if (stats.isFile()) {
// Add file to the list
foundFiles.push(fullPath)
@@ -115,7 +116,7 @@ export default class IPCs {
}
}
- searchFiles(folderPath)
+ await searchFiles(folderPath)
return foundFiles
} catch (error) {
@@ -134,10 +135,10 @@ export default class IPCs {
const filePath = join(userDataPath, fileName)
// Ensure directory exists
- ensureDirSync(userDataPath)
+ await ensureDir(userDataPath)
- if (existsSync(filePath)) {
- const data = readFileSync(filePath, 'utf-8')
+ if (await pathExists(filePath)) {
+ const data = await readFile(filePath, 'utf-8')
return data
}
return null
@@ -157,9 +158,9 @@ export default class IPCs {
const filePath = join(userDataPath, fileName)
// Ensure directory exists
- ensureDirSync(userDataPath)
+ await ensureDir(userDataPath)
- writeFileSync(filePath, data, 'utf-8')
+ await writeFile(filePath, data, 'utf-8')
return true
} catch (error) {
console.error('Error saving data:', error)
@@ -182,9 +183,9 @@ export default class IPCs {
const userDataPath = join(Constants.APP_DATA_PATH, 'data')
const filePath = join(userDataPath, 'templates.json')
- let templates = []
- if (existsSync(filePath)) {
- const templatesData = readFileSync(filePath, 'utf-8')
+ let templates: Template[] = []
+ if (await pathExists(filePath)) {
+ const templatesData = await readFile(filePath, 'utf-8')
templates = JSON.parse(templatesData)
}
@@ -200,14 +201,17 @@ export default class IPCs {
// Create base directory
const baseDirPath = join(targetPath, baseDirName)
- ensureDirSync(baseDirPath)
+ await ensureDir(baseDirPath)
// Helper function to traverse the tree and collect all nodes
- const collectAllNodes = (nodes, allNodes = []) => {
+ const collectAllNodes = (nodes: TreeNode[], allNodes: TreeNode[] = [], parent?: TreeNode) => {
for (const node of nodes) {
- allNodes.push(node);
+ allNodes.push({
+ ...node,
+ path: join(parent?.path || '', node.path)
+ });
if (node.children) {
- collectAllNodes(node.children, allNodes);
+ collectAllNodes(node.children, allNodes, node);
}
}
return allNodes;
@@ -222,18 +226,22 @@ export default class IPCs {
const nodePath = join(baseDirPath, node.path);
if (node.type === 'directory') {
- ensureDirSync(nodePath);
+ await ensureDir(nodePath);
} else if (node.type === 'file') {
const fileDir = dirname(nodePath);
- ensureDirSync(fileDir);
+ await ensureDir(fileDir);
- if (node.sourceFilePath) {
- // Copy from source file
- const sourceContent = readFileSync(node.sourceFilePath);
- writeFileSync(nodePath, sourceContent);
- } else if (node.content) {
+ if (node.sourceType === 'file') {
+ await copy(node.sourcePath, nodePath);
+ } else {
// Write content directly
- writeFileSync(nodePath, node.content, 'utf-8');
+ const files = await readdir(node.sourcePath, { withFileTypes: true })
+ for (const file of files) {
+ if (file.isFile() && file.name.startsWith(baseDirName)) {
+ const filePath = join(node.sourcePath, file.name);
+ await copy(filePath, nodePath);
+ }
+ }
}
}
}
diff --git a/src/renderer/App.vue b/src/renderer/App.vue
index cd1d162..75ab147 100644
--- a/src/renderer/App.vue
+++ b/src/renderer/App.vue
@@ -2,6 +2,7 @@
import { DefaultLayout } from '@/renderer/components/layout'
import GlobalDialog from '@/renderer/components/GlobalDialog.vue'
import UpdateDialog from '@/renderer/components/UpdateDialog.vue'
+import GlobalSnackbar from '@/renderer/components/GlobalSnackbar.vue'
import { onMounted } from 'vue'
import { useAppStore } from '@/renderer/store/app'
@@ -75,6 +76,7 @@ const checkForUpdates = async () => {
+