22 files changed
+1695
-867
No files matched your search
@@ -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`。
|
||||
@@ -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 中文
|
||||
@@ -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",
|
||||
|
||||
Generated
+170
@@ -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
|
||||
|
||||
+40
-32
@@ -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
|
||||
@@ -93,21 +96,19 @@ export default class IPCs {
|
||||
'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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 () => {
|
||||
</DefaultLayout>
|
||||
<GlobalDialog />
|
||||
<UpdateDialog />
|
||||
<GlobalSnackbar />
|
||||
</template>
|
||||
|
||||
<style>
|
||||
|
||||
Vendored
+631
@@ -0,0 +1,631 @@
|
||||
/* eslint-disable */
|
||||
/* prettier-ignore */
|
||||
// @ts-nocheck
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
// Generated by unplugin-auto-import
|
||||
// biome-ignore lint: disable
|
||||
export {}
|
||||
declare global {
|
||||
const EffectScope: typeof import('vue').EffectScope
|
||||
const acceptHMRUpdate: typeof import('pinia').acceptHMRUpdate
|
||||
const asyncComputed: typeof import('@vueuse/core').asyncComputed
|
||||
const autoResetRef: typeof import('@vueuse/core').autoResetRef
|
||||
const computed: typeof import('vue').computed
|
||||
const computedAsync: typeof import('@vueuse/core').computedAsync
|
||||
const computedEager: typeof import('@vueuse/core').computedEager
|
||||
const computedInject: typeof import('@vueuse/core').computedInject
|
||||
const computedWithControl: typeof import('@vueuse/core').computedWithControl
|
||||
const controlledComputed: typeof import('@vueuse/core').controlledComputed
|
||||
const controlledRef: typeof import('@vueuse/core').controlledRef
|
||||
const createApp: typeof import('vue').createApp
|
||||
const createEventHook: typeof import('@vueuse/core').createEventHook
|
||||
const createGlobalState: typeof import('@vueuse/core').createGlobalState
|
||||
const createInjectionState: typeof import('@vueuse/core').createInjectionState
|
||||
const createPinia: typeof import('pinia').createPinia
|
||||
const createReactiveFn: typeof import('@vueuse/core').createReactiveFn
|
||||
const createRef: typeof import('@vueuse/core').createRef
|
||||
const createReusableTemplate: typeof import('@vueuse/core').createReusableTemplate
|
||||
const createSharedComposable: typeof import('@vueuse/core').createSharedComposable
|
||||
const createTemplatePromise: typeof import('@vueuse/core').createTemplatePromise
|
||||
const createUnrefFn: typeof import('@vueuse/core').createUnrefFn
|
||||
const customRef: typeof import('vue').customRef
|
||||
const debouncedRef: typeof import('@vueuse/core').debouncedRef
|
||||
const debouncedWatch: typeof import('@vueuse/core').debouncedWatch
|
||||
const defineAsyncComponent: typeof import('vue').defineAsyncComponent
|
||||
const defineComponent: typeof import('vue').defineComponent
|
||||
const defineStore: typeof import('pinia').defineStore
|
||||
const eagerComputed: typeof import('@vueuse/core').eagerComputed
|
||||
const effectScope: typeof import('vue').effectScope
|
||||
const extendRef: typeof import('@vueuse/core').extendRef
|
||||
const getActivePinia: typeof import('pinia').getActivePinia
|
||||
const getCurrentInstance: typeof import('vue').getCurrentInstance
|
||||
const getCurrentScope: typeof import('vue').getCurrentScope
|
||||
const getCurrentWatcher: typeof import('vue').getCurrentWatcher
|
||||
const h: typeof import('vue').h
|
||||
const ignorableWatch: typeof import('@vueuse/core').ignorableWatch
|
||||
const inject: typeof import('vue').inject
|
||||
const injectLocal: typeof import('@vueuse/core').injectLocal
|
||||
const isDefined: typeof import('@vueuse/core').isDefined
|
||||
const isProxy: typeof import('vue').isProxy
|
||||
const isReactive: typeof import('vue').isReactive
|
||||
const isReadonly: typeof import('vue').isReadonly
|
||||
const isRef: typeof import('vue').isRef
|
||||
const isShallow: typeof import('vue').isShallow
|
||||
const makeDestructurable: typeof import('@vueuse/core').makeDestructurable
|
||||
const manualResetRef: typeof import('@vueuse/core').manualResetRef
|
||||
const mapActions: typeof import('pinia').mapActions
|
||||
const mapGetters: typeof import('pinia').mapGetters
|
||||
const mapState: typeof import('pinia').mapState
|
||||
const mapStores: typeof import('pinia').mapStores
|
||||
const mapWritableState: typeof import('pinia').mapWritableState
|
||||
const markRaw: typeof import('vue').markRaw
|
||||
const nextTick: typeof import('vue').nextTick
|
||||
const onActivated: typeof import('vue').onActivated
|
||||
const onBeforeMount: typeof import('vue').onBeforeMount
|
||||
const onBeforeRouteLeave: typeof import('vue-router').onBeforeRouteLeave
|
||||
const onBeforeRouteUpdate: typeof import('vue-router').onBeforeRouteUpdate
|
||||
const onBeforeUnmount: typeof import('vue').onBeforeUnmount
|
||||
const onBeforeUpdate: typeof import('vue').onBeforeUpdate
|
||||
const onClickOutside: typeof import('@vueuse/core').onClickOutside
|
||||
const onDeactivated: typeof import('vue').onDeactivated
|
||||
const onElementRemoval: typeof import('@vueuse/core').onElementRemoval
|
||||
const onErrorCaptured: typeof import('vue').onErrorCaptured
|
||||
const onKeyStroke: typeof import('@vueuse/core').onKeyStroke
|
||||
const onLongPress: typeof import('@vueuse/core').onLongPress
|
||||
const onMounted: typeof import('vue').onMounted
|
||||
const onRenderTracked: typeof import('vue').onRenderTracked
|
||||
const onRenderTriggered: typeof import('vue').onRenderTriggered
|
||||
const onScopeDispose: typeof import('vue').onScopeDispose
|
||||
const onServerPrefetch: typeof import('vue').onServerPrefetch
|
||||
const onStartTyping: typeof import('@vueuse/core').onStartTyping
|
||||
const onUnmounted: typeof import('vue').onUnmounted
|
||||
const onUpdated: typeof import('vue').onUpdated
|
||||
const onWatcherCleanup: typeof import('vue').onWatcherCleanup
|
||||
const pausableWatch: typeof import('@vueuse/core').pausableWatch
|
||||
const provide: typeof import('vue').provide
|
||||
const provideLocal: typeof import('@vueuse/core').provideLocal
|
||||
const reactify: typeof import('@vueuse/core').reactify
|
||||
const reactifyObject: typeof import('@vueuse/core').reactifyObject
|
||||
const reactive: typeof import('vue').reactive
|
||||
const reactiveComputed: typeof import('@vueuse/core').reactiveComputed
|
||||
const reactiveOmit: typeof import('@vueuse/core').reactiveOmit
|
||||
const reactivePick: typeof import('@vueuse/core').reactivePick
|
||||
const readonly: typeof import('vue').readonly
|
||||
const ref: typeof import('vue').ref
|
||||
const refAutoReset: typeof import('@vueuse/core').refAutoReset
|
||||
const refDebounced: typeof import('@vueuse/core').refDebounced
|
||||
const refDefault: typeof import('@vueuse/core').refDefault
|
||||
const refManualReset: typeof import('@vueuse/core').refManualReset
|
||||
const refThrottled: typeof import('@vueuse/core').refThrottled
|
||||
const refWithControl: typeof import('@vueuse/core').refWithControl
|
||||
const resolveComponent: typeof import('vue').resolveComponent
|
||||
const resolveRef: typeof import('@vueuse/core').resolveRef
|
||||
const setActivePinia: typeof import('pinia').setActivePinia
|
||||
const setMapStoreSuffix: typeof import('pinia').setMapStoreSuffix
|
||||
const shallowReactive: typeof import('vue').shallowReactive
|
||||
const shallowReadonly: typeof import('vue').shallowReadonly
|
||||
const shallowRef: typeof import('vue').shallowRef
|
||||
const storeToRefs: typeof import('pinia').storeToRefs
|
||||
const syncRef: typeof import('@vueuse/core').syncRef
|
||||
const syncRefs: typeof import('@vueuse/core').syncRefs
|
||||
const templateRef: typeof import('@vueuse/core').templateRef
|
||||
const throttledRef: typeof import('@vueuse/core').throttledRef
|
||||
const throttledWatch: typeof import('@vueuse/core').throttledWatch
|
||||
const toRaw: typeof import('vue').toRaw
|
||||
const toReactive: typeof import('@vueuse/core').toReactive
|
||||
const toRef: typeof import('vue').toRef
|
||||
const toRefs: typeof import('vue').toRefs
|
||||
const toValue: typeof import('vue').toValue
|
||||
const triggerRef: typeof import('vue').triggerRef
|
||||
const tryOnBeforeMount: typeof import('@vueuse/core').tryOnBeforeMount
|
||||
const tryOnBeforeUnmount: typeof import('@vueuse/core').tryOnBeforeUnmount
|
||||
const tryOnMounted: typeof import('@vueuse/core').tryOnMounted
|
||||
const tryOnScopeDispose: typeof import('@vueuse/core').tryOnScopeDispose
|
||||
const tryOnUnmounted: typeof import('@vueuse/core').tryOnUnmounted
|
||||
const unref: typeof import('vue').unref
|
||||
const unrefElement: typeof import('@vueuse/core').unrefElement
|
||||
const until: typeof import('@vueuse/core').until
|
||||
const useActiveElement: typeof import('@vueuse/core').useActiveElement
|
||||
const useAnimate: typeof import('@vueuse/core').useAnimate
|
||||
const useArrayDifference: typeof import('@vueuse/core').useArrayDifference
|
||||
const useArrayEvery: typeof import('@vueuse/core').useArrayEvery
|
||||
const useArrayFilter: typeof import('@vueuse/core').useArrayFilter
|
||||
const useArrayFind: typeof import('@vueuse/core').useArrayFind
|
||||
const useArrayFindIndex: typeof import('@vueuse/core').useArrayFindIndex
|
||||
const useArrayFindLast: typeof import('@vueuse/core').useArrayFindLast
|
||||
const useArrayIncludes: typeof import('@vueuse/core').useArrayIncludes
|
||||
const useArrayJoin: typeof import('@vueuse/core').useArrayJoin
|
||||
const useArrayMap: typeof import('@vueuse/core').useArrayMap
|
||||
const useArrayReduce: typeof import('@vueuse/core').useArrayReduce
|
||||
const useArraySome: typeof import('@vueuse/core').useArraySome
|
||||
const useArrayUnique: typeof import('@vueuse/core').useArrayUnique
|
||||
const useAsyncQueue: typeof import('@vueuse/core').useAsyncQueue
|
||||
const useAsyncState: typeof import('@vueuse/core').useAsyncState
|
||||
const useAttrs: typeof import('vue').useAttrs
|
||||
const useBase64: typeof import('@vueuse/core').useBase64
|
||||
const useBattery: typeof import('@vueuse/core').useBattery
|
||||
const useBluetooth: typeof import('@vueuse/core').useBluetooth
|
||||
const useBreakpoints: typeof import('@vueuse/core').useBreakpoints
|
||||
const useBroadcastChannel: typeof import('@vueuse/core').useBroadcastChannel
|
||||
const useBrowserLocation: typeof import('@vueuse/core').useBrowserLocation
|
||||
const useCached: typeof import('@vueuse/core').useCached
|
||||
const useClipboard: typeof import('@vueuse/core').useClipboard
|
||||
const useClipboardItems: typeof import('@vueuse/core').useClipboardItems
|
||||
const useCloned: typeof import('@vueuse/core').useCloned
|
||||
const useColorMode: typeof import('@vueuse/core').useColorMode
|
||||
const useConfirmDialog: typeof import('@vueuse/core').useConfirmDialog
|
||||
const useCountdown: typeof import('@vueuse/core').useCountdown
|
||||
const useCounter: typeof import('@vueuse/core').useCounter
|
||||
const useCssModule: typeof import('vue').useCssModule
|
||||
const useCssVar: typeof import('@vueuse/core').useCssVar
|
||||
const useCssVars: typeof import('vue').useCssVars
|
||||
const useCurrentElement: typeof import('@vueuse/core').useCurrentElement
|
||||
const useCycleList: typeof import('@vueuse/core').useCycleList
|
||||
const useDark: typeof import('@vueuse/core').useDark
|
||||
const useDateFormat: typeof import('@vueuse/core').useDateFormat
|
||||
const useDebounce: typeof import('@vueuse/core').useDebounce
|
||||
const useDebounceFn: typeof import('@vueuse/core').useDebounceFn
|
||||
const useDebouncedRefHistory: typeof import('@vueuse/core').useDebouncedRefHistory
|
||||
const useDeviceMotion: typeof import('@vueuse/core').useDeviceMotion
|
||||
const useDeviceOrientation: typeof import('@vueuse/core').useDeviceOrientation
|
||||
const useDevicePixelRatio: typeof import('@vueuse/core').useDevicePixelRatio
|
||||
const useDevicesList: typeof import('@vueuse/core').useDevicesList
|
||||
const useDisplayMedia: typeof import('@vueuse/core').useDisplayMedia
|
||||
const useDocumentVisibility: typeof import('@vueuse/core').useDocumentVisibility
|
||||
const useDraggable: typeof import('@vueuse/core').useDraggable
|
||||
const useDropZone: typeof import('@vueuse/core').useDropZone
|
||||
const useElementBounding: typeof import('@vueuse/core').useElementBounding
|
||||
const useElementByPoint: typeof import('@vueuse/core').useElementByPoint
|
||||
const useElementHover: typeof import('@vueuse/core').useElementHover
|
||||
const useElementSize: typeof import('@vueuse/core').useElementSize
|
||||
const useElementVisibility: typeof import('@vueuse/core').useElementVisibility
|
||||
const useEventBus: typeof import('@vueuse/core').useEventBus
|
||||
const useEventListener: typeof import('@vueuse/core').useEventListener
|
||||
const useEventSource: typeof import('@vueuse/core').useEventSource
|
||||
const useEyeDropper: typeof import('@vueuse/core').useEyeDropper
|
||||
const useFavicon: typeof import('@vueuse/core').useFavicon
|
||||
const useFetch: typeof import('@vueuse/core').useFetch
|
||||
const useFileDialog: typeof import('@vueuse/core').useFileDialog
|
||||
const useFileSystemAccess: typeof import('@vueuse/core').useFileSystemAccess
|
||||
const useFocus: typeof import('@vueuse/core').useFocus
|
||||
const useFocusWithin: typeof import('@vueuse/core').useFocusWithin
|
||||
const useFps: typeof import('@vueuse/core').useFps
|
||||
const useFullscreen: typeof import('@vueuse/core').useFullscreen
|
||||
const useGamepad: typeof import('@vueuse/core').useGamepad
|
||||
const useGeolocation: typeof import('@vueuse/core').useGeolocation
|
||||
const useI18n: typeof import('vue-i18n').useI18n
|
||||
const useId: typeof import('vue').useId
|
||||
const useIdle: typeof import('@vueuse/core').useIdle
|
||||
const useImage: typeof import('@vueuse/core').useImage
|
||||
const useInfiniteScroll: typeof import('@vueuse/core').useInfiniteScroll
|
||||
const useIntersectionObserver: typeof import('@vueuse/core').useIntersectionObserver
|
||||
const useInterval: typeof import('@vueuse/core').useInterval
|
||||
const useIntervalFn: typeof import('@vueuse/core').useIntervalFn
|
||||
const useKeyModifier: typeof import('@vueuse/core').useKeyModifier
|
||||
const useLastChanged: typeof import('@vueuse/core').useLastChanged
|
||||
const useLink: typeof import('vue-router').useLink
|
||||
const useLocalStorage: typeof import('@vueuse/core').useLocalStorage
|
||||
const useMagicKeys: typeof import('@vueuse/core').useMagicKeys
|
||||
const useManualRefHistory: typeof import('@vueuse/core').useManualRefHistory
|
||||
const useMediaControls: typeof import('@vueuse/core').useMediaControls
|
||||
const useMediaQuery: typeof import('@vueuse/core').useMediaQuery
|
||||
const useMemoize: typeof import('@vueuse/core').useMemoize
|
||||
const useMemory: typeof import('@vueuse/core').useMemory
|
||||
const useModel: typeof import('vue').useModel
|
||||
const useMounted: typeof import('@vueuse/core').useMounted
|
||||
const useMouse: typeof import('@vueuse/core').useMouse
|
||||
const useMouseInElement: typeof import('@vueuse/core').useMouseInElement
|
||||
const useMousePressed: typeof import('@vueuse/core').useMousePressed
|
||||
const useMutationObserver: typeof import('@vueuse/core').useMutationObserver
|
||||
const useNavigatorLanguage: typeof import('@vueuse/core').useNavigatorLanguage
|
||||
const useNetwork: typeof import('@vueuse/core').useNetwork
|
||||
const useNow: typeof import('@vueuse/core').useNow
|
||||
const useObjectUrl: typeof import('@vueuse/core').useObjectUrl
|
||||
const useOffsetPagination: typeof import('@vueuse/core').useOffsetPagination
|
||||
const useOnline: typeof import('@vueuse/core').useOnline
|
||||
const usePageLeave: typeof import('@vueuse/core').usePageLeave
|
||||
const useParallax: typeof import('@vueuse/core').useParallax
|
||||
const useParentElement: typeof import('@vueuse/core').useParentElement
|
||||
const usePerformanceObserver: typeof import('@vueuse/core').usePerformanceObserver
|
||||
const usePermission: typeof import('@vueuse/core').usePermission
|
||||
const usePointer: typeof import('@vueuse/core').usePointer
|
||||
const usePointerLock: typeof import('@vueuse/core').usePointerLock
|
||||
const usePointerSwipe: typeof import('@vueuse/core').usePointerSwipe
|
||||
const usePreferredColorScheme: typeof import('@vueuse/core').usePreferredColorScheme
|
||||
const usePreferredContrast: typeof import('@vueuse/core').usePreferredContrast
|
||||
const usePreferredDark: typeof import('@vueuse/core').usePreferredDark
|
||||
const usePreferredLanguages: typeof import('@vueuse/core').usePreferredLanguages
|
||||
const usePreferredReducedMotion: typeof import('@vueuse/core').usePreferredReducedMotion
|
||||
const usePreferredReducedTransparency: typeof import('@vueuse/core').usePreferredReducedTransparency
|
||||
const usePrevious: typeof import('@vueuse/core').usePrevious
|
||||
const useRafFn: typeof import('@vueuse/core').useRafFn
|
||||
const useRefHistory: typeof import('@vueuse/core').useRefHistory
|
||||
const useResizeObserver: typeof import('@vueuse/core').useResizeObserver
|
||||
const useRoute: typeof import('vue-router').useRoute
|
||||
const useRouter: typeof import('vue-router').useRouter
|
||||
const useSSRWidth: typeof import('@vueuse/core').useSSRWidth
|
||||
const useScreenOrientation: typeof import('@vueuse/core').useScreenOrientation
|
||||
const useScreenSafeArea: typeof import('@vueuse/core').useScreenSafeArea
|
||||
const useScriptTag: typeof import('@vueuse/core').useScriptTag
|
||||
const useScroll: typeof import('@vueuse/core').useScroll
|
||||
const useScrollLock: typeof import('@vueuse/core').useScrollLock
|
||||
const useSessionStorage: typeof import('@vueuse/core').useSessionStorage
|
||||
const useShare: typeof import('@vueuse/core').useShare
|
||||
const useSlots: typeof import('vue').useSlots
|
||||
const useSorted: typeof import('@vueuse/core').useSorted
|
||||
const useSpeechRecognition: typeof import('@vueuse/core').useSpeechRecognition
|
||||
const useSpeechSynthesis: typeof import('@vueuse/core').useSpeechSynthesis
|
||||
const useStepper: typeof import('@vueuse/core').useStepper
|
||||
const useStorage: typeof import('@vueuse/core').useStorage
|
||||
const useStorageAsync: typeof import('@vueuse/core').useStorageAsync
|
||||
const useStyleTag: typeof import('@vueuse/core').useStyleTag
|
||||
const useSupported: typeof import('@vueuse/core').useSupported
|
||||
const useSwipe: typeof import('@vueuse/core').useSwipe
|
||||
const useTemplateRef: typeof import('vue').useTemplateRef
|
||||
const useTemplateRefsList: typeof import('@vueuse/core').useTemplateRefsList
|
||||
const useTextDirection: typeof import('@vueuse/core').useTextDirection
|
||||
const useTextSelection: typeof import('@vueuse/core').useTextSelection
|
||||
const useTextareaAutosize: typeof import('@vueuse/core').useTextareaAutosize
|
||||
const useThrottle: typeof import('@vueuse/core').useThrottle
|
||||
const useThrottleFn: typeof import('@vueuse/core').useThrottleFn
|
||||
const useThrottledRefHistory: typeof import('@vueuse/core').useThrottledRefHistory
|
||||
const useTimeAgo: typeof import('@vueuse/core').useTimeAgo
|
||||
const useTimeAgoIntl: typeof import('@vueuse/core').useTimeAgoIntl
|
||||
const useTimeout: typeof import('@vueuse/core').useTimeout
|
||||
const useTimeoutFn: typeof import('@vueuse/core').useTimeoutFn
|
||||
const useTimeoutPoll: typeof import('@vueuse/core').useTimeoutPoll
|
||||
const useTimestamp: typeof import('@vueuse/core').useTimestamp
|
||||
const useTitle: typeof import('@vueuse/core').useTitle
|
||||
const useToNumber: typeof import('@vueuse/core').useToNumber
|
||||
const useToString: typeof import('@vueuse/core').useToString
|
||||
const useToggle: typeof import('@vueuse/core').useToggle
|
||||
const useTransition: typeof import('@vueuse/core').useTransition
|
||||
const useUrlSearchParams: typeof import('@vueuse/core').useUrlSearchParams
|
||||
const useUserMedia: typeof import('@vueuse/core').useUserMedia
|
||||
const useVModel: typeof import('@vueuse/core').useVModel
|
||||
const useVModels: typeof import('@vueuse/core').useVModels
|
||||
const useVibrate: typeof import('@vueuse/core').useVibrate
|
||||
const useVirtualList: typeof import('@vueuse/core').useVirtualList
|
||||
const useWakeLock: typeof import('@vueuse/core').useWakeLock
|
||||
const useWebNotification: typeof import('@vueuse/core').useWebNotification
|
||||
const useWebSocket: typeof import('@vueuse/core').useWebSocket
|
||||
const useWebWorker: typeof import('@vueuse/core').useWebWorker
|
||||
const useWebWorkerFn: typeof import('@vueuse/core').useWebWorkerFn
|
||||
const useWindowFocus: typeof import('@vueuse/core').useWindowFocus
|
||||
const useWindowScroll: typeof import('@vueuse/core').useWindowScroll
|
||||
const useWindowSize: typeof import('@vueuse/core').useWindowSize
|
||||
const watch: typeof import('vue').watch
|
||||
const watchArray: typeof import('@vueuse/core').watchArray
|
||||
const watchAtMost: typeof import('@vueuse/core').watchAtMost
|
||||
const watchDebounced: typeof import('@vueuse/core').watchDebounced
|
||||
const watchDeep: typeof import('@vueuse/core').watchDeep
|
||||
const watchEffect: typeof import('vue').watchEffect
|
||||
const watchIgnorable: typeof import('@vueuse/core').watchIgnorable
|
||||
const watchImmediate: typeof import('@vueuse/core').watchImmediate
|
||||
const watchOnce: typeof import('@vueuse/core').watchOnce
|
||||
const watchPausable: typeof import('@vueuse/core').watchPausable
|
||||
const watchPostEffect: typeof import('vue').watchPostEffect
|
||||
const watchSyncEffect: typeof import('vue').watchSyncEffect
|
||||
const watchThrottled: typeof import('@vueuse/core').watchThrottled
|
||||
const watchTriggerable: typeof import('@vueuse/core').watchTriggerable
|
||||
const watchWithFilter: typeof import('@vueuse/core').watchWithFilter
|
||||
const whenever: typeof import('@vueuse/core').whenever
|
||||
}
|
||||
// for type re-export
|
||||
declare global {
|
||||
// @ts-ignore
|
||||
export type { Component, Slot, Slots, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, ShallowRef, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
|
||||
import('vue')
|
||||
}
|
||||
|
||||
// for vue template auto import
|
||||
import { UnwrapRef } from 'vue'
|
||||
declare module 'vue' {
|
||||
interface GlobalComponents {}
|
||||
interface ComponentCustomProperties {
|
||||
readonly EffectScope: UnwrapRef<typeof import('vue')['EffectScope']>
|
||||
readonly acceptHMRUpdate: UnwrapRef<typeof import('pinia')['acceptHMRUpdate']>
|
||||
readonly asyncComputed: UnwrapRef<typeof import('@vueuse/core')['asyncComputed']>
|
||||
readonly autoResetRef: UnwrapRef<typeof import('@vueuse/core')['autoResetRef']>
|
||||
readonly computed: UnwrapRef<typeof import('vue')['computed']>
|
||||
readonly computedAsync: UnwrapRef<typeof import('@vueuse/core')['computedAsync']>
|
||||
readonly computedEager: UnwrapRef<typeof import('@vueuse/core')['computedEager']>
|
||||
readonly computedInject: UnwrapRef<typeof import('@vueuse/core')['computedInject']>
|
||||
readonly computedWithControl: UnwrapRef<typeof import('@vueuse/core')['computedWithControl']>
|
||||
readonly controlledComputed: UnwrapRef<typeof import('@vueuse/core')['controlledComputed']>
|
||||
readonly controlledRef: UnwrapRef<typeof import('@vueuse/core')['controlledRef']>
|
||||
readonly createApp: UnwrapRef<typeof import('vue')['createApp']>
|
||||
readonly createEventHook: UnwrapRef<typeof import('@vueuse/core')['createEventHook']>
|
||||
readonly createGlobalState: UnwrapRef<typeof import('@vueuse/core')['createGlobalState']>
|
||||
readonly createInjectionState: UnwrapRef<typeof import('@vueuse/core')['createInjectionState']>
|
||||
readonly createPinia: UnwrapRef<typeof import('pinia')['createPinia']>
|
||||
readonly createReactiveFn: UnwrapRef<typeof import('@vueuse/core')['createReactiveFn']>
|
||||
readonly createRef: UnwrapRef<typeof import('@vueuse/core')['createRef']>
|
||||
readonly createReusableTemplate: UnwrapRef<typeof import('@vueuse/core')['createReusableTemplate']>
|
||||
readonly createSharedComposable: UnwrapRef<typeof import('@vueuse/core')['createSharedComposable']>
|
||||
readonly createTemplatePromise: UnwrapRef<typeof import('@vueuse/core')['createTemplatePromise']>
|
||||
readonly createUnrefFn: UnwrapRef<typeof import('@vueuse/core')['createUnrefFn']>
|
||||
readonly customRef: UnwrapRef<typeof import('vue')['customRef']>
|
||||
readonly debouncedRef: UnwrapRef<typeof import('@vueuse/core')['debouncedRef']>
|
||||
readonly debouncedWatch: UnwrapRef<typeof import('@vueuse/core')['debouncedWatch']>
|
||||
readonly defineAsyncComponent: UnwrapRef<typeof import('vue')['defineAsyncComponent']>
|
||||
readonly defineComponent: UnwrapRef<typeof import('vue')['defineComponent']>
|
||||
readonly defineStore: UnwrapRef<typeof import('pinia')['defineStore']>
|
||||
readonly eagerComputed: UnwrapRef<typeof import('@vueuse/core')['eagerComputed']>
|
||||
readonly effectScope: UnwrapRef<typeof import('vue')['effectScope']>
|
||||
readonly extendRef: UnwrapRef<typeof import('@vueuse/core')['extendRef']>
|
||||
readonly getActivePinia: UnwrapRef<typeof import('pinia')['getActivePinia']>
|
||||
readonly getCurrentInstance: UnwrapRef<typeof import('vue')['getCurrentInstance']>
|
||||
readonly getCurrentScope: UnwrapRef<typeof import('vue')['getCurrentScope']>
|
||||
readonly getCurrentWatcher: UnwrapRef<typeof import('vue')['getCurrentWatcher']>
|
||||
readonly h: UnwrapRef<typeof import('vue')['h']>
|
||||
readonly ignorableWatch: UnwrapRef<typeof import('@vueuse/core')['ignorableWatch']>
|
||||
readonly inject: UnwrapRef<typeof import('vue')['inject']>
|
||||
readonly injectLocal: UnwrapRef<typeof import('@vueuse/core')['injectLocal']>
|
||||
readonly isDefined: UnwrapRef<typeof import('@vueuse/core')['isDefined']>
|
||||
readonly isProxy: UnwrapRef<typeof import('vue')['isProxy']>
|
||||
readonly isReactive: UnwrapRef<typeof import('vue')['isReactive']>
|
||||
readonly isReadonly: UnwrapRef<typeof import('vue')['isReadonly']>
|
||||
readonly isRef: UnwrapRef<typeof import('vue')['isRef']>
|
||||
readonly isShallow: UnwrapRef<typeof import('vue')['isShallow']>
|
||||
readonly makeDestructurable: UnwrapRef<typeof import('@vueuse/core')['makeDestructurable']>
|
||||
readonly manualResetRef: UnwrapRef<typeof import('@vueuse/core')['manualResetRef']>
|
||||
readonly mapActions: UnwrapRef<typeof import('pinia')['mapActions']>
|
||||
readonly mapGetters: UnwrapRef<typeof import('pinia')['mapGetters']>
|
||||
readonly mapState: UnwrapRef<typeof import('pinia')['mapState']>
|
||||
readonly mapStores: UnwrapRef<typeof import('pinia')['mapStores']>
|
||||
readonly mapWritableState: UnwrapRef<typeof import('pinia')['mapWritableState']>
|
||||
readonly markRaw: UnwrapRef<typeof import('vue')['markRaw']>
|
||||
readonly nextTick: UnwrapRef<typeof import('vue')['nextTick']>
|
||||
readonly onActivated: UnwrapRef<typeof import('vue')['onActivated']>
|
||||
readonly onBeforeMount: UnwrapRef<typeof import('vue')['onBeforeMount']>
|
||||
readonly onBeforeRouteLeave: UnwrapRef<typeof import('vue-router')['onBeforeRouteLeave']>
|
||||
readonly onBeforeRouteUpdate: UnwrapRef<typeof import('vue-router')['onBeforeRouteUpdate']>
|
||||
readonly onBeforeUnmount: UnwrapRef<typeof import('vue')['onBeforeUnmount']>
|
||||
readonly onBeforeUpdate: UnwrapRef<typeof import('vue')['onBeforeUpdate']>
|
||||
readonly onClickOutside: UnwrapRef<typeof import('@vueuse/core')['onClickOutside']>
|
||||
readonly onDeactivated: UnwrapRef<typeof import('vue')['onDeactivated']>
|
||||
readonly onElementRemoval: UnwrapRef<typeof import('@vueuse/core')['onElementRemoval']>
|
||||
readonly onErrorCaptured: UnwrapRef<typeof import('vue')['onErrorCaptured']>
|
||||
readonly onKeyStroke: UnwrapRef<typeof import('@vueuse/core')['onKeyStroke']>
|
||||
readonly onLongPress: UnwrapRef<typeof import('@vueuse/core')['onLongPress']>
|
||||
readonly onMounted: UnwrapRef<typeof import('vue')['onMounted']>
|
||||
readonly onRenderTracked: UnwrapRef<typeof import('vue')['onRenderTracked']>
|
||||
readonly onRenderTriggered: UnwrapRef<typeof import('vue')['onRenderTriggered']>
|
||||
readonly onScopeDispose: UnwrapRef<typeof import('vue')['onScopeDispose']>
|
||||
readonly onServerPrefetch: UnwrapRef<typeof import('vue')['onServerPrefetch']>
|
||||
readonly onStartTyping: UnwrapRef<typeof import('@vueuse/core')['onStartTyping']>
|
||||
readonly onUnmounted: UnwrapRef<typeof import('vue')['onUnmounted']>
|
||||
readonly onUpdated: UnwrapRef<typeof import('vue')['onUpdated']>
|
||||
readonly onWatcherCleanup: UnwrapRef<typeof import('vue')['onWatcherCleanup']>
|
||||
readonly pausableWatch: UnwrapRef<typeof import('@vueuse/core')['pausableWatch']>
|
||||
readonly provide: UnwrapRef<typeof import('vue')['provide']>
|
||||
readonly provideLocal: UnwrapRef<typeof import('@vueuse/core')['provideLocal']>
|
||||
readonly reactify: UnwrapRef<typeof import('@vueuse/core')['reactify']>
|
||||
readonly reactifyObject: UnwrapRef<typeof import('@vueuse/core')['reactifyObject']>
|
||||
readonly reactive: UnwrapRef<typeof import('vue')['reactive']>
|
||||
readonly reactiveComputed: UnwrapRef<typeof import('@vueuse/core')['reactiveComputed']>
|
||||
readonly reactiveOmit: UnwrapRef<typeof import('@vueuse/core')['reactiveOmit']>
|
||||
readonly reactivePick: UnwrapRef<typeof import('@vueuse/core')['reactivePick']>
|
||||
readonly readonly: UnwrapRef<typeof import('vue')['readonly']>
|
||||
readonly ref: UnwrapRef<typeof import('vue')['ref']>
|
||||
readonly refAutoReset: UnwrapRef<typeof import('@vueuse/core')['refAutoReset']>
|
||||
readonly refDebounced: UnwrapRef<typeof import('@vueuse/core')['refDebounced']>
|
||||
readonly refDefault: UnwrapRef<typeof import('@vueuse/core')['refDefault']>
|
||||
readonly refManualReset: UnwrapRef<typeof import('@vueuse/core')['refManualReset']>
|
||||
readonly refThrottled: UnwrapRef<typeof import('@vueuse/core')['refThrottled']>
|
||||
readonly refWithControl: UnwrapRef<typeof import('@vueuse/core')['refWithControl']>
|
||||
readonly resolveComponent: UnwrapRef<typeof import('vue')['resolveComponent']>
|
||||
readonly resolveRef: UnwrapRef<typeof import('@vueuse/core')['resolveRef']>
|
||||
readonly setActivePinia: UnwrapRef<typeof import('pinia')['setActivePinia']>
|
||||
readonly setMapStoreSuffix: UnwrapRef<typeof import('pinia')['setMapStoreSuffix']>
|
||||
readonly shallowReactive: UnwrapRef<typeof import('vue')['shallowReactive']>
|
||||
readonly shallowReadonly: UnwrapRef<typeof import('vue')['shallowReadonly']>
|
||||
readonly shallowRef: UnwrapRef<typeof import('vue')['shallowRef']>
|
||||
readonly storeToRefs: UnwrapRef<typeof import('pinia')['storeToRefs']>
|
||||
readonly syncRef: UnwrapRef<typeof import('@vueuse/core')['syncRef']>
|
||||
readonly syncRefs: UnwrapRef<typeof import('@vueuse/core')['syncRefs']>
|
||||
readonly templateRef: UnwrapRef<typeof import('@vueuse/core')['templateRef']>
|
||||
readonly throttledRef: UnwrapRef<typeof import('@vueuse/core')['throttledRef']>
|
||||
readonly throttledWatch: UnwrapRef<typeof import('@vueuse/core')['throttledWatch']>
|
||||
readonly toRaw: UnwrapRef<typeof import('vue')['toRaw']>
|
||||
readonly toReactive: UnwrapRef<typeof import('@vueuse/core')['toReactive']>
|
||||
readonly toRef: UnwrapRef<typeof import('vue')['toRef']>
|
||||
readonly toRefs: UnwrapRef<typeof import('vue')['toRefs']>
|
||||
readonly toValue: UnwrapRef<typeof import('vue')['toValue']>
|
||||
readonly triggerRef: UnwrapRef<typeof import('vue')['triggerRef']>
|
||||
readonly tryOnBeforeMount: UnwrapRef<typeof import('@vueuse/core')['tryOnBeforeMount']>
|
||||
readonly tryOnBeforeUnmount: UnwrapRef<typeof import('@vueuse/core')['tryOnBeforeUnmount']>
|
||||
readonly tryOnMounted: UnwrapRef<typeof import('@vueuse/core')['tryOnMounted']>
|
||||
readonly tryOnScopeDispose: UnwrapRef<typeof import('@vueuse/core')['tryOnScopeDispose']>
|
||||
readonly tryOnUnmounted: UnwrapRef<typeof import('@vueuse/core')['tryOnUnmounted']>
|
||||
readonly unref: UnwrapRef<typeof import('vue')['unref']>
|
||||
readonly unrefElement: UnwrapRef<typeof import('@vueuse/core')['unrefElement']>
|
||||
readonly until: UnwrapRef<typeof import('@vueuse/core')['until']>
|
||||
readonly useActiveElement: UnwrapRef<typeof import('@vueuse/core')['useActiveElement']>
|
||||
readonly useAnimate: UnwrapRef<typeof import('@vueuse/core')['useAnimate']>
|
||||
readonly useArrayDifference: UnwrapRef<typeof import('@vueuse/core')['useArrayDifference']>
|
||||
readonly useArrayEvery: UnwrapRef<typeof import('@vueuse/core')['useArrayEvery']>
|
||||
readonly useArrayFilter: UnwrapRef<typeof import('@vueuse/core')['useArrayFilter']>
|
||||
readonly useArrayFind: UnwrapRef<typeof import('@vueuse/core')['useArrayFind']>
|
||||
readonly useArrayFindIndex: UnwrapRef<typeof import('@vueuse/core')['useArrayFindIndex']>
|
||||
readonly useArrayFindLast: UnwrapRef<typeof import('@vueuse/core')['useArrayFindLast']>
|
||||
readonly useArrayIncludes: UnwrapRef<typeof import('@vueuse/core')['useArrayIncludes']>
|
||||
readonly useArrayJoin: UnwrapRef<typeof import('@vueuse/core')['useArrayJoin']>
|
||||
readonly useArrayMap: UnwrapRef<typeof import('@vueuse/core')['useArrayMap']>
|
||||
readonly useArrayReduce: UnwrapRef<typeof import('@vueuse/core')['useArrayReduce']>
|
||||
readonly useArraySome: UnwrapRef<typeof import('@vueuse/core')['useArraySome']>
|
||||
readonly useArrayUnique: UnwrapRef<typeof import('@vueuse/core')['useArrayUnique']>
|
||||
readonly useAsyncQueue: UnwrapRef<typeof import('@vueuse/core')['useAsyncQueue']>
|
||||
readonly useAsyncState: UnwrapRef<typeof import('@vueuse/core')['useAsyncState']>
|
||||
readonly useAttrs: UnwrapRef<typeof import('vue')['useAttrs']>
|
||||
readonly useBase64: UnwrapRef<typeof import('@vueuse/core')['useBase64']>
|
||||
readonly useBattery: UnwrapRef<typeof import('@vueuse/core')['useBattery']>
|
||||
readonly useBluetooth: UnwrapRef<typeof import('@vueuse/core')['useBluetooth']>
|
||||
readonly useBreakpoints: UnwrapRef<typeof import('@vueuse/core')['useBreakpoints']>
|
||||
readonly useBroadcastChannel: UnwrapRef<typeof import('@vueuse/core')['useBroadcastChannel']>
|
||||
readonly useBrowserLocation: UnwrapRef<typeof import('@vueuse/core')['useBrowserLocation']>
|
||||
readonly useCached: UnwrapRef<typeof import('@vueuse/core')['useCached']>
|
||||
readonly useClipboard: UnwrapRef<typeof import('@vueuse/core')['useClipboard']>
|
||||
readonly useClipboardItems: UnwrapRef<typeof import('@vueuse/core')['useClipboardItems']>
|
||||
readonly useCloned: UnwrapRef<typeof import('@vueuse/core')['useCloned']>
|
||||
readonly useColorMode: UnwrapRef<typeof import('@vueuse/core')['useColorMode']>
|
||||
readonly useConfirmDialog: UnwrapRef<typeof import('@vueuse/core')['useConfirmDialog']>
|
||||
readonly useCountdown: UnwrapRef<typeof import('@vueuse/core')['useCountdown']>
|
||||
readonly useCounter: UnwrapRef<typeof import('@vueuse/core')['useCounter']>
|
||||
readonly useCssModule: UnwrapRef<typeof import('vue')['useCssModule']>
|
||||
readonly useCssVar: UnwrapRef<typeof import('@vueuse/core')['useCssVar']>
|
||||
readonly useCssVars: UnwrapRef<typeof import('vue')['useCssVars']>
|
||||
readonly useCurrentElement: UnwrapRef<typeof import('@vueuse/core')['useCurrentElement']>
|
||||
readonly useCycleList: UnwrapRef<typeof import('@vueuse/core')['useCycleList']>
|
||||
readonly useDark: UnwrapRef<typeof import('@vueuse/core')['useDark']>
|
||||
readonly useDateFormat: UnwrapRef<typeof import('@vueuse/core')['useDateFormat']>
|
||||
readonly useDebounce: UnwrapRef<typeof import('@vueuse/core')['useDebounce']>
|
||||
readonly useDebounceFn: UnwrapRef<typeof import('@vueuse/core')['useDebounceFn']>
|
||||
readonly useDebouncedRefHistory: UnwrapRef<typeof import('@vueuse/core')['useDebouncedRefHistory']>
|
||||
readonly useDeviceMotion: UnwrapRef<typeof import('@vueuse/core')['useDeviceMotion']>
|
||||
readonly useDeviceOrientation: UnwrapRef<typeof import('@vueuse/core')['useDeviceOrientation']>
|
||||
readonly useDevicePixelRatio: UnwrapRef<typeof import('@vueuse/core')['useDevicePixelRatio']>
|
||||
readonly useDevicesList: UnwrapRef<typeof import('@vueuse/core')['useDevicesList']>
|
||||
readonly useDisplayMedia: UnwrapRef<typeof import('@vueuse/core')['useDisplayMedia']>
|
||||
readonly useDocumentVisibility: UnwrapRef<typeof import('@vueuse/core')['useDocumentVisibility']>
|
||||
readonly useDraggable: UnwrapRef<typeof import('@vueuse/core')['useDraggable']>
|
||||
readonly useDropZone: UnwrapRef<typeof import('@vueuse/core')['useDropZone']>
|
||||
readonly useElementBounding: UnwrapRef<typeof import('@vueuse/core')['useElementBounding']>
|
||||
readonly useElementByPoint: UnwrapRef<typeof import('@vueuse/core')['useElementByPoint']>
|
||||
readonly useElementHover: UnwrapRef<typeof import('@vueuse/core')['useElementHover']>
|
||||
readonly useElementSize: UnwrapRef<typeof import('@vueuse/core')['useElementSize']>
|
||||
readonly useElementVisibility: UnwrapRef<typeof import('@vueuse/core')['useElementVisibility']>
|
||||
readonly useEventBus: UnwrapRef<typeof import('@vueuse/core')['useEventBus']>
|
||||
readonly useEventListener: UnwrapRef<typeof import('@vueuse/core')['useEventListener']>
|
||||
readonly useEventSource: UnwrapRef<typeof import('@vueuse/core')['useEventSource']>
|
||||
readonly useEyeDropper: UnwrapRef<typeof import('@vueuse/core')['useEyeDropper']>
|
||||
readonly useFavicon: UnwrapRef<typeof import('@vueuse/core')['useFavicon']>
|
||||
readonly useFetch: UnwrapRef<typeof import('@vueuse/core')['useFetch']>
|
||||
readonly useFileDialog: UnwrapRef<typeof import('@vueuse/core')['useFileDialog']>
|
||||
readonly useFileSystemAccess: UnwrapRef<typeof import('@vueuse/core')['useFileSystemAccess']>
|
||||
readonly useFocus: UnwrapRef<typeof import('@vueuse/core')['useFocus']>
|
||||
readonly useFocusWithin: UnwrapRef<typeof import('@vueuse/core')['useFocusWithin']>
|
||||
readonly useFps: UnwrapRef<typeof import('@vueuse/core')['useFps']>
|
||||
readonly useFullscreen: UnwrapRef<typeof import('@vueuse/core')['useFullscreen']>
|
||||
readonly useGamepad: UnwrapRef<typeof import('@vueuse/core')['useGamepad']>
|
||||
readonly useGeolocation: UnwrapRef<typeof import('@vueuse/core')['useGeolocation']>
|
||||
readonly useI18n: UnwrapRef<typeof import('vue-i18n')['useI18n']>
|
||||
readonly useId: UnwrapRef<typeof import('vue')['useId']>
|
||||
readonly useIdle: UnwrapRef<typeof import('@vueuse/core')['useIdle']>
|
||||
readonly useImage: UnwrapRef<typeof import('@vueuse/core')['useImage']>
|
||||
readonly useInfiniteScroll: UnwrapRef<typeof import('@vueuse/core')['useInfiniteScroll']>
|
||||
readonly useIntersectionObserver: UnwrapRef<typeof import('@vueuse/core')['useIntersectionObserver']>
|
||||
readonly useInterval: UnwrapRef<typeof import('@vueuse/core')['useInterval']>
|
||||
readonly useIntervalFn: UnwrapRef<typeof import('@vueuse/core')['useIntervalFn']>
|
||||
readonly useKeyModifier: UnwrapRef<typeof import('@vueuse/core')['useKeyModifier']>
|
||||
readonly useLastChanged: UnwrapRef<typeof import('@vueuse/core')['useLastChanged']>
|
||||
readonly useLink: UnwrapRef<typeof import('vue-router')['useLink']>
|
||||
readonly useLocalStorage: UnwrapRef<typeof import('@vueuse/core')['useLocalStorage']>
|
||||
readonly useMagicKeys: UnwrapRef<typeof import('@vueuse/core')['useMagicKeys']>
|
||||
readonly useManualRefHistory: UnwrapRef<typeof import('@vueuse/core')['useManualRefHistory']>
|
||||
readonly useMediaControls: UnwrapRef<typeof import('@vueuse/core')['useMediaControls']>
|
||||
readonly useMediaQuery: UnwrapRef<typeof import('@vueuse/core')['useMediaQuery']>
|
||||
readonly useMemoize: UnwrapRef<typeof import('@vueuse/core')['useMemoize']>
|
||||
readonly useMemory: UnwrapRef<typeof import('@vueuse/core')['useMemory']>
|
||||
readonly useModel: UnwrapRef<typeof import('vue')['useModel']>
|
||||
readonly useMounted: UnwrapRef<typeof import('@vueuse/core')['useMounted']>
|
||||
readonly useMouse: UnwrapRef<typeof import('@vueuse/core')['useMouse']>
|
||||
readonly useMouseInElement: UnwrapRef<typeof import('@vueuse/core')['useMouseInElement']>
|
||||
readonly useMousePressed: UnwrapRef<typeof import('@vueuse/core')['useMousePressed']>
|
||||
readonly useMutationObserver: UnwrapRef<typeof import('@vueuse/core')['useMutationObserver']>
|
||||
readonly useNavigatorLanguage: UnwrapRef<typeof import('@vueuse/core')['useNavigatorLanguage']>
|
||||
readonly useNetwork: UnwrapRef<typeof import('@vueuse/core')['useNetwork']>
|
||||
readonly useNow: UnwrapRef<typeof import('@vueuse/core')['useNow']>
|
||||
readonly useObjectUrl: UnwrapRef<typeof import('@vueuse/core')['useObjectUrl']>
|
||||
readonly useOffsetPagination: UnwrapRef<typeof import('@vueuse/core')['useOffsetPagination']>
|
||||
readonly useOnline: UnwrapRef<typeof import('@vueuse/core')['useOnline']>
|
||||
readonly usePageLeave: UnwrapRef<typeof import('@vueuse/core')['usePageLeave']>
|
||||
readonly useParallax: UnwrapRef<typeof import('@vueuse/core')['useParallax']>
|
||||
readonly useParentElement: UnwrapRef<typeof import('@vueuse/core')['useParentElement']>
|
||||
readonly usePerformanceObserver: UnwrapRef<typeof import('@vueuse/core')['usePerformanceObserver']>
|
||||
readonly usePermission: UnwrapRef<typeof import('@vueuse/core')['usePermission']>
|
||||
readonly usePointer: UnwrapRef<typeof import('@vueuse/core')['usePointer']>
|
||||
readonly usePointerLock: UnwrapRef<typeof import('@vueuse/core')['usePointerLock']>
|
||||
readonly usePointerSwipe: UnwrapRef<typeof import('@vueuse/core')['usePointerSwipe']>
|
||||
readonly usePreferredColorScheme: UnwrapRef<typeof import('@vueuse/core')['usePreferredColorScheme']>
|
||||
readonly usePreferredContrast: UnwrapRef<typeof import('@vueuse/core')['usePreferredContrast']>
|
||||
readonly usePreferredDark: UnwrapRef<typeof import('@vueuse/core')['usePreferredDark']>
|
||||
readonly usePreferredLanguages: UnwrapRef<typeof import('@vueuse/core')['usePreferredLanguages']>
|
||||
readonly usePreferredReducedMotion: UnwrapRef<typeof import('@vueuse/core')['usePreferredReducedMotion']>
|
||||
readonly usePreferredReducedTransparency: UnwrapRef<typeof import('@vueuse/core')['usePreferredReducedTransparency']>
|
||||
readonly usePrevious: UnwrapRef<typeof import('@vueuse/core')['usePrevious']>
|
||||
readonly useRafFn: UnwrapRef<typeof import('@vueuse/core')['useRafFn']>
|
||||
readonly useRefHistory: UnwrapRef<typeof import('@vueuse/core')['useRefHistory']>
|
||||
readonly useResizeObserver: UnwrapRef<typeof import('@vueuse/core')['useResizeObserver']>
|
||||
readonly useRoute: UnwrapRef<typeof import('vue-router')['useRoute']>
|
||||
readonly useRouter: UnwrapRef<typeof import('vue-router')['useRouter']>
|
||||
readonly useSSRWidth: UnwrapRef<typeof import('@vueuse/core')['useSSRWidth']>
|
||||
readonly useScreenOrientation: UnwrapRef<typeof import('@vueuse/core')['useScreenOrientation']>
|
||||
readonly useScreenSafeArea: UnwrapRef<typeof import('@vueuse/core')['useScreenSafeArea']>
|
||||
readonly useScriptTag: UnwrapRef<typeof import('@vueuse/core')['useScriptTag']>
|
||||
readonly useScroll: UnwrapRef<typeof import('@vueuse/core')['useScroll']>
|
||||
readonly useScrollLock: UnwrapRef<typeof import('@vueuse/core')['useScrollLock']>
|
||||
readonly useSessionStorage: UnwrapRef<typeof import('@vueuse/core')['useSessionStorage']>
|
||||
readonly useShare: UnwrapRef<typeof import('@vueuse/core')['useShare']>
|
||||
readonly useSlots: UnwrapRef<typeof import('vue')['useSlots']>
|
||||
readonly useSorted: UnwrapRef<typeof import('@vueuse/core')['useSorted']>
|
||||
readonly useSpeechRecognition: UnwrapRef<typeof import('@vueuse/core')['useSpeechRecognition']>
|
||||
readonly useSpeechSynthesis: UnwrapRef<typeof import('@vueuse/core')['useSpeechSynthesis']>
|
||||
readonly useStepper: UnwrapRef<typeof import('@vueuse/core')['useStepper']>
|
||||
readonly useStorage: UnwrapRef<typeof import('@vueuse/core')['useStorage']>
|
||||
readonly useStorageAsync: UnwrapRef<typeof import('@vueuse/core')['useStorageAsync']>
|
||||
readonly useStyleTag: UnwrapRef<typeof import('@vueuse/core')['useStyleTag']>
|
||||
readonly useSupported: UnwrapRef<typeof import('@vueuse/core')['useSupported']>
|
||||
readonly useSwipe: UnwrapRef<typeof import('@vueuse/core')['useSwipe']>
|
||||
readonly useTemplateRef: UnwrapRef<typeof import('vue')['useTemplateRef']>
|
||||
readonly useTemplateRefsList: UnwrapRef<typeof import('@vueuse/core')['useTemplateRefsList']>
|
||||
readonly useTextDirection: UnwrapRef<typeof import('@vueuse/core')['useTextDirection']>
|
||||
readonly useTextSelection: UnwrapRef<typeof import('@vueuse/core')['useTextSelection']>
|
||||
readonly useTextareaAutosize: UnwrapRef<typeof import('@vueuse/core')['useTextareaAutosize']>
|
||||
readonly useThrottle: UnwrapRef<typeof import('@vueuse/core')['useThrottle']>
|
||||
readonly useThrottleFn: UnwrapRef<typeof import('@vueuse/core')['useThrottleFn']>
|
||||
readonly useThrottledRefHistory: UnwrapRef<typeof import('@vueuse/core')['useThrottledRefHistory']>
|
||||
readonly useTimeAgo: UnwrapRef<typeof import('@vueuse/core')['useTimeAgo']>
|
||||
readonly useTimeAgoIntl: UnwrapRef<typeof import('@vueuse/core')['useTimeAgoIntl']>
|
||||
readonly useTimeout: UnwrapRef<typeof import('@vueuse/core')['useTimeout']>
|
||||
readonly useTimeoutFn: UnwrapRef<typeof import('@vueuse/core')['useTimeoutFn']>
|
||||
readonly useTimeoutPoll: UnwrapRef<typeof import('@vueuse/core')['useTimeoutPoll']>
|
||||
readonly useTimestamp: UnwrapRef<typeof import('@vueuse/core')['useTimestamp']>
|
||||
readonly useTitle: UnwrapRef<typeof import('@vueuse/core')['useTitle']>
|
||||
readonly useToNumber: UnwrapRef<typeof import('@vueuse/core')['useToNumber']>
|
||||
readonly useToString: UnwrapRef<typeof import('@vueuse/core')['useToString']>
|
||||
readonly useToggle: UnwrapRef<typeof import('@vueuse/core')['useToggle']>
|
||||
readonly useTransition: UnwrapRef<typeof import('@vueuse/core')['useTransition']>
|
||||
readonly useUrlSearchParams: UnwrapRef<typeof import('@vueuse/core')['useUrlSearchParams']>
|
||||
readonly useUserMedia: UnwrapRef<typeof import('@vueuse/core')['useUserMedia']>
|
||||
readonly useVModel: UnwrapRef<typeof import('@vueuse/core')['useVModel']>
|
||||
readonly useVModels: UnwrapRef<typeof import('@vueuse/core')['useVModels']>
|
||||
readonly useVibrate: UnwrapRef<typeof import('@vueuse/core')['useVibrate']>
|
||||
readonly useVirtualList: UnwrapRef<typeof import('@vueuse/core')['useVirtualList']>
|
||||
readonly useWakeLock: UnwrapRef<typeof import('@vueuse/core')['useWakeLock']>
|
||||
readonly useWebNotification: UnwrapRef<typeof import('@vueuse/core')['useWebNotification']>
|
||||
readonly useWebSocket: UnwrapRef<typeof import('@vueuse/core')['useWebSocket']>
|
||||
readonly useWebWorker: UnwrapRef<typeof import('@vueuse/core')['useWebWorker']>
|
||||
readonly useWebWorkerFn: UnwrapRef<typeof import('@vueuse/core')['useWebWorkerFn']>
|
||||
readonly useWindowFocus: UnwrapRef<typeof import('@vueuse/core')['useWindowFocus']>
|
||||
readonly useWindowScroll: UnwrapRef<typeof import('@vueuse/core')['useWindowScroll']>
|
||||
readonly useWindowSize: UnwrapRef<typeof import('@vueuse/core')['useWindowSize']>
|
||||
readonly watch: UnwrapRef<typeof import('vue')['watch']>
|
||||
readonly watchArray: UnwrapRef<typeof import('@vueuse/core')['watchArray']>
|
||||
readonly watchAtMost: UnwrapRef<typeof import('@vueuse/core')['watchAtMost']>
|
||||
readonly watchDebounced: UnwrapRef<typeof import('@vueuse/core')['watchDebounced']>
|
||||
readonly watchDeep: UnwrapRef<typeof import('@vueuse/core')['watchDeep']>
|
||||
readonly watchEffect: UnwrapRef<typeof import('vue')['watchEffect']>
|
||||
readonly watchIgnorable: UnwrapRef<typeof import('@vueuse/core')['watchIgnorable']>
|
||||
readonly watchImmediate: UnwrapRef<typeof import('@vueuse/core')['watchImmediate']>
|
||||
readonly watchOnce: UnwrapRef<typeof import('@vueuse/core')['watchOnce']>
|
||||
readonly watchPausable: UnwrapRef<typeof import('@vueuse/core')['watchPausable']>
|
||||
readonly watchPostEffect: UnwrapRef<typeof import('vue')['watchPostEffect']>
|
||||
readonly watchSyncEffect: UnwrapRef<typeof import('vue')['watchSyncEffect']>
|
||||
readonly watchThrottled: UnwrapRef<typeof import('@vueuse/core')['watchThrottled']>
|
||||
readonly watchTriggerable: UnwrapRef<typeof import('@vueuse/core')['watchTriggerable']>
|
||||
readonly watchWithFilter: UnwrapRef<typeof import('@vueuse/core')['watchWithFilter']>
|
||||
readonly whenever: UnwrapRef<typeof import('@vueuse/core')['whenever']>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
<template>
|
||||
<v-dialog
|
||||
v-model="isVisible"
|
||||
max-width="500"
|
||||
@after-leave="reset"
|
||||
>
|
||||
<v-card>
|
||||
<v-card-title>
|
||||
{{ isEditMode ? '编辑目录' : '添加目录' }}
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<v-form v-model="formValid">
|
||||
<v-text-field
|
||||
v-model="directoryPath"
|
||||
label="目录名称"
|
||||
placeholder="请输入目录名称"
|
||||
:rules="[requiredRule('目录名称')]"
|
||||
required
|
||||
density="comfortable"
|
||||
ref="inputRef"
|
||||
@keydown.enter="confirm"
|
||||
/>
|
||||
</v-form>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer />
|
||||
<v-btn @click="close">取消</v-btn>
|
||||
<v-btn
|
||||
color="primary"
|
||||
@click="confirm"
|
||||
:disabled="!formValid"
|
||||
>
|
||||
{{ isEditMode ? '保存' : '添加' }}
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, watch, nextTick } from 'vue'
|
||||
import { TreeNode } from '@/types'
|
||||
|
||||
interface Props {
|
||||
modelValue: boolean
|
||||
isEditMode?: boolean
|
||||
parentDirectory?: TreeNode | null
|
||||
editingItem?: TreeNode | null
|
||||
}
|
||||
|
||||
interface Emits {
|
||||
(e: 'update:modelValue', value: boolean): void
|
||||
(e: 'confirm', data: { path: string; }): void
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
isEditMode: false,
|
||||
parentDirectory: null,
|
||||
editingItem: null
|
||||
})
|
||||
|
||||
const emit = defineEmits<Emits>()
|
||||
|
||||
// Internal state
|
||||
const isVisible = ref(false)
|
||||
const formValid = ref(false)
|
||||
const directoryPath = ref('')
|
||||
const inputRef = ref<HTMLInputElement | null>(null)
|
||||
|
||||
// Computed
|
||||
const isEditMode = computed(() => props.isEditMode)
|
||||
|
||||
// Watch for visibility changes
|
||||
watch(() => props.modelValue, (newValue) => {
|
||||
isVisible.value = newValue
|
||||
if (newValue) {
|
||||
// Reset form when dialog opens
|
||||
directoryPath.value = props.editingItem?.path || ''
|
||||
autoFocusInput()
|
||||
}
|
||||
})
|
||||
|
||||
// Watch for internal visibility changes and emit update
|
||||
watch(isVisible, (newValue) => {
|
||||
emit('update:modelValue', newValue)
|
||||
})
|
||||
|
||||
// Validation rules
|
||||
const requiredRule = (fieldName: string) => (v: string | null | undefined) =>
|
||||
!!v || `${fieldName}为必填项`
|
||||
|
||||
// Methods
|
||||
const autoFocusInput = async () => {
|
||||
await nextTick()
|
||||
if (inputRef.value) {
|
||||
;(inputRef.value as HTMLInputElement).focus()
|
||||
}
|
||||
}
|
||||
|
||||
const confirm = () => {
|
||||
if (!directoryPath.value.trim()) return
|
||||
|
||||
// Construct the full path if there's a parent directory
|
||||
|
||||
emit('confirm', {
|
||||
path: directoryPath.value,
|
||||
})
|
||||
|
||||
close()
|
||||
}
|
||||
const reset = () => {
|
||||
directoryPath.value = ''
|
||||
formValid.value = false
|
||||
}
|
||||
|
||||
const close = () => {
|
||||
isVisible.value = false
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,200 @@
|
||||
<template>
|
||||
<v-dialog
|
||||
v-model="isVisible"
|
||||
max-width="600"
|
||||
@after-leave="reset"
|
||||
>
|
||||
<v-card>
|
||||
<v-card-title>
|
||||
{{ isEditMode ? '编辑文件' : '添加文件' }}
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<v-form v-model="formValid">
|
||||
<v-text-field
|
||||
v-model="filePath"
|
||||
label="文件名"
|
||||
placeholder="文件名需要带上后缀,如:style skech.doc"
|
||||
:rules="[requiredRule('文件名')]"
|
||||
required
|
||||
density="comfortable"
|
||||
ref="inputRef"
|
||||
/>
|
||||
|
||||
<!-- 文件选择输入框 -->
|
||||
<v-text-field
|
||||
v-model="selectedFilePath"
|
||||
label="选择文件"
|
||||
placeholder="点击输入框选择文件"
|
||||
readonly
|
||||
:append-inner-icon="'mdi-file'"
|
||||
density="comfortable"
|
||||
class="mt-4"
|
||||
@click="selectSourceFile"
|
||||
/>
|
||||
|
||||
<!-- 文件夹选择输入框 -->
|
||||
<v-text-field
|
||||
v-model="selectedFolderPath"
|
||||
label="选择文件夹"
|
||||
placeholder="点击输入框选择文件夹"
|
||||
readonly
|
||||
:append-inner-icon="'mdi-folder'"
|
||||
density="comfortable"
|
||||
class="mt-4"
|
||||
@click="selectSourceFolder"
|
||||
/>
|
||||
|
||||
<!-- 选择提示 -->
|
||||
<v-alert
|
||||
type="info"
|
||||
variant="tonal"
|
||||
class="mt-2"
|
||||
>
|
||||
<div class="d-flex align-start flex-column">
|
||||
<span>选择文件会直接复制到目标位置</span>
|
||||
<span>
|
||||
选择文件夹则会自动匹配该文件夹下的文件进行复制并且重命名
|
||||
</span>
|
||||
<span class="mt-1 font-weight-bold">
|
||||
文件和文件夹选择其中一个即可
|
||||
</span>
|
||||
</div>
|
||||
</v-alert>
|
||||
</v-form>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer />
|
||||
<v-btn @click="close">取消</v-btn>
|
||||
<v-btn
|
||||
color="primary"
|
||||
@click="confirm"
|
||||
:disabled="!formValid || (!selectedFilePath && !selectedFolderPath && !isEditMode)"
|
||||
>
|
||||
{{ isEditMode ? '保存' : '添加' }}
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, watch, nextTick } from 'vue'
|
||||
import { TreeNode } from '@/types'
|
||||
|
||||
interface Props {
|
||||
modelValue: boolean
|
||||
isEditMode?: boolean
|
||||
parentDirectory?: TreeNode | null
|
||||
editingItem?: TreeNode | null
|
||||
}
|
||||
|
||||
interface Emits {
|
||||
(e: 'update:modelValue', value: boolean): void
|
||||
(e: 'confirm', data: { path: string; sourcePath?: string; sourceType?: 'file' | 'folder' }): void
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
isEditMode: false,
|
||||
parentDirectory: null,
|
||||
editingItem: null
|
||||
})
|
||||
|
||||
const emit = defineEmits<Emits>()
|
||||
|
||||
// Internal state
|
||||
const isVisible = ref(false)
|
||||
const formValid = ref(false)
|
||||
const filePath = ref('')
|
||||
const selectedFilePath = ref<string>('')
|
||||
const selectedFolderPath = ref<string>('')
|
||||
const inputRef = ref<HTMLInputElement | null>(null)
|
||||
|
||||
// Computed
|
||||
const isEditMode = computed(() => props.isEditMode)
|
||||
|
||||
// Watch for visibility changes
|
||||
watch(() => props.modelValue, (newValue) => {
|
||||
isVisible.value = newValue
|
||||
if (newValue) {
|
||||
// Reset form when dialog opens
|
||||
filePath.value = props.editingItem?.path || ''
|
||||
selectedFilePath.value = props.editingItem?.sourceType === 'file' ? props.editingItem?.sourcePath || '' : ''
|
||||
selectedFolderPath.value = props.editingItem?.sourceType === 'folder' ? props.editingItem?.sourcePath || '' : ''
|
||||
autoFocusInput()
|
||||
}
|
||||
})
|
||||
|
||||
// Watch for internal visibility changes and emit update
|
||||
watch(isVisible, (newValue) => {
|
||||
emit('update:modelValue', newValue)
|
||||
})
|
||||
|
||||
// Validation rules
|
||||
const requiredRule = (fieldName: string) => (v: string | null | undefined) =>
|
||||
!!v || `${fieldName}为必填项`
|
||||
|
||||
|
||||
|
||||
// Methods
|
||||
const autoFocusInput = async () => {
|
||||
await nextTick()
|
||||
if (inputRef.value) {
|
||||
;(inputRef.value as HTMLInputElement).focus()
|
||||
}
|
||||
}
|
||||
|
||||
const selectSourceFile = async () => {
|
||||
// 使用主进程API来选择文件
|
||||
const result = await window.mainApi.invoke('msgOpenFile', 'any')
|
||||
|
||||
if (result && !result.canceled && result.filePaths.length > 0) {
|
||||
selectedFilePath.value = result.filePaths[0]
|
||||
selectedFolderPath.value = '' // 清空文件夹选择
|
||||
}
|
||||
}
|
||||
|
||||
const selectSourceFolder = async () => {
|
||||
// 使用主进程API来选择文件夹
|
||||
const result = await window.mainApi.invoke('msgSelectDirectory')
|
||||
|
||||
if (result && !result.canceled && result.filePath) {
|
||||
selectedFolderPath.value = result.filePath
|
||||
selectedFilePath.value = '' // 清空文件选择
|
||||
}
|
||||
}
|
||||
|
||||
const confirm = () => {
|
||||
if (!filePath.value.trim()) return
|
||||
|
||||
// 确定选择的源类型和路径
|
||||
let sourcePathValue: string | undefined
|
||||
let sourceType: 'file' | 'folder' | undefined
|
||||
|
||||
if (selectedFilePath.value) {
|
||||
sourcePathValue = selectedFilePath.value
|
||||
sourceType = 'file'
|
||||
} else if (selectedFolderPath.value) {
|
||||
sourcePathValue = selectedFolderPath.value
|
||||
sourceType = 'folder'
|
||||
}
|
||||
|
||||
emit('confirm', {
|
||||
path: filePath.value,
|
||||
sourcePath: sourcePathValue,
|
||||
sourceType
|
||||
})
|
||||
|
||||
close()
|
||||
}
|
||||
|
||||
const reset = () => {
|
||||
filePath.value = ''
|
||||
selectedFilePath.value = ''
|
||||
selectedFolderPath.value = ''
|
||||
formValid.value = false
|
||||
}
|
||||
|
||||
const close = () => {
|
||||
isVisible.value = false
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,34 @@
|
||||
<template>
|
||||
<v-snackbar
|
||||
v-model="snackbar.isVisible"
|
||||
:color="snackbar.color"
|
||||
:timeout="snackbar.timeout"
|
||||
location="top"
|
||||
>
|
||||
{{ snackbar.message }}
|
||||
<template #actions>
|
||||
<v-btn
|
||||
v-for="(action, index) in snackbar.actions"
|
||||
:key="index"
|
||||
:color="action.color || 'white'"
|
||||
variant="text"
|
||||
@click="action.handler && action.handler()"
|
||||
>
|
||||
{{ action.text }}
|
||||
</v-btn>
|
||||
<v-btn
|
||||
icon
|
||||
variant="text"
|
||||
@click="snackbar.hide"
|
||||
>
|
||||
<v-icon>mdi-close</v-icon>
|
||||
</v-btn>
|
||||
</template>
|
||||
</v-snackbar>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useSnackbarStore } from '@/renderer/store/snackbar'
|
||||
|
||||
const snackbar = useSnackbarStore()
|
||||
</script>
|
||||
@@ -0,0 +1,108 @@
|
||||
<template>
|
||||
<v-card class="d-flex flex-column" height="100%" variant="outlined">
|
||||
<v-card-item>
|
||||
<v-card-title>{{ template.name }}</v-card-title>
|
||||
<v-card-subtitle>{{ template.description }}</v-card-subtitle>
|
||||
</v-card-item>
|
||||
|
||||
<v-card-text class="flex-grow-1 py-2">
|
||||
<v-chip-group column>
|
||||
<v-chip size="small" color="primary" variant="tonal">
|
||||
文件: {{ nodeCount.files }}
|
||||
</v-chip>
|
||||
<v-chip size="small" color="success" variant="tonal">
|
||||
目录: {{ nodeCount.directories }}
|
||||
</v-chip>
|
||||
</v-chip-group>
|
||||
</v-card-text>
|
||||
|
||||
<v-divider class="mt-auto"></v-divider>
|
||||
|
||||
<v-card-actions class="pa-2 justify-space-between">
|
||||
<div>
|
||||
<v-btn color="primary" variant="text" size="small" @click="$emit('view', template)">
|
||||
查看
|
||||
</v-btn>
|
||||
<v-btn color="success" variant="text" size="small" @click="$emit('execute', template)">
|
||||
执行
|
||||
</v-btn>
|
||||
</div>
|
||||
|
||||
<v-menu location="bottom end">
|
||||
<template v-slot:activator="{ props }">
|
||||
<v-btn v-bind="props" icon variant="text" size="small" density="comfortable">
|
||||
<v-icon>mdi-dots-vertical</v-icon>
|
||||
</v-btn>
|
||||
</template>
|
||||
|
||||
<v-list density="compact">
|
||||
<v-list-item @click="$emit('edit', template)">
|
||||
<template v-slot:prepend>
|
||||
<v-icon>mdi-pencil</v-icon>
|
||||
</template>
|
||||
<v-list-item-title>修改</v-list-item-title>
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item @click="$emit('copy', template)">
|
||||
<template v-slot:prepend>
|
||||
<v-icon color="primary">mdi-content-copy</v-icon>
|
||||
</template>
|
||||
<v-list-item-title>复制</v-list-item-title>
|
||||
</v-list-item>
|
||||
|
||||
<v-divider></v-divider>
|
||||
|
||||
<v-list-item @click="$emit('delete', template)">
|
||||
<template v-slot:prepend>
|
||||
<v-icon color="error">mdi-delete</v-icon>
|
||||
</template>
|
||||
<v-list-item-title class="text-error">删除</v-list-item-title>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { Template, TreeNode } from '@/types'
|
||||
|
||||
interface Props {
|
||||
template: Template
|
||||
}
|
||||
|
||||
interface Emits {
|
||||
(e: 'view', template: Template): void
|
||||
(e: 'execute', template: Template): void
|
||||
(e: 'edit', template: Template): void
|
||||
(e: 'delete', template: Template): void
|
||||
(e: 'copy', template: Template): void
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
const emit = defineEmits<Emits>()
|
||||
|
||||
// Count files and directories in tree structure
|
||||
const nodeCount = computed(() => {
|
||||
let files = 0
|
||||
let directories = 0
|
||||
|
||||
const count = (nodeList: TreeNode[]) => {
|
||||
nodeList.forEach(node => {
|
||||
if (node.type === 'file') {
|
||||
files++
|
||||
} else if (node.type === 'directory') {
|
||||
directories++
|
||||
if (node.children) {
|
||||
count(node.children)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
count(props.template.treeStructure || [])
|
||||
|
||||
return { files, directories }
|
||||
})
|
||||
</script>
|
||||
@@ -3,15 +3,18 @@
|
||||
variant="outlined"
|
||||
class="pa-2"
|
||||
:height="height"
|
||||
style="overflow: auto;"
|
||||
>
|
||||
<v-treeview
|
||||
open-all
|
||||
:items="items"
|
||||
item-title="name"
|
||||
item-key="id"
|
||||
item-children="children"
|
||||
item-value="id"
|
||||
open-on-click
|
||||
:hoverable="true"
|
||||
:indent-lines="'default'"
|
||||
separate-roots
|
||||
density="compact"
|
||||
>
|
||||
<template #prepend="{ item }">
|
||||
<v-icon
|
||||
|
||||
@@ -32,25 +32,35 @@ const headerMenus: {
|
||||
text: 'title.second',
|
||||
path: '/second'
|
||||
}
|
||||
]
|
||||
]
|
||||
|
||||
// Get app version
|
||||
const appVersion = ref('')
|
||||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
appVersion.value = await window.mainApi.invoke('msgRequestGetVersion')
|
||||
} catch (error) {
|
||||
console.error('Failed to get app version:', error)
|
||||
appVersion.value = 'unknown'
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
<v-app-bar color="primary" density="compact">
|
||||
<v-app-bar-title @click="handleRoute('/')">
|
||||
GDT Tool
|
||||
</v-app-bar-title>
|
||||
<!-- <template #append>
|
||||
<v-btn
|
||||
v-for="menu in headerMenus"
|
||||
:key="menu.path"
|
||||
:prepend-icon="menu.icon"
|
||||
variant="text"
|
||||
:class="{ active: isCurrentRoute(menu.path) }"
|
||||
@click="handleRoute(menu.path)"
|
||||
<template #append>
|
||||
<v-chip
|
||||
variant="tonal"
|
||||
color="white"
|
||||
size="small"
|
||||
class="mr-2"
|
||||
>
|
||||
{{ t(menu.text) }}
|
||||
</v-btn>
|
||||
</template> -->
|
||||
v{{ appVersion }}
|
||||
</v-chip>
|
||||
</template>
|
||||
</v-app-bar>
|
||||
</template>
|
||||
<style scoped>
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -28,62 +28,14 @@
|
||||
<div v-else>
|
||||
<v-row>
|
||||
<v-col v-for="template in templates" :key="template.id" cols="12" sm="6" md="4" lg="3">
|
||||
<v-card class="d-flex flex-column" height="100%">
|
||||
<v-card-item>
|
||||
<v-card-title>{{ template.name }}</v-card-title>
|
||||
<v-card-subtitle>{{ template.description }}</v-card-subtitle>
|
||||
</v-card-item>
|
||||
|
||||
<v-card-text class="flex-grow-1 py-2">
|
||||
<v-chip-group column>
|
||||
<v-chip size="small" color="primary" variant="tonal">
|
||||
节点: {{ countTreeNodes(template.treeStructure).files }}
|
||||
</v-chip>
|
||||
<v-chip size="small" color="success" variant="tonal">
|
||||
目录: {{ countTreeNodes(template.treeStructure).directories }}
|
||||
</v-chip>
|
||||
</v-chip-group>
|
||||
</v-card-text>
|
||||
|
||||
<v-divider class="mt-auto"></v-divider>
|
||||
|
||||
<v-card-actions class="pa-2 justify-space-between">
|
||||
<div>
|
||||
<v-btn color="primary" variant="text" size="small" @click="viewTemplate(template)">
|
||||
查看
|
||||
</v-btn>
|
||||
<v-btn color="success" variant="text" size="small" @click="executeTemplate(template)">
|
||||
执行
|
||||
</v-btn>
|
||||
</div>
|
||||
|
||||
<v-menu location="bottom end">
|
||||
<template v-slot:activator="{ props }">
|
||||
<v-btn v-bind="props" icon variant="text" size="small" density="comfortable">
|
||||
<v-icon>mdi-dots-vertical</v-icon>
|
||||
</v-btn>
|
||||
</template>
|
||||
|
||||
<v-list density="compact">
|
||||
<v-list-item @click="editTemplate(template)">
|
||||
<template v-slot:prepend>
|
||||
<v-icon>mdi-pencil</v-icon>
|
||||
</template>
|
||||
<v-list-item-title>修改</v-list-item-title>
|
||||
</v-list-item>
|
||||
|
||||
<v-divider></v-divider>
|
||||
|
||||
<v-list-item @click="deleteTemplate(template)">
|
||||
<template v-slot:prepend>
|
||||
<v-icon color="error">mdi-delete</v-icon>
|
||||
</template>
|
||||
<v-list-item-title class="text-error">删除</v-list-item-title>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
<TemplateCard
|
||||
:template="template"
|
||||
@view="viewTemplate"
|
||||
@execute="executeTemplate"
|
||||
@edit="editTemplate"
|
||||
@copy="copyTemplate"
|
||||
@delete="deleteTemplate"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</div>
|
||||
@@ -113,7 +65,7 @@
|
||||
<!-- Execute template dialog -->
|
||||
<v-dialog v-model="showExecuteDialog" max-width="600">
|
||||
<v-card>
|
||||
<v-card-title>执行模板</v-card-title>
|
||||
<v-card-title>执行模板: {{ selectedTemplate?.name }}</v-card-title>
|
||||
<v-card-text>
|
||||
<v-form v-model="executeFormValid">
|
||||
<v-text-field v-model="executePath" label="选择目录" readonly @click="selectDirectory"
|
||||
@@ -138,9 +90,10 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useTemplateStore, TreeNode } from '@/renderer/store/template'
|
||||
import { Template } from '@/renderer/store/template'
|
||||
import { useTemplateStore } from '@/renderer/store/template'
|
||||
import { TreeNode, Template } from '@/types'
|
||||
import TemplateTree from '@/renderer/components/TemplateTree.vue'
|
||||
import TemplateCard from '@/renderer/components/TemplateCard.vue'
|
||||
import { ConfirmDialogService } from '@/renderer/utils/confirm-dialog-service'
|
||||
|
||||
const router = useRouter()
|
||||
@@ -166,28 +119,7 @@ const executePath = ref('')
|
||||
const baseDirNames = ref('')
|
||||
const executeFormValid = ref(false)
|
||||
|
||||
// Count files and directories in tree structure
|
||||
const countTreeNodes = (nodes: TreeNode[]) => {
|
||||
let files = 0;
|
||||
let directories = 0;
|
||||
|
||||
const count = (nodeList: TreeNode[]) => {
|
||||
nodeList.forEach(node => {
|
||||
if (node.type === 'file') {
|
||||
files++;
|
||||
} else if (node.type === 'directory') {
|
||||
directories++;
|
||||
if (node.children) {
|
||||
count(node.children);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
count(nodes || []);
|
||||
|
||||
return { files, directories };
|
||||
}
|
||||
|
||||
const templateTree = computed<TreeNode[]>(() => {
|
||||
if (!selectedTemplate.value) return []
|
||||
@@ -209,6 +141,11 @@ const editTemplate = (template: Template) => {
|
||||
router.push(`/create-template/${template.id}`)
|
||||
}
|
||||
|
||||
const copyTemplate = (template: Template) => {
|
||||
router.push(`/create-template?copyId=${template.id}`)
|
||||
}
|
||||
|
||||
|
||||
const deleteTemplate = async (template: Template) => {
|
||||
const confirmed = await ConfirmDialogService.confirm({
|
||||
title: '删除模板',
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
|
||||
export interface SnackbarAction {
|
||||
text: string
|
||||
color?: string
|
||||
handler?: () => void
|
||||
}
|
||||
|
||||
export const useSnackbarStore = defineStore('snackbar', () => {
|
||||
const isVisible = ref(false)
|
||||
const message = ref('')
|
||||
const color = ref('info')
|
||||
const timeout = ref(3000)
|
||||
const actions = ref<SnackbarAction[]>([])
|
||||
|
||||
const show = (msg: string, clr = 'info', tout = 3000, actionList: SnackbarAction[] = []) => {
|
||||
message.value = msg
|
||||
color.value = clr
|
||||
timeout.value = tout
|
||||
actions.value = actionList
|
||||
isVisible.value = true
|
||||
}
|
||||
|
||||
const success = (msg: string, tout = 3000) => show(msg, 'success', tout)
|
||||
const error = (msg: string, tout = 3000) => show(msg, 'error', tout)
|
||||
const warning = (msg: string, tout = 3000) => show(msg, 'warning', tout)
|
||||
const info = (msg: string, tout = 3000) => show(msg, 'info', tout)
|
||||
|
||||
const hide = () => {
|
||||
isVisible.value = false
|
||||
actions.value = []
|
||||
}
|
||||
|
||||
return {
|
||||
isVisible,
|
||||
message,
|
||||
color,
|
||||
timeout,
|
||||
actions,
|
||||
show,
|
||||
success,
|
||||
error,
|
||||
warning,
|
||||
info,
|
||||
hide
|
||||
}
|
||||
})
|
||||
@@ -1,25 +1,6 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
|
||||
// 定义树状结构的节点
|
||||
export interface TreeNode {
|
||||
id: string
|
||||
name: string
|
||||
path: string // 完整路径
|
||||
type: 'directory' | 'file'
|
||||
children?: TreeNode[]
|
||||
// 文件特定属性
|
||||
content?: string
|
||||
sourceFilePath?: string
|
||||
}
|
||||
|
||||
export interface Template {
|
||||
id: string
|
||||
name: string
|
||||
description: string
|
||||
// 使用树状结构存储
|
||||
treeStructure: TreeNode[]
|
||||
}
|
||||
import { TreeNode, Template } from '@/types'
|
||||
|
||||
export const useTemplateStore = defineStore('template', () => {
|
||||
const templates = ref<Template[]>([])
|
||||
|
||||
@@ -9,3 +9,14 @@ export async function openExternal(url: string): Promise<void> {
|
||||
export async function openFile(type: string): Promise<any> {
|
||||
return window.mainApi.invoke('msgOpenFile', type)
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成唯一ID
|
||||
* @param prefix ID前缀,默认为空
|
||||
* @returns 唯一ID字符串
|
||||
*/
|
||||
export function generateUniqueId(prefix: string = ''): string {
|
||||
const timestamp = Date.now().toString(36) // 转换为36进制,更短
|
||||
const randomStr = Math.random().toString(36).substring(2, 9) // 7位随机字符
|
||||
return prefix ? `${prefix}-${timestamp}-${randomStr}` : `${timestamp}-${randomStr}`
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
// 定义树状结构的节点
|
||||
export interface TreeNode {
|
||||
id: string
|
||||
name: string
|
||||
path: string // 完整路径
|
||||
type: 'directory' | 'file'
|
||||
children?: TreeNode[]
|
||||
sourcePath?: string
|
||||
sourceType?: 'file' | 'folder' // 记录选择的是文件还是文件夹
|
||||
}
|
||||
|
||||
export interface Template {
|
||||
id: string
|
||||
name: string
|
||||
description: string
|
||||
// 使用树状结构存储
|
||||
treeStructure: TreeNode[]
|
||||
}
|
||||
+1
-1
@@ -19,7 +19,7 @@
|
||||
},
|
||||
"lib": ["esnext", "dom"]
|
||||
},
|
||||
"include": ["src/*.ts", "src/*.d.ts", "src/renderer"],
|
||||
"include": ["src/*.ts", "src/*.d.ts", "src/renderer", "src/types"],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.node.json"
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
"include": [
|
||||
"src/main",
|
||||
"src/preload",
|
||||
"src/types",
|
||||
"package.json",
|
||||
"eslint.config.ts",
|
||||
"vite.config.mts",
|
||||
|
||||
@@ -6,6 +6,7 @@ import EslintPlugin from 'vite-plugin-eslint'
|
||||
import VuetifyPlugin from 'vite-plugin-vuetify'
|
||||
import VueJsx from '@vitejs/plugin-vue-jsx'
|
||||
import Vue from '@vitejs/plugin-vue'
|
||||
import AutoImport from 'unplugin-auto-import/vite'
|
||||
import { rmSync } from 'fs'
|
||||
import { resolve, dirname } from 'path'
|
||||
import { builtinModules } from 'module'
|
||||
@@ -100,6 +101,23 @@ export default defineConfig(({ mode }) => {
|
||||
plugins: [
|
||||
Vue(),
|
||||
VueJsx(),
|
||||
// Auto import commonly used APIs
|
||||
AutoImport({
|
||||
imports: [
|
||||
'vue',
|
||||
'vue-router',
|
||||
'vue-i18n',
|
||||
'@vueuse/core',
|
||||
'pinia'
|
||||
],
|
||||
dirs: [
|
||||
'./src/renderer/composables',
|
||||
'./src/renderer/utils',
|
||||
'./src/renderer/store',
|
||||
'./src/renderer/components'
|
||||
],
|
||||
vueTemplate: true
|
||||
}),
|
||||
// Docs: https://github.com/vuetifyjs/vuetify-loader
|
||||
VuetifyPlugin({
|
||||
autoImport: true
|
||||
|
||||
Reference in new issue
Block a user