diff --git a/package.json b/package.json index 06b5d2f..4cbe0a0 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ }, "dependencies": { "@mdi/font": "^7.4.47", + "@vueuse/core": "^14.0.0", "electron-log": "^5.4.3", "fs-extra": "^11.3.2", "pinia": "^3.0.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5a65942..6f26cfd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,6 +11,9 @@ importers: '@mdi/font': specifier: ^7.4.47 version: 7.4.47 + '@vueuse/core': + specifier: ^14.0.0 + version: 14.0.0(vue@3.5.22(typescript@5.9.3)) electron-log: specifier: ^5.4.3 version: 5.4.3 @@ -286,8 +289,8 @@ packages: resolution: {integrity: sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==} engines: {node: '>=12'} - '@electron/node-gyp@git+https://git@github.com:electron/node-gyp.git#06b29aafb7708acef8b3669835c8a7857ebc92d2': - resolution: {commit: 06b29aafb7708acef8b3669835c8a7857ebc92d2, repo: git@github.com:electron/node-gyp.git, type: git} + '@electron/node-gyp@https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2': + resolution: {tarball: https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2} version: 10.2.0-electron.1 engines: {node: '>=12.13.0'} hasBin: true @@ -802,6 +805,9 @@ packages: '@types/verror@1.10.11': resolution: {integrity: sha512-RlDm9K7+o5stv0Co8i8ZRGxDbrTxhJtgjqjFyVh/tXQyl/rYtTKlnTvZ88oSTeYREWurwx20Js4kTuKCsFkUtg==} + '@types/web-bluetooth@0.0.21': + resolution: {integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==} + '@types/yauzl@2.10.3': resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} @@ -976,6 +982,19 @@ packages: vue: ^3.0.0 vuetify: ^3.0.0 + '@vueuse/core@14.0.0': + resolution: {integrity: sha512-d6tKRWkZE8IQElX2aHBxXOMD478fHIYV+Dzm2y9Ag122ICBpNKtGICiXKOhWU3L1kKdttDD9dCMS4bGP3jhCTQ==} + peerDependencies: + vue: ^3.5.0 + + '@vueuse/metadata@14.0.0': + resolution: {integrity: sha512-6yoGqbJcMldVCevkFiHDBTB1V5Hq+G/haPlGIuaFZHpXC0HADB0EN1ryQAAceiW+ryS3niUwvdFbGiqHqBrfVA==} + + '@vueuse/shared@14.0.0': + resolution: {integrity: sha512-mTCA0uczBgurRlwVaQHfG0Ja7UdGe4g9mwffiJmvLiTtp1G4AQyIjej6si/k8c8pUwTfVpNufck+23gXptPAkw==} + peerDependencies: + vue: ^3.5.0 + '@xmldom/xmldom@0.8.10': resolution: {integrity: sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==} engines: {node: '>=10.0.0'} @@ -3403,7 +3422,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@electron/node-gyp@git+https://git@github.com:electron/node-gyp.git#06b29aafb7708acef8b3669835c8a7857ebc92d2': + '@electron/node-gyp@https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2': dependencies: env-paths: 2.2.1 exponential-backoff: 3.1.2 @@ -3440,7 +3459,7 @@ snapshots: '@electron/rebuild@3.7.2': dependencies: - '@electron/node-gyp': git+https://git@github.com:electron/node-gyp.git#06b29aafb7708acef8b3669835c8a7857ebc92d2 + '@electron/node-gyp': https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2 '@malept/cross-spawn-promise': 2.0.0 chalk: 4.1.2 debug: 4.4.0 @@ -3853,6 +3872,8 @@ snapshots: '@types/verror@1.10.11': optional: true + '@types/web-bluetooth@0.0.21': {} + '@types/yauzl@2.10.3': dependencies: '@types/node': 22.15.15 @@ -4136,6 +4157,19 @@ snapshots: vue: 3.5.22(typescript@5.9.3) vuetify: 3.10.5(typescript@5.9.3)(vite-plugin-vuetify@2.1.2)(vue@3.5.22(typescript@5.9.3)) + '@vueuse/core@14.0.0(vue@3.5.22(typescript@5.9.3))': + dependencies: + '@types/web-bluetooth': 0.0.21 + '@vueuse/metadata': 14.0.0 + '@vueuse/shared': 14.0.0(vue@3.5.22(typescript@5.9.3)) + vue: 3.5.22(typescript@5.9.3) + + '@vueuse/metadata@14.0.0': {} + + '@vueuse/shared@14.0.0(vue@3.5.22(typescript@5.9.3))': + dependencies: + vue: 3.5.22(typescript@5.9.3) + '@xmldom/xmldom@0.8.10': {} abbrev@1.1.1: {} diff --git a/src/renderer/components/TemplateTree.vue b/src/renderer/components/TemplateTree.vue new file mode 100644 index 0000000..dc8a339 --- /dev/null +++ b/src/renderer/components/TemplateTree.vue @@ -0,0 +1,224 @@ + + + + + diff --git a/src/renderer/screens/CreateTemplateScreen.vue b/src/renderer/screens/CreateTemplateScreen.vue index 8bcbe34..23f922f 100644 --- a/src/renderer/screens/CreateTemplateScreen.vue +++ b/src/renderer/screens/CreateTemplateScreen.vue @@ -138,143 +138,25 @@ - - - - - - - - - -
- - mdi-folder-open-outline - -

暂无文件或目录

-

右键点击空白区域添加根目录或文件

-
-
- - - - - - - - {{ currentContextItem ? '添加子目录' : '添加根目录' }} - - - - - - - {{ currentContextItem ? '添加子文件' : '添加根文件' }} - - - - + :expanded="expandedNodes" + :show-context-menu-var="showContextMenuVar" + :context-menu-x="contextMenuX" + :context-menu-y="contextMenuY" + :current-context-item="currentContextItem" + :empty-text="'暂无文件或目录'" + :read-only="false" + @showContextMenu="showContextMenu" + @add-new-item-to-current-directory="addNewItemToCurrentDirectory" + @edit-file="editFile" + @delete-item="deleteItem" + @add-directory="addDirectory" + @add-file="addFile" + @update:showContextMenuVar="handleContextMenuUpdate" + @update:expanded="expandedNodes = $event" + /> @@ -295,6 +177,7 @@ required density="comfortable" ref="directoryInputRef" + @keydown.enter="confirmAddDirectory" /> @@ -329,6 +212,7 @@ required density="comfortable" ref="fileInputRef" + @keydown.enter="confirmAddFile" /> @@ -394,6 +278,7 @@ import { ref, computed, onMounted, onUnmounted, watch, nextTick } from 'vue' import { useRoute, useRouter } from 'vue-router' import { useTemplateStore } from '@/renderer/store/template' import { Template } from '@/renderer/store/template' +import TemplateTree from '@/renderer/components/TemplateTree.vue' const router = useRouter() const route = useRoute() @@ -425,6 +310,11 @@ const contextMenuX = ref(0) const contextMenuY = ref(0) const currentContextItem = ref(null) +// Handler for context menu visibility updates from TemplateTree component +const handleContextMenuUpdate = (value: boolean) => { + showContextMenuVar.value = value +} + // New item state const newDirectoryPath = ref('') const newFilePath = ref('') @@ -677,14 +567,14 @@ const deleteItem = (item: TreeItem) => { const autoFocusDirectoryInput = async () => { await nextTick() if (directoryInputRef.value) { - (directoryInputRef.value as HTMLInputElement).focus() + ;(directoryInputRef.value as HTMLInputElement).focus() } } const autoFocusFileInput = async () => { await nextTick() if (fileInputRef.value) { - (fileInputRef.value as HTMLInputElement).focus() + ;(fileInputRef.value as HTMLInputElement).focus() } } diff --git a/src/renderer/screens/TemplateListScreen.vue b/src/renderer/screens/TemplateListScreen.vue index a809a51..3eaeb2b 100644 --- a/src/renderer/screens/TemplateListScreen.vue +++ b/src/renderer/screens/TemplateListScreen.vue @@ -98,18 +98,14 @@ - - - + @@ -144,6 +140,7 @@ import { ref, computed, onMounted } from 'vue' import { useRouter } from 'vue-router' import { useTemplateStore } from '@/renderer/store/template' import { Template } from '@/renderer/store/template' +import TemplateTree from '@/renderer/components/TemplateTree.vue' const router = useRouter() const templateStore = useTemplateStore() @@ -160,6 +157,7 @@ const templates = computed(() => templateStore.templates) // Template detail view const showTemplateDetail = ref(false) const selectedTemplate = ref