Compare commits
5 Commits
6002ac1418
...
9eb44cac9c
| Author | SHA1 | Date | |
|---|---|---|---|
| 9eb44cac9c | |||
| 4730f7c948 | |||
| 00b5ed9a79 | |||
| aa16a81d8c | |||
| 615dd44129 |
11
.idea/inspectionProfiles/Project_Default.xml
generated
11
.idea/inspectionProfiles/Project_Default.xml
generated
@@ -1,6 +1,17 @@
|
|||||||
<component name="InspectionProjectProfileManager">
|
<component name="InspectionProjectProfileManager">
|
||||||
<profile version="1.0">
|
<profile version="1.0">
|
||||||
<option name="myName" value="Project Default" />
|
<option name="myName" value="Project Default" />
|
||||||
|
<inspection_tool class="CssUnknownProperty" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="myCustomPropertiesEnabled" value="true" />
|
||||||
|
<option name="myIgnoreVendorSpecificProperties" value="false" />
|
||||||
|
<option name="myCustomPropertiesList">
|
||||||
|
<value>
|
||||||
|
<list size="1">
|
||||||
|
<item index="0" class="java.lang.String" itemvalue="app-region" />
|
||||||
|
</list>
|
||||||
|
</value>
|
||||||
|
</option>
|
||||||
|
</inspection_tool>
|
||||||
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
|
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
<inspection_tool class="PyPackageRequirementsInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
<inspection_tool class="PyPackageRequirementsInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
<option name="ignoredPackages">
|
<option name="ignoredPackages">
|
||||||
|
|||||||
21
LICENSE.txt
Normal file
21
LICENSE.txt
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) [year] [fullname]
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
125
package-lock.json
generated
125
package-lock.json
generated
@@ -36,6 +36,7 @@
|
|||||||
"@vitejs/plugin-vue": "^6.0.2",
|
"@vitejs/plugin-vue": "^6.0.2",
|
||||||
"electron": "^39.2.6",
|
"electron": "^39.2.6",
|
||||||
"electron-builder": "^26.0.12",
|
"electron-builder": "^26.0.12",
|
||||||
|
"electron-devtools-installer": "^4.0.0",
|
||||||
"electron-vite": "^5.0.0",
|
"electron-vite": "^5.0.0",
|
||||||
"eslint": "^9.39.1",
|
"eslint": "^9.39.1",
|
||||||
"eslint-plugin-vue": "^10.6.2",
|
"eslint-plugin-vue": "^10.6.2",
|
||||||
@@ -4272,8 +4273,7 @@
|
|||||||
"resolved": "https://registry.npmmirror.com/core-util-is/-/core-util-is-1.0.2.tgz",
|
"resolved": "https://registry.npmmirror.com/core-util-is/-/core-util-is-1.0.2.tgz",
|
||||||
"integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==",
|
"integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT"
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"node_modules/crc": {
|
"node_modules/crc": {
|
||||||
"version": "3.8.0",
|
"version": "3.8.0",
|
||||||
@@ -4977,6 +4977,16 @@
|
|||||||
"node": ">= 10.0.0"
|
"node": ">= 10.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/electron-devtools-installer": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/electron-devtools-installer/-/electron-devtools-installer-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-9Tntu/jtfSn0n6N/ZI6IdvRqXpDyLQiDuuIbsBI+dL+1Ef7C8J2JwByw58P3TJiNeuqyV3ZkphpNWuZK5iSY2w==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"unzip-crx-3": "^0.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/electron-publish": {
|
"node_modules/electron-publish": {
|
||||||
"version": "26.8.1",
|
"version": "26.8.1",
|
||||||
"resolved": "https://registry.npmmirror.com/electron-publish/-/electron-publish-26.8.1.tgz",
|
"resolved": "https://registry.npmmirror.com/electron-publish/-/electron-publish-26.8.1.tgz",
|
||||||
@@ -6435,6 +6445,13 @@
|
|||||||
"node": ">= 4"
|
"node": ">= 4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/immediate": {
|
||||||
|
"version": "3.0.6",
|
||||||
|
"resolved": "https://registry.npmmirror.com/immediate/-/immediate-3.0.6.tgz",
|
||||||
|
"integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/immutable": {
|
"node_modules/immutable": {
|
||||||
"version": "5.1.5",
|
"version": "5.1.5",
|
||||||
"resolved": "https://registry.npmmirror.com/immutable/-/immutable-5.1.5.tgz",
|
"resolved": "https://registry.npmmirror.com/immutable/-/immutable-5.1.5.tgz",
|
||||||
@@ -6577,6 +6594,13 @@
|
|||||||
"url": "https://github.com/sponsors/mesqueeb"
|
"url": "https://github.com/sponsors/mesqueeb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/isarray": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/isarray/-/isarray-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/isbinaryfile": {
|
"node_modules/isbinaryfile": {
|
||||||
"version": "5.0.7",
|
"version": "5.0.7",
|
||||||
"resolved": "https://registry.npmmirror.com/isbinaryfile/-/isbinaryfile-5.0.7.tgz",
|
"resolved": "https://registry.npmmirror.com/isbinaryfile/-/isbinaryfile-5.0.7.tgz",
|
||||||
@@ -6725,6 +6749,52 @@
|
|||||||
"graceful-fs": "^4.1.6"
|
"graceful-fs": "^4.1.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/jszip": {
|
||||||
|
"version": "3.10.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/jszip/-/jszip-3.10.1.tgz",
|
||||||
|
"integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "(MIT OR GPL-3.0-or-later)",
|
||||||
|
"dependencies": {
|
||||||
|
"lie": "~3.3.0",
|
||||||
|
"pako": "~1.0.2",
|
||||||
|
"readable-stream": "~2.3.6",
|
||||||
|
"setimmediate": "^1.0.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/jszip/node_modules/readable-stream": {
|
||||||
|
"version": "2.3.8",
|
||||||
|
"resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-2.3.8.tgz",
|
||||||
|
"integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"core-util-is": "~1.0.0",
|
||||||
|
"inherits": "~2.0.3",
|
||||||
|
"isarray": "~1.0.0",
|
||||||
|
"process-nextick-args": "~2.0.0",
|
||||||
|
"safe-buffer": "~5.1.1",
|
||||||
|
"string_decoder": "~1.1.1",
|
||||||
|
"util-deprecate": "~1.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/jszip/node_modules/safe-buffer": {
|
||||||
|
"version": "5.1.2",
|
||||||
|
"resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||||
|
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/jszip/node_modules/string_decoder": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"safe-buffer": "~5.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/keyv": {
|
"node_modules/keyv": {
|
||||||
"version": "4.5.4",
|
"version": "4.5.4",
|
||||||
"resolved": "https://registry.npmmirror.com/keyv/-/keyv-4.5.4.tgz",
|
"resolved": "https://registry.npmmirror.com/keyv/-/keyv-4.5.4.tgz",
|
||||||
@@ -6754,6 +6824,16 @@
|
|||||||
"node": ">= 0.8.0"
|
"node": ">= 0.8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/lie": {
|
||||||
|
"version": "3.3.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/lie/-/lie-3.3.0.tgz",
|
||||||
|
"integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"immediate": "~3.0.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/load-json-file": {
|
"node_modules/load-json-file": {
|
||||||
"version": "7.0.1",
|
"version": "7.0.1",
|
||||||
"resolved": "https://registry.npmmirror.com/load-json-file/-/load-json-file-7.0.1.tgz",
|
"resolved": "https://registry.npmmirror.com/load-json-file/-/load-json-file-7.0.1.tgz",
|
||||||
@@ -7190,7 +7270,6 @@
|
|||||||
"integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
|
"integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"minimist": "^1.2.6"
|
"minimist": "^1.2.6"
|
||||||
},
|
},
|
||||||
@@ -7603,6 +7682,13 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "BlueOak-1.0.0"
|
"license": "BlueOak-1.0.0"
|
||||||
},
|
},
|
||||||
|
"node_modules/pako": {
|
||||||
|
"version": "1.0.11",
|
||||||
|
"resolved": "https://registry.npmmirror.com/pako/-/pako-1.0.11.tgz",
|
||||||
|
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "(MIT AND Zlib)"
|
||||||
|
},
|
||||||
"node_modules/parent-module": {
|
"node_modules/parent-module": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmmirror.com/parent-module/-/parent-module-1.0.1.tgz",
|
"resolved": "https://registry.npmmirror.com/parent-module/-/parent-module-1.0.1.tgz",
|
||||||
@@ -7923,6 +8009,13 @@
|
|||||||
"node": "^18.17.0 || >=20.5.0"
|
"node": "^18.17.0 || >=20.5.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/process-nextick-args": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/progress": {
|
"node_modules/progress": {
|
||||||
"version": "2.0.3",
|
"version": "2.0.3",
|
||||||
"resolved": "https://registry.npmmirror.com/progress/-/progress-2.0.3.tgz",
|
"resolved": "https://registry.npmmirror.com/progress/-/progress-2.0.3.tgz",
|
||||||
@@ -8696,6 +8789,13 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/setimmediate": {
|
||||||
|
"version": "1.0.5",
|
||||||
|
"resolved": "https://registry.npmmirror.com/setimmediate/-/setimmediate-1.0.5.tgz",
|
||||||
|
"integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/shebang-command": {
|
"node_modules/shebang-command": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmmirror.com/shebang-command/-/shebang-command-2.0.0.tgz",
|
"resolved": "https://registry.npmmirror.com/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||||
@@ -9497,6 +9597,18 @@
|
|||||||
"url": "https://paulmillr.com/funding/"
|
"url": "https://paulmillr.com/funding/"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/unzip-crx-3": {
|
||||||
|
"version": "0.2.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/unzip-crx-3/-/unzip-crx-3-0.2.0.tgz",
|
||||||
|
"integrity": "sha512-0+JiUq/z7faJ6oifVB5nSwt589v1KCduqIJupNVDoWSXZtWDmjDGO3RAEOvwJ07w90aoXoP4enKsR7ecMrJtWQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"jszip": "^3.1.0",
|
||||||
|
"mkdirp": "^0.5.1",
|
||||||
|
"yaku": "^0.16.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/update-browserslist-db": {
|
"node_modules/update-browserslist-db": {
|
||||||
"version": "1.2.3",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmmirror.com/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
|
"resolved": "https://registry.npmmirror.com/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
|
||||||
@@ -10449,6 +10561,13 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/yaku": {
|
||||||
|
"version": "0.16.7",
|
||||||
|
"resolved": "https://registry.npmmirror.com/yaku/-/yaku-0.16.7.tgz",
|
||||||
|
"integrity": "sha512-Syu3IB3rZvKvYk7yTiyl1bo/jiEFaaStrgv1V2TIJTqYPStSMQVO8EQjg/z+DRzLq/4LIIharNT3iH1hylEIRw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/yallist": {
|
"node_modules/yallist": {
|
||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmmirror.com/yallist/-/yallist-3.1.1.tgz",
|
"resolved": "https://registry.npmmirror.com/yallist/-/yallist-3.1.1.tgz",
|
||||||
|
|||||||
@@ -49,6 +49,7 @@
|
|||||||
"@vitejs/plugin-vue": "^6.0.2",
|
"@vitejs/plugin-vue": "^6.0.2",
|
||||||
"electron": "^39.2.6",
|
"electron": "^39.2.6",
|
||||||
"electron-builder": "^26.0.12",
|
"electron-builder": "^26.0.12",
|
||||||
|
"electron-devtools-installer": "^4.0.0",
|
||||||
"electron-vite": "^5.0.0",
|
"electron-vite": "^5.0.0",
|
||||||
"eslint": "^9.39.1",
|
"eslint": "^9.39.1",
|
||||||
"eslint-plugin-vue": "^10.6.2",
|
"eslint-plugin-vue": "^10.6.2",
|
||||||
|
|||||||
93
src/main/code-launchpad/code-launchpad.ts
Normal file
93
src/main/code-launchpad/code-launchpad.ts
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
import { BrowserWindow, screen, shell, Tray } from 'electron'
|
||||||
|
import { settingsManager } from '../settings'
|
||||||
|
import { codeLaunchpadIcon } from '../resources'
|
||||||
|
import path from 'path'
|
||||||
|
import { is } from '@electron-toolkit/utils'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建代码启动台窗口。
|
||||||
|
* @return 布尔值,表明创建是否成功
|
||||||
|
*/
|
||||||
|
export function createCodeLaunchpadWindow(closeOnBlur: boolean): boolean {
|
||||||
|
// 不允许重复创建
|
||||||
|
if (global.codeLaunchpadWindow !== null) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
const windowWidth = settingsManager._settings?.codeLaunchpadWidth
|
||||||
|
? settingsManager._settings?.codeLaunchpadWidth
|
||||||
|
: 460
|
||||||
|
const windowHeight = settingsManager._settings?.codeLaunchpadHeight
|
||||||
|
? settingsManager._settings?.codeLaunchpadHeight
|
||||||
|
: 760
|
||||||
|
const position = settingsManager._settings?.codeLaunchpadPosition
|
||||||
|
? settingsManager._settings.codeLaunchpadPosition
|
||||||
|
: 'left top'
|
||||||
|
|
||||||
|
const codeLaunchpadWindow = new BrowserWindow({
|
||||||
|
width: windowWidth,
|
||||||
|
height: windowHeight,
|
||||||
|
x:
|
||||||
|
position === 'left top' || position === 'left bottom'
|
||||||
|
? 0
|
||||||
|
: screen.getPrimaryDisplay().workArea.width - windowWidth,
|
||||||
|
y:
|
||||||
|
position === 'left top' || position === 'right top'
|
||||||
|
? 0
|
||||||
|
: screen.getPrimaryDisplay().workArea.height - windowHeight,
|
||||||
|
frame: false,
|
||||||
|
show: false,
|
||||||
|
autoHideMenuBar: true,
|
||||||
|
// 代码启动台需要置顶
|
||||||
|
alwaysOnTop: true,
|
||||||
|
resizable: false,
|
||||||
|
backgroundColor: '#1f1f1f',
|
||||||
|
icon: codeLaunchpadIcon,
|
||||||
|
webPreferences: {
|
||||||
|
preload: path.join(__dirname, '../preload/index.mjs'),
|
||||||
|
sandbox: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
codeLaunchpadWindow.on('ready-to-show', () => {
|
||||||
|
codeLaunchpadWindow.show()
|
||||||
|
})
|
||||||
|
|
||||||
|
// 如有必要,失去焦点时自动关闭
|
||||||
|
if (closeOnBlur) {
|
||||||
|
codeLaunchpadWindow.on('blur', () => {
|
||||||
|
codeLaunchpadWindow.close()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭代码启动台时
|
||||||
|
codeLaunchpadWindow.on('close', () => {
|
||||||
|
global.codeLaunchpadWindow = null
|
||||||
|
})
|
||||||
|
|
||||||
|
codeLaunchpadWindow.webContents.setWindowOpenHandler((details) => {
|
||||||
|
shell.openExternal(details.url)
|
||||||
|
return { action: 'deny' }
|
||||||
|
})
|
||||||
|
|
||||||
|
// 开发和生产环境的各自设置
|
||||||
|
if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
|
||||||
|
codeLaunchpadWindow.loadURL(process.env['ELECTRON_RENDERER_URL'] + '#/codeLaunchpad/IDEs')
|
||||||
|
} else {
|
||||||
|
codeLaunchpadWindow.loadFile(path.join(__dirname, '../renderer/index.html'), {
|
||||||
|
hash: '/codeLaunchpad/IDEs'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
global.codeLaunchpadWindow = codeLaunchpadWindow
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createCodeLaunchpadTray(): Tray {
|
||||||
|
const tray = new Tray(codeLaunchpadIcon)
|
||||||
|
|
||||||
|
tray.on('click', () => createCodeLaunchpadWindow(true))
|
||||||
|
|
||||||
|
return tray
|
||||||
|
}
|
||||||
@@ -6,11 +6,7 @@ import { loadJsonFile } from 'load-json-file'
|
|||||||
import { XMLParser } from 'fast-xml-parser'
|
import { XMLParser } from 'fast-xml-parser'
|
||||||
import { VSCodeGlobalStorageJson } from '@my-type/vscode-globalstorage-json'
|
import { VSCodeGlobalStorageJson } from '@my-type/vscode-globalstorage-json'
|
||||||
import { JetBrainsIdeOptionsRecentProjects } from '@my-type/jetbrains-ide-options-recentProjects'
|
import { JetBrainsIdeOptionsRecentProjects } from '@my-type/jetbrains-ide-options-recentProjects'
|
||||||
import {
|
import { JetBrainsIDEDisplayNameEnum, JetBrainsProductCode, toProductCode } from '@my-type/jetbrains-state-tools'
|
||||||
JetBrainsIDEDisplayNameEnum,
|
|
||||||
JetBrainsProductCode,
|
|
||||||
toProductCode
|
|
||||||
} from '@my-type/jetbrains-state-tools'
|
|
||||||
import { checkIDEsResultDto, IDECode } from '@my-type/settings'
|
import { checkIDEsResultDto, IDECode } from '@my-type/settings'
|
||||||
import { spawn } from 'node:child_process'
|
import { spawn } from 'node:child_process'
|
||||||
|
|
||||||
@@ -43,7 +39,7 @@ export async function getVscodeProjects(): Promise<IdeProjectsDto> {
|
|||||||
// 还有一种协议名是 vscode-remote:// 将会保留,以作为 VSCode Remote 的标识
|
// 还有一种协议名是 vscode-remote:// 将会保留,以作为 VSCode Remote 的标识
|
||||||
const path = decodeURIComponent(workspace[0]).replace('file:///', '')
|
const path = decodeURIComponent(workspace[0]).replace('file:///', '')
|
||||||
const name = <string>path.split('/').at(-1)
|
const name = <string>path.split('/').at(-1)
|
||||||
result.push({ name, path, ide: ['VSC'] })
|
result.push({ name, path, timestamp: 0, ide: ['VSC'] })
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
@@ -89,17 +85,42 @@ export async function getJetBrainsProjects(): Promise<IdeProjectsDto> {
|
|||||||
await fs.readFile(rpp, 'utf-8')
|
await fs.readFile(rpp, 'utf-8')
|
||||||
)
|
)
|
||||||
for (const datum of data.application.component.option) {
|
for (const datum of data.application.component.option) {
|
||||||
|
// 检索正确的 xml 路径
|
||||||
|
if (datum['@_name'] !== 'additionalInfo') continue
|
||||||
for (const entry of datum.map.entry) {
|
for (const entry of datum.map.entry) {
|
||||||
const name = <string>entry.value.RecentProjectMetaInfo['@_frameTitle'].split(' – ').at(0)
|
const name = <string>entry.value.RecentProjectMetaInfo['@_frameTitle'].split(' – ').at(0)
|
||||||
const path = entry['@_key'].replace('$USER_HOME$', os.homedir())
|
const path = entry['@_key'].replace('$USER_HOME$', os.homedir())
|
||||||
|
// 项目的上次打开时间 projectOpenTimestamp 是一个时间戳,这里提供默认值 0 表示来自 1970 年的上古项目
|
||||||
|
let timestamp = 0
|
||||||
|
for (const option of entry.value.RecentProjectMetaInfo.option) {
|
||||||
|
if (option['@_name'] === 'projectOpenTimestamp') {
|
||||||
|
timestamp = Number(option['@_value'])
|
||||||
|
}
|
||||||
|
}
|
||||||
// 认为包含此(安装/设置?)目录的是未保存的编辑,例如 light-edit 模式
|
// 认为包含此(安装/设置?)目录的是未保存的编辑,例如 light-edit 模式
|
||||||
// 正常来说不会在这样的目录下保存项目的……吧?而且俺寻思 IDE 用这种变量的话也不像是人为刻意保存到此目录。
|
// 正常来说不会在这样的目录下保存项目的……吧?而且俺寻思 IDE 用这种变量的话也不像是人为刻意保存到此目录。
|
||||||
if (path.includes('$APPLICATION_CONFIG_DIR$/')) continue
|
if (path.includes('$APPLICATION_CONFIG_DIR$/')) continue
|
||||||
result.push({
|
// 去重。
|
||||||
name,
|
let pass = false
|
||||||
path,
|
for (const resultElement of result) {
|
||||||
ide: [ide]
|
// 如果路径已存在,即此项目被用其他 JetBrains IDE 打开过
|
||||||
})
|
if (resultElement.path === path) {
|
||||||
|
// 如果 IDE 与该项目已有的工作 IDE 不同,就把这个 IDE 加进列表里去
|
||||||
|
if (!resultElement.ide.includes(ide)) {
|
||||||
|
resultElement.ide.push(ide)
|
||||||
|
}
|
||||||
|
// 如果 IDE 也重复了就忽略,然后直接
|
||||||
|
pass = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!pass) {
|
||||||
|
result.push({
|
||||||
|
name,
|
||||||
|
path,
|
||||||
|
timestamp,
|
||||||
|
ide: [ide]
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
|
|||||||
@@ -6,18 +6,16 @@ import type {
|
|||||||
IDECode
|
IDECode
|
||||||
} from '@my-type/settings'
|
} from '@my-type/settings'
|
||||||
import { execSync } from 'node:child_process'
|
import { execSync } from 'node:child_process'
|
||||||
import { BrowserWindow, screen, shell, Tray } from 'electron'
|
|
||||||
import { is } from '@electron-toolkit/utils'
|
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import { loadJsonFile } from 'load-json-file'
|
import { loadJsonFile } from 'load-json-file'
|
||||||
import os from 'os'
|
import os from 'os'
|
||||||
import {
|
import {
|
||||||
JetBrainsIDEDisplayNameEnum as JIN,
|
JetBrainsIDEDisplayNameEnum as JIN,
|
||||||
JetBrainsProductCode,
|
JetBrainsProductCode,
|
||||||
JetBrainsStateDto
|
JetBrainsStateDto,
|
||||||
|
toProductDisplayName
|
||||||
} from '@my-type/jetbrains-state-tools'
|
} from '@my-type/jetbrains-state-tools'
|
||||||
import { settingsManager } from '../settings'
|
import { settingsManager } from '../settings'
|
||||||
import { codeLaunchpadIcon } from '../resources'
|
|
||||||
import { isNodeError } from '@my-type/node-error'
|
import { isNodeError } from '@my-type/node-error'
|
||||||
import { JetBrainsDataProductDto } from '@my-type/jetbrains-data-products'
|
import { JetBrainsDataProductDto } from '@my-type/jetbrains-data-products'
|
||||||
|
|
||||||
@@ -140,20 +138,20 @@ async function checkVSCodeVersion(): Promise<checkIDEVersionDto> {
|
|||||||
*/
|
*/
|
||||||
export async function checkJetBrainsIDEsVersion(): Promise<checkIDEsVersionDto> {
|
export async function checkJetBrainsIDEsVersion(): Promise<checkIDEsVersionDto> {
|
||||||
// 构建数据结构的辅助函数
|
// 构建数据结构的辅助函数
|
||||||
const _ = (display: string, code: JetBrainsProductCode): checkIDEVersionDto => {
|
const _ = (code: JetBrainsProductCode): checkIDEVersionDto => {
|
||||||
return {
|
return {
|
||||||
code,
|
code,
|
||||||
display,
|
display: toProductDisplayName(code) as string,
|
||||||
install: 'unknown',
|
install: 'unknown',
|
||||||
latest: 'unknown'
|
latest: 'unknown'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const result: checkIDEsVersionDto = {
|
const result: checkIDEsVersionDto = {
|
||||||
PY: _('pycharm', 'PY'),
|
PY: _('PY'),
|
||||||
CL: _('clion', 'CL'),
|
CL: _('CL'),
|
||||||
WS: _('webstorm', 'WS'),
|
WS: _('WS'),
|
||||||
PS: _('phpstorm', 'PS'),
|
PS: _('PS'),
|
||||||
IU: _('idea', 'IU')
|
IU: _('IU')
|
||||||
}
|
}
|
||||||
|
|
||||||
// 尝试从 JBTState.json 获取已安装的 JetBrains IDEs 的版本
|
// 尝试从 JBTState.json 获取已安装的 JetBrains IDEs 的版本
|
||||||
@@ -233,91 +231,3 @@ export async function checkIDEsVersion(): Promise<checkIDEsVersionDto> {
|
|||||||
global.installedIDEsVersion = result
|
global.installedIDEsVersion = result
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建代码启动台窗口。
|
|
||||||
* @return 布尔值,表明创建是否成功
|
|
||||||
*/
|
|
||||||
export function createCodeLaunchpadWindow(closeOnBlur: boolean): boolean {
|
|
||||||
// 不允许重复创建
|
|
||||||
if (global.codeLaunchpadWindow !== null) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
const windowWidth = settingsManager._settings?.codeLaunchpadWidth
|
|
||||||
? settingsManager._settings?.codeLaunchpadWidth
|
|
||||||
: 460
|
|
||||||
const windowHeight = settingsManager._settings?.codeLaunchpadHeight
|
|
||||||
? settingsManager._settings?.codeLaunchpadHeight
|
|
||||||
: 760
|
|
||||||
const position = settingsManager._settings?.codeLaunchpadPosition
|
|
||||||
? settingsManager._settings.codeLaunchpadPosition
|
|
||||||
: 'left top'
|
|
||||||
|
|
||||||
const codeLaunchpadWindow = new BrowserWindow({
|
|
||||||
width: windowWidth,
|
|
||||||
height: windowHeight,
|
|
||||||
x:
|
|
||||||
position === 'left top' || position === 'left bottom'
|
|
||||||
? 0
|
|
||||||
: screen.getPrimaryDisplay().workArea.width - windowWidth,
|
|
||||||
y:
|
|
||||||
position === 'left top' || position === 'right top'
|
|
||||||
? 0
|
|
||||||
: screen.getPrimaryDisplay().workArea.height - windowHeight,
|
|
||||||
frame: false,
|
|
||||||
show: false,
|
|
||||||
autoHideMenuBar: true,
|
|
||||||
// 代码启动台需要置顶
|
|
||||||
alwaysOnTop: true,
|
|
||||||
resizable: false,
|
|
||||||
backgroundColor: '#1f1f1f',
|
|
||||||
icon: codeLaunchpadIcon,
|
|
||||||
webPreferences: {
|
|
||||||
preload: path.join(__dirname, '../preload/index.mjs'),
|
|
||||||
sandbox: false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
codeLaunchpadWindow.on('ready-to-show', () => {
|
|
||||||
codeLaunchpadWindow.show()
|
|
||||||
})
|
|
||||||
|
|
||||||
// 如有必要,失去焦点时自动关闭
|
|
||||||
if (closeOnBlur) {
|
|
||||||
codeLaunchpadWindow.on('blur', () => {
|
|
||||||
codeLaunchpadWindow.close()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 关闭代码启动台时
|
|
||||||
codeLaunchpadWindow.on('close', () => {
|
|
||||||
global.codeLaunchpadWindow = null
|
|
||||||
})
|
|
||||||
|
|
||||||
codeLaunchpadWindow.webContents.setWindowOpenHandler((details) => {
|
|
||||||
shell.openExternal(details.url)
|
|
||||||
return { action: 'deny' }
|
|
||||||
})
|
|
||||||
|
|
||||||
// 开发和生产环境的各自设置
|
|
||||||
if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
|
|
||||||
codeLaunchpadWindow.loadURL(process.env['ELECTRON_RENDERER_URL'] + '#/codeLaunchpad/IDEs')
|
|
||||||
} else {
|
|
||||||
codeLaunchpadWindow.loadFile(path.join(__dirname, '../renderer/index.html'), {
|
|
||||||
hash: '/codeLaunchpad/IDEs'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
global.codeLaunchpadWindow = codeLaunchpadWindow
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createCodeLaunchpadTray(): Tray {
|
|
||||||
const tray = new Tray(codeLaunchpadIcon)
|
|
||||||
|
|
||||||
tray.on('click', () => createCodeLaunchpadWindow(true))
|
|
||||||
|
|
||||||
return tray
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -4,14 +4,15 @@ import { saveSettingsToLocal, updateSettingsFromLocal } from './settings'
|
|||||||
import {
|
import {
|
||||||
checkIDEs,
|
checkIDEs,
|
||||||
checkIDEsVersion,
|
checkIDEsVersion,
|
||||||
createCodeLaunchpadTray,
|
|
||||||
createCodeLaunchpadWindow,
|
|
||||||
getIDEs,
|
getIDEs,
|
||||||
getIDEsVersion
|
getIDEsVersion
|
||||||
} from './code-launchpad/ide-versions-check'
|
} from './code-launchpad/ide-versions-check'
|
||||||
import { fanToolsIcon } from './resources'
|
import { fanToolsIcon } from './resources'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import { getJetBrainsProjects, getVscodeProjects, openProject } from './code-launchpad/ide-projects'
|
import { getJetBrainsProjects, getVscodeProjects, openProject } from './code-launchpad/ide-projects'
|
||||||
|
import { createCodeLaunchpadTray, createCodeLaunchpadWindow } from './code-launchpad/code-launchpad'
|
||||||
|
import type { IDECode } from '@my-type/settings'
|
||||||
|
import installExtension, { VUEJS_DEVTOOLS } from 'electron-devtools-installer'
|
||||||
|
|
||||||
let mainWindow: BrowserWindow | null = null
|
let mainWindow: BrowserWindow | null = null
|
||||||
// @ts-ignore 保存引用,禁用报错
|
// @ts-ignore 保存引用,禁用报错
|
||||||
@@ -31,6 +32,7 @@ function createWindow(): BrowserWindow {
|
|||||||
show: false,
|
show: false,
|
||||||
autoHideMenuBar: true,
|
autoHideMenuBar: true,
|
||||||
backgroundColor: '#1f1f1f',
|
backgroundColor: '#1f1f1f',
|
||||||
|
frame: false,
|
||||||
icon: fanToolsIcon,
|
icon: fanToolsIcon,
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
preload: path.join(__dirname, '../preload/index.mjs'),
|
preload: path.join(__dirname, '../preload/index.mjs'),
|
||||||
@@ -97,6 +99,14 @@ app.whenReady().then(async () => {
|
|||||||
// Set app user model id for windows
|
// Set app user model id for windows
|
||||||
electronApp.setAppUserModelId('com.electron')
|
electronApp.setAppUserModelId('com.electron')
|
||||||
|
|
||||||
|
// 安装 DevTools 插件
|
||||||
|
if (is.dev) {
|
||||||
|
// 安装Vue DevTools
|
||||||
|
installExtension(VUEJS_DEVTOOLS)
|
||||||
|
.then((name) => console.log(`已安装扩展: ${name}`))
|
||||||
|
.catch((err) => console.log('安装失败:', err))
|
||||||
|
}
|
||||||
|
|
||||||
// Default open or close DevTools by F12 in development
|
// Default open or close DevTools by F12 in development
|
||||||
// and ignore CommandOrControl + R in production.
|
// and ignore CommandOrControl + R in production.
|
||||||
// see https://github.com/alex8088/electron-toolkit/tree/master/packages/utils
|
// see https://github.com/alex8088/electron-toolkit/tree/master/packages/utils
|
||||||
@@ -125,13 +135,26 @@ app.whenReady().then(async () => {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
|
ipcMain.handle('window:minimize', () => {
|
||||||
|
mainWindow?.minimize()
|
||||||
|
})
|
||||||
|
ipcMain.handle('window:maximize', () => {
|
||||||
|
if (mainWindow?.isMaximized()) {
|
||||||
|
mainWindow?.unmaximize()
|
||||||
|
} else {
|
||||||
|
mainWindow?.maximize()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
ipcMain.handle('window:closeWindow', () => {
|
||||||
|
mainWindow?.hide()
|
||||||
|
})
|
||||||
ipcMain.handle('codeLaunchpad:getIDEs', getIDEs)
|
ipcMain.handle('codeLaunchpad:getIDEs', getIDEs)
|
||||||
ipcMain.handle('codeLaunchpad:checkIDEs', checkIDEs)
|
ipcMain.handle('codeLaunchpad:checkIDEs', checkIDEs)
|
||||||
ipcMain.handle('codeLaunchpad:getIDEsVersion', getIDEsVersion)
|
ipcMain.handle('codeLaunchpad:getIDEsVersion', getIDEsVersion)
|
||||||
ipcMain.handle('codeLaunchpad:checkIDEsVersion', checkIDEsVersion)
|
ipcMain.handle('codeLaunchpad:checkIDEsVersion', checkIDEsVersion)
|
||||||
ipcMain.handle('codeLaunchpad:getVSCodeProjects', getVscodeProjects)
|
ipcMain.handle('codeLaunchpad:getVSCodeProjects', getVscodeProjects)
|
||||||
ipcMain.handle('codeLaunchpad:getJetBrainsProjects', getJetBrainsProjects)
|
ipcMain.handle('codeLaunchpad:getJetBrainsProjects', getJetBrainsProjects)
|
||||||
ipcMain.handle('codeLaunchpad:openProject', (_, ide: string, path: string) => {
|
ipcMain.handle('codeLaunchpad:openProject', (_, ide: IDECode, path: string) => {
|
||||||
return openProject(ide, path)
|
return openProject(ide, path)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
11
src/my-type/dataFormatter.ts
Normal file
11
src/my-type/dataFormatter.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
export const formatTimestamp = (timestamp: number, locale = 'zh-CN'): string => {
|
||||||
|
return new Date(timestamp).toLocaleString(locale, {
|
||||||
|
year: 'numeric',
|
||||||
|
month: '2-digit',
|
||||||
|
day: '2-digit',
|
||||||
|
hour: '2-digit',
|
||||||
|
minute: '2-digit',
|
||||||
|
second: '2-digit',
|
||||||
|
hour12: false
|
||||||
|
})
|
||||||
|
}
|
||||||
1
src/my-type/ide-projects.d.ts
vendored
1
src/my-type/ide-projects.d.ts
vendored
@@ -5,6 +5,7 @@ type Ide = JetBrainsProductCode | 'VSC'
|
|||||||
export interface IdeProjectDto {
|
export interface IdeProjectDto {
|
||||||
name: string
|
name: string
|
||||||
path: string
|
path: string
|
||||||
|
timestamp: number
|
||||||
ide: Ide[]
|
ide: Ide[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,23 +1,29 @@
|
|||||||
// 这些数据结构是由 XMLParser 解析成的 Javascript 对象,解析设置允许属性。
|
// 这些数据结构是由 XMLParser 解析成的 Javascript 对象,解析设置允许属性。
|
||||||
// 不完整,因为我也看不懂很多东西是干嘛用的,写完整了也用不到,所以把用到的定义一下就酱了
|
// 不完整,因为我也看不懂很多东西是干嘛用的,写完整了也用不到,所以把用到的定义一下就酱了
|
||||||
|
|
||||||
export interface RecentProjectMetaInfo {
|
|
||||||
option: []
|
|
||||||
frame: object
|
|
||||||
'@_frameTitle': string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface JetBrainsIdeOptionsRecentProjects {
|
export interface JetBrainsIdeOptionsRecentProjects {
|
||||||
application: {
|
application: {
|
||||||
component: {
|
component: {
|
||||||
option: [
|
option: [
|
||||||
|
{
|
||||||
|
'@_name': 'activationTimestamp'
|
||||||
|
'@_value': string
|
||||||
|
},
|
||||||
{
|
{
|
||||||
map: {
|
map: {
|
||||||
entry: {
|
entry: {
|
||||||
value: { RecentProjectMetaInfo: RecentProjectMetaInfo }
|
value: {
|
||||||
|
RecentProjectMetaInfo: {
|
||||||
|
// option 中还有很多东西,这里只有我们需要的
|
||||||
|
option: [{ '@_name': 'projectOpenTimestamp'; '@_value': string }]
|
||||||
|
frame: object
|
||||||
|
'@_frameTitle': string
|
||||||
|
}
|
||||||
|
}
|
||||||
'@_key': string
|
'@_key': string
|
||||||
}[]
|
}[]
|
||||||
}
|
}
|
||||||
|
'@_name': 'additionalInfo'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
'@_name': 'RecentProjectsManager'
|
'@_name': 'RecentProjectsManager'
|
||||||
|
|||||||
3
src/preload/index.d.ts
vendored
3
src/preload/index.d.ts
vendored
@@ -13,6 +13,9 @@ declare global {
|
|||||||
_updateSettings: () => Promise<settingsDto>
|
_updateSettings: () => Promise<settingsDto>
|
||||||
_openCodeLaunchpad: () => Promise<boolean>
|
_openCodeLaunchpad: () => Promise<boolean>
|
||||||
_closeCodeLaunchpad: () => Promise<boolean>
|
_closeCodeLaunchpad: () => Promise<boolean>
|
||||||
|
_minimize: () => Promise<void>
|
||||||
|
_maximize: () => Promise<void>
|
||||||
|
_closeWindow: () => Promise<void>
|
||||||
}
|
}
|
||||||
codeLaunchpad: {
|
codeLaunchpad: {
|
||||||
_getIDEs: () => Promise<checkIDEsResultDto>
|
_getIDEs: () => Promise<checkIDEsResultDto>
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
// noinspection JSUnusedGlobalSymbols
|
||||||
|
|
||||||
import { contextBridge, ipcRenderer } from 'electron'
|
import { contextBridge, ipcRenderer } from 'electron'
|
||||||
import { electronAPI } from '@electron-toolkit/preload'
|
import { electronAPI } from '@electron-toolkit/preload'
|
||||||
import { settingsDto } from '@my-type/settings'
|
import { settingsDto } from '@my-type/settings'
|
||||||
@@ -8,7 +10,10 @@ const api = {
|
|||||||
_saveSettings: (settings: settingsDto) => ipcRenderer.invoke('settings:save', settings),
|
_saveSettings: (settings: settingsDto) => ipcRenderer.invoke('settings:save', settings),
|
||||||
_updateSettings: () => ipcRenderer.invoke('settings:update'),
|
_updateSettings: () => ipcRenderer.invoke('settings:update'),
|
||||||
_openCodeLaunchpad: () => ipcRenderer.invoke('tools:openCodeLaunchpad'),
|
_openCodeLaunchpad: () => ipcRenderer.invoke('tools:openCodeLaunchpad'),
|
||||||
_closeCodeLaunchpad: () => ipcRenderer.invoke('tools:closeCodeLaunchpad')
|
_closeCodeLaunchpad: () => ipcRenderer.invoke('tools:closeCodeLaunchpad'),
|
||||||
|
_minimize: () => ipcRenderer.invoke('window:minimize'),
|
||||||
|
_maximize: () => ipcRenderer.invoke('window:maximize'),
|
||||||
|
_closeWindow: () => ipcRenderer.invoke('window:closeWindow')
|
||||||
}
|
}
|
||||||
|
|
||||||
const codeLaunchpadApi = {
|
const codeLaunchpadApi = {
|
||||||
|
|||||||
2
src/renderer/components.d.ts
vendored
2
src/renderer/components.d.ts
vendored
@@ -17,6 +17,7 @@ declare module 'vue' {
|
|||||||
DetectedIDECard: typeof import('./src/components/DetectedIDECard.vue')['default']
|
DetectedIDECard: typeof import('./src/components/DetectedIDECard.vue')['default']
|
||||||
DetectedIDECardList: typeof import('./src/components/DetectedIDECardList.vue')['default']
|
DetectedIDECardList: typeof import('./src/components/DetectedIDECardList.vue')['default']
|
||||||
NAlert: typeof import('naive-ui')['NAlert']
|
NAlert: typeof import('naive-ui')['NAlert']
|
||||||
|
NavigatorBar: typeof import('./src/components/NavigatorBar.vue')['default']
|
||||||
NButton: typeof import('naive-ui')['NButton']
|
NButton: typeof import('naive-ui')['NButton']
|
||||||
NButtonGroup: typeof import('naive-ui')['NButtonGroup']
|
NButtonGroup: typeof import('naive-ui')['NButtonGroup']
|
||||||
NCard: typeof import('naive-ui')['NCard']
|
NCard: typeof import('naive-ui')['NCard']
|
||||||
@@ -37,6 +38,7 @@ declare module 'vue' {
|
|||||||
NInputNumber: typeof import('naive-ui')['NInputNumber']
|
NInputNumber: typeof import('naive-ui')['NInputNumber']
|
||||||
NMenu: typeof import('naive-ui')['NMenu']
|
NMenu: typeof import('naive-ui')['NMenu']
|
||||||
NMessageProvider: typeof import('naive-ui')['NMessageProvider']
|
NMessageProvider: typeof import('naive-ui')['NMessageProvider']
|
||||||
|
NModal: typeof import('naive-ui')['NModal']
|
||||||
NP: typeof import('naive-ui')['NP']
|
NP: typeof import('naive-ui')['NP']
|
||||||
NSelect: typeof import('naive-ui')['NSelect']
|
NSelect: typeof import('naive-ui')['NSelect']
|
||||||
NSpace: typeof import('naive-ui')['NSpace']
|
NSpace: typeof import('naive-ui')['NSpace']
|
||||||
|
|||||||
@@ -1,39 +1,57 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import SidebarRouter from '@renderer/components/SidebarRouter.vue'
|
import SidebarRouter from '@renderer/components/SidebarRouter.vue'
|
||||||
import SaveSettingsButton from '@renderer/components/SaveSettingsButton.vue'
|
import SaveSettingsButton from '@renderer/components/SaveSettingsButton.vue'
|
||||||
|
import NavigatorBar from '@renderer/components/NavigatorBar.vue'
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="everything-container">
|
<div class="main-app-container">
|
||||||
<div class="sidebar-router-container scrollarea">
|
<div class="navigator-bar">
|
||||||
<SidebarRouter />
|
<NavigatorBar />
|
||||||
</div>
|
</div>
|
||||||
<div class="content-container scrollarea">
|
<div class="everything-container">
|
||||||
<n-message-provider placement="bottom">
|
<div class="sidebar-router-container scrollarea">
|
||||||
<RouterView />
|
<SidebarRouter />
|
||||||
<SaveSettingsButton />
|
</div>
|
||||||
</n-message-provider>
|
<div class="content-container scrollarea">
|
||||||
|
<n-message-provider placement="bottom">
|
||||||
|
<RouterView />
|
||||||
|
<SaveSettingsButton />
|
||||||
|
</n-message-provider>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
div.everything-container {
|
div.main-app-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: column;
|
||||||
overflow: hidden;
|
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
div.sidebar-router-container {
|
div.navigator-bar {
|
||||||
flex: 0;
|
padding: 8px;
|
||||||
min-width: 200px;
|
-webkit-app-region: drag;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.content-container {
|
div.everything-container {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
padding: 20px 10px 20px 0;
|
display: flex;
|
||||||
overflow-x: hidden;
|
flex-direction: row;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
div.sidebar-router-container {
|
||||||
|
flex: 0;
|
||||||
|
min-width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.content-container {
|
||||||
|
flex: 1;
|
||||||
|
padding: 20px 10px 20px 0;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -10,8 +10,24 @@ body {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.no-padding {
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.small-padding {
|
||||||
|
padding: 10px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-padding-top {
|
||||||
|
padding-top: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-margin-top {
|
||||||
|
margin-top: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
.no-margin-bottom {
|
.no-margin-bottom {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 滚动区域
|
// 滚动区域
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { EllipsisHorizontalSharp as EllipsisIcon } from '@vicons/ionicons5'
|
|||||||
import type { IdeProjectDto } from '@my-type/ide-projects'
|
import type { IdeProjectDto } from '@my-type/ide-projects'
|
||||||
import { toProductDisplayName } from '@my-type/jetbrains-state-tools'
|
import { toProductDisplayName } from '@my-type/jetbrains-state-tools'
|
||||||
import { useMessage } from 'naive-ui'
|
import { useMessage } from 'naive-ui'
|
||||||
|
import { formatTimestamp } from '@my-type/dataFormatter'
|
||||||
|
|
||||||
const message = useMessage()
|
const message = useMessage()
|
||||||
|
|
||||||
@@ -67,11 +68,11 @@ async function openWithIDE(ide: string): Promise<void> {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<n-card>
|
<n-card content-class="no-padding" footer-class="no-padding-top small-padding">
|
||||||
<template #default>
|
<template #default>
|
||||||
<div @click="() => (showDetail = true)">
|
<div class="click-area" @click="() => (showDetail = true)">
|
||||||
<n-flex justify="left">
|
<n-flex justify="left">
|
||||||
<n-h4>{{ project.name }}</n-h4>
|
<n-h4 class="no-margin-bottom">{{ project.name }}</n-h4>
|
||||||
<n-tag v-for="tag in ideTags" :key="tag" round :type="tag === 'WSL' ? 'primary' : 'info'">
|
<n-tag v-for="tag in ideTags" :key="tag" round :type="tag === 'WSL' ? 'primary' : 'info'">
|
||||||
{{ tag }}
|
{{ tag }}
|
||||||
</n-tag>
|
</n-tag>
|
||||||
@@ -80,29 +81,48 @@ async function openWithIDE(ide: string): Promise<void> {
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template v-if="showDetail" #footer>
|
<template v-if="showDetail" #footer>
|
||||||
<n-flex>
|
<n-flex vertical>
|
||||||
<n-button-group>
|
<n-p v-if="project.timestamp !== 0" class="no-margin-bottom" type="default">
|
||||||
<n-button
|
上次打开于 {{ formatTimestamp(project.timestamp) }}
|
||||||
v-for="ide in project.ide"
|
</n-p>
|
||||||
:key="ide"
|
<n-flex>
|
||||||
round
|
<n-button-group>
|
||||||
type="info"
|
<n-button
|
||||||
@click="() => openWithIDE(ide)"
|
v-for="ide in project.ide"
|
||||||
>
|
:key="ide"
|
||||||
用 {{ ide === 'VSC' ? 'VS Code' : toProductDisplayName(ide) }} 打开
|
round
|
||||||
</n-button>
|
type="info"
|
||||||
<n-dropdown trigger="click" :options @select="(key) => openWithIDE(key as string)">
|
size="small"
|
||||||
<n-button type="info" circle>
|
@click="() => openWithIDE(ide)"
|
||||||
<n-icon>
|
>
|
||||||
<EllipsisIcon />
|
用 {{ ide === 'VSC' ? 'VS Code' : toProductDisplayName(ide) }} 打开
|
||||||
</n-icon>
|
|
||||||
</n-button>
|
</n-button>
|
||||||
</n-dropdown>
|
<n-dropdown trigger="click" :options @select="(key) => openWithIDE(key as string)">
|
||||||
</n-button-group>
|
<n-button type="info" circle size="small">
|
||||||
<n-button round secondary type="primary" @click="() => (showDetail = false)">收起</n-button>
|
<n-icon>
|
||||||
|
<EllipsisIcon />
|
||||||
|
</n-icon>
|
||||||
|
</n-button>
|
||||||
|
</n-dropdown>
|
||||||
|
</n-button-group>
|
||||||
|
<n-button round secondary type="primary" size="small" @click="() => (showDetail = false)">
|
||||||
|
收起
|
||||||
|
</n-button>
|
||||||
|
</n-flex>
|
||||||
</n-flex>
|
</n-flex>
|
||||||
</template>
|
</template>
|
||||||
</n-card>
|
</n-card>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped>
|
||||||
|
div.click-area {
|
||||||
|
padding: 10px;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
border-radius: 4px;
|
||||||
|
transition: border-color 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.click-area:hover {
|
||||||
|
border: 1px solid #74c072;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
70
src/renderer/src/components/NavigatorBar.vue
Normal file
70
src/renderer/src/components/NavigatorBar.vue
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { CloseOutline as CloseIcon } from '@vicons/ionicons5'
|
||||||
|
import { CropSquareOutlined as FullScreenIcon } from '@vicons/material'
|
||||||
|
import { ArrowMinimize20Filled as HideIcon } from '@vicons/fluent'
|
||||||
|
|
||||||
|
function minimize(): void {
|
||||||
|
window.api._minimize()
|
||||||
|
}
|
||||||
|
|
||||||
|
function maximize(): void {
|
||||||
|
window.api._maximize()
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeWindow(): void {
|
||||||
|
window.api._closeWindow()
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="title-bar">
|
||||||
|
<div class="title">
|
||||||
|
<n-text strong type="info">芒果工具箱 FanTools</n-text>
|
||||||
|
</div>
|
||||||
|
<div class="button-group">
|
||||||
|
<n-flex justify="right" align="center" class="no-drag">
|
||||||
|
<n-button circle type="default" size="small" @click="minimize()">
|
||||||
|
<n-icon size="large">
|
||||||
|
<HideIcon />
|
||||||
|
</n-icon>
|
||||||
|
</n-button>
|
||||||
|
<n-button circle type="warning" size="small" @click="maximize()">
|
||||||
|
<n-icon size="large">
|
||||||
|
<FullScreenIcon />
|
||||||
|
</n-icon>
|
||||||
|
</n-button>
|
||||||
|
<n-button circle type="error" size="small" @click="closeWindow()">
|
||||||
|
<n-icon size="large">
|
||||||
|
<CloseIcon />
|
||||||
|
</n-icon>
|
||||||
|
</n-button>
|
||||||
|
</n-flex>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.no-drag {
|
||||||
|
-webkit-app-region: no-drag;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.title-bar {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
|
||||||
|
div.title {
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
align-content: center;
|
||||||
|
font-size: 16px;
|
||||||
|
background-color: rgb(57 57 57 / 0.4);
|
||||||
|
border: 1px solid #8cb0bc;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.button-group {
|
||||||
|
flex: 0;
|
||||||
|
min-width: 120px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -2,11 +2,12 @@
|
|||||||
import ProjectCard from '@renderer/components-code-launchpad/ProjectCard.vue'
|
import ProjectCard from '@renderer/components-code-launchpad/ProjectCard.vue'
|
||||||
import { useProjects } from '@renderer/stores'
|
import { useProjects } from '@renderer/stores'
|
||||||
import { computed, onMounted, ref } from 'vue'
|
import { computed, onMounted, ref } from 'vue'
|
||||||
import { RefreshOutline as RefreshIcon } from '@vicons/ionicons5'
|
import { AlertOutline as AlertIcon, RefreshOutline as RefreshIcon } from '@vicons/ionicons5'
|
||||||
|
|
||||||
const projects = useProjects()
|
const projects = useProjects()
|
||||||
|
|
||||||
const ide = ref<'VSCode' | 'JetBrains'>('VSCode')
|
const ide = ref<'VSCode' | 'JetBrains'>('VSCode')
|
||||||
|
const showModal = ref(false)
|
||||||
|
|
||||||
// 此 switch-case 结构已经触及所有情况
|
// 此 switch-case 结构已经触及所有情况
|
||||||
// eslint-disable-next-line vue/return-in-computed-property
|
// eslint-disable-next-line vue/return-in-computed-property
|
||||||
@@ -15,7 +16,7 @@ const reverseProjects = computed(() => {
|
|||||||
case 'VSCode':
|
case 'VSCode':
|
||||||
return projects.vscodeProjects.toReversed()
|
return projects.vscodeProjects.toReversed()
|
||||||
case 'JetBrains':
|
case 'JetBrains':
|
||||||
return projects.jetBrainsProjects.toReversed()
|
return projects.jetBrainsProjects.toSorted((a, b) => (a.timestamp > b.timestamp ? -1 : 1))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -32,10 +33,12 @@ onMounted(() => {
|
|||||||
<template>
|
<template>
|
||||||
<n-flex>
|
<n-flex>
|
||||||
<n-button-group class="ide-button-group">
|
<n-button-group class="ide-button-group">
|
||||||
<n-button type="primary" secondary round @click="() => (ide = 'VSCode')">VS Code</n-button>
|
<n-button type="primary" secondary round @click="() => (ide = 'VSCode')">
|
||||||
<n-button type="primary" secondary round @click="() => (ide = 'JetBrains')"
|
<n-text :strong="ide === 'VSCode'" type="success">VS Code</n-text>
|
||||||
>JetBrains</n-button
|
</n-button>
|
||||||
>
|
<n-button type="primary" secondary round @click="() => (ide = 'JetBrains')">
|
||||||
|
<n-text :strong="ide === 'JetBrains'" type="success">JetBrains</n-text>
|
||||||
|
</n-button>
|
||||||
</n-button-group>
|
</n-button-group>
|
||||||
<n-button
|
<n-button
|
||||||
type="primary"
|
type="primary"
|
||||||
@@ -52,12 +55,38 @@ onMounted(() => {
|
|||||||
<RefreshIcon />
|
<RefreshIcon />
|
||||||
</n-icon>
|
</n-icon>
|
||||||
</n-button>
|
</n-button>
|
||||||
|
<n-button type="default" secondary circle @click="() => (showModal = true)">
|
||||||
|
<n-icon>
|
||||||
|
<AlertIcon />
|
||||||
|
</n-icon>
|
||||||
|
</n-button>
|
||||||
</n-flex>
|
</n-flex>
|
||||||
<n-flex size="small" vertical>
|
<n-flex size="small" vertical>
|
||||||
<div v-for="project of reverseProjects" :key="project.path" class="project-card">
|
<div v-for="project of reverseProjects" :key="project.path" class="project-card">
|
||||||
<ProjectCard :project />
|
<ProjectCard :project />
|
||||||
</div>
|
</div>
|
||||||
</n-flex>
|
</n-flex>
|
||||||
|
|
||||||
|
<n-modal v-model:show="showModal" preset="card" title="管理项目?">
|
||||||
|
<n-p>
|
||||||
|
代码启动台仅在此罗列找到的项目。
|
||||||
|
<n-text type="warning" strong>您无法在这里管理、删除某个项目。</n-text>
|
||||||
|
</n-p>
|
||||||
|
<n-p>
|
||||||
|
你可以在这里选择用其他 IDE 打开一个项目,但是并非所有 IDE 都支持某些特殊 URI 的项目。 例如,
|
||||||
|
<n-code inline>vscode-remote://</n-code>
|
||||||
|
协议是
|
||||||
|
<n-text strong type="info">VS Code 远程项目</n-text>
|
||||||
|
的协议,你无法使用 JetBrains IDEs 打开此协议的项目,哪怕它们可能运行在
|
||||||
|
<n-text type="success" strong>WSL</n-text>
|
||||||
|
中。
|
||||||
|
</n-p>
|
||||||
|
<template #footer>
|
||||||
|
<a href="https://gitea.mangofanfan.cn/MangoFanFanw/FanTools/wiki" target="_blank">
|
||||||
|
<n-button secondary type="primary">在 FanTools.wiki 中查看</n-button>
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
|
</n-modal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<n-h1 prefix="bar"><n-text type="success">FanTools - 芒果工具箱</n-text></n-h1>
|
<n-h1 prefix="bar"><n-text type="success">FanTools - 芒果工具箱</n-text></n-h1>
|
||||||
<n-h2>主页</n-h2>
|
<n-h2>主页</n-h2>
|
||||||
|
<n-h3>简介</n-h3>
|
||||||
<n-p
|
<n-p
|
||||||
>FanTools,或者,芒果工具箱,是一个使用 Electron 技术开发的 Windows
|
>FanTools,或者,芒果工具箱,是一个使用 Electron 技术开发的 Windows
|
||||||
桌面应用程序,提供一些工具功能,从名称上也能看得出来。</n-p
|
桌面应用程序,提供一些工具功能,从名称上也能看得出来。</n-p
|
||||||
@@ -12,4 +13,12 @@
|
|||||||
>窗口右下角的浮动按钮是<n-text strong type="success">保存</n-text
|
>窗口右下角的浮动按钮是<n-text strong type="success">保存</n-text
|
||||||
>!设置需要保存之后才能生效,部分设置还需要重启工具箱来生效。如果你改动了设置,记得保存。</n-p
|
>!设置需要保存之后才能生效,部分设置还需要重启工具箱来生效。如果你改动了设置,记得保存。</n-p
|
||||||
>
|
>
|
||||||
|
|
||||||
|
<n-h3>包含工具</n-h3>
|
||||||
|
<n-p>左侧边栏中列出了所有工具。</n-p>
|
||||||
|
<n-p>
|
||||||
|
对于未来的更多工具开发计划,不会考虑添加已经由
|
||||||
|
<n-text strong type="info">PowerToys</n-text>
|
||||||
|
或其他知名同类软件实现的功能。
|
||||||
|
</n-p>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
Reference in New Issue
Block a user