Compare commits
190 Commits
v2.0.1-bet
...
v2.4.4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
62bcc345da | ||
|
|
637c1238ae | ||
|
|
2008b62a45 | ||
|
|
c2a23f0c6c | ||
|
|
4e266d4d92 | ||
|
|
5857af30b9 | ||
|
|
4ef93e8f6d | ||
|
|
113cd3dfbc | ||
|
|
84d15cd20f | ||
|
|
a2f0908d38 | ||
|
|
a5fb7f05a5 | ||
|
|
e3b10d53e2 | ||
|
|
6cbd5fe15b | ||
|
|
06d2d9bfbc | ||
|
|
e9f45cf3af | ||
|
|
2cdfcbbbae | ||
|
|
eef24dbb76 | ||
|
|
1080f6e960 | ||
|
|
6339228c47 | ||
|
|
36afdae707 | ||
|
|
a2f9e1d01c | ||
|
|
7a96bf395a | ||
|
|
676c2b9c6a | ||
|
|
6516042809 | ||
|
|
f72ae23691 | ||
|
|
5946e06693 | ||
|
|
cc6098258c | ||
|
|
47bada5c01 | ||
|
|
e236ee15b2 | ||
|
|
6dcec6cede | ||
|
|
ca6629988a | ||
|
|
40c92dbd99 | ||
|
|
a827438dbe | ||
|
|
e2ea081d25 | ||
|
|
46eeb8d320 | ||
|
|
16e8d90141 | ||
|
|
867a7b1fec | ||
|
|
d7d7e1423e | ||
|
|
1fc3d00f9c | ||
|
|
6ea706127d | ||
|
|
53ec3a8bb2 | ||
|
|
7802d359c4 | ||
|
|
2eff73f581 | ||
|
|
a7926aff60 | ||
|
|
1dfb39c2e7 | ||
|
|
5d7e2e97c2 | ||
|
|
b6b1c2eb08 | ||
|
|
e52d3bbbc9 | ||
|
|
de7fee6a23 | ||
|
|
971ad0e3e2 | ||
|
|
a1296953e9 | ||
|
|
e8d69214b7 | ||
|
|
668a470276 | ||
|
|
9f81854139 | ||
|
|
296e3a164a | ||
|
|
6e30f330d3 | ||
|
|
d64eed6f7f | ||
|
|
794235c72d | ||
|
|
edbc4d0749 | ||
|
|
2cd70bd386 | ||
|
|
9ee8d78b1b | ||
|
|
6f02359727 | ||
|
|
529f46dafe | ||
|
|
5eb07118b0 | ||
|
|
215b4895fb | ||
|
|
cffbbaf0dc | ||
|
|
b42bc6461d | ||
|
|
1fa0b9fb9c | ||
|
|
35c9a32604 | ||
|
|
a8006ec199 | ||
|
|
283542df21 | ||
|
|
2341d75533 | ||
|
|
57781e7b5a | ||
|
|
bfbbf3463e | ||
|
|
9c47c4e6a6 | ||
|
|
d5a532218a | ||
|
|
39f511e548 | ||
|
|
adf3e8807e | ||
|
|
afbe7dc385 | ||
|
|
1f391c7cb5 | ||
|
|
12a1961405 | ||
|
|
4115051bad | ||
|
|
e156642684 | ||
|
|
47eacb86cb | ||
|
|
f766ea3bde | ||
|
|
9e2b6f52a4 | ||
|
|
958e20fef9 | ||
|
|
77d3d00f7a | ||
|
|
3fded762df | ||
|
|
19d98ec07c | ||
|
|
1736037411 | ||
|
|
e6af7f30ee | ||
|
|
433e7c9850 | ||
|
|
dc74251bd0 | ||
|
|
4f58bfdc4f | ||
|
|
a407f84981 | ||
|
|
c16f703cef | ||
|
|
9b02915e44 | ||
|
|
ce46d0b37f | ||
|
|
7909475ed3 | ||
|
|
5a038031e7 | ||
|
|
7f4203aeb1 | ||
|
|
36b1fd5588 | ||
|
|
f69bc59130 | ||
|
|
391c9f2952 | ||
|
|
3846489611 | ||
|
|
ac1b202f44 | ||
|
|
9f21823792 | ||
|
|
6b0f00f71a | ||
|
|
5d0aca0e4a | ||
|
|
6608f02467 | ||
|
|
1cdd50d62d | ||
|
|
cfc10a6aee | ||
|
|
17436b0e9a | ||
|
|
68cfa14100 | ||
|
|
d3cbae7223 | ||
|
|
f33941446d | ||
|
|
976075d1c6 | ||
|
|
5b6995febe | ||
|
|
8acaff15f2 | ||
|
|
b43c2c0091 | ||
|
|
900a568ddf | ||
|
|
8d3d55bdd8 | ||
|
|
310dba0aa3 | ||
|
|
343079d24f | ||
|
|
c49b55992c | ||
|
|
d562d88768 | ||
|
|
554b208f80 | ||
|
|
ef563717a3 | ||
|
|
173a3a93ba | ||
|
|
cdc4fa3a09 | ||
|
|
a2d7c9b9c4 | ||
|
|
915288499e | ||
|
|
e1ccbb69a5 | ||
|
|
9613c24deb | ||
|
|
91b075a439 | ||
|
|
6cecfbf77d | ||
|
|
aada416790 | ||
|
|
65932ca22a | ||
|
|
419dc21618 | ||
|
|
313142e6f0 | ||
|
|
039b69f4be | ||
|
|
e0d0de4baf | ||
|
|
4d621c7521 | ||
|
|
cd4036a805 | ||
|
|
3e3c198a7f | ||
|
|
02dcc34a4b | ||
|
|
ba0ccbb8ff | ||
|
|
56b6ca9e89 | ||
|
|
9869d9fecf | ||
|
|
1e4757f70d | ||
|
|
6adf25dbee | ||
|
|
7fbb12d04b | ||
|
|
ded16b9580 | ||
|
|
d379c58082 | ||
|
|
8a536374ea | ||
|
|
bcfc968c9d | ||
|
|
4bf3f3a602 | ||
|
|
497de040cf | ||
|
|
a22a78fa0a | ||
|
|
d2894c66ba | ||
|
|
ff7473deb2 | ||
|
|
842a44a6d1 | ||
|
|
751c73b3a6 | ||
|
|
240175c571 | ||
|
|
8107d74537 | ||
|
|
861950145f | ||
|
|
7b320c9dd1 | ||
|
|
6640d66fac | ||
|
|
357846d2e6 | ||
|
|
3b3ddf224c | ||
|
|
4439d0548f | ||
|
|
21163b2277 | ||
|
|
480aaf2970 | ||
|
|
06596d87ae | ||
|
|
1008e86fbb | ||
|
|
62ec316337 | ||
|
|
735a450260 | ||
|
|
417ab071df | ||
|
|
1e73ab5ee6 | ||
|
|
e5ff219685 | ||
|
|
2beac06e7c | ||
|
|
6b96df3da5 | ||
|
|
8521262344 | ||
|
|
4cf00f9270 | ||
|
|
bdae8c280b | ||
|
|
04e674d1cd | ||
|
|
371565744e | ||
|
|
58aabb9f1e | ||
|
|
19cd77b26c |
20
.eslintrc.js
@@ -4,17 +4,23 @@ module.exports = {
|
||||
node: true,
|
||||
},
|
||||
extends: [
|
||||
"plugin:vue/vue3-essential",
|
||||
"eslint:recommended",
|
||||
"@vue/typescript/recommended",
|
||||
"@vue/prettier",
|
||||
"@vue/prettier/@typescript-eslint",
|
||||
'plugin:vue/vue3-essential',
|
||||
'eslint:recommended',
|
||||
'@vue/typescript/recommended',
|
||||
'@vue/prettier',
|
||||
'@vue/prettier/@typescript-eslint',
|
||||
],
|
||||
parserOptions: {
|
||||
ecmaVersion: 2020,
|
||||
},
|
||||
rules: {
|
||||
"no-console": process.env.NODE_ENV === "production" ? "warn" : "off",
|
||||
"no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off"
|
||||
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
|
||||
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
|
||||
'prettier/prettier': [
|
||||
'warn',
|
||||
{
|
||||
singleQuote: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
2
.github/FUNDING.yml
vendored
@@ -1,4 +1,4 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: #muwoo
|
||||
custom: ['https://muwoo.github.io/blogs'] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
||||
custom: ['https://rubickcenter.github.io/rubick/run/#%E8%B5%9E%E5%8A%A9'] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
||||
|
||||
11
.github/workflows/main.yml
vendored
@@ -23,7 +23,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-latest, windows-2019]
|
||||
os: [macos-latest, windows-2019, ubuntu-latest]
|
||||
|
||||
# create steps
|
||||
steps:
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: ${{ matrix.node }}
|
||||
node-version: 16.x
|
||||
|
||||
- name: Install system deps
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
@@ -47,7 +47,12 @@ jobs:
|
||||
run: |
|
||||
yarn
|
||||
yarn global add xvfb-maybe
|
||||
|
||||
yarn global add @vue/cli
|
||||
- name: Build feature
|
||||
run: |
|
||||
cd ./feature
|
||||
yarn
|
||||
npm run build
|
||||
- name: Build & release app
|
||||
run: |
|
||||
npm run release
|
||||
|
||||
1
.npmrc
Normal file
@@ -0,0 +1 @@
|
||||
electron_mirror=https://npm.taobao.org/mirrors/electron/
|
||||
19
.prettierrc
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"tabWidth": 2,
|
||||
"useTabs": false,
|
||||
"semi": true,
|
||||
"singleQuote": true,
|
||||
"jsxSingleQuote": true,
|
||||
"trailingComma": "es5",
|
||||
"bracketSpacing": true,
|
||||
"jsxBracketSameLine": false,
|
||||
"arrowParens": "always",
|
||||
"printWidth": 80,
|
||||
"embeddedLanguageFormatting": "auto",
|
||||
"htmlWhitespaceSensitivity": "ignore",
|
||||
"preserve": "preserve",
|
||||
"insertPragma": false,
|
||||
"quoteProps": "as-needed",
|
||||
"requirePragma": false,
|
||||
"endOfLine": "auto"
|
||||
}
|
||||
19
README.md
@@ -14,7 +14,7 @@ English | [简体中文](./README.zh-CN.md)
|
||||
<img alt="release" src="https://img.shields.io/github/package-json/v/rubickCenter/rubick" />
|
||||
</a>
|
||||
<a href="https://github.com/rubickCenter/rubick/actions">
|
||||
<img alt=building src=https://img.shields.io/github/workflow/status/rubickCenter/rubick/Build>
|
||||
<img alt=building src=https://img.shields.io/github/actions/workflow/status/rubickCenter/rubick/main.yml>
|
||||
</a>
|
||||
<a href="https://github.com/rubickCenter/rubick/blob/master/LICENSE">
|
||||
<img alt="npm" src="https://img.shields.io/github/license/rubickCenter/rubick" />
|
||||
@@ -29,9 +29,18 @@ English | [简体中文](./README.zh-CN.md)
|
||||
|
||||
Based on electron open source toolbox, free integration of rich plug-ins, to create the ultimate desktop efficiency tool。Rubick is one of the heroes of Dota ,The core skill is the ability to use other heroes as plug-ins,Finished the walk 。Very consistent with the design concept of this tool,So named Rubick。
|
||||
|
||||
## Sponsor
|
||||
我们通过有偿的方式积累高质量的常见问题、最佳实践文档,加入星球后可以和作者进行互动和答疑。我们提供技术支持、答疑解惑、定制化插件开发、二次定制化开发 rubick 等等官方服务。
|
||||
|
||||
权益明细可以参考文档:[权益明细](https://rubickcenter.github.io/rubick/super/)
|
||||
|
||||
<img width=400 src=https://picx.zhimg.com/80/v2-6deabf65175d18080439ef813102d18c_720w.png />
|
||||
|
||||
## Installation package
|
||||
* [Rubick Mac OS](https://github.com/rubickCenter/rubick/releases)
|
||||
* [Rubick Windows](https://github.com/rubickCenter/rubick/releases)
|
||||
* [Rubick Linux](https://github.com/rubickCenter/rubick/releases)
|
||||
|
||||
|
||||
## Feature list
|
||||
- [x] Plug-in management based on npm package mode, installing plugins is as easy as installing npm packages.
|
||||
@@ -41,7 +50,7 @@ Based on electron open source toolbox, free integration of rich plug-ins, to cre
|
||||
- [x] Support searching for locally installed apps or preferences
|
||||
- [x] Support MacOS
|
||||
- [x] Support Windows
|
||||
|
||||
- [x] Support Linux
|
||||
|
||||
## Docs
|
||||
|
||||
@@ -76,12 +85,6 @@ Search for `Preferences` in `rubick`, and then turn on the `Auto Paste` function
|
||||
If you need more features, please come here to give us suggestions:[issues](https://github.com/rubickCenter/rubick/issues) 。
|
||||
We will add valuable ideas to the later development. At the same time, welcome to join and build together。
|
||||
|
||||
## Sponsor
|
||||
开源不容易,如果该项目对你有用的话,可以打赏我们喝杯 coffee ☕️.
|
||||
|
||||
<img width=200 src=https://pic1.zhimg.com/80/v2-688385687a37e962fe32daf136139feb_720w.png />
|
||||
<img width=200 src=https://pica.zhimg.com/80/v2-1ba296fd2cece45ee1094ee7c259035c_720w.png />
|
||||
|
||||
## 贡献
|
||||
This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)]. <a href="https://github.com/rubickCenter/rubick/graphs/contributors"><img src="https://opencollective.com/rubick/contributors.svg?width=890&button=false" /></a>
|
||||
|
||||
|
||||
@@ -30,9 +30,17 @@
|
||||
|
||||
基于 electron 的开源工具箱,自由集成丰富插件,打造极致的桌面端效能工具。Rubick(拉比克) 是 dota 里面的英雄之一,其核心技能是插件化使用其他英雄的技能,用完即走。非常符合本工具的设计理念,所以取名 Rubick。
|
||||
|
||||
## 赞助和服务
|
||||
我们通过有偿的方式积累高质量的常见问题、最佳实践文档,加入星球后可以和作者进行互动和答疑。我们提供技术支持、答疑解惑、定制化插件开发、二次定制化开发 rubick 等等官方服务。
|
||||
|
||||
权益明细可以参考文档:[权益明细](https://rubickcenter.github.io/rubick/super/)
|
||||
|
||||
<img width=400 src=https://picx.zhimg.com/80/v2-6deabf65175d18080439ef813102d18c_720w.png />
|
||||
|
||||
## 安装包
|
||||
* [Rubick Mac OS](https://github.com/rubickCenter/rubick/releases)
|
||||
* [Rubick Windows](https://github.com/rubickCenter/rubick/releases)
|
||||
* [Rubick Linux](https://github.com/rubickCenter/rubick/releases)
|
||||
|
||||
## 支持能力
|
||||
- [x] 基于 npm 包模式的插件管理,安装插件和安装 npm 包一样简单
|
||||
@@ -42,7 +50,7 @@
|
||||
- [x] 支持搜索本地已安装 app 或 偏好设置
|
||||
- [x] 支持 MacOS
|
||||
- [x] 支持 Windows
|
||||
|
||||
- [x] 支持 Linux
|
||||
|
||||
## 使用文档
|
||||
|
||||
@@ -77,12 +85,6 @@
|
||||
如果您还需要更多功能,欢迎来这里给我们提建议:[issues](https://github.com/rubickCenter/rubick/issues) 。
|
||||
有价值的想法我们会加入到后期的开发当中。同时也欢迎一起加入共建。
|
||||
|
||||
## 赞助
|
||||
开源不容易,如果该项目对你有用的话,可以打赏我们喝杯 coffee ☕️.
|
||||
|
||||
<img width=200 src=https://pic1.zhimg.com/80/v2-688385687a37e962fe32daf136139feb_720w.png />
|
||||
<img width=200 src=https://pica.zhimg.com/80/v2-1ba296fd2cece45ee1094ee7c259035c_720w.png />
|
||||
|
||||
## 贡献
|
||||
This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)]. <a href="https://github.com/rubickCenter/rubick/graphs/contributors"><img src="https://opencollective.com/rubick/contributors.svg?width=890&button=false" /></a>
|
||||
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
module.exports = {
|
||||
presets: ["@vue/cli-plugin-babel/preset"],
|
||||
plugins: [
|
||||
[
|
||||
"import",
|
||||
{ libraryName: "ant-design-vue", libraryDirectory: "es", style: "css" },
|
||||
], // `style: true` 会加载 less 文件
|
||||
],
|
||||
};
|
||||
|
||||
23
detach/.gitignore
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
.DS_Store
|
||||
node_modules
|
||||
/dist
|
||||
|
||||
|
||||
# local env files
|
||||
.env.local
|
||||
.env.*.local
|
||||
|
||||
# Log files
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
|
||||
# Editor directories and files
|
||||
.idea
|
||||
.vscode
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
24
detach/README.md
Normal file
@@ -0,0 +1,24 @@
|
||||
# detach
|
||||
|
||||
## Project setup
|
||||
```
|
||||
npm install
|
||||
```
|
||||
|
||||
### Compiles and hot-reloads for development
|
||||
```
|
||||
npm run serve
|
||||
```
|
||||
|
||||
### Compiles and minifies for production
|
||||
```
|
||||
npm run build
|
||||
```
|
||||
|
||||
### Lints and fixes files
|
||||
```
|
||||
npm run lint
|
||||
```
|
||||
|
||||
### Customize configuration
|
||||
See [Configuration Reference](https://cli.vuejs.org/config/).
|
||||
3
detach/babel.config.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
presets: ["@vue/cli-plugin-babel/preset"],
|
||||
};
|
||||
13238
detach/package-lock.json
generated
Normal file
57
detach/package.json
Normal file
@@ -0,0 +1,57 @@
|
||||
{
|
||||
"name": "detach",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve --port 8082",
|
||||
"build": "vue-cli-service build",
|
||||
"lint": "vue-cli-service lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"core-js": "^3.6.5",
|
||||
"lodash.throttle": "^4.1.1",
|
||||
"vue": "^3.0.0",
|
||||
"vue-router": "^4.0.0-0",
|
||||
"vuex": "^4.0.0-0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "^4.18.0",
|
||||
"@typescript-eslint/parser": "^4.18.0",
|
||||
"@vue/cli-plugin-babel": "~4.5.0",
|
||||
"@vue/cli-plugin-eslint": "~4.5.0",
|
||||
"@vue/cli-plugin-router": "~4.5.0",
|
||||
"@vue/cli-plugin-typescript": "~4.5.0",
|
||||
"@vue/cli-plugin-vuex": "~4.5.0",
|
||||
"@vue/cli-service": "~4.5.0",
|
||||
"@vue/compiler-sfc": "^3.0.0",
|
||||
"@vue/eslint-config-prettier": "^6.0.0",
|
||||
"@vue/eslint-config-typescript": "^7.0.0",
|
||||
"eslint": "^6.7.2",
|
||||
"eslint-plugin-prettier": "^3.3.1",
|
||||
"eslint-plugin-vue": "^7.0.0",
|
||||
"prettier": "^2.2.1",
|
||||
"typescript": "~4.1.5"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"root": true,
|
||||
"env": {
|
||||
"node": true
|
||||
},
|
||||
"extends": [
|
||||
"plugin:vue/vue3-essential",
|
||||
"eslint:recommended",
|
||||
"@vue/typescript/recommended",
|
||||
"@vue/prettier",
|
||||
"@vue/prettier/@typescript-eslint"
|
||||
],
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2020
|
||||
},
|
||||
"rules": {}
|
||||
},
|
||||
"browserslist": [
|
||||
"> 1%",
|
||||
"last 2 versions",
|
||||
"not dead"
|
||||
]
|
||||
}
|
||||
BIN
detach/public/favicon.ico
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
17
detach/public/index.html
Normal file
@@ -0,0 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||
</noscript>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
</body>
|
||||
</html>
|
||||
221
detach/src/App.vue
Normal file
@@ -0,0 +1,221 @@
|
||||
<template>
|
||||
<div :class="[platform, 'detach']">
|
||||
<div class="info">
|
||||
<img :src="plugInfo.logo"/>
|
||||
<input
|
||||
autofocus
|
||||
@input="changeValue"
|
||||
v-if="showInput"
|
||||
:value="plugInfo.subInput?.value"
|
||||
:placeholder="plugInfo.subInput?.placeholder"
|
||||
/>
|
||||
<span v-else>{{ plugInfo.pluginName }}</span>
|
||||
</div>
|
||||
<div class="handle-container">
|
||||
<div class="handle">
|
||||
<div class="devtool" @click="openDevTool" title="开发者工具"></div>
|
||||
</div>
|
||||
<div class="window-handle" v-if="platform !== 'darwin'">
|
||||
<div class="minimize" @click="minimize"></div>
|
||||
<div class="maximize" @click="maximize"></div>
|
||||
<div class="close" @click="close"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import throttle from 'lodash.throttle';
|
||||
import { ref } from 'vue';
|
||||
|
||||
const { ipcRenderer } = window.require('electron');
|
||||
|
||||
const platform = ref(window.process.platform);
|
||||
const showInput = ref(false);
|
||||
|
||||
const storeInfo = localStorage.getItem('rubick-system-detach') || '{}';
|
||||
const plugInfo = ref({});
|
||||
|
||||
window.initDetach = (pluginInfo) => {
|
||||
plugInfo.value = pluginInfo;
|
||||
showInput.value =
|
||||
pluginInfo.subInput &&
|
||||
(!!pluginInfo.subInput.value || !!pluginInfo.subInput.placeholder);
|
||||
localStorage.setItem('rubick-system-detach', JSON.stringify(pluginInfo));
|
||||
};
|
||||
|
||||
try {
|
||||
window.initDetach(JSON.parse(storeInfo));
|
||||
} catch (e) {
|
||||
// ...
|
||||
}
|
||||
|
||||
const changeValue = throttle((e) => {
|
||||
ipcRenderer.send('msg-trigger', {
|
||||
type: 'detachInputChange',
|
||||
data: {
|
||||
text: e.target.value,
|
||||
},
|
||||
});
|
||||
}, 500);
|
||||
|
||||
const openDevTool = () => {
|
||||
ipcRenderer.send('msg-trigger', { type: 'openPluginDevTools' });
|
||||
};
|
||||
|
||||
const minimize = () => {
|
||||
ipcRenderer.send('detach:service', { type: 'minimize' });
|
||||
};
|
||||
|
||||
const maximize = () => {
|
||||
ipcRenderer.send('detach:service', { type: 'maximize' });
|
||||
};
|
||||
|
||||
const close = () => {
|
||||
ipcRenderer.send('detach:service', { type: 'close' });
|
||||
};
|
||||
|
||||
Object.assign(window, {
|
||||
setSubInputValue: ({ value }) => {
|
||||
plugInfo.value.subInput.value = value;
|
||||
},
|
||||
setSubInput: (placeholder) => {
|
||||
plugInfo.value.subInput.placeholder = placeholder;
|
||||
},
|
||||
removeSubInput: () => {
|
||||
plugInfo.value.subInput = null;
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: system-ui, "PingFang SC", "Helvetica Neue", "Microsoft Yahei", sans-serif;
|
||||
user-select: none;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.detach {
|
||||
width: 100%;
|
||||
height: 60px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.detach {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 18px;
|
||||
padding-left: 10px;
|
||||
font-weight: 500;
|
||||
box-sizing: border-box;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.detach.darwin {
|
||||
padding-left: 80px;
|
||||
-webkit-app-region: drag;
|
||||
}
|
||||
|
||||
.detach.win32 {
|
||||
-webkit-app-region: drag;
|
||||
}
|
||||
|
||||
.detach img {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.detach input {
|
||||
background-color: var(--color-body-bg);
|
||||
color: var(--color-text-primary);
|
||||
width: 360px;
|
||||
height: 36px;
|
||||
line-height: 36px;
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
border: none;
|
||||
padding: 0 10px;
|
||||
outline: none;
|
||||
-webkit-app-region: no-drag;
|
||||
}
|
||||
|
||||
.detach input::-webkit-input-placeholder {
|
||||
color: #aaa;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.detach .info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.handle {
|
||||
display: flex;
|
||||
-webkit-app-region: no-drag;
|
||||
}
|
||||
|
||||
.handle > div {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 18px;
|
||||
cursor: pointer;
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
.handle > div:hover {
|
||||
background-color: #dee2e6;
|
||||
}
|
||||
|
||||
.handle .devtool {
|
||||
background: center no-repeat url("./assets/tool.svg")
|
||||
}
|
||||
|
||||
.handle-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.window-handle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
-webkit-app-region: no-drag;
|
||||
}
|
||||
|
||||
.window-handle > div {
|
||||
width: 48px;
|
||||
height: 56px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.window-handle > div:hover {
|
||||
background-color: #dee2e6;
|
||||
}
|
||||
|
||||
.window-handle .minimize {
|
||||
background: center / 20px no-repeat url("./assets/minimize.svg");
|
||||
}
|
||||
|
||||
.window-handle .maximize {
|
||||
background: center / 20px no-repeat url("./assets/maximize.svg");
|
||||
}
|
||||
|
||||
.window-handle .unmaximize {
|
||||
background: center / 20px no-repeat url("./assets/unmaximize.svg");
|
||||
}
|
||||
|
||||
.window-handle .close {
|
||||
background: center / 20px no-repeat url("./assets/close.svg");
|
||||
}
|
||||
|
||||
.window-handle .close:hover {
|
||||
background-color: #e53935 !important;
|
||||
background-image: url("./assets/close-hover.svg") !important;
|
||||
}
|
||||
|
||||
</style>
|
||||
1
detach/src/assets/close-hover.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1618205429990" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2034" width="64" height="64" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style type="text/css"></style></defs><path d="M529.066667 524.8l241.066666-241.066667c8.533333-8.533333 8.533333-21.333333 0-29.866666s-21.333333-8.533333-29.866666 0L499.2 494.933333 258.133333 253.866667c-8.533333-8.533333-21.333333-8.533333-29.866666 0s-8.533333 21.333333 0 29.866666L469.333333 524.8 228.266667 765.866667c-8.533333 8.533333-8.533333 21.333333 0 29.866666 4.266667 4.266667 10.666667 6.4 14.933333 6.4s10.666667-2.133333 14.933333-6.4L499.2 554.666667l241.066667 241.066666c4.266667 4.266667 10.666667 6.4 14.933333 6.4s10.666667-2.133333 14.933333-6.4c8.533333-8.533333 8.533333-21.333333 0-29.866666L529.066667 524.8z" fill="#ffffff" p-id="2035"></path></svg>
|
||||
|
After Width: | Height: | Size: 1011 B |
1
detach/src/assets/close.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1618205429990" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2034" width="64" height="64" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style type="text/css"></style></defs><path d="M529.066667 524.8l241.066666-241.066667c8.533333-8.533333 8.533333-21.333333 0-29.866666s-21.333333-8.533333-29.866666 0L499.2 494.933333 258.133333 253.866667c-8.533333-8.533333-21.333333-8.533333-29.866666 0s-8.533333 21.333333 0 29.866666L469.333333 524.8 228.266667 765.866667c-8.533333 8.533333-8.533333 21.333333 0 29.866666 4.266667 4.266667 10.666667 6.4 14.933333 6.4s10.666667-2.133333 14.933333-6.4L499.2 554.666667l241.066667 241.066666c4.266667 4.266667 10.666667 6.4 14.933333 6.4s10.666667-2.133333 14.933333-6.4c8.533333-8.533333 8.533333-21.333333 0-29.866666L529.066667 524.8z" fill="#888888" p-id="2035"></path></svg>
|
||||
|
After Width: | Height: | Size: 1011 B |
1
detach/src/assets/devtool.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1576121932768" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2610" width="32" height="32" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style type="text/css"></style></defs><path d="M344.792 518.575L303.4 477.184a26.947 26.947 0 0 1 38.13-38.13l60.174 60.173a26.947 26.947 0 0 1 0.27 37.834L114.392 833.16a26.947 26.947 0 0 0 0.27 37.834l68.984 68.958a26.947 26.947 0 0 0 38.077 0l291.301-291.3a26.947 26.947 0 0 1 38.104 0l146.324 146.323a26.947 26.947 0 1 1-38.104 38.13L532.076 705.833 259.853 978.055a80.842 80.842 0 0 1-114.337 0L76.53 909.096a80.842 80.842 0 0 1-0.809-113.475l269.043-277.046z m473.546 155.54a26.947 26.947 0 1 1-38.104 38.104L597.288 529.273a26.947 26.947 0 0 1 0-38.103l148.13-148.103a26.947 26.947 0 0 1 15.36-7.653l88.603-12.18 89.627-170.927-56.697-60.39-167.37 97.254-16.546 85.53a26.947 26.947 0 0 1-7.384 13.96l-148.13 148.102a26.947 26.947 0 0 1-38.103 0l-77.474-77.474a26.947 26.947 0 1 1 38.104-38.103l58.422 58.422 123.23-123.23 17.273-89.466a26.947 26.947 0 0 1 12.935-18.19l196.5-114.175a26.947 26.947 0 0 1 33.173 4.85l84.48 90.004a26.947 26.947 0 0 1 4.203 30.963l-104.96 200.165a26.947 26.947 0 0 1-20.21 14.201l-93.346 12.854-122.637 122.637 163.867 163.894z" p-id="2611" fill="#888888"></path><path d="M610.816 784.573a26.947 26.947 0 0 1 38.104-38.104l52.089 52.09a26.947 26.947 0 0 1-38.104 38.103l-52.089-52.09zM368.371 543.42a26.947 26.947 0 1 1 37.995-38.185L705.671 803.22a26.947 26.947 0 0 1 7.814 21.45 111.373 111.373 0 0 0 31.475 87.471 107.79 107.79 0 1 0 68.662-183.727c-2.129 0.135-3.934 0.081-5.578-0.054a26.947 26.947 0 0 1-19.537-7.868L485.24 417.954a26.947 26.947 0 1 1 38.05-38.158l295.181 294.481A161.684 161.684 0 1 1 706.83 950.272a165.16 165.16 0 0 1-47.642-117.275L368.37 543.421z" p-id="2612" fill="#888888"></path><path d="M783.076 874.036a53.895 53.895 0 1 0 76.22-76.219 53.895 53.895 0 1 0-76.22 76.219zM421.807 588.989a26.947 26.947 0 0 1 38.104 38.13L221.723 865.28a26.947 26.947 0 1 1-38.104-38.104L421.807 588.99z m81.597-229.808a26.947 26.947 0 1 1-38.104 38.104l-37.996-37.996a26.947 26.947 0 0 1-5.847-29.345c0.808-1.914 1.05-2.426 3.368-7.06l0.189-0.432c0.754-1.509 1.24-2.506 1.159-2.263a188.632 188.632 0 0 0-43.601-198.818 187.877 187.877 0 0 0-129.698-55.215 189.736 189.736 0 0 0-73.135 13.15l-2.506 0.97-1.752 0.728a26.947 26.947 0 0 1-21.073-49.61c1.887-0.809 1.887-0.809 3.423-1.402l2.102-0.808a242.068 242.068 0 0 1 93.992-16.896 241.772 241.772 0 0 1 166.723 70.98 242.526 242.526 0 0 1 57.722 250.88l25.007 25.033zM25.869 160.013a26.947 26.947 0 0 1 49.61 21.02 187.284 187.284 0 0 0-14.74 65.374 188.039 188.039 0 0 0 55.054 141.743 188.632 188.632 0 0 0 44.463 33.037 26.947 26.947 0 1 1-25.411 47.536 242.526 242.526 0 0 1-57.129-42.47A241.907 241.907 0 0 1 6.9 244.035a243.443 243.443 0 0 1 18.97-84.022z m224.337 337.274a26.947 26.947 0 0 1-0.215-53.895 189.17 189.17 0 0 0 61.79-10.644c4.366-1.51 7.168-2.21 10.94-1.563a26.947 26.947 0 0 1 18.81 7.895l33.145 33.146a26.947 26.947 0 0 1-38.103 38.13l-21.99-22.016a243.308 243.308 0 0 1-64.377 8.947z" p-id="2613" fill="#888888"></path><path d="M148.48 77.824a26.947 26.947 0 1 1 38.104-38.104l161.792 161.82a26.947 26.947 0 0 1 7.087 25.6l-22.986 91.35a26.947 26.947 0 0 1-19.564 19.565L221.56 361.04a26.947 26.947 0 0 1-25.6-7.06L30.343 188.362a26.947 26.947 0 1 1 38.13-38.103L223.26 305.044l60.901-15.306 15.306-60.9L148.48 77.823z" p-id="2614" fill="#888888"></path></svg>
|
||||
|
After Width: | Height: | Size: 3.5 KiB |
1
detach/src/assets/info.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg width="20" height="20" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg"><rect width="48" height="48" fill="white" fill-opacity="0.01"/><path d="M24 44C29.5228 44 34.5228 41.7614 38.1421 38.1421C41.7614 34.5228 44 29.5228 44 24C44 18.4772 41.7614 13.4772 38.1421 9.85786C34.5228 6.23858 29.5228 4 24 4C18.4772 4 13.4772 6.23858 9.85786 9.85786C6.23858 13.4772 4 18.4772 4 24C4 29.5228 6.23858 34.5228 9.85786 38.1421C13.4772 41.7614 18.4772 44 24 44Z" fill="none" stroke="#888" stroke-width="3" stroke-linejoin="round"/><path fill-rule="evenodd" clip-rule="evenodd" d="M24 11C25.3807 11 26.5 12.1193 26.5 13.5C26.5 14.8807 25.3807 16 24 16C22.6193 16 21.5 14.8807 21.5 13.5C21.5 12.1193 22.6193 11 24 11Z" fill="#888"/><path d="M24.5 34V20H23.5H22.5" stroke="#888" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/><path d="M21 34H28" stroke="#888" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||||
|
After Width: | Height: | Size: 995 B |
1
detach/src/assets/maximize.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1618205323520" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1376" width="64" height="64" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style type="text/css"></style></defs><path d="M832 832H192V192h640v640z m-597.333333-42.666667h554.666666V234.666667H234.666667v554.666666z" fill="#888888" p-id="1377"></path></svg>
|
||||
|
After Width: | Height: | Size: 510 B |
1
detach/src/assets/minimize.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1618205449254" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2381" width="64" height="64" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style type="text/css"></style></defs><path d="M768 533.333333H256c-12.8 0-21.333333-8.533333-21.333333-21.333333s8.533333-21.333333 21.333333-21.333333h512c12.8 0 21.333333 8.533333 21.333333 21.333333s-8.533333 21.333333-21.333333 21.333333z" fill="#888888" p-id="2382"></path></svg>
|
||||
|
After Width: | Height: | Size: 613 B |
1
detach/src/assets/pin.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg width="20" height="20" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#icon-3d122e4c72881c3e)"><path d="M10.6963 17.5042C13.3347 14.8657 16.4701 14.9387 19.8781 16.8076L32.62 9.74509L31.8989 4.78683L43.2126 16.1005L38.2656 15.3907L31.1918 28.1214C32.9752 31.7589 33.1337 34.6647 30.4953 37.3032C30.4953 37.3032 26.235 33.0429 22.7171 29.525L6.44305 41.5564L18.4382 25.2461C14.9202 21.7281 10.6963 17.5042 10.6963 17.5042Z" fill="#888" stroke="#888" stroke-width="3" stroke-linejoin="round"/></g><defs><clipPath id="icon-3d122e4c72881c3e"><rect width="48" height="48" fill="#FFF"/></clipPath></defs></svg>
|
||||
|
After Width: | Height: | Size: 685 B |
1
detach/src/assets/setting.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg width="20" height="20" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg"><rect width="48" height="48" fill="white" fill-opacity="0.01"/><path d="M34.0003 41L44 24L34.0003 7H14.0002L4 24L14.0002 41H34.0003Z" fill="none" stroke="#888" stroke-width="3" stroke-linejoin="round"/><path d="M24 29C26.7614 29 29 26.7614 29 24C29 21.2386 26.7614 19 24 19C21.2386 19 19 21.2386 19 24C19 26.7614 21.2386 29 24 29Z" fill="none" stroke="#888" stroke-width="3" stroke-linejoin="round"/></svg>
|
||||
|
After Width: | Height: | Size: 539 B |
1
detach/src/assets/tool.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg width="20" height="20" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg"><rect width="48" height="48" fill="white" fill-opacity="0.01"/><path d="M44 16C44 22.6274 38.6274 28 32 28C29.9733 28 28.0639 27.4975 26.3896 26.6104L9 44L4 39L21.3896 21.6104C20.5025 19.9361 20 18.0267 20 16C20 9.37258 25.3726 4 32 4C34.0267 4 35.9361 4.50245 37.6104 5.38959L30 13L35 18L42.6104 10.3896C43.4975 12.0639 44 13.9733 44 16Z" fill="none" stroke="#888" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||||
|
After Width: | Height: | Size: 570 B |
1
detach/src/assets/unmaximize.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1618205464128" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2718" width="64" height="64" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style type="text/css"></style></defs><path d="M855.466667 168.533333h-554.666667V277.333333H192v554.666667h554.666667v-108.8h108.8v-554.666667zM704 789.333333H234.666667V320h469.333333v469.333333z m108.8-108.8H746.666667V277.333333H343.466667V211.2h469.333333v469.333333z" fill="#888888" p-id="2719"></path></svg>
|
||||
|
After Width: | Height: | Size: 642 B |
1
detach/src/assets/unpin.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg width="20" height="20" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#icon-7599d19572881c3e)"><path d="M10.6963 17.5042C13.3347 14.8657 16.4701 14.9387 19.8781 16.8076L32.62 9.74509L31.8989 4.78683L43.2126 16.1005L38.2656 15.3907L31.1918 28.1214C32.9752 31.7589 33.1337 34.6647 30.4953 37.3032C30.4953 37.3032 26.235 33.0429 22.7171 29.525L6.44305 41.5564L18.4382 25.2461C14.9202 21.7281 10.6963 17.5042 10.6963 17.5042Z" fill="none" stroke="#888" stroke-width="3" stroke-linejoin="round"/></g><defs><clipPath id="icon-7599d19572881c3e"><rect width="48" height="48" fill="#888"/></clipPath></defs></svg>
|
||||
|
After Width: | Height: | Size: 685 B |
25
detach/src/assets/var.less
Normal file
@@ -0,0 +1,25 @@
|
||||
:root {
|
||||
--color-text-primary: rgba(0, 0, 0, 0.85);
|
||||
--color-text-content: #141414;
|
||||
--color-text-desc: rgba(0, 0, 0, 0.45);
|
||||
// 背景色
|
||||
--color-body-bg: #fff;
|
||||
--color-menu-bg: #f3efef;
|
||||
--color-list-hover: #e2e2e2;
|
||||
--color-input-hover: #fff;
|
||||
// 边框
|
||||
--color-border-light: #f0f0f0;
|
||||
}
|
||||
|
||||
.dark {
|
||||
--color-text-primary: #e8e8f0;
|
||||
--color-text-content: #ccccd8;
|
||||
--color-text-desc: #8f8fa6;
|
||||
// 背景色
|
||||
--color-body-bg: #1c1c28;
|
||||
--color-menu-bg: #1c1c28;
|
||||
--color-list-hover: #33333d;
|
||||
--color-input-hover: #33333d;
|
||||
// 边框
|
||||
--color-border-light: #33333d;
|
||||
}
|
||||
1
detach/src/assets/zoom.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg width="20" height="20" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg"><rect width="48" height="48" fill="white" fill-opacity="0.01"/><path d="M21 38C30.3888 38 38 30.3888 38 21C38 11.6112 30.3888 4 21 4C11.6112 4 4 11.6112 4 21C4 30.3888 11.6112 38 21 38Z" fill="none" stroke="#888" stroke-width="3" stroke-linejoin="round"/><path d="M21 15L21 27" stroke="#888" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/><path d="M15 21L27 21" stroke="#888" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/><path d="M33.2218 33.2218L41.7071 41.7071" stroke="#888" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||||
|
After Width: | Height: | Size: 720 B |
5
detach/src/main.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { createApp } from 'vue';
|
||||
import App from './App.vue';
|
||||
import './assets/var.less';
|
||||
|
||||
createApp(App).mount('#app');
|
||||
6
detach/src/shims-vue.d.ts
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
/* eslint-disable */
|
||||
declare module '*.vue' {
|
||||
import type { DefineComponent } from 'vue'
|
||||
const component: DefineComponent<{}, {}, any>
|
||||
export default component
|
||||
}
|
||||
39
detach/tsconfig.json
Normal file
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "esnext",
|
||||
"module": "esnext",
|
||||
"strict": true,
|
||||
"jsx": "preserve",
|
||||
"importHelpers": true,
|
||||
"moduleResolution": "node",
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"sourceMap": true,
|
||||
"baseUrl": ".",
|
||||
"types": [
|
||||
"webpack-env"
|
||||
],
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"src/*"
|
||||
]
|
||||
},
|
||||
"lib": [
|
||||
"esnext",
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"scripthost"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"src/**/*.tsx",
|
||||
"src/**/*.vue",
|
||||
"tests/**/*.ts",
|
||||
"tests/**/*.tsx"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
13
detach/vue.config.js
Normal file
@@ -0,0 +1,13 @@
|
||||
const path = require("path");
|
||||
|
||||
module.exports = {
|
||||
css: { // 配置css模块
|
||||
loaderOptions: { // 向预处理器 Loader 传递配置选项
|
||||
less: { // 配置less(其他样式解析用法一致)
|
||||
javascriptEnabled: true, // 设置为true
|
||||
},
|
||||
},
|
||||
},
|
||||
outputDir: path.join(__dirname, "../public/detach"),
|
||||
publicPath: process.env.NODE_ENV === "production" ? "" : "/",
|
||||
};
|
||||
9401
detach/yarn.lock
Normal file
@@ -24,6 +24,10 @@ module.exports = {
|
||||
title: '插件开发',
|
||||
path: '/dev/',
|
||||
},
|
||||
{
|
||||
title: '特殊服务',
|
||||
path: '/super/',
|
||||
},
|
||||
{
|
||||
title: 'API',
|
||||
path: '/api/',
|
||||
|
||||
1
docs/docs/.vuepress/dist
Submodule
@@ -23,7 +23,7 @@
|
||||
#### 示例
|
||||
|
||||
```js
|
||||
rubcik.onPluginReady(({ code, type, payload }) => {
|
||||
rubick.onPluginReady(({ code, type, payload }) => {
|
||||
console.log('插件装配完成,已准备好')
|
||||
})
|
||||
/*
|
||||
|
||||
@@ -113,7 +113,7 @@ rubick-system-plugin-demo
|
||||
"version": "0.0.0",
|
||||
"description": "rubick 系统插件demo",
|
||||
"entry": "index.js",
|
||||
"logo": "httpss://static.91jkys.com/upload/202112/08/5bac90649c5343cabb63930b131cf8e6.png",
|
||||
"logo": "https://xxxx/upload/202112/08/5bac90649c5343cabb63930b131cf8e6.png",
|
||||
"pluginType": "system",
|
||||
"author": "muwoo",
|
||||
"homepage": ""
|
||||
@@ -171,6 +171,6 @@ $ npm link
|
||||
$ npm publish
|
||||
```
|
||||
|
||||
然后再给 [rubick-database/plugins/total-plugins.json](https://gitee.com/monkeyWang/rubick-database/blob/master/plugins/total-plugins.json) 仓库提个 `pull request`, 把你的 `package.json` 信息加入 `json` 文件内,等我们 merge 了您的提交,插件将会自动上架。
|
||||
然后再给 [rubick-database/plugins/total-plugins.json](https://gitcode.net/rubickcenter/rubick-database/-/blob/master/plugins/total-plugins.json) 仓库提个 `pull request`, 把你的 `package.json` 信息加入 `json` 文件内,等我们 merge 了您的提交,插件将会自动上架。
|
||||
|
||||
|
||||
|
||||
@@ -18,13 +18,11 @@ rubick 之前的插件管理,依托于云服务器存储,我们需要为服
|
||||
## 下载 rubick
|
||||
[rubick 下载安装地址](https://github.com/rubickCenter/rubick/releases)
|
||||
|
||||
macos 选择 `pkg` 文件,windows 选择 `exe` 文件。
|
||||
macos 选择 `pkg` 文件,windows 选择 `exe` 文件,Debian/Ubuntu选择`deb`。
|
||||
安装完成后打开 rubick 即可看到主搜索界面:
|
||||
|
||||

|
||||
|
||||
目前支持 windows 和 macos。linux 小伙伴正在开发中
|
||||
|
||||
## 功能说明
|
||||
接下来详细介绍 rubick 所包含和支持的功能
|
||||
|
||||
@@ -50,6 +48,27 @@ macos 选择 `pkg` 文件,windows 选择 `exe` 文件。
|
||||
|
||||

|
||||
|
||||
### 内网部署
|
||||
::: tip
|
||||
如果把插件发布到公网 `npm` 如果不符合您的公司安全要求,`rubick` 支持内网私有源和私有插件库,如果您需要内网部署使用,可以自行配置以下规则。
|
||||
:::
|
||||
`rubick` 依赖 `npm` 仓库做插件管理,依赖 `gitcode` 做插件数据存储,所以如果要进行内网部署,主要需要替换这2个设置。详细设置:
|
||||
`插件市场 -> 设置 -> 内网部署设置`
|
||||
|
||||

|
||||
|
||||
#### 1. 替换 npm 源
|
||||
插件发布到私有 `npm` 源即可。
|
||||
|
||||
#### 2. 替换 `gitcode` 源为内网 `gitlab`: database url
|
||||
|
||||
* clone 下载 rubick 插件库:[https://gitcode.net/rubickcenter/rubick-database](https://gitcode.net/rubickcenter/rubick-database)
|
||||
* 提交仓库到私有 `gitlab` 库。
|
||||
|
||||
替换格式:`https://gitlab.xxx.com/api/v4/projects/{projectId}/repository/files/` 。因为接口为 `gitlab openAPI`,所以需要填写仓库 `access_token`
|
||||
|
||||
|
||||
### 更多功能
|
||||
如果您还需要更多功能,欢迎来这里给我们提建议:[issues](https://github.com/rubickCenter/rubick/issues) 。
|
||||
有价值的想法我们会加入到后期的开发当中。同时也欢迎一起加入共建。
|
||||
|
||||
|
||||
@@ -101,5 +101,3 @@ $ npm run electron:build
|
||||
5. Make sure that running npm run prepublish outputs the correct files.
|
||||
6. Rebase before creating a PR to keep commit history clear. (Merge request to branch dev)
|
||||
7. Provide some description about your PR.
|
||||
|
||||
|
||||
|
||||
19
docs/docs/super/README.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# 特殊服务
|
||||
## 说明
|
||||
`rubick` 一直坚持开源免费,现在不会变,以后也不会变。但是纯开源 `MIT` 模式下,是一种 0 收入用爱发电的,完全依靠
|
||||
作者自己的爱好和激情。但这种用爱发电的模式很难持续维持,为了更好的持续迭代和发展壮大 `rubick`, 我们需要一定的现金持续激励 `rubick` 的核心开发者们,让更多的人成为 `rubick`
|
||||
的核心开发者。所以 `rubick` 开启了一个新的模式尝试,那是服务付费:`rubick` 用户可以购买我们提供技术支持、答疑解惑、定制化插件开发、二次定制化开发 `rubick` 等等官方服务...
|
||||
|
||||
## 可以提供哪些服务?
|
||||
我们收集了大量用户的问题,目前约定可以支持到的服务有:
|
||||
1. 二次定制化开发 `rubick`
|
||||
2. 轻量级插件开发
|
||||
3. `rubick` 实现原理手把手介绍
|
||||
4. `rubick` 使用答疑
|
||||
5. `rubick` 内网部署一条龙服务
|
||||
6. 前端圈各种技术支持(作者分别是前蚂蚁集团和字节跳动的前端技术专家)
|
||||
7. 未来能提供的一切...
|
||||
|
||||
## 如何加入特殊服务?
|
||||
扫描下方的二维码,加入知识星球即可:
|
||||
<img width=400 src=https://picx.zhimg.com/80/v2-6deabf65175d18080439ef813102d18c_720w.png />
|
||||
24918
docs/package-lock.json
generated
10220
docs/pnpm-lock.yaml
generated
8688
docs/yarn.lock
Normal file
1
feature/.env.development
Normal file
@@ -0,0 +1 @@
|
||||
VUE_APP_API_BASE=http://localhost:7001/
|
||||
1
feature/.env.production
Normal file
@@ -0,0 +1 @@
|
||||
VUE_APP_API_BASE=https://rubick.vip/api/
|
||||
7339
feature/package-lock.json
generated
@@ -3,19 +3,22 @@
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve",
|
||||
"serve": "vue-cli-service serve --port 8081",
|
||||
"build": "vue-cli-service build",
|
||||
"lint": "vue-cli-service lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ant-design/icons-vue": "^6.0.1",
|
||||
"ant-design-vue": "^2.2.8",
|
||||
"@vue/cli-service": "~4.5.0",
|
||||
"ant-design-vue": "3.2.14",
|
||||
"axios": "^0.24.0",
|
||||
"core-js": "^3.6.5",
|
||||
"lodash.debounce": "^4.0.8",
|
||||
"lodash.throttle": "^4.1.1",
|
||||
"markdown-it": "^12.2.0",
|
||||
"vue": "^3.0.0",
|
||||
"nanoid": "^4.0.2",
|
||||
"vue": "3.2.45",
|
||||
"vue-i18n": "^9.2.2",
|
||||
"vue-router": "^4.0.0-0",
|
||||
"vuex": "^4.0.0-0"
|
||||
},
|
||||
@@ -34,6 +37,8 @@
|
||||
"eslint": "^6.7.2",
|
||||
"eslint-plugin-prettier": "^3.3.1",
|
||||
"eslint-plugin-vue": "^7.0.0",
|
||||
"less": "^4.1.3",
|
||||
"less-loader": "5.0.0",
|
||||
"prettier": "^2.2.1",
|
||||
"typescript": "~4.1.5"
|
||||
},
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"pluginName": "rubick 系统菜单",
|
||||
"description": "rubick 系统菜单",
|
||||
"main": "index.html",
|
||||
"logo": "https://static.91jkys.com/upload/202112/08/8a1abbb051bf4b05bbc9bbf66ade63f2.png",
|
||||
"logo": "https://pic1.zhimg.com/80/v2-c09780808301668a82e6646cb42f0806_720w.png",
|
||||
"version": "0.0.0",
|
||||
"preload":"preload.js",
|
||||
"pluginType": "ui",
|
||||
|
||||
@@ -1,36 +1,34 @@
|
||||
<template>
|
||||
<div class="main-container">
|
||||
<div class="slider-bar">
|
||||
<a-menu v-model:selectedKeys="active" mode="horizontal" @select="({key}) => changeMenu(key)">
|
||||
<a-menu
|
||||
v-model:selectedKeys="active"
|
||||
mode="horizontal"
|
||||
@select="({ key }) => changeMenu(key)"
|
||||
>
|
||||
<a-menu-item key="market">
|
||||
<template #icon>
|
||||
<AppstoreOutlined />
|
||||
</template>
|
||||
插件市场
|
||||
{{ $t('feature.market.title') }}
|
||||
</a-menu-item>
|
||||
<a-menu-item key="installed">
|
||||
<template #icon>
|
||||
<HeartOutlined />
|
||||
</template>
|
||||
已安装
|
||||
{{ $t('feature.installed.title') }}
|
||||
</a-menu-item>
|
||||
<a-menu-item key="settings">
|
||||
<template #icon>
|
||||
<SettingOutlined />
|
||||
</template>
|
||||
设置
|
||||
</a-menu-item>
|
||||
<a-menu-item key="account">
|
||||
<template #icon>
|
||||
<UserOutlined />
|
||||
</template>
|
||||
账户
|
||||
{{ $t('feature.settings.title') }}
|
||||
</a-menu-item>
|
||||
<a-menu-item key="dev">
|
||||
<template #icon>
|
||||
<BugOutlined />
|
||||
</template>
|
||||
开发者
|
||||
{{ $t('feature.dev.title') }}
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</div>
|
||||
@@ -39,18 +37,18 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
import { ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import {
|
||||
HeartOutlined,
|
||||
UserOutlined,
|
||||
AppstoreOutlined,
|
||||
SettingOutlined,
|
||||
BugOutlined,
|
||||
} from "@ant-design/icons-vue";
|
||||
import { useStore } from "vuex";
|
||||
} from '@ant-design/icons-vue';
|
||||
import { useStore } from 'vuex';
|
||||
|
||||
const router = useRouter();
|
||||
const active = ref(["market"]);
|
||||
const active = ref(['market']);
|
||||
const changeMenu = (key: any) => {
|
||||
router.push(key);
|
||||
};
|
||||
@@ -61,11 +59,10 @@ window.rubick.onPluginEnter(({ code }: { code: string }) => {
|
||||
});
|
||||
|
||||
const store = useStore();
|
||||
const init = () => store.dispatch("init");
|
||||
const init = () => store.dispatch('init');
|
||||
init();
|
||||
|
||||
</script>
|
||||
<style lang="less">
|
||||
<style lang="less" scoped>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
@@ -74,11 +71,20 @@ init();
|
||||
.main-container {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
background: #F2EFEF;
|
||||
background: var(--color-body-bg);
|
||||
flex-direction: column;
|
||||
|
||||
.slider-bar {
|
||||
width: 100%;
|
||||
.ant-menu {
|
||||
background: var(--color-body-bg);
|
||||
border-color: var(--color-border-light);
|
||||
:deep(.ant-menu-item) {
|
||||
&:not(.ant-menu-item-selected) {
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,30 @@
|
||||
@import '~ant-design-vue/dist/antd.less'; // 引入官方提供的 less 样式入口文件
|
||||
@import "~ant-design-vue/dist/antd.less"; // 引入官方提供的 less 样式入口文件
|
||||
|
||||
@primary-color: #ff4ea4; // 全局主色
|
||||
@link-color: #ff4ea4; // 链接色
|
||||
@error-color: #ff4ea4; // 错误色
|
||||
|
||||
:root {
|
||||
--color-text-primary: rgba(0, 0, 0, 0.85);
|
||||
--color-text-content: #141414;
|
||||
--color-text-desc: rgba(0, 0, 0, 0.45);
|
||||
// 背景色
|
||||
--color-body-bg: #fff;
|
||||
--color-menu-bg: #f3efef;
|
||||
--color-list-hover: #e2e2e2;
|
||||
--color-input-hover: #fff;
|
||||
// 边框
|
||||
--color-border-light: #f0f0f0;
|
||||
}
|
||||
|
||||
.dark {
|
||||
--color-text-primary: #e8e8f0;
|
||||
--color-text-content: #ccccd8;
|
||||
--color-text-desc: #8f8fa6;
|
||||
// 背景色
|
||||
--color-body-bg: #1c1c28;
|
||||
--color-menu-bg: #1c1c28;
|
||||
--color-list-hover: #33333d;
|
||||
--color-input-hover: #33333d;
|
||||
// 边框
|
||||
--color-border-light: #33333d;
|
||||
}
|
||||
|
||||
37
feature/src/assets/common.less
Normal file
@@ -0,0 +1,37 @@
|
||||
.left-menu {
|
||||
width: 200px;
|
||||
// height: 100vh;
|
||||
border-right: 1px solid var(--color-border-light);
|
||||
.search-container {
|
||||
padding: 10px;
|
||||
}
|
||||
.ant-input-affix-wrapper {
|
||||
border: none;
|
||||
background: var(--color-input-hover);
|
||||
:deep(input) {
|
||||
background: none;
|
||||
color: var(--color-text-desc);
|
||||
}
|
||||
:deep(.anticon) {
|
||||
color: var(--color-text-desc);
|
||||
}
|
||||
}
|
||||
:deep(.ant-menu) {
|
||||
background: var(--color-menu-bg);
|
||||
height: 100%;
|
||||
border-right: none;
|
||||
.ant-menu-item {
|
||||
color: var(--color-text-content);
|
||||
&:active {
|
||||
background: none;
|
||||
}
|
||||
}
|
||||
.ant-menu-item-selected {
|
||||
background-color: var(--color-list-hover);
|
||||
color: var(--color-text-primary);
|
||||
&:after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,30 +1,62 @@
|
||||
import axios from "axios";
|
||||
import axios from 'axios';
|
||||
|
||||
let baseURL = 'https://gitcode.net/rubickcenter/rubick-database/-/raw/master';
|
||||
let access_token = '';
|
||||
|
||||
try {
|
||||
const dbdata = window.rubick.db.get('rubick-localhost-config');
|
||||
baseURL = dbdata.data.database;
|
||||
access_token = dbdata.data.access_token;
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
const instance = axios.create({
|
||||
baseURL:
|
||||
baseURL || 'https://gitcode.net/rubickcenter/rubick-database/-/raw/master',
|
||||
});
|
||||
|
||||
export default {
|
||||
async getTotalPlugins() {
|
||||
const res = await axios.get(
|
||||
"https://gitee.com/monkeyWang/rubick-database/raw/master/plugins/total-plugins.json"
|
||||
);
|
||||
let targetPath = 'plugins/total-plugins.json';
|
||||
if (access_token) {
|
||||
targetPath = `${encodeURIComponent(
|
||||
targetPath
|
||||
)}/raw?access_token=${access_token}&ref=master`;
|
||||
}
|
||||
const res = await instance.get(targetPath);
|
||||
return res.data;
|
||||
},
|
||||
|
||||
async getFinderDetail() {
|
||||
const res = await axios.get(
|
||||
"https://gitee.com/monkeyWang/rubick-database/raw/master/plugins/finder.json"
|
||||
);
|
||||
let targetPath = 'plugins/finder.json';
|
||||
if (access_token) {
|
||||
targetPath = `${encodeURIComponent(
|
||||
targetPath
|
||||
)}/raw?access_token=${access_token}&ref=master`;
|
||||
}
|
||||
const res = await instance.get(targetPath);
|
||||
return res.data;
|
||||
},
|
||||
|
||||
async getSystemDetail() {
|
||||
const res = await axios.get(
|
||||
"https://gitee.com/monkeyWang/rubick-database/raw/master/plugins/system.json"
|
||||
);
|
||||
let targetPath = 'plugins/system.json';
|
||||
if (access_token) {
|
||||
targetPath = `${encodeURIComponent(
|
||||
targetPath
|
||||
)}/raw?access_token=${access_token}&ref=master`;
|
||||
}
|
||||
const res = await instance.get(targetPath);
|
||||
return res.data;
|
||||
},
|
||||
async getWorkerDetail() {
|
||||
const res = await axios.get(
|
||||
"https://gitee.com/monkeyWang/rubick-database/raw/master/plugins/worker.json"
|
||||
);
|
||||
let targetPath = 'plugins/worker.json';
|
||||
if (access_token) {
|
||||
targetPath = `${encodeURIComponent(
|
||||
targetPath
|
||||
)}/raw?access_token=${access_token}&ref=master`;
|
||||
}
|
||||
const res = await instance.get(targetPath);
|
||||
return res.data;
|
||||
},
|
||||
|
||||
@@ -33,16 +65,34 @@ export default {
|
||||
return res.data;
|
||||
},
|
||||
|
||||
async getSearchDetail(url: string) {
|
||||
const res = await axios.get(
|
||||
"https://gitee.com/monkeyWang/rubick-database/raw/master/plugins/search.json"
|
||||
);
|
||||
async getSearchDetail() {
|
||||
let targetPath = 'plugins/search.json';
|
||||
if (access_token) {
|
||||
targetPath = `${encodeURIComponent(
|
||||
targetPath
|
||||
)}/raw?access_token=${access_token}&ref=master`;
|
||||
}
|
||||
const res = await instance.get(targetPath);
|
||||
return res.data;
|
||||
},
|
||||
async getDevDetail(url: string) {
|
||||
const res = await axios.get(
|
||||
"https://gitee.com/monkeyWang/rubick-database/raw/master/plugins/dev.json"
|
||||
);
|
||||
async getDevDetail() {
|
||||
let targetPath = 'plugins/dev.json';
|
||||
if (access_token) {
|
||||
targetPath = `${encodeURIComponent(
|
||||
targetPath
|
||||
)}/raw?access_token=${access_token}&ref=master`;
|
||||
}
|
||||
const res = await instance.get(targetPath);
|
||||
return res.data;
|
||||
},
|
||||
async getImageDetail() {
|
||||
let targetPath = 'plugins/image.json';
|
||||
if (access_token) {
|
||||
targetPath = `${encodeURIComponent(
|
||||
targetPath
|
||||
)}/raw?access_token=${access_token}&ref=master`;
|
||||
}
|
||||
const res = await instance.get(targetPath);
|
||||
return res.data;
|
||||
},
|
||||
};
|
||||
|
||||
30
feature/src/assets/service/index.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import axios from 'axios';
|
||||
|
||||
const instance = axios.create({
|
||||
baseURL: process.env.VUE_APP_API_BASE,
|
||||
});
|
||||
|
||||
export default {
|
||||
async getScanCode({ scene }: { scene: string }) {
|
||||
const res = await instance.get('/users/getScanCode', {
|
||||
params: {
|
||||
scene,
|
||||
},
|
||||
});
|
||||
return res.data;
|
||||
},
|
||||
|
||||
async checkLoginStatus({ scene }: { scene: string }) {
|
||||
const res = await instance.post('/users/checkLoginStatus', {
|
||||
scene,
|
||||
});
|
||||
return res.data;
|
||||
},
|
||||
|
||||
async getUserInfo({ openId }: { openId: string }) {
|
||||
const res = await instance.post('/users/getUserInfo', {
|
||||
openId,
|
||||
});
|
||||
return res.data;
|
||||
},
|
||||
};
|
||||
19
feature/src/languages/i18n.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { createI18n } from 'vue-i18n';
|
||||
import messages from './langs';
|
||||
const { remote } = window.require('electron');
|
||||
const { perf } = remote.getGlobal('OP_CONFIG').get();
|
||||
|
||||
console.log(messages);
|
||||
console.log(perf);
|
||||
|
||||
// 2. Create i18n instance with options
|
||||
const i18n = createI18n({
|
||||
legacy: false,
|
||||
locale: perf.common.lang || 'zh-CN', // set locale
|
||||
fallbackLocale: 'zh-CN', // set fallback locale
|
||||
messages, // set locale messages
|
||||
// If you need to specify other options, you can set other options
|
||||
// ...
|
||||
});
|
||||
|
||||
export default i18n;
|
||||
111
feature/src/languages/langs/en-US.ts
Normal file
@@ -0,0 +1,111 @@
|
||||
export default {
|
||||
'en-US': {
|
||||
feature: {
|
||||
market: {
|
||||
title: 'Market',
|
||||
search: 'Search Plugins',
|
||||
searchResult: 'Search Results',
|
||||
explore: 'Explore',
|
||||
efficiency: 'Efficiency',
|
||||
searchTool: 'Search Tools',
|
||||
imageTool: 'Image Tools',
|
||||
developTool: 'Develop Tools',
|
||||
systemTool: 'System Tools',
|
||||
finder: {
|
||||
recommended: 'Recommended',
|
||||
lastUpdated: 'Last Updated',
|
||||
},
|
||||
install: 'Install',
|
||||
},
|
||||
installed: {
|
||||
title: 'Installed',
|
||||
tips1: 'There are no plug-ins.',
|
||||
tips2: 'Go to the plugin market and choose the plugin to install!',
|
||||
developer: 'Developer',
|
||||
unknown: 'Unknown',
|
||||
remove: 'Remove',
|
||||
functionKey: 'Function Key',
|
||||
detailInfo: 'Detail Info',
|
||||
addToPanel: 'Click the + sign to pin the keyword to the super panel',
|
||||
removeFromPanel:
|
||||
'Click the - sign to remove the keyword from the super panel',
|
||||
},
|
||||
settings: {
|
||||
title: 'Account And Setting',
|
||||
account: {
|
||||
accountInfo: 'Account Info',
|
||||
tips1: 'rubick',
|
||||
tips2:
|
||||
'After the software preferences are set, please restart the software. Please go to the mini program set avatar and nickname.',
|
||||
themeColor: 'Theme Color',
|
||||
primaryColor: 'Primary Color',
|
||||
errorColor: 'Error Color',
|
||||
warningColor: 'Warning Color',
|
||||
successColor: 'Success Color',
|
||||
infoColor: 'Info Color',
|
||||
personalized: 'Personalized',
|
||||
greeting: 'Search Box Greeting',
|
||||
logo: 'Logo',
|
||||
replace: 'Repalce Logo',
|
||||
reset: 'Reset Default',
|
||||
},
|
||||
basic: {
|
||||
title: 'Basic',
|
||||
shortcutKey: 'Shortcut Key',
|
||||
showOrHiddle: 'Show Or Hiddle',
|
||||
screenCapture: 'Screen Capture',
|
||||
common: 'Common',
|
||||
autoPaste: 'Auto Paste',
|
||||
autoBoot: 'Auto Boot Up',
|
||||
spaceExec: 'Space Execution',
|
||||
on: 'on',
|
||||
off: 'off',
|
||||
theme: 'Theme',
|
||||
darkMode: 'Dark Mode',
|
||||
language: 'Language',
|
||||
changeLang: 'Change Language',
|
||||
cn: '简体中文',
|
||||
en: 'English',
|
||||
},
|
||||
global: {
|
||||
title: 'Global Shortcut Key',
|
||||
instructions: 'Instructions and examples',
|
||||
tips: 'Press the shortcut key, automatically search for the corresponding keyword, when the keyword result is exactly matched, and the result is unique, it will point directly to this function.',
|
||||
example: 'Example',
|
||||
example1: 'Shortcut key 「Alt + W」 keyword 「Wechat」',
|
||||
tips1: 'Press 「Alt + W」 to open the local Wechat app directly',
|
||||
example2: 'Shortcut key 「Ctrl + Alt + A」 keyword 「screenshot」',
|
||||
tips2: 'Press 「Ctrl + Alt + A」 to take a screenshot',
|
||||
shortcutKey: 'Shortcut Key',
|
||||
funtionKey: 'Funtion Key',
|
||||
addShortcutKey: 'ADD Global Shortcut Key',
|
||||
addShortcutKeyTips:
|
||||
'Press the function keys (Ctrl, Shift, {optionKeyName}) first, and then press other normal keys. Or press the F1-F12 button.',
|
||||
},
|
||||
superPanel: {
|
||||
title: 'Super Panel',
|
||||
tips: 'Please select the common plug-ins that need to be added to the super panel.',
|
||||
add: 'Add',
|
||||
remove: 'Revome',
|
||||
},
|
||||
intranet: {
|
||||
title: 'Intranet Deployment',
|
||||
tips: "If publishing plug-ins to the public network npm does not meet your company's security requirements, rubick supports private network private sources and private plug-in libraries. If you need private network deployment, you can configure the following rules.",
|
||||
npmMirror: 'npm mirror',
|
||||
dbUrl: 'database url',
|
||||
accessToken: 'access token',
|
||||
placeholder: 'required for private network gitlab warehouse',
|
||||
},
|
||||
},
|
||||
dev: {
|
||||
title: 'Developer',
|
||||
tips: 'The rubick plug-in system relies on npm management. Local debugging needs to first execute npm link in the current directory of the local plug-in.',
|
||||
pluginName: 'Plugin Name',
|
||||
install: 'Install',
|
||||
refreshPlugins: 'Refresh Plugins',
|
||||
installSuccess: '{pluginName} Install Successed!',
|
||||
refreshSuccess: '{pluginName} Refresh Successed!',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
9
feature/src/languages/langs/index.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import en from './en-US';
|
||||
import cn from './zh-CN';
|
||||
|
||||
const langs = {
|
||||
...en,
|
||||
...cn,
|
||||
};
|
||||
|
||||
export default langs;
|
||||
109
feature/src/languages/langs/zh-CN.ts
Normal file
@@ -0,0 +1,109 @@
|
||||
export default {
|
||||
'zh-CN': {
|
||||
feature: {
|
||||
market: {
|
||||
title: '插件市场',
|
||||
search: '搜索插件',
|
||||
searchResult: '搜索结果',
|
||||
explore: '探索',
|
||||
efficiency: '效率',
|
||||
searchTool: '搜索工具',
|
||||
imageTool: '图像',
|
||||
developTool: '开发者',
|
||||
systemTool: '系统',
|
||||
finder: {
|
||||
recommended: '推荐',
|
||||
lastUpdated: '最近更新',
|
||||
},
|
||||
install: '安装',
|
||||
},
|
||||
installed: {
|
||||
title: '已安装',
|
||||
tips1: '暂无任何插件',
|
||||
tips2: '去插件市场选择安装合适的插件吧!',
|
||||
developer: '开发者',
|
||||
unknown: '未知',
|
||||
remove: '移除',
|
||||
functionKey: '功能关键字',
|
||||
detailInfo: '详情介绍',
|
||||
addToPanel: '点击+号,固定关键词到超级面板',
|
||||
removeFromPanel: '点击-号,从超级面板移除关键词',
|
||||
},
|
||||
settings: {
|
||||
title: '账户和设置',
|
||||
account: {
|
||||
accountInfo: '账户信息',
|
||||
tips1: 'rubick 用户',
|
||||
tips2: '软件偏好设置完成后需重启软件,头像和昵称请前往小程序设置',
|
||||
themeColor: '主题色设置',
|
||||
primaryColor: '主色调',
|
||||
errorColor: '错误色',
|
||||
warningColor: '警告色',
|
||||
successColor: '成功色',
|
||||
infoColor: '提醒色',
|
||||
personalized: '用户个性化设置',
|
||||
greeting: '主搜索框欢迎语',
|
||||
logo: '界面 logo',
|
||||
replace: '点我替换',
|
||||
reset: '恢复默认设置',
|
||||
},
|
||||
basic: {
|
||||
title: '基本设置',
|
||||
shortcutKey: '快捷键',
|
||||
showOrHiddle: '显示/隐藏快捷键',
|
||||
screenCapture: '截屏',
|
||||
common: '通用',
|
||||
autoPaste: '输入框自动粘贴',
|
||||
autoBoot: '开机启动',
|
||||
spaceExec: '空格执行',
|
||||
on: '开',
|
||||
off: '关',
|
||||
theme: '主题',
|
||||
darkMode: '暗黑模式',
|
||||
language: '语言',
|
||||
changeLang: '切换语言',
|
||||
cn: '简体中文',
|
||||
en: 'English',
|
||||
},
|
||||
global: {
|
||||
title: '全局快捷键',
|
||||
instructions: '说明及示例',
|
||||
tips: '按下快捷键,自动搜索对应关键字,当关键字结果完全匹配,且结果唯一时,会直接指向该功能。',
|
||||
example: '示例',
|
||||
example1: '快捷键 「 Alt + W」 关键字 「 微信」',
|
||||
tips1: '按下Alt + W 直接打开本地微信应用',
|
||||
example2: '快捷键 「 Ctrl + Alt + A」 关键字 「 截屏」',
|
||||
tips2: '按下 Ctrl + Alt + A 进行截屏',
|
||||
shortcutKey: '快捷键',
|
||||
funtionKey: '功能关键字',
|
||||
addShortcutKey: '新增全局快捷功能',
|
||||
addShortcutKeyTips:
|
||||
'先按功能键(Ctrl、Shift、{optionKeyName}),再按其他普通键。或按 F1-F12 单键。',
|
||||
},
|
||||
superPanel: {
|
||||
title: '超级面板设置',
|
||||
tips: '请选择需要添加到超级面板中的常用插件',
|
||||
add: '添加',
|
||||
remove: '移除',
|
||||
},
|
||||
intranet: {
|
||||
title: '内网部署配置',
|
||||
tips: '把插件发布到公网 npm 如果不符合您的公司安全要求,rubick 支持内网私有源和私有插件库,如果您需要内网部署使用,可以自行配置以下规则。',
|
||||
npmMirror: 'npm 源',
|
||||
dbUrl: 'database url',
|
||||
accessToken: 'access token',
|
||||
placeholder: '内网gitlab仓库必填',
|
||||
},
|
||||
},
|
||||
dev: {
|
||||
title: '开发者',
|
||||
tips: 'rubick 插件系统依托于 npm 管理,本地调试需要先在本地插件当前目录执行 npm link',
|
||||
pluginName: '插件名称',
|
||||
install: '安装',
|
||||
refreshPlugins: '刷新插件',
|
||||
installSuccess: '{pluginName}安装成功!',
|
||||
refreshSuccess: '{pluginName}刷新成功!',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -1,8 +1,18 @@
|
||||
import { createApp } from "vue";
|
||||
import Antd from "ant-design-vue";
|
||||
import App from "./App.vue";
|
||||
import router from "./router";
|
||||
import store from "./store";
|
||||
import "./assets/ant-reset.less";
|
||||
import { createApp } from 'vue';
|
||||
import Antd, { ConfigProvider } from 'ant-design-vue';
|
||||
import App from './App.vue';
|
||||
import router from './router';
|
||||
import store from './store';
|
||||
import './assets/ant-reset.less';
|
||||
import 'ant-design-vue/dist/antd.variable.min.css';
|
||||
import registerI18n from './languages/i18n';
|
||||
|
||||
createApp(App).use(store).use(Antd).use(router).mount("#app");
|
||||
const { remote } = window.require('electron');
|
||||
|
||||
const { perf } = remote.getGlobal('OP_CONFIG').get();
|
||||
|
||||
ConfigProvider.config({
|
||||
theme: perf.custom || {},
|
||||
});
|
||||
|
||||
createApp(App).use(registerI18n).use(store).use(Antd).use(router).mount('#app');
|
||||
|
||||
@@ -1,39 +1,39 @@
|
||||
import { createRouter, createWebHashHistory, RouteRecordRaw } from "vue-router";
|
||||
import Market from "../views/market/index.vue";
|
||||
import Installed from "../views/installed/index.vue";
|
||||
import Account from "../views/account/index.vue";
|
||||
import Settings from "../views/settings/index.vue";
|
||||
import Dev from "../views/dev/index.vue";
|
||||
import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router';
|
||||
import Market from '../views/market/index.vue';
|
||||
import Installed from '../views/installed/index.vue';
|
||||
import Account from '../views/account/index.vue';
|
||||
import Settings from '../views/settings/user.vue';
|
||||
import Dev from '../views/dev/index.vue';
|
||||
|
||||
const routes: Array<RouteRecordRaw> = [
|
||||
{
|
||||
path: "/market",
|
||||
name: "market",
|
||||
path: '/market',
|
||||
name: 'market',
|
||||
component: Market,
|
||||
},
|
||||
{
|
||||
path: "/installed",
|
||||
name: "installed",
|
||||
path: '/installed',
|
||||
name: 'installed',
|
||||
component: Installed,
|
||||
},
|
||||
{
|
||||
path: "/account",
|
||||
name: "account",
|
||||
path: '/account',
|
||||
name: 'account',
|
||||
component: Account,
|
||||
},
|
||||
{
|
||||
path: "/settings",
|
||||
name: "settings",
|
||||
path: '/settings',
|
||||
name: 'settings',
|
||||
component: Settings,
|
||||
},
|
||||
{
|
||||
path: "/dev",
|
||||
name: "dev",
|
||||
path: '/dev',
|
||||
name: 'dev',
|
||||
component: Dev,
|
||||
},
|
||||
{
|
||||
path: "/:catchAll(.*)",
|
||||
name: "market",
|
||||
path: '/:catchAll(.*)',
|
||||
name: 'market',
|
||||
component: Market,
|
||||
},
|
||||
];
|
||||
|
||||
11
feature/src/shims-vue.d.ts
vendored
@@ -8,5 +8,14 @@ declare module '*.vue' {
|
||||
declare module 'axios'
|
||||
|
||||
interface Window {
|
||||
rubick: any
|
||||
rubick: any;
|
||||
market: any
|
||||
}
|
||||
|
||||
namespace Market {
|
||||
interface Plugin {
|
||||
isdownload?: boolean;
|
||||
name?: string;
|
||||
isloading: boolean
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { createStore } from "vuex";
|
||||
import request from "@/assets/request";
|
||||
import { createStore } from 'vuex';
|
||||
import request from '@/assets/request';
|
||||
|
||||
const isDownload = (item: any, targets: any[]) => {
|
||||
const isDownload = (item: Market.Plugin, targets: any[]) => {
|
||||
let isDownload = false;
|
||||
targets.some((plugin) => {
|
||||
if (plugin.name === item.name) {
|
||||
@@ -16,6 +16,7 @@ export default createStore({
|
||||
state: {
|
||||
totalPlugins: [],
|
||||
localPlugins: [],
|
||||
searchValue: '',
|
||||
},
|
||||
mutations: {
|
||||
commonUpdate(state: any, payload) {
|
||||
@@ -23,57 +24,95 @@ export default createStore({
|
||||
state[key] = payload[key];
|
||||
});
|
||||
},
|
||||
setSearchValue(state: any, payload) {
|
||||
state.searchValue = payload;
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
async init({ commit }) {
|
||||
const totalPlugins = await request.getTotalPlugins();
|
||||
const localPlugins = (window as any).market.getLocalPlugins();
|
||||
const localPlugins = window.market.getLocalPlugins();
|
||||
|
||||
totalPlugins.forEach(
|
||||
(origin: { isdwonload?: any; name?: any; isloading: boolean }) => {
|
||||
origin.isdwonload = isDownload(origin, localPlugins);
|
||||
origin.isloading = false;
|
||||
}
|
||||
);
|
||||
commit("commonUpdate", {
|
||||
totalPlugins.forEach((origin: Market.Plugin) => {
|
||||
origin.isdownload = isDownload(origin, localPlugins);
|
||||
origin.isloading = false;
|
||||
});
|
||||
// 修复卸载失败,一直转圈的问题。
|
||||
localPlugins.forEach((origin: Market.Plugin) => {
|
||||
origin.isloading = false;
|
||||
});
|
||||
|
||||
commit('commonUpdate', {
|
||||
localPlugins,
|
||||
totalPlugins,
|
||||
});
|
||||
},
|
||||
startDownload({ commit, state }, name) {
|
||||
const totalPlugins = JSON.parse(JSON.stringify(state.totalPlugins));
|
||||
totalPlugins.forEach(
|
||||
(origin: { isdwonload?: any; name?: any; isloading: boolean }) => {
|
||||
if (origin.name === name) {
|
||||
origin.isloading = true;
|
||||
}
|
||||
totalPlugins.forEach((origin: Market.Plugin) => {
|
||||
if (origin.name === name) {
|
||||
origin.isloading = true;
|
||||
}
|
||||
);
|
||||
commit("commonUpdate", {
|
||||
});
|
||||
commit('commonUpdate', {
|
||||
totalPlugins,
|
||||
});
|
||||
},
|
||||
|
||||
startUnDownload({ commit, state }, name) {
|
||||
const localPlugins = window.market.getLocalPlugins();
|
||||
localPlugins.forEach((origin: Market.Plugin) => {
|
||||
if (origin.name === name) {
|
||||
origin.isloading = true;
|
||||
}
|
||||
});
|
||||
commit('commonUpdate', {
|
||||
localPlugins,
|
||||
});
|
||||
},
|
||||
|
||||
errorUnDownload({ commit, state }, name) {
|
||||
const localPlugins = window.market.getLocalPlugins();
|
||||
// 修复卸载失败,一直转圈的问题。
|
||||
localPlugins.forEach((origin: Market.Plugin) => {
|
||||
if (origin.name === name) {
|
||||
origin.isloading = false;
|
||||
}
|
||||
});
|
||||
|
||||
commit('commonUpdate', {
|
||||
localPlugins,
|
||||
});
|
||||
},
|
||||
|
||||
successDownload({ commit, state }, name) {
|
||||
const totalPlugins = JSON.parse(JSON.stringify(state.totalPlugins));
|
||||
totalPlugins.forEach(
|
||||
(origin: { isdwonload?: any; name?: any; isloading: boolean }) => {
|
||||
if (origin.name === name) {
|
||||
origin.isloading = false;
|
||||
origin.isdwonload = true;
|
||||
}
|
||||
totalPlugins.forEach((origin: Market.Plugin) => {
|
||||
if (origin.name === name) {
|
||||
origin.isloading = false;
|
||||
origin.isdownload = true;
|
||||
}
|
||||
);
|
||||
const localPlugins = (window as any).market.getLocalPlugins();
|
||||
});
|
||||
const localPlugins = window.market.getLocalPlugins();
|
||||
|
||||
commit("commonUpdate", {
|
||||
commit('commonUpdate', {
|
||||
totalPlugins,
|
||||
localPlugins,
|
||||
});
|
||||
},
|
||||
updateLocalPlugin({ commit }) {
|
||||
const localPlugins = (window as any).market.getLocalPlugins();
|
||||
commit("commonUpdate", {
|
||||
|
||||
async updateLocalPlugin({ commit }) {
|
||||
const localPlugins = window.market.getLocalPlugins();
|
||||
const totalPlugins = await request.getTotalPlugins();
|
||||
|
||||
totalPlugins.forEach((origin: Market.Plugin) => {
|
||||
origin.isdownload = isDownload(origin, localPlugins);
|
||||
origin.isloading = false;
|
||||
});
|
||||
|
||||
commit('commonUpdate', {
|
||||
localPlugins,
|
||||
totalPlugins,
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,21 +1,85 @@
|
||||
<template>
|
||||
<div class="account">
|
||||
<a-result status="404" title="玩命开发中" sub-title="个人中心正在开发中,敬请期待...">
|
||||
<a-result
|
||||
v-if="!userInfo"
|
||||
title="请先登录"
|
||||
sub-title="用户暂未登录,无法体验更多设置"
|
||||
>
|
||||
<template #extra>
|
||||
<a-button @click="showModal" type="primary">
|
||||
使用微信小程序登录
|
||||
</a-button>
|
||||
</template>
|
||||
</a-result>
|
||||
<a-modal :footer="null" v-model:visible="visible">
|
||||
<a-result
|
||||
title="请使用微信扫码登录!"
|
||||
sub-title="使用微信扫描上面的 rubick 小程序二维码进行授权登录"
|
||||
>
|
||||
<template #icon>
|
||||
<img width="200" :src="imgCode" />
|
||||
</template>
|
||||
</a-result>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
<script setup>
|
||||
import { nanoid } from 'nanoid';
|
||||
import { ref, watch } from 'vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
import service from '../../assets/service';
|
||||
|
||||
const userInfo = ref(window.rubick.dbStorage.getItem('rubick-user-info'));
|
||||
|
||||
const imgCode = ref('');
|
||||
const scene = nanoid();
|
||||
|
||||
const visible = ref(false);
|
||||
const showModal = () => {
|
||||
visible.value = true;
|
||||
if (!imgCode.value && !userInfo.value) {
|
||||
service.getScanCode({ scene }).then((res) => {
|
||||
imgCode.value = `data:image/png;base64,${res.dataUrl}`;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
let timer = null;
|
||||
watch([visible], () => {
|
||||
if (visible.value) {
|
||||
timer = setInterval(() => {
|
||||
service.checkLoginStatus({ scene }).then((res) => {
|
||||
console.log(res);
|
||||
if (res.openId) {
|
||||
window.rubick.dbStorage.setItem('rubick-user-info', res);
|
||||
userInfo.value = res;
|
||||
message.success('登录成功!');
|
||||
visible.value = false;
|
||||
clearInterval(timer);
|
||||
timer = null;
|
||||
}
|
||||
});
|
||||
}, 2000);
|
||||
} else {
|
||||
clearInterval(timer);
|
||||
timer = null;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
<style lang="less" scoped>
|
||||
.account {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
overflow-x: hidden;
|
||||
background: #f3efef;
|
||||
height: calc(~"100vh - 46px");
|
||||
background: var(--color-body-bg);
|
||||
height: calc(~'100vh - 46px');
|
||||
:deep(.ant-result-title) {
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
:deep(.ant-result-subtitle) {
|
||||
color: var(--color-text-desc);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
<template>
|
||||
<div class="dev">
|
||||
<a-alert style="margin-bottom: 40px;" message="rubick 插件系统依托于 npm 管理,本地调试需要先在本地插件当前目录执行 npm link" type="warning" />
|
||||
<a-alert
|
||||
style="margin-bottom: 40px"
|
||||
:message="$t('feature.dev.tips')"
|
||||
type="warning"
|
||||
/>
|
||||
<a-form
|
||||
ref="formRef"
|
||||
:model="formState"
|
||||
@@ -8,21 +12,27 @@
|
||||
:label-col="labelCol"
|
||||
:wrapper-col="wrapperCol"
|
||||
>
|
||||
<a-form-item label="插件名称" name="name">
|
||||
<a-form-item :label="$t('feature.dev.pluginName')" name="name">
|
||||
<a-input v-model:value="formState.name" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item :wrapper-col="{ span: 14, offset: 4 }">
|
||||
<a-button :loading="loading" type="primary" @click="onSubmit">安装</a-button>
|
||||
<a-button @click="refresh" style="margin-left: 10px;">刷新插件</a-button>
|
||||
<a-button :loading="loading" type="primary" @click="onSubmit">
|
||||
{{ $t('feature.dev.install') }}
|
||||
</a-button>
|
||||
<a-button @click="refresh" style="margin-left: 10px">
|
||||
{{ $t('feature.dev.refreshPlugins') }}
|
||||
</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive, ref } from "vue";
|
||||
import { message } from "ant-design-vue";
|
||||
import { reactive, ref } from 'vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
const { t } = useI18n();
|
||||
|
||||
const formRef = ref();
|
||||
const formState = reactive({
|
||||
@@ -31,7 +41,7 @@ const formState = reactive({
|
||||
const rules = {
|
||||
name: {
|
||||
required: true,
|
||||
message: "Please input name",
|
||||
message: 'Please input name',
|
||||
},
|
||||
};
|
||||
const onSubmit = () => {
|
||||
@@ -47,7 +57,7 @@ const downloadPlugin = async (pluginName) => {
|
||||
name: pluginName,
|
||||
isDev: true,
|
||||
});
|
||||
message.success(`${pluginName}安装成功!`);
|
||||
message.success(t('feature.dev.installSuccess', { pluginName: pluginName }));
|
||||
loading.value = false;
|
||||
};
|
||||
|
||||
@@ -56,7 +66,9 @@ const refresh = () => {
|
||||
window.market.refreshPlugin({
|
||||
name: formState.name,
|
||||
});
|
||||
message.success(`${formState.name}刷新成功!`);
|
||||
message.success(
|
||||
t('feature.dev.refreshSuccess', { pluginName: formState.name })
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -64,13 +76,20 @@ const labelCol = { span: 4 };
|
||||
const wrapperCol = { span: 14 };
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
<style lang="less" scoped>
|
||||
.dev {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
overflow-x: hidden;
|
||||
background: #fff;
|
||||
height: calc(~"100vh - 46px");
|
||||
background: var(--color-body-bg);
|
||||
height: calc(~'100vh - 46px');
|
||||
padding: 20px;
|
||||
:deep(label) {
|
||||
color: var(--color-text-content);
|
||||
}
|
||||
:deep(.ant-input) {
|
||||
background: var(--color-input-hover);
|
||||
color: var(--color-text-content);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
<template>
|
||||
<div class="installed">
|
||||
<div v-if="!localPlugins.length">
|
||||
<a-result status="404" title="暂无任何插件" sub-title="去插件市场选择安装合适的插件吧!" />
|
||||
<a-result
|
||||
status="404"
|
||||
:title="$t('feature.installed.tips1')"
|
||||
:sub-title="$t('feature.installed.tips2')"
|
||||
/>
|
||||
</div>
|
||||
<div class="container" v-else>
|
||||
<div class="installed-list">
|
||||
@@ -29,7 +33,9 @@
|
||||
<a-tag>{{ pluginDetail.version }}</a-tag>
|
||||
</div>
|
||||
<div class="desc">
|
||||
开发者:{{ `${pluginDetail.author || "未知"}` }}
|
||||
{{ $t('feature.installed.developer') }}:{{
|
||||
`${pluginDetail.author || $t('feature.installed.unknown')}`
|
||||
}}
|
||||
</div>
|
||||
<div class="desc">
|
||||
{{ pluginDetail.description }}
|
||||
@@ -40,13 +46,15 @@
|
||||
type="danger"
|
||||
size="small"
|
||||
shape="round"
|
||||
:loading="pluginDetail.isloading"
|
||||
@click="deletePlugin(pluginDetail)"
|
||||
>移除</a-button
|
||||
>
|
||||
{{ $t('feature.installed.remove') }}
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
<a-tabs default-active-key="1">
|
||||
<a-tab-pane key="1" tab="功能关键字">
|
||||
<a-tab-pane key="1" :tab="$t('feature.installed.functionKey')">
|
||||
<div class="feature-container">
|
||||
<div
|
||||
class="desc-item"
|
||||
@@ -56,51 +64,79 @@
|
||||
<div>{{ item.explain }}</div>
|
||||
<a-tag
|
||||
:key="cmd"
|
||||
@click="
|
||||
openPlugin({
|
||||
cmd,
|
||||
plugin: pluginDetail,
|
||||
feature: item,
|
||||
router: $router,
|
||||
})
|
||||
"
|
||||
v-for="cmd in item.cmds"
|
||||
:class="{ executable: !cmd.label }"
|
||||
>
|
||||
{{ cmd }}
|
||||
<span
|
||||
@click="
|
||||
!cmd.label &&
|
||||
openPlugin({
|
||||
code: item.code,
|
||||
cmd,
|
||||
})
|
||||
"
|
||||
>
|
||||
{{ cmd.label || cmd }}
|
||||
</span>
|
||||
<template v-if="!cmd.label" #icon>
|
||||
<a-tooltip
|
||||
v-if="!hasAdded(cmd)"
|
||||
placement="topLeft"
|
||||
:title="$t('feature.installed.addToPanel')"
|
||||
>
|
||||
<PlusCircleOutlined
|
||||
@click="addCmdToSuperPanel({ code: item.code, cmd })"
|
||||
/>
|
||||
</a-tooltip>
|
||||
<a-tooltip
|
||||
v-else
|
||||
placement="topLeft"
|
||||
:title="$t('feature.installed.removeFromPanel')"
|
||||
>
|
||||
<MinusCircleOutlined
|
||||
@click="removePluginToSuperPanel(cmd)"
|
||||
/>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
</a-tag>
|
||||
</div>
|
||||
</div>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="2" tab="详情介绍">
|
||||
<a-tab-pane key="2" :tab="$t('feature.installed.detailInfo')">
|
||||
<div class="detail-container" v-html="readme"></div>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useStore } from "vuex";
|
||||
import { computed, ref } from "vue";
|
||||
import path from "path";
|
||||
import MarkdownIt from "markdown-it";
|
||||
import { useStore } from 'vuex';
|
||||
import { computed, ref, toRaw } from 'vue';
|
||||
import path from 'path';
|
||||
import MarkdownIt from 'markdown-it';
|
||||
import { PlusCircleOutlined, MinusCircleOutlined } from '@ant-design/icons-vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
|
||||
const { remote } = window.require("electron");
|
||||
const fs = window.require("fs");
|
||||
const { ipcRenderer } = window.require('electron');
|
||||
|
||||
const { remote } = window.require('electron');
|
||||
const fs = window.require('fs');
|
||||
const md = new MarkdownIt();
|
||||
|
||||
const appPath = remote.app.getPath("cache");
|
||||
const baseDir = path.join(appPath, "./rubick-plugins");
|
||||
const appPath = remote.app.getPath('cache');
|
||||
const baseDir = path.join(appPath, './rubick-plugins');
|
||||
|
||||
const store = useStore();
|
||||
const localPlugins = computed(() =>
|
||||
store.state.localPlugins.filter(
|
||||
(plugin) => plugin.name !== "rubick-system-feature"
|
||||
(plugin) => plugin.name !== 'rubick-system-feature'
|
||||
)
|
||||
);
|
||||
const updateLocalPlugin = () => store.dispatch("updateLocalPlugin");
|
||||
const updateLocalPlugin = () => store.dispatch('updateLocalPlugin');
|
||||
const startUnDownload = (name) => store.dispatch('startUnDownload', name);
|
||||
const errorUnDownload = (name) => store.dispatch('errorUnDownload', name);
|
||||
|
||||
const currentSelect = ref([0]);
|
||||
|
||||
@@ -108,34 +144,106 @@ const pluginDetail = computed(() => {
|
||||
return localPlugins.value[currentSelect.value] || {};
|
||||
});
|
||||
|
||||
const superPanelPlugins = ref(
|
||||
window.rubick.db.get('super-panel-plugins') || {
|
||||
data: [],
|
||||
_id: 'super-panel-plugins',
|
||||
}
|
||||
);
|
||||
|
||||
const addCmdToSuperPanel = ({ cmd, code }) => {
|
||||
const plugin = {
|
||||
...toRaw(pluginDetail.value),
|
||||
cmd,
|
||||
ext: {
|
||||
code,
|
||||
type: 'text',
|
||||
payload: null,
|
||||
},
|
||||
};
|
||||
superPanelPlugins.value.data.push(plugin);
|
||||
window.rubick.db.put(toRaw(superPanelPlugins.value));
|
||||
};
|
||||
|
||||
const removePluginToSuperPanel = (cmd) => {
|
||||
superPanelPlugins.value.data = toRaw(superPanelPlugins.value).data.filter(
|
||||
(item) => {
|
||||
return item.cmd !== cmd;
|
||||
}
|
||||
);
|
||||
console.log(toRaw(superPanelPlugins.value));
|
||||
window.rubick.db.put(toRaw(superPanelPlugins.value));
|
||||
};
|
||||
|
||||
const hasAdded = (cmd) => {
|
||||
let added = false;
|
||||
superPanelPlugins.value.data.some((item) => {
|
||||
if (item.cmd === cmd) {
|
||||
added = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
return added;
|
||||
};
|
||||
|
||||
const openPlugin = ({ cmd, code }) => {
|
||||
window.rubick.openPlugin(
|
||||
JSON.parse(
|
||||
JSON.stringify({
|
||||
...pluginDetail.value,
|
||||
cmd,
|
||||
ext: {
|
||||
code,
|
||||
type: 'text',
|
||||
payload: null,
|
||||
},
|
||||
})
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
const readme = computed(() => {
|
||||
if (!pluginDetail.value.name) return "";
|
||||
if (!pluginDetail.value.name) return '';
|
||||
const readmePath = path.resolve(
|
||||
baseDir,
|
||||
"node_modules",
|
||||
'node_modules',
|
||||
pluginDetail.value.name,
|
||||
"readme.md"
|
||||
'readme.md'
|
||||
);
|
||||
if (fs.existsSync(readmePath)) {
|
||||
const str = fs.readFileSync(readmePath, "utf-8");
|
||||
const str = fs.readFileSync(readmePath, 'utf-8');
|
||||
return md.render(str);
|
||||
}
|
||||
return "";
|
||||
return '';
|
||||
});
|
||||
|
||||
const deletePlugin = async (plugin) => {
|
||||
startUnDownload(plugin.name);
|
||||
const timer = setTimeout(() => {
|
||||
errorUnDownload(plugin.name);
|
||||
message.error('卸载超时,请重试!');
|
||||
}, 20000);
|
||||
await window.market.deletePlugin(plugin);
|
||||
updateLocalPlugin();
|
||||
clearTimeout(timer);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
<style lang="less" scoped>
|
||||
.installed {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
background: #f3efef;
|
||||
height: calc(~"100vh - 46px");
|
||||
background: var(--color-body-bg);
|
||||
height: calc(~'100vh - 46px');
|
||||
:deep(.ant-result-title) {
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
:deep(.ant-result-subtitle) {
|
||||
color: var(--color-text-desc);
|
||||
}
|
||||
|
||||
.container {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
@@ -144,67 +252,106 @@ const deletePlugin = async (plugin) => {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.installed-list {
|
||||
width: 40%;
|
||||
background: #fff;
|
||||
background: var(--color-body-bg);
|
||||
height: 100%;
|
||||
padding: 10px 0;
|
||||
border-right: 1px solid #eee;
|
||||
border-right: 1px solid var(--color-border-light);
|
||||
overflow: auto;
|
||||
|
||||
.item {
|
||||
padding: 10px 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: var(--color-text-content);
|
||||
img {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.desc {
|
||||
color: #999;
|
||||
color: var(--color-text-desc);
|
||||
}
|
||||
|
||||
&.active {
|
||||
background: #eee;
|
||||
background: var(--color-list-hover);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.plugin-detail {
|
||||
padding: 20px 20px 0 20px;
|
||||
box-sizing: border-box;
|
||||
width: 60%;
|
||||
height: 100%;
|
||||
background: #fff;
|
||||
background: var(--color-body-bg);
|
||||
.plugin-top {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
|
||||
.title {
|
||||
font-size: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: var(--color-text-primary);
|
||||
.ant-tag {
|
||||
background: var(--color-input-hover);
|
||||
border: 1px solid var(--color-border-light);
|
||||
color: var(--color-text-content);
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.desc {
|
||||
font-size: 13px;
|
||||
color: #999;
|
||||
color: var(--color-text-desc);
|
||||
}
|
||||
}
|
||||
.ant-tabs {
|
||||
:deep(.ant-tabs-bar) {
|
||||
color: var(--color-text-content);
|
||||
border-bottom: 1px solid var(--color-border-light);
|
||||
}
|
||||
}
|
||||
|
||||
.detail-container,
|
||||
.feature-container {
|
||||
height: 380px;
|
||||
overflow: auto;
|
||||
color: var(--color-text-content);
|
||||
img {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.desc-item {
|
||||
border-bottom: 1px solid #ddd;
|
||||
border-bottom: 1px solid var(--color-border-light);
|
||||
padding: 10px 0;
|
||||
color: var(--color-text-content);
|
||||
.ant-tag {
|
||||
margin-top: 6px;
|
||||
|
||||
&.executable {
|
||||
cursor: pointer;
|
||||
color: var(--ant-info-color);
|
||||
&:hover {
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.desc-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.desc-info {
|
||||
color: #999;
|
||||
color: var(--color-text-desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,18 +3,18 @@
|
||||
<PluginList
|
||||
v-if="dev && !!dev.length"
|
||||
@downloadSuccess="downloadSuccess"
|
||||
title="开发"
|
||||
:title="$t('feature.market.developTool')"
|
||||
:list="dev"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onBeforeMount } from "vue";
|
||||
import request from "../../../assets/request/index";
|
||||
import PluginList from "./plugin-list.vue";
|
||||
import { ref, computed, onBeforeMount } from 'vue';
|
||||
import request from '../../../assets/request/index';
|
||||
import PluginList from './plugin-list.vue';
|
||||
|
||||
import { useStore } from "vuex";
|
||||
import { useStore } from 'vuex';
|
||||
const store = useStore();
|
||||
const totalPlugins = computed(() => store.state.totalPlugins);
|
||||
|
||||
|
||||
@@ -11,34 +11,31 @@
|
||||
<right-circle-outlined />
|
||||
</div>
|
||||
</template>
|
||||
<div :key="index" v-for="(banner, index) in (data.banners || [])">
|
||||
<div :key="index" v-for="(banner, index) in data.banners || []">
|
||||
<img @click="jumpTo(banner.link)" width="100%" :src="banner.src" />
|
||||
</div>
|
||||
</a-carousel>
|
||||
<PluginList
|
||||
v-if="recommend && !!recommend.length"
|
||||
@downloadSuccess="downloadSuccess"
|
||||
title="推荐"
|
||||
:title="$t('feature.market.finder.recommended')"
|
||||
:list="recommend"
|
||||
/>
|
||||
<PluginList
|
||||
v-if="newList && !!newList.length"
|
||||
title="最近更新"
|
||||
:title="$t('feature.market.finder.lastUpdated')"
|
||||
:list="newList"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
LeftCircleOutlined,
|
||||
RightCircleOutlined,
|
||||
} from "@ant-design/icons-vue";
|
||||
import { ref, computed, onBeforeMount } from "vue";
|
||||
import request from "../../../assets/request/index";
|
||||
import PluginList from "./plugin-list.vue";
|
||||
import { LeftCircleOutlined, RightCircleOutlined } from '@ant-design/icons-vue';
|
||||
import { ref, computed, onBeforeMount } from 'vue';
|
||||
import request from '../../../assets/request/index';
|
||||
import PluginList from './plugin-list.vue';
|
||||
|
||||
import { useStore } from "vuex";
|
||||
import { useStore } from 'vuex';
|
||||
const store = useStore();
|
||||
const totalPlugins = computed(() => store.state.totalPlugins);
|
||||
|
||||
@@ -75,7 +72,6 @@ const newList = computed(() => {
|
||||
return searchInfo;
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
|
||||
@@ -1,13 +1,49 @@
|
||||
<template>
|
||||
|
||||
<div class="system">
|
||||
<PluginList
|
||||
v-if="system && !!system.length"
|
||||
@downloadSuccess="downloadSuccess"
|
||||
:title="$t('feature.market.imageTool')"
|
||||
:list="system"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "image"
|
||||
};
|
||||
<script setup>
|
||||
import { ref, computed, onBeforeMount } from 'vue';
|
||||
import request from '../../../assets/request/index';
|
||||
import PluginList from './plugin-list.vue';
|
||||
|
||||
import { useStore } from 'vuex';
|
||||
const store = useStore();
|
||||
const totalPlugins = computed(() => store.state.totalPlugins);
|
||||
|
||||
const data = ref([]);
|
||||
|
||||
onBeforeMount(async () => {
|
||||
data.value = await request.getImageDetail();
|
||||
});
|
||||
|
||||
const system = computed(() => {
|
||||
const defaultData = data.value || [];
|
||||
if (!defaultData.length) return [];
|
||||
return defaultData.map((plugin) => {
|
||||
let searchInfo = null;
|
||||
totalPlugins.value.forEach((t) => {
|
||||
if (t.name === plugin) {
|
||||
searchInfo = t;
|
||||
}
|
||||
});
|
||||
return searchInfo;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
<style lang="less">
|
||||
.system {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
overflow-x: hidden;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -2,13 +2,20 @@
|
||||
<div class="panel-item">
|
||||
<h3 class="title">{{ title }}</h3>
|
||||
<div class="list-item">
|
||||
<a-list :grid="{ gutter: 16, column: 2 }" :data-source="list">
|
||||
<a-list
|
||||
:grid="{ gutter: 16, column: 2 }"
|
||||
:data-source="list.filter((item) => !!item)"
|
||||
>
|
||||
<template #renderItem="{ item, index }">
|
||||
<a-list-item @click="showDetail(item)">
|
||||
<a-list-item v-if="item" @click="showDetail(item)">
|
||||
<template #actions>
|
||||
<a-button style="color: #ff4ea4;" type="text" :loading="item.isloading">
|
||||
<a-button
|
||||
class="download-plugin-btn"
|
||||
type="text"
|
||||
:loading="item.isloading"
|
||||
>
|
||||
<CloudDownloadOutlined
|
||||
v-show="!item.isloading && !item.isdwonload"
|
||||
v-show="!item.isloading && !item.isdownload"
|
||||
@click.stop="downloadPlugin(item, index)"
|
||||
style="font-size: 20px; cursor: pointer"
|
||||
/>
|
||||
@@ -16,7 +23,7 @@
|
||||
</template>
|
||||
<a-list-item-meta>
|
||||
<template #description>
|
||||
<span class="ellipse">{{ item.description }}</span>
|
||||
<span class="ellipse desc">{{ item.description }}</span>
|
||||
</template>
|
||||
<template #title>
|
||||
<span class="ellipse">{{ item.pluginName }}</span>
|
||||
@@ -38,18 +45,15 @@
|
||||
:get-container="false"
|
||||
class="plugin-info"
|
||||
:style="{ position: 'absolute' }"
|
||||
@close="visible=false"
|
||||
@close="visible = false"
|
||||
>
|
||||
<template #title>
|
||||
<div class="plugin-title-info">
|
||||
<div class="back-icon" @click="visible=false">
|
||||
<div class="back-icon" @click="visible = false">
|
||||
<ArrowLeftOutlined />
|
||||
</div>
|
||||
<div class="info">
|
||||
<img
|
||||
:src="detail.logo"
|
||||
class="plugin-icon"
|
||||
/>
|
||||
<img :src="detail.logo" class="plugin-icon" />
|
||||
<div class="plugin-desc">
|
||||
<div class="title">
|
||||
{{ detail.pluginName }}
|
||||
@@ -57,11 +61,19 @@
|
||||
<div class="desc">
|
||||
{{ detail.description }}
|
||||
</div>
|
||||
<a-button shape="round" type="primary">
|
||||
<a-button
|
||||
v-if="!detail.isdownload"
|
||||
@click.stop="downloadPlugin(detail)"
|
||||
shape="round"
|
||||
type="primary"
|
||||
:loading="detail.isloading"
|
||||
>
|
||||
<template #icon>
|
||||
<CloudDownloadOutlined />
|
||||
<CloudDownloadOutlined
|
||||
v-show="!detail.isloading && !detail.isdownload"
|
||||
/>
|
||||
</template>
|
||||
获取
|
||||
{{ $t('feature.market.install') }}
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -75,18 +87,20 @@
|
||||
import {
|
||||
CloudDownloadOutlined,
|
||||
ArrowLeftOutlined,
|
||||
} from "@ant-design/icons-vue";
|
||||
} from '@ant-design/icons-vue';
|
||||
|
||||
import { defineProps, ref } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
import { message } from "ant-design-vue";
|
||||
import MarkdownIt from "markdown-it";
|
||||
import request from "../../../assets/request/index";
|
||||
import { defineProps, ref } from 'vue';
|
||||
import { useStore } from 'vuex';
|
||||
import { message } from 'ant-design-vue';
|
||||
import MarkdownIt from 'markdown-it';
|
||||
import request from '../../../assets/request/index';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
const { t } = useI18n();
|
||||
|
||||
const store = useStore();
|
||||
|
||||
const startDownload = (name) => store.dispatch("startDownload", name);
|
||||
const successDownload = (name) => store.dispatch("successDownload", name);
|
||||
const startDownload = (name) => store.dispatch('startDownload', name);
|
||||
const successDownload = (name) => store.dispatch('successDownload', name);
|
||||
|
||||
defineProps({
|
||||
list: {
|
||||
@@ -99,19 +113,19 @@ defineProps({
|
||||
const downloadPlugin = async (plugin) => {
|
||||
startDownload(plugin.name);
|
||||
await window.market.downloadPlugin(plugin);
|
||||
message.success(`${plugin.name}安装成功!`);
|
||||
message.success(t('feature.dev.installSuccess', { pluginName: plugin.name }));
|
||||
successDownload(plugin.name);
|
||||
};
|
||||
|
||||
const visible = ref(false);
|
||||
const detail = ref({});
|
||||
const markdown = new MarkdownIt();
|
||||
const content = ref("");
|
||||
const content = ref('');
|
||||
|
||||
const showDetail = async (item) => {
|
||||
visible.value = true;
|
||||
detail.value = item;
|
||||
let mdContent = "暂无内容";
|
||||
let mdContent = '暂无内容';
|
||||
if (item.homePage) {
|
||||
mdContent = await request.getPluginDetail(item.homePage);
|
||||
}
|
||||
@@ -125,8 +139,12 @@ const showDetail = async (item) => {
|
||||
}
|
||||
.panel-item {
|
||||
margin: 20px 0;
|
||||
.download-plugin-btn {
|
||||
color: var(--ant-primary-color);
|
||||
}
|
||||
.title {
|
||||
margin-bottom: 30px;
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
.ellipse {
|
||||
display: inline-block;
|
||||
@@ -134,13 +152,17 @@ const showDetail = async (item) => {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
width: 100%;
|
||||
color: var(--color-text-content);
|
||||
&.desc {
|
||||
color: var(--color-text-desc);
|
||||
}
|
||||
}
|
||||
&:after{
|
||||
content: " ";
|
||||
&:after {
|
||||
content: ' ';
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
border-bottom: 1px solid #eee;
|
||||
border-bottom: 1px solid var(--color-border-light);
|
||||
transform: scaleY(0.5);
|
||||
}
|
||||
.ant-list-item {
|
||||
@@ -156,6 +178,21 @@ const showDetail = async (item) => {
|
||||
|
||||
.ant-drawer-content-wrapper {
|
||||
box-shadow: none !important;
|
||||
.ant-drawer-content {
|
||||
background: var(--color-body-bg);
|
||||
}
|
||||
.ant-drawer-header {
|
||||
background: var(--color-body-bg);
|
||||
border-bottom: 1px solid var(--color-border-light);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dark {
|
||||
.plugin-title-info {
|
||||
.back-icon {
|
||||
filter: invert(1) brightness(200%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,6 +219,7 @@ const showDetail = async (item) => {
|
||||
.title {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.desc {
|
||||
@@ -189,11 +227,15 @@ const showDetail = async (item) => {
|
||||
font-weight: normal;
|
||||
margin-top: 5px;
|
||||
margin-bottom: 20px;
|
||||
color: var(--color-text-desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.home-page-container {
|
||||
* {
|
||||
color: var(--color-text-content);
|
||||
}
|
||||
img {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
45
feature/src/views/market/components/result.vue
Normal file
@@ -0,0 +1,45 @@
|
||||
<template>
|
||||
<div class="result">
|
||||
<PluginList
|
||||
v-if="result && !!result.length"
|
||||
@downloadSuccess="downloadSuccess"
|
||||
:title="$t('feature.market.searchResult')"
|
||||
:list="result"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue';
|
||||
import PluginList from './plugin-list.vue';
|
||||
|
||||
import { useStore } from 'vuex';
|
||||
const store = useStore();
|
||||
|
||||
const totalPlugins = computed(() => store.state.totalPlugins);
|
||||
const searchValue = computed(() => store.state.searchValue);
|
||||
|
||||
const result = computed(() => {
|
||||
if (searchValue.value.trim().length > 0) {
|
||||
const pattern = new RegExp(searchValue.value);
|
||||
return totalPlugins.value.filter((plugin) => {
|
||||
if (plugin.pluginName.match(pattern)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
return totalPlugins.value;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.result {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
overflow-x: hidden;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
</style>
|
||||
@@ -3,18 +3,18 @@
|
||||
<PluginList
|
||||
v-if="system && !!system.length"
|
||||
@downloadSuccess="downloadSuccess"
|
||||
title="系统插件"
|
||||
:title="$t('feature.market.systemTool')"
|
||||
:list="system"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onBeforeMount } from "vue";
|
||||
import request from "../../../assets/request/index";
|
||||
import PluginList from "./plugin-list.vue";
|
||||
import { ref, computed, onBeforeMount } from 'vue';
|
||||
import request from '../../../assets/request/index';
|
||||
import PluginList from './plugin-list.vue';
|
||||
|
||||
import { useStore } from "vuex";
|
||||
import { useStore } from 'vuex';
|
||||
const store = useStore();
|
||||
const totalPlugins = computed(() => store.state.totalPlugins);
|
||||
|
||||
|
||||
@@ -3,18 +3,18 @@
|
||||
<PluginList
|
||||
v-if="tools && !!tools.length"
|
||||
@downloadSuccess="downloadSuccess"
|
||||
title="搜索工具"
|
||||
:title="$t('feature.market.searchTool')"
|
||||
:list="tools"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onBeforeMount } from "vue";
|
||||
import request from "../../../assets/request/index";
|
||||
import PluginList from "./plugin-list.vue";
|
||||
import { ref, computed, onBeforeMount } from 'vue';
|
||||
import request from '../../../assets/request/index';
|
||||
import PluginList from './plugin-list.vue';
|
||||
|
||||
import { useStore } from "vuex";
|
||||
import { useStore } from 'vuex';
|
||||
const store = useStore();
|
||||
const totalPlugins = computed(() => store.state.totalPlugins);
|
||||
|
||||
|
||||
@@ -3,18 +3,18 @@
|
||||
<PluginList
|
||||
v-if="system && !!system.length"
|
||||
@downloadSuccess="downloadSuccess"
|
||||
title="生产效率"
|
||||
:title="$t('feature.market.efficiency')"
|
||||
:list="system"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onBeforeMount } from "vue";
|
||||
import request from "../../../assets/request/index";
|
||||
import PluginList from "./plugin-list.vue";
|
||||
import { ref, computed, onBeforeMount } from 'vue';
|
||||
import request from '../../../assets/request/index';
|
||||
import PluginList from './plugin-list.vue';
|
||||
|
||||
import { useStore } from "vuex";
|
||||
import { useStore } from 'vuex';
|
||||
const store = useStore();
|
||||
const totalPlugins = computed(() => store.state.totalPlugins);
|
||||
|
||||
|
||||
@@ -4,8 +4,9 @@
|
||||
<div class="search-container">
|
||||
<a-input-search
|
||||
v-model:value="searchValue"
|
||||
placeholder="搜索插件"
|
||||
:placeholder="$t('feature.market.search')"
|
||||
style="width: 100%"
|
||||
class="search"
|
||||
@search="onSearch"
|
||||
/>
|
||||
</div>
|
||||
@@ -15,37 +16,37 @@
|
||||
<template #icon>
|
||||
<StarOutlined />
|
||||
</template>
|
||||
探索
|
||||
{{ $t('feature.market.explore') }}
|
||||
</a-menu-item>
|
||||
<a-menu-item key="worker">
|
||||
<template #icon>
|
||||
<SendOutlined style="transform: rotate(-45deg)" />
|
||||
</template>
|
||||
效率
|
||||
{{ $t('feature.market.efficiency') }}
|
||||
</a-menu-item>
|
||||
<a-menu-item key="tools">
|
||||
<template #icon>
|
||||
<SearchOutlined />
|
||||
</template>
|
||||
搜索工具
|
||||
{{ $t('feature.market.searchTool') }}
|
||||
</a-menu-item>
|
||||
<a-menu-item key="image">
|
||||
<template #icon>
|
||||
<FileImageOutlined />
|
||||
</template>
|
||||
图像
|
||||
{{ $t('feature.market.imageTool') }}
|
||||
</a-menu-item>
|
||||
<a-menu-item key="dev">
|
||||
<template #icon>
|
||||
<CodeOutlined />
|
||||
</template>
|
||||
开发
|
||||
{{ $t('feature.market.developTool') }}
|
||||
</a-menu-item>
|
||||
<a-menu-item key="system">
|
||||
<template #icon>
|
||||
<DatabaseOutlined />
|
||||
</template>
|
||||
系统
|
||||
{{ $t('feature.market.systemTool') }}
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</div>
|
||||
@@ -63,26 +64,30 @@ import {
|
||||
FileImageOutlined,
|
||||
DatabaseOutlined,
|
||||
CodeOutlined,
|
||||
} from "@ant-design/icons-vue";
|
||||
import { reactive, toRefs, computed } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
import Finder from "./components/finder.vue";
|
||||
import System from "./components/system.vue";
|
||||
import Worker from "./components/worker.vue";
|
||||
import Tools from "./components/tools.vue";
|
||||
import Dev from "./components/devlopment.vue";
|
||||
} from '@ant-design/icons-vue';
|
||||
import { reactive, toRefs, computed } from 'vue';
|
||||
import { useStore } from 'vuex';
|
||||
import Finder from './components/finder.vue';
|
||||
import System from './components/system.vue';
|
||||
import Worker from './components/worker.vue';
|
||||
import Tools from './components/tools.vue';
|
||||
import Dev from './components/devlopment.vue';
|
||||
import Image from './components/image.vue';
|
||||
import Result from './components/result.vue';
|
||||
|
||||
const Components = {
|
||||
finder: Finder,
|
||||
system: System,
|
||||
worker: Worker,
|
||||
image: Image,
|
||||
tools: Tools,
|
||||
dev: Dev,
|
||||
result: Result,
|
||||
};
|
||||
|
||||
const state = reactive({
|
||||
searchValue: "",
|
||||
current: ["finder"],
|
||||
searchValue: '',
|
||||
current: ['finder'],
|
||||
});
|
||||
|
||||
const store = useStore();
|
||||
@@ -90,39 +95,34 @@ const store = useStore();
|
||||
const totalPlugins = computed(() => store.state.totalPlugins);
|
||||
|
||||
const { searchValue, current } = toRefs(state);
|
||||
|
||||
const onSearch = (searchValue: string) => {
|
||||
state.current = ['result'];
|
||||
store.commit('setSearchValue', searchValue);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
<style lang="less" scoped>
|
||||
@import '~@/assets/common.less';
|
||||
.market {
|
||||
display: flex;
|
||||
box-sizing: border-box;
|
||||
align-items: flex-start;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
background: #F3EFEF;
|
||||
height: calc(~"100vh - 46px");
|
||||
.left-menu {
|
||||
width: 200px;
|
||||
height: 100vh;
|
||||
.search-container {
|
||||
padding: 10px;
|
||||
}
|
||||
.ant-input-affix-wrapper {
|
||||
border: none;
|
||||
}
|
||||
.ant-menu {
|
||||
background: #F3EFEF;
|
||||
.ant-menu-item-selected {
|
||||
background-color: #E2E2E2;
|
||||
color: #141414;
|
||||
&:after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
background: var(--color-menu-bg);
|
||||
height: calc(~'100vh - 46px');
|
||||
.search {
|
||||
:deep(.ant-btn),
|
||||
:deep(.ant-input),
|
||||
:deep(.ant-input-group-addon) {
|
||||
color: var(--ant-primary-color) !important;
|
||||
background: var(--color-input-hover);
|
||||
border-color: var(--color-border-light);
|
||||
}
|
||||
}
|
||||
.container {
|
||||
background: #fff;
|
||||
background: var(--color-body-bg);
|
||||
width: calc(~'100% - 200px');
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
|
||||
@@ -2,104 +2,170 @@
|
||||
<div class="settings">
|
||||
<div class="left-menu">
|
||||
<a-menu v-model:selectedKeys="currentSelect" mode="inline">
|
||||
<a-menu-item key="userInfo">
|
||||
<template #icon>
|
||||
<UserOutlined />
|
||||
</template>
|
||||
{{ $t('feature.settings.account.accountInfo') }}
|
||||
</a-menu-item>
|
||||
<a-menu-item key="normal">
|
||||
<template #icon>
|
||||
<ToolOutlined />
|
||||
</template>
|
||||
基本设置
|
||||
{{ $t('feature.settings.basic.title') }}
|
||||
</a-menu-item>
|
||||
<a-menu-item key="global">
|
||||
<template #icon>
|
||||
<LaptopOutlined />
|
||||
</template>
|
||||
全局快捷键
|
||||
{{ $t('feature.settings.global.title') }}
|
||||
</a-menu-item>
|
||||
<!-- <a-menu-item key="superpanel">-->
|
||||
<!-- <template #icon>-->
|
||||
<!-- <FileAddOutlined />-->
|
||||
<!-- </template>-->
|
||||
<!-- {{ $t('feature.settings.superPanel.title') }}-->
|
||||
<!-- </a-menu-item>-->
|
||||
<a-menu-item key="localhost">
|
||||
<template #icon>
|
||||
<DatabaseOutlined />
|
||||
</template>
|
||||
{{ $t('feature.settings.intranet.title') }}
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</div>
|
||||
<div class="settings-detail">
|
||||
<UserInfo v-if="currentSelect[0] === 'userInfo'" />
|
||||
<div v-if="currentSelect[0] === 'normal'">
|
||||
<div class="setting-item">
|
||||
<div class="title">
|
||||
快捷键(需要使用 option/ctrl/shift/command 键修饰)
|
||||
{{ $t('feature.settings.basic.shortcutKey') }}
|
||||
</div>
|
||||
<div class="settings-item-li">
|
||||
<div class="label">显示/隐藏快捷键</div>
|
||||
<div
|
||||
class="value"
|
||||
tabIndex="-1"
|
||||
@keyup="(e) => changeShortCut(e, 'showAndHidden')"
|
||||
>
|
||||
{{ shortCut.showAndHidden }}
|
||||
<div class="label">
|
||||
{{ $t('feature.settings.basic.showOrHiddle') }}
|
||||
</div>
|
||||
<a-tooltip placement="top" trigger="click">
|
||||
<template #title>
|
||||
<span>{{ tipText }}</span>
|
||||
<template v-if="isWindows">
|
||||
<br />
|
||||
<span
|
||||
style="cursor: pointer; text-decoration: underline"
|
||||
@click="resetDefault('Alt')"
|
||||
>
|
||||
Alt+Space
|
||||
</span>
|
||||
<span
|
||||
style="
|
||||
cursor: pointer;
|
||||
margin-left: 8px;
|
||||
text-decoration: underline;
|
||||
"
|
||||
@click="resetDefault('Ctrl')"
|
||||
>
|
||||
Ctrl+Space
|
||||
</span>
|
||||
</template>
|
||||
</template>
|
||||
<div
|
||||
class="value"
|
||||
tabIndex="-1"
|
||||
@keyup="(e) => changeShortCut(e, 'showAndHidden')"
|
||||
>
|
||||
{{ shortCut.showAndHidden }}
|
||||
</div>
|
||||
</a-tooltip>
|
||||
</div>
|
||||
<div class="settings-item-li">
|
||||
<div class="label">
|
||||
{{ $t('feature.settings.basic.screenCapture') }}
|
||||
</div>
|
||||
<a-tooltip placement="top" trigger="click">
|
||||
<template #title>
|
||||
<span>{{ tipText }}</span>
|
||||
</template>
|
||||
<div
|
||||
class="value"
|
||||
tabIndex="-1"
|
||||
@keyup="(e) => changeShortCut(e, 'capture')"
|
||||
>
|
||||
{{ shortCut.capture }}
|
||||
</div>
|
||||
</a-tooltip>
|
||||
</div>
|
||||
<!-- <div class="settings-item-li">-->
|
||||
<!-- <div class="label">插件分离快捷键</div>-->
|
||||
<!-- <div-->
|
||||
<!-- class="value"-->
|
||||
<!-- tabIndex="-1"-->
|
||||
<!-- @keyup="(e) => changeShortCut(e, 'separate')"-->
|
||||
<!-- >-->
|
||||
<!-- {{ shortCut.separate }}-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="settings-item-li">-->
|
||||
<!-- <div class="label">返回主界面</div>-->
|
||||
<!-- <div-->
|
||||
<!-- class="value"-->
|
||||
<!-- tabIndex="-1"-->
|
||||
<!-- @keyup="(e) => changeShortCut(e, 'quit')"-->
|
||||
<!-- >-->
|
||||
<!-- {{ shortCut.quit }}-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div class="title">通用</div>
|
||||
<div class="title">{{ $t('feature.settings.basic.common') }}</div>
|
||||
<div class="settings-item-li">
|
||||
<div class="label">输入框自动粘贴</div>
|
||||
<div class="label">
|
||||
{{ $t('feature.settings.basic.autoPaste') }}
|
||||
</div>
|
||||
<a-switch
|
||||
v-model:checked="common.autoPast"
|
||||
checked-children="开"
|
||||
un-checked-children="关"
|
||||
:checked-children="$t('feature.settings.basic.on')"
|
||||
:un-checked-children="$t('feature.settings.basic.off')"
|
||||
></a-switch>
|
||||
</div>
|
||||
<div class="settings-item-li">
|
||||
<div class="label">开机启动</div>
|
||||
<div class="label">{{ $t('feature.settings.basic.autoBoot') }}</div>
|
||||
<a-switch
|
||||
v-model:checked="common.start"
|
||||
checked-children="开"
|
||||
un-checked-children="关"
|
||||
:checked-children="$t('feature.settings.basic.on')"
|
||||
:un-checked-children="$t('feature.settings.basic.off')"
|
||||
></a-switch>
|
||||
</div>
|
||||
<div class="settings-item-li">
|
||||
<div class="label">空格执行</div>
|
||||
<div class="label">
|
||||
{{ $t('feature.settings.basic.spaceExec') }}
|
||||
</div>
|
||||
<a-switch
|
||||
v-model:checked="common.space"
|
||||
checked-children="开"
|
||||
un-checked-children="关"
|
||||
:checked-children="$t('feature.settings.basic.on')"
|
||||
:un-checked-children="$t('feature.settings.basic.off')"
|
||||
></a-switch>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="setting-item">-->
|
||||
<!-- <div class="title">本地搜索启动</div>-->
|
||||
<!-- <div class="settings-item-li">-->
|
||||
<!-- <div class="label">搜索启动应用&文件</div>-->
|
||||
<!-- <a-switch-->
|
||||
<!-- v-model:checked="local.search"-->
|
||||
<!-- checked-children="开"-->
|
||||
<!-- un-checked-children="关"-->
|
||||
<!-- ></a-switch>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<div class="setting-item">
|
||||
<div class="title">{{ $t('feature.settings.basic.theme') }}</div>
|
||||
<div class="settings-item-li">
|
||||
<div class="label">{{ $t('feature.settings.basic.darkMode') }}</div>
|
||||
<a-switch
|
||||
v-model:checked="common.darkMode"
|
||||
:checked-children="$t('feature.settings.basic.on')"
|
||||
:un-checked-children="$t('feature.settings.basic.off')"
|
||||
></a-switch>
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div class="title">{{ $t('feature.settings.basic.language') }}</div>
|
||||
<div class="settings-item-li">
|
||||
<div class="label">
|
||||
{{ $t('feature.settings.basic.changeLang') }}
|
||||
</div>
|
||||
<a-select
|
||||
v-model:value="state.common.lang"
|
||||
label-in-value
|
||||
style="width: 240px"
|
||||
:options="options"
|
||||
@change="changeLanguage"
|
||||
></a-select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="currentSelect[0] === 'global'">
|
||||
<a-collapse>
|
||||
<a-collapse-panel key="1" header="说明及示例">
|
||||
<a-collapse-panel
|
||||
key="1"
|
||||
:header="$t('feature.settings.global.instructions')"
|
||||
>
|
||||
<div>
|
||||
按下快捷键,自动搜索对应关键字,当关键字结果完全匹配,且结果唯一时,会直接指向该功能。
|
||||
{{ $t('feature.settings.global.tips') }}
|
||||
</div>
|
||||
<h3 style="margin-top: 10px;">示例</h3>
|
||||
<a-divider style="margin: 5px 0;" />
|
||||
<h3 style="margin-top: 10px">
|
||||
{{ $t('feature.settings.global.example') }}
|
||||
</h3>
|
||||
<a-divider style="margin: 5px 0" />
|
||||
<a-list item-layout="horizontal" :data-source="examples">
|
||||
<template #renderItem="{ item }">
|
||||
<a-list-item>
|
||||
@@ -115,58 +181,78 @@
|
||||
</a-collapse>
|
||||
<div class="feature-container">
|
||||
<div class="keywords item">
|
||||
<div>快捷键</div>
|
||||
<a-tooltip placement="top" trigger="click">
|
||||
<template #title>
|
||||
<span>先按功能键(Ctrl、Shift、Alt、Option、Command),再按其他普通键。或按
|
||||
F1-F12 单键
|
||||
</span>
|
||||
</template>
|
||||
<div
|
||||
:key="index"
|
||||
v-for="(item, index) in global"
|
||||
class="value"
|
||||
tabIndex="2"
|
||||
@keyup="(e) => changeGlobalKey(e, index)"
|
||||
>
|
||||
{{ item.key }}
|
||||
</div>
|
||||
</a-tooltip>
|
||||
<div>{{ $t('feature.settings.global.shortcutKey') }}</div>
|
||||
<template :key="index" v-for="(item, index) in global">
|
||||
<a-tooltip placement="top" trigger="click">
|
||||
<template #title>
|
||||
<span>{{ tipText }}</span>
|
||||
</template>
|
||||
<div
|
||||
class="value"
|
||||
tabIndex="2"
|
||||
@keyup="(e) => changeGlobalKey(e, index)"
|
||||
>
|
||||
{{ item.key }}
|
||||
<MinusCircleOutlined
|
||||
@click.stop="deleteGlobalKey(e, index)"
|
||||
/>
|
||||
</div>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
</div>
|
||||
<div class="short-cut item">
|
||||
<div>功能关键字</div>
|
||||
<a-input
|
||||
:key="index"
|
||||
:value="item.value"
|
||||
v-for="(item, index) in global"
|
||||
class="value"
|
||||
:disabled="!item.key"
|
||||
@change="(e) => changeGlobalValue(index, e.target.value)"
|
||||
/>
|
||||
<div>{{ $t('feature.settings.global.funtionKey') }}</div>
|
||||
<template v-for="(item, index) in global" :key="index">
|
||||
<a-input
|
||||
:value="item.value"
|
||||
class="value"
|
||||
allowClear
|
||||
:disabled="!item.key"
|
||||
@change="(e) => changeGlobalValue(index, e.target.value)"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<div @click="addConfig" class="add-global">+ 新增全局快捷功能</div>
|
||||
<div @click="addConfig" class="add-global">
|
||||
<PlusCircleOutlined />
|
||||
{{ $t('feature.settings.global.addShortcutKey') }}
|
||||
</div>
|
||||
</div>
|
||||
<SuperPanel v-if="currentSelect[0] === 'superpanel'" />
|
||||
<Localhost v-if="currentSelect[0] === 'localhost'" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ToolOutlined, LaptopOutlined } from "@ant-design/icons-vue";
|
||||
import debounce from "lodash.debounce";
|
||||
import { ref, reactive, watch, toRefs, toRaw } from "vue";
|
||||
import keycodes from "./keycode";
|
||||
import {
|
||||
ToolOutlined,
|
||||
LaptopOutlined,
|
||||
DatabaseOutlined,
|
||||
MinusCircleOutlined,
|
||||
PlusCircleOutlined,
|
||||
FileAddOutlined,
|
||||
UserOutlined,
|
||||
} from '@ant-design/icons-vue';
|
||||
import debounce from 'lodash.debounce';
|
||||
import { ref, reactive, watch, toRefs, computed, onMounted, toRaw } from 'vue';
|
||||
import keycodes from './keycode';
|
||||
import Localhost from './localhost.vue';
|
||||
import SuperPanel from './super-panel.vue';
|
||||
import UserInfo from './user-info';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
const { locale, t } = useI18n();
|
||||
|
||||
const { remote, ipcRenderer } = window.require("electron");
|
||||
const { remote, ipcRenderer } = window.require('electron');
|
||||
|
||||
const examples = [
|
||||
{
|
||||
title: "快捷键 「 Alt + W」 关键字 「 微信」",
|
||||
desc: "按下Alt + W 直接打开本地微信应用",
|
||||
title: t('feature.settings.global.example1'),
|
||||
desc: t('feature.settings.global.tips1'),
|
||||
},
|
||||
{
|
||||
title: "快捷键 「 Alt + Q」 关键字 「 取色」",
|
||||
desc: "按下Alt + Q 直接打开屏幕取色功能",
|
||||
title: t('feature.settings.global.example2'),
|
||||
desc: t('feature.settings.global.tips2'),
|
||||
},
|
||||
];
|
||||
|
||||
@@ -175,135 +261,209 @@ const state = reactive({
|
||||
common: {},
|
||||
local: {},
|
||||
global: [],
|
||||
custom: {},
|
||||
});
|
||||
|
||||
const currentSelect = ref(["normal"]);
|
||||
const isWindows = window?.rubick?.isWindows();
|
||||
const tipText = computed(() => {
|
||||
const optionKeyName = isWindows ? 'Alt' : 'Option、Command';
|
||||
return t('feature.settings.global.addShortcutKeyTips', {
|
||||
optionKeyName: optionKeyName,
|
||||
});
|
||||
});
|
||||
|
||||
const {perf, global: defaultGlobal} = remote.getGlobal("OP_CONFIG").get();
|
||||
const currentSelect = ref(['userInfo']);
|
||||
|
||||
const { perf, global: defaultGlobal } = remote.getGlobal('OP_CONFIG').get();
|
||||
|
||||
state.shortCut = perf.shortCut;
|
||||
state.custom = perf.custom;
|
||||
state.common = perf.common;
|
||||
state.local = perf.local;
|
||||
state.global = defaultGlobal;
|
||||
|
||||
const setConfig = debounce(() => {
|
||||
remote.getGlobal("OP_CONFIG").set(JSON.parse(JSON.stringify({
|
||||
perf: {
|
||||
shortCut: state.shortCut,
|
||||
common: state.common,
|
||||
local: state.local,
|
||||
},
|
||||
global: state.global,
|
||||
})));
|
||||
ipcRenderer.send("re-register");
|
||||
}, 2000);
|
||||
remote.getGlobal('OP_CONFIG').set(
|
||||
JSON.parse(
|
||||
JSON.stringify({
|
||||
perf: {
|
||||
shortCut: state.shortCut,
|
||||
common: state.common,
|
||||
local: state.local,
|
||||
custom: state.custom,
|
||||
},
|
||||
global: state.global,
|
||||
})
|
||||
)
|
||||
);
|
||||
ipcRenderer.send('re-register');
|
||||
}, 500);
|
||||
|
||||
watch(state, setConfig);
|
||||
|
||||
const changeShortCut = (e, key) => {
|
||||
if (e.altKey && e.keyCode !== 18) {
|
||||
const compose = `Option+${keycodes[e.keyCode].toUpperCase()}`;
|
||||
state.shortCut[key] = compose;
|
||||
}
|
||||
let compose = '';
|
||||
// 添加是否包含功能键的判断
|
||||
let incluFuncKeys = false;
|
||||
if (e.ctrlKey && e.keyCode !== 17) {
|
||||
const compose = `Ctrl+${keycodes[e.keyCode].toUpperCase()}`;
|
||||
state.perf.shortCut[key] = compose;
|
||||
compose += '+Ctrl';
|
||||
incluFuncKeys = true;
|
||||
}
|
||||
if (e.shiftKey && e.keyCode !== 16) {
|
||||
const compose = `Shift+${keycodes[e.keyCode].toUpperCase()}`;
|
||||
state.perf.shortCut[key] = compose;
|
||||
compose += '+Shift';
|
||||
incluFuncKeys = true;
|
||||
}
|
||||
if (e.altKey && e.keyCode !== 18) {
|
||||
compose += '+Option';
|
||||
incluFuncKeys = true;
|
||||
}
|
||||
if (e.metaKey && e.keyCode !== 93) {
|
||||
const compose = `Command+${keycodes[e.keyCode].toUpperCase()}`;
|
||||
state.perf.shortCut[key] = compose;
|
||||
compose += '+Command';
|
||||
incluFuncKeys = true;
|
||||
}
|
||||
compose += '+' + keycodes[e.keyCode].toUpperCase();
|
||||
compose = compose.substring(1);
|
||||
if (
|
||||
incluFuncKeys &&
|
||||
e.keyCode !== 16 &&
|
||||
e.keyCode !== 17 &&
|
||||
e.keyCode !== 18 &&
|
||||
e.keyCode !== 93
|
||||
) {
|
||||
state.shortCut[key] = compose;
|
||||
} else {
|
||||
// 不做处理
|
||||
}
|
||||
};
|
||||
|
||||
const changeGlobalKey = (e, index) => {
|
||||
let compose;
|
||||
if (e.altKey && e.keyCode !== 18) {
|
||||
compose = `Alt+${keycodes[e.keyCode].toUpperCase()}`;
|
||||
}
|
||||
let compose = '';
|
||||
// 添加是否包含功能键的判断
|
||||
let incluFuncKeys = false;
|
||||
if (e.ctrlKey && e.keyCode !== 17) {
|
||||
compose = `Ctrl+${keycodes[e.keyCode].toUpperCase()}`;
|
||||
compose += '+Ctrl';
|
||||
incluFuncKeys = true;
|
||||
}
|
||||
if (e.shiftKey && e.keyCode !== 16) {
|
||||
compose = `Shift+${keycodes[e.keyCode].toUpperCase()}`;
|
||||
compose += '+Shift';
|
||||
incluFuncKeys = true;
|
||||
}
|
||||
if (e.altKey && e.keyCode !== 18) {
|
||||
compose += '+Option';
|
||||
incluFuncKeys = true;
|
||||
}
|
||||
if (e.metaKey && e.keyCode !== 93) {
|
||||
compose = `Command+${keycodes[e.keyCode].toUpperCase()}`;
|
||||
compose += '+Command';
|
||||
incluFuncKeys = true;
|
||||
}
|
||||
if (compose) {
|
||||
compose += '+' + keycodes[e.keyCode].toUpperCase();
|
||||
compose = compose.substring(1);
|
||||
if (
|
||||
incluFuncKeys &&
|
||||
e.keyCode !== 16 &&
|
||||
e.keyCode !== 17 &&
|
||||
e.keyCode !== 18 &&
|
||||
e.keyCode !== 93
|
||||
) {
|
||||
state.global[index].key = compose;
|
||||
} else {
|
||||
// 不做处理
|
||||
}
|
||||
// f1 - f12
|
||||
if (e.keyCode >= 112 && e.keyCode <= 123) {
|
||||
if (!incluFuncKeys && e.keyCode >= 112 && e.keyCode <= 123) {
|
||||
compose = keycodes[e.keyCode].toUpperCase();
|
||||
}
|
||||
if (compose) {
|
||||
state.global[index].key = compose;
|
||||
}
|
||||
};
|
||||
|
||||
const resetDefault = (key) => {
|
||||
switch (key) {
|
||||
case 'Alt':
|
||||
state.shortCut['showAndHidden'] = 'Option+SPACE';
|
||||
// copyValue.value = "Option+SPACE";
|
||||
break;
|
||||
case 'Ctrl':
|
||||
state.shortCut['showAndHidden'] = 'Ctrl+SPACE';
|
||||
// copyValue.value = "Ctrl+SPACE";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
setConfig();
|
||||
};
|
||||
|
||||
const changeGlobalValue = (index, value) => {
|
||||
state.global[index].value = value;
|
||||
}
|
||||
};
|
||||
|
||||
const deleteGlobalKey = (e, index) => {
|
||||
state.global.splice(index, 1);
|
||||
// delete state.global[index];
|
||||
};
|
||||
|
||||
const addConfig = () => {
|
||||
state.global.push({
|
||||
key: "",
|
||||
value: "",
|
||||
key: '',
|
||||
value: '',
|
||||
});
|
||||
};
|
||||
|
||||
const {shortCut, common, local, global} = toRefs(state);
|
||||
const { shortCut, common, local, global } = toRefs(state);
|
||||
|
||||
const options = ref([
|
||||
{
|
||||
value: 'zh-CN',
|
||||
label: t('feature.settings.basic.cn'),
|
||||
},
|
||||
{
|
||||
value: 'en-US',
|
||||
label: t('feature.settings.basic.en'),
|
||||
},
|
||||
]);
|
||||
|
||||
const changeLanguage = (value) => {
|
||||
state.common.lang = value.key;
|
||||
locale.value = value.key;
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@import '~@/assets/common.less';
|
||||
|
||||
.settings {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
overflow-x: hidden;
|
||||
background: #f3efef;
|
||||
height: calc(~"100vh - 46px");
|
||||
background: var(--color-body-bg);
|
||||
height: calc(~'100vh - 46px');
|
||||
display: flex;
|
||||
.left-menu {
|
||||
width: 200px;
|
||||
height: 100%;
|
||||
.search-container {
|
||||
padding: 10px;
|
||||
}
|
||||
.ant-input-affix-wrapper {
|
||||
border: none;
|
||||
}
|
||||
.ant-menu {
|
||||
background: #F3EFEF;
|
||||
.ant-menu-item-selected {
|
||||
background-color: #E2E2E2;
|
||||
color: #141414;
|
||||
&:after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ant-menu {
|
||||
background: var(--color-body-bg) !important;
|
||||
color: var(--color-text-content) !important;
|
||||
}
|
||||
|
||||
.settings-detail {
|
||||
padding: 20px;
|
||||
box-sizing: border-box;
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
height: 100%;
|
||||
background: #fff;
|
||||
background: var(--color-body-bg);
|
||||
|
||||
.setting-item {
|
||||
margin-bottom: 20px;
|
||||
|
||||
.ant-form-item {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.title {
|
||||
color: #6c9fe2;
|
||||
color: var(--ant-primary-color);
|
||||
font-size: 15px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.settings-item-li {
|
||||
padding-left: 20px;
|
||||
display: flex;
|
||||
@@ -311,49 +471,123 @@ const {shortCut, common, local, global} = toRefs(state);
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 10px;
|
||||
|
||||
.label {
|
||||
color: #646464;
|
||||
color: var(--color-text-content);
|
||||
}
|
||||
|
||||
.value {
|
||||
width: 300px;
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
border: 1px solid #ddd;
|
||||
color: #6c9fe2;
|
||||
border: 1px solid var(--color-border-light);
|
||||
color: var(--ant-primary-color);
|
||||
font-size: 14px;
|
||||
height: 24px;
|
||||
font-weight: lighter;
|
||||
background: var(--color-input-hover);
|
||||
.ant-input {
|
||||
text-align: center;
|
||||
color: var(--ant-primary-color);
|
||||
font-size: 14px;
|
||||
font-weight: lighter;
|
||||
background: var(--color-input-hover);
|
||||
}
|
||||
}
|
||||
|
||||
.ant-switch {
|
||||
&:not(.ant-switch-checked) {
|
||||
background: var(--color-list-hover);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.feature-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-top: 10px;
|
||||
font-size: 14px;
|
||||
|
||||
.item {
|
||||
flex: 1;
|
||||
color: var(--color-text-content);
|
||||
}
|
||||
|
||||
.short-cut {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.value {
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
border: 1px solid #ddd;
|
||||
color: #6c9fe2;
|
||||
border: 1px solid var(--color-border-light);
|
||||
color: var(--ant-primary-color);
|
||||
font-size: 14px;
|
||||
height: 24px;
|
||||
font-weight: lighter;
|
||||
margin-top: 10px;
|
||||
position: relative;
|
||||
background: var(--color-input-hover);
|
||||
|
||||
.ant-input {
|
||||
color: var(--ant-primary-color);
|
||||
font-weight: lighter;
|
||||
background: none;
|
||||
}
|
||||
|
||||
.anticon {
|
||||
color: var(--color-text-desc);
|
||||
}
|
||||
|
||||
&.ant-input-affix-wrapper {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.anticon {
|
||||
display: block;
|
||||
color: var(--color-text-content);
|
||||
}
|
||||
}
|
||||
|
||||
.anticon {
|
||||
position: absolute;
|
||||
display: none;
|
||||
right: 4px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.add-global {
|
||||
color: #6c9fe2;
|
||||
color: var(--ant-primary-color);
|
||||
margin-top: 20px;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.ant-collapse {
|
||||
background: var(--color-input-hover);
|
||||
|
||||
.ant-collapse-content {
|
||||
background: var(--color-input-hover);
|
||||
color: var(--color-text-content);
|
||||
}
|
||||
|
||||
h3,
|
||||
.ant-collapse-header,
|
||||
.ant-list-item-meta-title {
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.ant-list-item-meta-description {
|
||||
color: var(--color-text-desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
116
feature/src/views/settings/localhost.vue
Normal file
@@ -0,0 +1,116 @@
|
||||
<template>
|
||||
<a-alert
|
||||
:message="$t('feature.settings.intranet.tips')"
|
||||
type="warning"
|
||||
style="margin-bottom: 20px"
|
||||
/>
|
||||
<a-form
|
||||
name="custom-validation"
|
||||
ref="formRef"
|
||||
:model="formState"
|
||||
:rules="rules"
|
||||
v-bind="layout"
|
||||
>
|
||||
<a-form-item
|
||||
has-feedback
|
||||
:label="$t('feature.settings.intranet.npmMirror')"
|
||||
name="register"
|
||||
>
|
||||
<a-input
|
||||
placeholder="https://registry.npm.taobao.org"
|
||||
v-model:value="formState.register"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
has-feedback
|
||||
:label="$t('feature.settings.intranet.dbUrl')"
|
||||
name="database"
|
||||
>
|
||||
<a-input
|
||||
placeholder="https://gitcode.net/rubickcenter/rubick-database/-/raw/master"
|
||||
v-model:value="formState.database"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
has-feedback
|
||||
:label="$t('feature.settings.intranet.accessToken')"
|
||||
name="access_token"
|
||||
>
|
||||
<a-input
|
||||
:placeholder="$t('feature.settings.intranet.placeholder')"
|
||||
v-model:value="formState.access_token"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item :wrapper-col="{ span: 18, offset: 6 }">
|
||||
<a-button @click="submit" type="primary">确定</a-button>
|
||||
<a-button style="margin-left: 10px" @click="resetForm">恢复默认</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, toRaw } from 'vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
|
||||
let _rev: any;
|
||||
|
||||
let defaultConfig = {
|
||||
register: 'https://registry.npm.taobao.org',
|
||||
database: 'https://gitcode.net/rubickcenter/rubick-database/-/raw/master',
|
||||
access_token: '',
|
||||
};
|
||||
|
||||
try {
|
||||
const dbdata = window.rubick.db.get('rubick-localhost-config');
|
||||
defaultConfig = dbdata.data;
|
||||
_rev = dbdata._rev;
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
const formState = ref(JSON.parse(JSON.stringify(defaultConfig)));
|
||||
|
||||
const rules = {
|
||||
register: [{ required: true, trigger: 'change' }],
|
||||
database: [{ required: true, trigger: 'change' }],
|
||||
};
|
||||
const layout = {
|
||||
labelCol: { span: 6 },
|
||||
wrapperCol: { span: 18 },
|
||||
};
|
||||
|
||||
const resetForm = () => {
|
||||
formState.value = {
|
||||
register: 'https://registry.npmmirror.com',
|
||||
database: 'https://gitcode.net/rubickcenter/rubick-database/-/raw/master',
|
||||
access_token: '',
|
||||
};
|
||||
};
|
||||
|
||||
const submit = () => {
|
||||
const changeData: any = {
|
||||
_id: 'rubick-localhost-config',
|
||||
data: toRaw(formState.value),
|
||||
};
|
||||
|
||||
if (_rev) {
|
||||
changeData._rev = _rev;
|
||||
}
|
||||
|
||||
window.rubick.db.put(changeData);
|
||||
message.success('设置成功!重启插件市场后生效!');
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.ant-form {
|
||||
:deep(.ant-form-item) {
|
||||
label {
|
||||
color: var(--color-text-content);
|
||||
}
|
||||
}
|
||||
}
|
||||
:deep(.ant-input) {
|
||||
background: var(--color-input-hover);
|
||||
color: var(--color-text-content);
|
||||
}
|
||||
</style>
|
||||
99
feature/src/views/settings/super-panel.vue
Normal file
@@ -0,0 +1,99 @@
|
||||
<template>
|
||||
<p>{{ $t('feature.settings.superPanel.tips') }}</p>
|
||||
<div class="super-list-item panel-item">
|
||||
<a-list
|
||||
:grid="{ gutter: 16, column: 2 }"
|
||||
:data-source="localPlugins.filter((item) => !!item)"
|
||||
>
|
||||
<template #renderItem="{ item }">
|
||||
<a-list-item v-if="item">
|
||||
<template #actions>
|
||||
<a-button
|
||||
v-if="!hasAdded(item)"
|
||||
@click="addPluginToSuperPanel(item)"
|
||||
style="color: #7ec699"
|
||||
type="text"
|
||||
>
|
||||
{{ $t('feature.settings.superPanel.add') }}
|
||||
</a-button>
|
||||
<a-button
|
||||
v-else
|
||||
@click="removePluginToSuperPanel(item)"
|
||||
style="color: #ff4ea4"
|
||||
type="text"
|
||||
>
|
||||
{{ $t('feature.settings.superPanel.remove') }}
|
||||
</a-button>
|
||||
</template>
|
||||
<a-list-item-meta>
|
||||
<template #description>
|
||||
<span class="ellipse">{{ item.description }}</span>
|
||||
</template>
|
||||
<template #title>
|
||||
<span class="ellipse">{{ item.pluginName }}</span>
|
||||
</template>
|
||||
<template #avatar>
|
||||
<a-avatar :src="item.logo" />
|
||||
</template>
|
||||
</a-list-item-meta>
|
||||
</a-list-item>
|
||||
</template>
|
||||
</a-list>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { useStore } from 'vuex';
|
||||
import { computed, ref, toRaw } from 'vue';
|
||||
|
||||
const store = useStore();
|
||||
const localPlugins = computed(() =>
|
||||
store.state.localPlugins.filter(
|
||||
(plugin) =>
|
||||
plugin.name !== 'rubick-system-feature' &&
|
||||
plugin.name !== 'rubick-system-super-panel'
|
||||
)
|
||||
);
|
||||
|
||||
const hasAdded = (plugin) => {
|
||||
let added = false;
|
||||
superPanelPlugins.value.data.some((item) => {
|
||||
if (item.name === plugin.name) {
|
||||
added = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
return added;
|
||||
};
|
||||
|
||||
const superPanelPlugins = ref(
|
||||
window.rubick.db.get('super-panel-db') || {
|
||||
data: [],
|
||||
_id: 'super-panel-db',
|
||||
}
|
||||
);
|
||||
|
||||
const addPluginToSuperPanel = (plugin) => {
|
||||
superPanelPlugins.value.data.push(toRaw(plugin));
|
||||
window.rubick.db.put(toRaw(superPanelPlugins.value));
|
||||
};
|
||||
|
||||
const removePluginToSuperPanel = (plugin) => {
|
||||
superPanelPlugins.value.data = toRaw(superPanelPlugins.value).data.filter(
|
||||
(item) => {
|
||||
return item.name !== plugin.name;
|
||||
}
|
||||
);
|
||||
window.rubick.db.put(toRaw(superPanelPlugins.value));
|
||||
};
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
p {
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
.super-list-item.panel-item {
|
||||
&:after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
228
feature/src/views/settings/user-info.vue
Normal file
@@ -0,0 +1,228 @@
|
||||
<template>
|
||||
<div class="user-info">
|
||||
<!-- <div class="info-container">-->
|
||||
<!-- <a-result-->
|
||||
<!-- class="user-info-result"-->
|
||||
<!-- :title="userInfo.name || $t('feature.settings.account.tips1')"-->
|
||||
<!-- :sub-title="$t('feature.settings.account.tips2')"-->
|
||||
<!-- >-->
|
||||
<!-- <template #icon>-->
|
||||
<!-- <a-avatar :size="64" v-if="!userInfo.avatar">-->
|
||||
<!-- <template #icon><UserOutlined /></template>-->
|
||||
<!-- </a-avatar>-->
|
||||
<!-- <a-avatar :src="userInfo.avatar" :size="64" v-else />-->
|
||||
<!-- </template>-->
|
||||
<!-- </a-result>-->
|
||||
<!-- </div>-->
|
||||
<div class="settings-container">
|
||||
<div class="setting-item">
|
||||
<div class="title">
|
||||
{{ $t('feature.settings.account.themeColor') }}
|
||||
</div>
|
||||
<div class="settings-item-li">
|
||||
<div class="label">
|
||||
{{ $t('feature.settings.account.primaryColor') }}
|
||||
</div>
|
||||
<a-input v-model:value="custom.primaryColor" class="value">
|
||||
<template #prefix>
|
||||
<div
|
||||
:style="{
|
||||
background: custom.primaryColor,
|
||||
width: '10px',
|
||||
height: '10px',
|
||||
}"
|
||||
></div>
|
||||
</template>
|
||||
</a-input>
|
||||
</div>
|
||||
<div class="settings-item-li">
|
||||
<div class="label">
|
||||
{{ $t('feature.settings.account.errorColor') }}
|
||||
</div>
|
||||
<a-input v-model:value="custom.errorColor" class="value">
|
||||
<template #prefix>
|
||||
<div
|
||||
:style="{
|
||||
background: custom.errorColor,
|
||||
width: '10px',
|
||||
height: '10px',
|
||||
}"
|
||||
></div>
|
||||
</template>
|
||||
</a-input>
|
||||
</div>
|
||||
<div class="settings-item-li">
|
||||
<div class="label">
|
||||
{{ $t('feature.settings.account.warningColor') }}
|
||||
</div>
|
||||
<a-input v-model:value="custom.warningColor" class="value">
|
||||
<template #prefix>
|
||||
<div
|
||||
:style="{
|
||||
background: custom.warningColor,
|
||||
width: '10px',
|
||||
height: '10px',
|
||||
}"
|
||||
></div>
|
||||
</template>
|
||||
</a-input>
|
||||
</div>
|
||||
<div class="settings-item-li">
|
||||
<div class="label">
|
||||
{{ $t('feature.settings.account.successColor') }}
|
||||
</div>
|
||||
<a-input v-model:value="custom.successColor" class="value">
|
||||
<template #prefix>
|
||||
<div
|
||||
:style="{
|
||||
background: custom.successColor,
|
||||
width: '10px',
|
||||
height: '10px',
|
||||
}"
|
||||
></div>
|
||||
</template>
|
||||
</a-input>
|
||||
</div>
|
||||
<div class="settings-item-li">
|
||||
<div class="label">
|
||||
{{ $t('feature.settings.account.infoColor') }}
|
||||
</div>
|
||||
<a-input v-model:value="custom.infoColor" class="value">
|
||||
<template #prefix>
|
||||
<div
|
||||
:style="{
|
||||
background: custom.infoColor,
|
||||
width: '10px',
|
||||
height: '10px',
|
||||
}"
|
||||
></div>
|
||||
</template>
|
||||
</a-input>
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div class="title">
|
||||
{{ $t('feature.settings.account.personalized') }}
|
||||
</div>
|
||||
<div class="settings-item-li">
|
||||
<div class="label">
|
||||
{{ $t('feature.settings.account.greeting') }}
|
||||
</div>
|
||||
<a-input v-model:value="custom.placeholder" class="value"></a-input>
|
||||
</div>
|
||||
<div class="settings-item-li">
|
||||
<div class="label">
|
||||
{{ $t('feature.settings.account.logo') }}
|
||||
</div>
|
||||
<div class="img-container">
|
||||
<img class="custom-img" :src="custom.logo" />
|
||||
<a-button @click="changeLogo" size="small" type="link">
|
||||
{{ $t('feature.settings.account.replace') }}
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer-btn">
|
||||
<a-button @click="reset" type="danger">
|
||||
{{ $t('feature.settings.account.reset') }}
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive, ref, toRefs, watch } from 'vue';
|
||||
import { Modal } from 'ant-design-vue';
|
||||
import { UserOutlined } from '@ant-design/icons-vue';
|
||||
import debounce from 'lodash.debounce';
|
||||
|
||||
import service from '../../assets/service';
|
||||
|
||||
const { remote, ipcRenderer } = window.require('electron');
|
||||
|
||||
const state = reactive({
|
||||
custom: {},
|
||||
});
|
||||
|
||||
const { perf } = remote.getGlobal('OP_CONFIG').get();
|
||||
|
||||
state.custom = perf.custom || {};
|
||||
|
||||
const userInfo = ref(window.rubick.dbStorage.getItem('rubick-user-info'));
|
||||
|
||||
service.getUserInfo({ openId: userInfo.value.openId }).then((res) => {
|
||||
userInfo.value = res;
|
||||
});
|
||||
|
||||
const setConfig = debounce(() => {
|
||||
remote.getGlobal('OP_CONFIG').set(
|
||||
JSON.parse(
|
||||
JSON.stringify({
|
||||
perf: {
|
||||
...perf,
|
||||
custom: state.custom,
|
||||
},
|
||||
})
|
||||
)
|
||||
);
|
||||
ipcRenderer.send('re-register');
|
||||
}, 500);
|
||||
|
||||
watch(state, setConfig);
|
||||
const { custom } = toRefs(state);
|
||||
|
||||
const changeLogo = () => {
|
||||
const [logoPath] = window.rubick.showOpenDialog({
|
||||
title: '请选择 logo 路径',
|
||||
filters: [{ name: 'images', extensions: ['png'] }],
|
||||
properties: ['openFile'],
|
||||
});
|
||||
state.custom.logo = `file://${logoPath}`;
|
||||
};
|
||||
|
||||
const reset = () => {
|
||||
Modal.warning({
|
||||
title: '确定恢复默认设置吗?',
|
||||
content: '回复后之前的设置将会被清空',
|
||||
onOk() {
|
||||
const defaultcustom = remote.getGlobal('OP_CONFIG').getDefaultConfig()
|
||||
.perf.custom;
|
||||
state.custom = JSON.parse(JSON.stringify(defaultcustom));
|
||||
},
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.settings-container {
|
||||
margin-top: 18px;
|
||||
}
|
||||
.user-info-result {
|
||||
padding: 0;
|
||||
&.ant-result {
|
||||
padding: 24px;
|
||||
}
|
||||
.icon {
|
||||
font-size: 48px;
|
||||
}
|
||||
.ant-result-icon {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.ant-result-title {
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
.img-container {
|
||||
width: 300px;
|
||||
}
|
||||
.custom-img {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
}
|
||||
.footer-btn {
|
||||
text-align: right;
|
||||
border-top: 1px dashed #ddd;
|
||||
padding-top: 12px;
|
||||
}
|
||||
</style>
|
||||
88
feature/src/views/settings/user.vue
Normal file
@@ -0,0 +1,88 @@
|
||||
<template>
|
||||
<div class="account">
|
||||
<!-- todo 暂时先去掉登录,等小程序做好了再加回来吧 -->
|
||||
<!-- <a-result-->
|
||||
<!-- v-if="!userInfo"-->
|
||||
<!-- title="请先登录"-->
|
||||
<!-- sub-title="登录后可开启用户个性化设置"-->
|
||||
<!-- >-->
|
||||
<!-- <template #extra>-->
|
||||
<!-- <a-button @click="showModal" type="primary">-->
|
||||
<!-- 使用微信小程序登录-->
|
||||
<!-- </a-button>-->
|
||||
<!-- </template>-->
|
||||
<!-- </a-result>-->
|
||||
<Index />
|
||||
<a-modal :footer="null" v-model:visible="visible">
|
||||
<a-result
|
||||
title="请使用微信扫码登录!"
|
||||
sub-title="使用微信扫描上面的 rubick 小程序二维码进行授权登录"
|
||||
>
|
||||
<template #icon>
|
||||
<img width="200" :src="imgCode" />
|
||||
</template>
|
||||
</a-result>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { nanoid } from 'nanoid';
|
||||
import { ref, watch } from 'vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
import Index from './index';
|
||||
import service from '../../assets/service';
|
||||
|
||||
const userInfo = ref(window.rubick.dbStorage.getItem('rubick-user-info'));
|
||||
|
||||
const imgCode = ref('');
|
||||
const scene = nanoid();
|
||||
|
||||
const visible = ref(false);
|
||||
const showModal = () => {
|
||||
visible.value = true;
|
||||
if (!imgCode.value && !userInfo.value) {
|
||||
service.getScanCode({ scene }).then((res) => {
|
||||
imgCode.value = `data:image/png;base64,${res.dataUrl}`;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
let timer = null;
|
||||
watch([visible], () => {
|
||||
if (visible.value) {
|
||||
timer = setInterval(() => {
|
||||
service.checkLoginStatus({ scene }).then((res) => {
|
||||
console.log(res);
|
||||
if (res.openId) {
|
||||
window.rubick.dbStorage.setItem('rubick-user-info', res);
|
||||
userInfo.value = res;
|
||||
message.success('登录成功!');
|
||||
visible.value = false;
|
||||
clearInterval(timer);
|
||||
timer = null;
|
||||
}
|
||||
});
|
||||
}, 2000);
|
||||
} else {
|
||||
clearInterval(timer);
|
||||
timer = null;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.account {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
overflow-x: hidden;
|
||||
background: var(--color-body-bg);
|
||||
height: calc(~'100vh - 46px');
|
||||
:deep(.ant-result-title) {
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
:deep(.ant-result-subtitle) {
|
||||
color: var(--color-text-desc);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"target": "esnext",
|
||||
"module": "esnext",
|
||||
"strict": true,
|
||||
|
||||
9607
feature/yarn.lock
Normal file
23
guide/.gitignore
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
.DS_Store
|
||||
node_modules
|
||||
/dist
|
||||
|
||||
|
||||
# local env files
|
||||
.env.local
|
||||
.env.*.local
|
||||
|
||||
# Log files
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
|
||||
# Editor directories and files
|
||||
.idea
|
||||
.vscode
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
24
guide/README.md
Normal file
@@ -0,0 +1,24 @@
|
||||
# guide
|
||||
|
||||
## Project setup
|
||||
```
|
||||
yarn install
|
||||
```
|
||||
|
||||
### Compiles and hot-reloads for development
|
||||
```
|
||||
yarn serve
|
||||
```
|
||||
|
||||
### Compiles and minifies for production
|
||||
```
|
||||
yarn build
|
||||
```
|
||||
|
||||
### Lints and fixes files
|
||||
```
|
||||
yarn lint
|
||||
```
|
||||
|
||||
### Customize configuration
|
||||
See [Configuration Reference](https://cli.vuejs.org/config/).
|
||||
5
guide/babel.config.js
Normal file
@@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
presets: [
|
||||
'@vue/cli-plugin-babel/preset'
|
||||
]
|
||||
}
|
||||
19
guide/jsconfig.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"module": "esnext",
|
||||
"baseUrl": "./",
|
||||
"moduleResolution": "node",
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"src/*"
|
||||
]
|
||||
},
|
||||
"lib": [
|
||||
"esnext",
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"scripthost"
|
||||
]
|
||||
}
|
||||
}
|
||||
43
guide/package.json
Normal file
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"name": "guide",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve --port 8083",
|
||||
"build": "vue-cli-service build",
|
||||
"lint": "vue-cli-service lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"core-js": "^3.8.3",
|
||||
"vue": "^3.2.13"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.12.16",
|
||||
"@babel/eslint-parser": "^7.12.16",
|
||||
"@vue/cli-plugin-babel": "~5.0.0",
|
||||
"@vue/cli-plugin-eslint": "~5.0.0",
|
||||
"@vue/cli-service": "~5.0.0",
|
||||
"eslint": "^7.32.0",
|
||||
"eslint-plugin-vue": "^8.0.3"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"root": true,
|
||||
"env": {
|
||||
"node": true
|
||||
},
|
||||
"extends": [
|
||||
"plugin:vue/vue3-essential",
|
||||
"eslint:recommended"
|
||||
],
|
||||
"parserOptions": {
|
||||
"parser": "@babel/eslint-parser"
|
||||
},
|
||||
"rules": {}
|
||||
},
|
||||
"browserslist": [
|
||||
"> 1%",
|
||||
"last 2 versions",
|
||||
"not dead",
|
||||
"not ie 11"
|
||||
]
|
||||
}
|
||||
BIN
guide/public/favicon.ico
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
17
guide/public/index.html
Normal file
@@ -0,0 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||
<title>rubick 桌面端开源工具箱</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||
</noscript>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
</body>
|
||||
</html>
|
||||
166
guide/src/App.vue
Normal file
@@ -0,0 +1,166 @@
|
||||
<template>
|
||||
<div class="guide-container">
|
||||
<div class="step0" v-show="step === 0">
|
||||
<div class="title">您好,我叫 Rubick</div>
|
||||
<div class="desc">快捷键 <span class="down-line">Alt + R</span> 可以快速打开我</div>
|
||||
<div class="img-container">
|
||||
<img class="img" src="./assets/img.png" />
|
||||
<div class="info">
|
||||
<svg class="top-icon" focusable="false" aria-hidden="true" viewBox="0 0 24 24" data-testid="NorthIcon"><path d="m5 9 1.41 1.41L11 5.83V22h2V5.83l4.59 4.59L19 9l-7-7-7 7z"></path></svg>
|
||||
点击 logo 进入插件市场
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="step0 step1" v-show="step === 1">
|
||||
<div class="title">选择需要的插件安装</div>
|
||||
<div class="desc">基于 <span class="down-line">npm</span> 的插件包管理,像小程序一样,用完即走</div>
|
||||
<div class="img-container">
|
||||
<img class="img" src="./assets/img_1.png" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="step0" v-show="step === 2">
|
||||
<div class="title"><span class="down-line">关键字</span>搜索应用和插件</div>
|
||||
<div class="desc">搜索框内输入关键字可以搜索安装的应用和插件</div>
|
||||
<div class="img-container">
|
||||
<img class="img" src="./assets/img_2.png" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="step0 step1" v-show="step === 3">
|
||||
<div class="title">完全开源免费,支持内网部署</div>
|
||||
<div class="desc">进入插件市场的 <span class="down-line">账户与设置</span> 菜单,进行内网部署设置</div>
|
||||
<div class="img-container">
|
||||
<img class="img" src="./assets/img_3.png" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<div></div>
|
||||
<div class="step">
|
||||
<span class="step-num">{{ step + 1 }} / 4</span>
|
||||
<div class="button" @click="netStep">{{ step + 1 === 4 ? '完成' : '下一步' }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
|
||||
const step = ref(0);
|
||||
const { ipcRenderer } = window.require('electron');
|
||||
|
||||
const netStep = () => {
|
||||
if (step.value >= 3) {
|
||||
return ipcRenderer.send('guide:service', { type: 'close' });
|
||||
}
|
||||
step.value = step.value + 1;
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@text-color: #574777; // 全局主色
|
||||
@primary-color: #ff4ea4; // 全局主色
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.guide-container {
|
||||
.step0 {
|
||||
padding: 28px;
|
||||
padding-top: 36px;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
}
|
||||
.title {
|
||||
font-size: 28px;
|
||||
font-weight: 600;
|
||||
color: @text-color;
|
||||
}
|
||||
.down-line {
|
||||
line-height: 24px;
|
||||
color: @primary-color;
|
||||
}
|
||||
.desc {
|
||||
padding-top: 10px;
|
||||
box-sizing: border-box;
|
||||
font-size: 24px;
|
||||
}
|
||||
.img-container {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.img {
|
||||
width: 680px;
|
||||
}
|
||||
.info {
|
||||
padding-top: 42px;
|
||||
margin-right: 178px;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
text-align: right;
|
||||
position: relative;
|
||||
color: @text-color;
|
||||
.top-icon {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
user-select: none;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
display: inline-block;
|
||||
fill: currentcolor;
|
||||
flex-shrink: 0;
|
||||
transition: fill 200ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
.footer {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 20px;
|
||||
box-sizing: border-box;
|
||||
.step {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.step-num {
|
||||
margin-right: 20px;
|
||||
}
|
||||
.button {
|
||||
width: 100px;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
background: @primary-color;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
aligin-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.step4 {
|
||||
.img {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
.step1 {
|
||||
.img {
|
||||
width: 550px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
BIN
guide/src/assets/bg.png
Normal file
|
After Width: | Height: | Size: 80 KiB |
BIN
guide/src/assets/img.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
guide/src/assets/img_1.png
Normal file
|
After Width: | Height: | Size: 144 KiB |
BIN
guide/src/assets/img_2.png
Normal file
|
After Width: | Height: | Size: 69 KiB |
BIN
guide/src/assets/img_3.png
Normal file
|
After Width: | Height: | Size: 110 KiB |
BIN
guide/src/assets/logo.png
Normal file
|
After Width: | Height: | Size: 6.7 KiB |
4
guide/src/main.js
Normal file
@@ -0,0 +1,4 @@
|
||||
import { createApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
|
||||
createApp(App).mount('#app')
|
||||
16
guide/vue.config.js
Normal file
@@ -0,0 +1,16 @@
|
||||
const path = require('path');
|
||||
|
||||
module.exports = {
|
||||
css: {
|
||||
// 配置css模块
|
||||
loaderOptions: {
|
||||
// 向预处理器 Loader 传递配置选项
|
||||
less: {
|
||||
// 配置less(其他样式解析用法一致)
|
||||
javascriptEnabled: true, // 设置为true
|
||||
},
|
||||
},
|
||||
},
|
||||
outputDir: path.join(__dirname, '../public/guide'),
|
||||
publicPath: process.env.NODE_ENV === 'production' ? '' : '/',
|
||||
};
|
||||
6168
guide/yarn.lock
Normal file
20388
package-lock.json
generated
Normal file
23
package.json
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"name": "rubick",
|
||||
"version": "2.0.1-beta.10",
|
||||
"version": "2.4.4",
|
||||
"author": "muwoo <2424880409@qq.com>",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve",
|
||||
@@ -14,17 +15,22 @@
|
||||
"postuninstall": "electron-builder install-app-deps"
|
||||
},
|
||||
"main": "background.js",
|
||||
"optionalDependencies": {
|
||||
"electron-clipboard-ex": "^1.3.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@better-scroll/core": "^2.4.2",
|
||||
"ant-design-vue": "^2.2.8",
|
||||
"ant-design-vue": "3.2.14",
|
||||
"axios": "^1.3.4",
|
||||
"core-js": "^3.6.5",
|
||||
"cross-spawn": "^7.0.3",
|
||||
"electron-updater": "^4.6.5",
|
||||
"extract-file-icon": "^0.3.2",
|
||||
"fix-path": "^3.0.0",
|
||||
"get-mac-apps": "^1.0.2",
|
||||
"got": "^11.8.3",
|
||||
"libnpmsearch": "^3.1.2",
|
||||
"lodash.throttle": "^4.1.1",
|
||||
"node-key-sender": "^1.0.11",
|
||||
"pouchdb": "^7.2.2",
|
||||
"vue": "^3.0.0",
|
||||
"vue-router": "^4.0.0-0",
|
||||
@@ -45,18 +51,21 @@
|
||||
"@vue/compiler-sfc": "^3.0.0",
|
||||
"@vue/eslint-config-prettier": "^6.0.0",
|
||||
"@vue/eslint-config-typescript": "^7.0.0",
|
||||
"babel-plugin-import": "^1.13.3",
|
||||
"electron": "^13.0.0",
|
||||
"electron-builder": "22.13.1",
|
||||
"electron-devtools-installer": "^3.1.0",
|
||||
"eslint": "^6.7.2",
|
||||
"eslint-plugin-prettier": "^3.3.1",
|
||||
"eslint-plugin-vue": "^7.0.0",
|
||||
"less": "^3.0.4",
|
||||
"less-loader": "^5.0.0",
|
||||
"prettier": "^2.2.1",
|
||||
"prettier": "^2.8.4",
|
||||
"typescript": "~4.1.5",
|
||||
"vue-cli-plugin-electron-builder": "~2.1.1",
|
||||
"worker-plugin": "^5.0.1",
|
||||
"electron-builder": "22.13.1"
|
||||
"worker-plugin": "^5.0.1"
|
||||
},
|
||||
"__npminstall_done": false
|
||||
"resolutions": {
|
||||
"vue-cli-plugin-electron-builder/electron-builder": "^23.0.3"
|
||||
}
|
||||
}
|
||||
|
||||