Compare commits
478 Commits
v0.0.3-bet
...
9813573679
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9813573679 | ||
|
|
61ec18f0dc | ||
|
|
5ca1ba1271 | ||
|
|
8c3186afef | ||
|
|
de0e9ed8f2 | ||
|
|
ef85084730 | ||
|
|
b4b7c81b60 | ||
|
|
4b79cce2f4 | ||
|
|
ae10dac5f7 | ||
|
|
1e0babe22d | ||
|
|
5ec18caa72 | ||
|
|
b7d8932291 | ||
|
|
5608a147f7 | ||
|
|
132fb94289 | ||
|
|
bb1a74b3b9 | ||
|
|
bf9da854c7 | ||
|
|
a2c5bcc90c | ||
|
|
b9f4333c01 | ||
|
|
bbeddb3fe6 | ||
|
|
4a2ca33e02 | ||
|
|
0578c7c7eb | ||
|
|
ef34452a4f | ||
|
|
286d9da8d1 | ||
|
|
6b9d5182bf | ||
|
|
2053491782 | ||
|
|
e128d01b81 | ||
|
|
c3bc0bdb9e | ||
|
|
f1f4e62177 | ||
|
|
c07d4bae55 | ||
|
|
c78dd9c4b6 | ||
|
|
2dd4ed10cc | ||
|
|
70ce3dd037 | ||
|
|
a0644c0ccf | ||
|
|
583e9934fa | ||
|
|
7e66b3f3e9 | ||
|
|
342f0f36a5 | ||
|
|
2a75e440ad | ||
|
|
11f53d1e07 | ||
|
|
beb8134539 | ||
|
|
d916525934 | ||
|
|
7d4ccb83a2 | ||
|
|
36c2a714b5 | ||
|
|
696c24657b | ||
|
|
f59069b2ec | ||
|
|
0c16139313 | ||
|
|
c99ec18151 | ||
|
|
dcea66e848 | ||
|
|
75e3111587 | ||
|
|
bd1757e068 | ||
|
|
2055bf61b1 | ||
|
|
6c096fcd99 | ||
|
|
1656418c10 | ||
|
|
f671b83b6a | ||
|
|
dfb8446cfd | ||
|
|
4e59294b16 | ||
|
|
562a13fdff | ||
|
|
9663232864 | ||
|
|
3f7285b177 | ||
|
|
e8c8f40bae | ||
|
|
6ae15b8f37 | ||
|
|
a3a7dfde98 | ||
|
|
289165de82 | ||
|
|
6da9e2fe9c | ||
|
|
c00963fabb | ||
|
|
4b8f0e4657 | ||
|
|
28e7d2aa46 | ||
|
|
404cb4fcb5 | ||
|
|
5553170c5a | ||
|
|
d8fabc6b4c | ||
|
|
88e4e325f3 | ||
|
|
c0aaae08ee | ||
|
|
35598159a6 | ||
|
|
2a1a332fbb | ||
|
|
6d105e0f56 | ||
|
|
d2acdeaad6 | ||
|
|
54ad4ef7b2 | ||
|
|
7fb299d270 | ||
|
|
606cb8bb22 | ||
|
|
142387d684 | ||
|
|
77127b55b0 | ||
|
|
bde5377282 | ||
|
|
d48f8638ed | ||
|
|
9c92e0f5fa | ||
|
|
af11f46518 | ||
|
|
d4a4a168cd | ||
|
|
a7a85a7c62 | ||
|
|
8fd9f342b8 | ||
|
|
7db7b9e391 | ||
|
|
9eb59a9158 | ||
|
|
3a2f44a448 | ||
|
|
437419aca3 | ||
|
|
e8d947f18a | ||
|
|
0233bda981 | ||
|
|
90b57d8f02 | ||
|
|
87ef15ffd2 | ||
|
|
96bc02905a | ||
|
|
9445cf098f | ||
|
|
c5ddeef8bc | ||
|
|
3cf0d3471f | ||
|
|
0d0f745fc1 | ||
|
|
1ab00151e3 | ||
|
|
4c2dcc1d3e | ||
|
|
645a94b5f2 | ||
|
|
68f4e01942 | ||
|
|
ad3138244b | ||
|
|
effd00f10f | ||
|
|
0cbbe3525e | ||
|
|
d1ce6a307d | ||
|
|
a26a03e948 | ||
|
|
c99a3eb74c | ||
|
|
32c6cf5d1c | ||
|
|
978b48264f | ||
|
|
79e39018fd | ||
|
|
9412d3bc59 | ||
|
|
ef77ca30b9 | ||
|
|
dcd18fe8a1 | ||
|
|
fe159427b8 | ||
|
|
b94d725d69 | ||
|
|
9fed8c4c7b | ||
|
|
8fe916020b | ||
|
|
d442fae447 | ||
|
|
60ba2bb6ad | ||
|
|
9a3ca8403b | ||
|
|
96f53e3b40 | ||
|
|
b06df01527 | ||
|
|
c7eb266002 | ||
|
|
9b303aa5c7 | ||
|
|
aa059b2596 | ||
|
|
c21c08c370 | ||
|
|
b3c5d30bfb | ||
|
|
2255cb783f | ||
|
|
ecb6b6bc29 | ||
|
|
61b4e37fe0 | ||
|
|
25dd314042 | ||
|
|
6dffd1a793 | ||
|
|
f4f91e1639 | ||
|
|
d2d94c13b7 | ||
|
|
6e5a08b9d8 | ||
|
|
78ea2ac576 | ||
|
|
5080f23ef9 | ||
|
|
d96fbd99ec | ||
|
|
bd871a1320 | ||
|
|
62bcc345da | ||
|
|
637c1238ae | ||
|
|
2008b62a45 | ||
|
|
a8883cd74d | ||
|
|
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 | ||
|
|
472879f9b2 | ||
|
|
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 | ||
|
|
c69be6c24f | ||
|
|
8ca01d900d | ||
|
|
1be13e5aa1 | ||
|
|
56faae0e35 | ||
|
|
f94c52f490 | ||
|
|
a8eeac5f8f | ||
|
|
91ce71f139 | ||
|
|
ab8b616f6a | ||
|
|
905838235c | ||
|
|
7bebcf4d54 | ||
|
|
01df2041a6 | ||
|
|
ee4c8031c4 | ||
|
|
cf19617714 | ||
|
|
cfa4f80d63 | ||
|
|
e89cfd049a | ||
|
|
1644f5606e | ||
|
|
86a5a4bb23 | ||
|
|
1cac93f1d2 | ||
|
|
024aace801 | ||
|
|
acddbb724f | ||
|
|
dc656d3bca | ||
|
|
5cfaa70c67 | ||
|
|
2cd6bab58c | ||
|
|
581599614b | ||
|
|
3ba4be2e4a | ||
|
|
5101491cc1 | ||
|
|
7c692e28be | ||
|
|
571ff12730 | ||
|
|
ff118dfe2d | ||
|
|
ced8aa846b | ||
|
|
7cb78e00a8 | ||
|
|
8250dfdb59 | ||
|
|
ef33ff0a3d | ||
|
|
8bcc5d409c | ||
|
|
afca4f2b5a | ||
|
|
c855fb470e | ||
|
|
898e78080c | ||
|
|
2c6d0c4c15 | ||
|
|
777cf015ef | ||
|
|
3a05e13948 | ||
|
|
7fc60e2ca8 | ||
|
|
a9538f5d86 | ||
|
|
6f9830a181 | ||
|
|
6ee0b2a795 | ||
|
|
6310b5a1bd | ||
|
|
9f3397f369 | ||
|
|
c9d6b04a7d | ||
|
|
1ee379b288 | ||
|
|
b3a00c88ad | ||
|
|
fc7e3e91bd | ||
|
|
64f2eba2fa | ||
|
|
8a35e60e48 | ||
|
|
951f21f5fa | ||
|
|
a9827c6db1 | ||
|
|
1353c440aa | ||
|
|
cd41f0561c | ||
|
|
0132a11d7e | ||
|
|
c2f43bea39 | ||
|
|
766ba46dcc | ||
|
|
8fb01cd158 | ||
|
|
4a2b2ab82d | ||
|
|
072d57f068 | ||
|
|
a7cbc2c890 | ||
|
|
b3ad8343ca | ||
|
|
b198288c7f | ||
|
|
2315e095cc | ||
|
|
0fda62e82c | ||
|
|
b95c8fad6f | ||
|
|
c0adb7a03d | ||
|
|
81cc106452 | ||
|
|
566927ab7b | ||
|
|
4309a86eff | ||
|
|
28f8c47752 | ||
|
|
74e4956050 | ||
|
|
ba45c627ab | ||
|
|
747c5512a7 | ||
|
|
60b1138dd8 | ||
|
|
960b16bb4c | ||
|
|
ef6ac06c40 | ||
|
|
80476aadf7 | ||
|
|
c3fdbbc3a8 | ||
|
|
bcd89ec3c3 | ||
|
|
50452bc36b | ||
|
|
79b60b89a5 | ||
|
|
e4aafb8e60 | ||
|
|
7064f504de | ||
|
|
96f2f62787 | ||
|
|
26bd47cce7 | ||
|
|
daa422b8e7 | ||
|
|
243c954ab6 | ||
|
|
6e02163752 | ||
|
|
f9559ac1b0 | ||
|
|
fb6006d96b | ||
|
|
c89ecb9c66 | ||
|
|
0a1ba91792 | ||
|
|
858bec38b2 | ||
|
|
3bd9271403 | ||
|
|
69626ed69e | ||
|
|
a16b198798 | ||
|
|
988acd7638 | ||
|
|
6a9d3517c4 | ||
|
|
96f9d41460 | ||
|
|
ace106a231 | ||
|
|
6864836399 | ||
|
|
7a1777e083 | ||
|
|
fa30074019 | ||
|
|
5f4e77f88e | ||
|
|
2df00360e4 | ||
|
|
1c893542b9 | ||
|
|
e9fa7b2276 | ||
|
|
db12d66ff7 | ||
|
|
9d3e7fc4a5 | ||
|
|
be21302738 | ||
|
|
a535c5d89b | ||
|
|
1eeb0fad9a | ||
|
|
511b357e28 | ||
|
|
87e7501c0a | ||
|
|
9242f17cde | ||
|
|
d047119076 | ||
|
|
5118fa6ca4 | ||
|
|
424c40a99c | ||
|
|
651e202ab1 | ||
|
|
614d5ae369 | ||
|
|
f287d10ca9 | ||
|
|
a04efd0d4f | ||
|
|
153d9dc5d7 | ||
|
|
de138955b5 | ||
|
|
8d340cb76c | ||
|
|
579b283a55 | ||
|
|
3858f35559 | ||
|
|
57504ab1eb | ||
|
|
0991d0ad64 | ||
|
|
e71eed00ad | ||
|
|
be5bce68dc | ||
|
|
871beba4bf | ||
|
|
f0b757c01f | ||
|
|
f480508200 | ||
|
|
247c2b7ab9 | ||
|
|
a489a8f130 | ||
|
|
d38dcab9cc | ||
|
|
64541ad651 | ||
|
|
5b1cef93c8 | ||
|
|
8dd59720e0 | ||
|
|
bf6e95e370 |
30
.babelrc
@@ -1,30 +0,0 @@
|
||||
{
|
||||
"comments": false,
|
||||
"env": {
|
||||
"main": {
|
||||
"presets": [
|
||||
["env", {
|
||||
"targets": { "node": 7 }
|
||||
}],
|
||||
"stage-0"
|
||||
]
|
||||
},
|
||||
"renderer": {
|
||||
"presets": [
|
||||
["env", {
|
||||
"modules": false
|
||||
}],
|
||||
"stage-0"
|
||||
]
|
||||
},
|
||||
"web": {
|
||||
"presets": [
|
||||
["env", {
|
||||
"modules": false
|
||||
}],
|
||||
"stage-0"
|
||||
]
|
||||
}
|
||||
},
|
||||
"plugins": ["transform-runtime"]
|
||||
}
|
||||
3
.browserslistrc
Normal file
@@ -0,0 +1,3 @@
|
||||
> 1%
|
||||
last 2 versions
|
||||
not dead
|
||||
@@ -1,132 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
process.env.NODE_ENV = 'production'
|
||||
|
||||
const { say } = require('cfonts')
|
||||
const chalk = require('chalk')
|
||||
const del = require('del')
|
||||
const { spawn } = require('child_process')
|
||||
const webpack = require('webpack')
|
||||
const Multispinner = require('multispinner')
|
||||
|
||||
|
||||
const mainConfig = require('./webpack.main.config')
|
||||
const rendererConfig = require('./webpack.renderer.config')
|
||||
const webConfig = require('./webpack.web.config')
|
||||
|
||||
const doneLog = chalk.bgGreen.white(' DONE ') + ' '
|
||||
const errorLog = chalk.bgRed.white(' ERROR ') + ' '
|
||||
const okayLog = chalk.bgBlue.white(' OKAY ') + ' '
|
||||
const isCI = process.env.CI || false
|
||||
|
||||
if (process.env.BUILD_TARGET === 'clean') clean()
|
||||
else if (process.env.BUILD_TARGET === 'web') web()
|
||||
else build()
|
||||
|
||||
function clean () {
|
||||
del.sync(['build/*', '!build/icons', '!build/icons/icon.*'])
|
||||
console.log(`\n${doneLog}\n`)
|
||||
process.exit()
|
||||
}
|
||||
|
||||
function build () {
|
||||
greeting()
|
||||
|
||||
del.sync(['dist/electron/*', '!.gitkeep'])
|
||||
|
||||
const tasks = ['main', 'renderer']
|
||||
const m = new Multispinner(tasks, {
|
||||
preText: 'building',
|
||||
postText: 'process'
|
||||
})
|
||||
|
||||
let results = ''
|
||||
|
||||
m.on('success', () => {
|
||||
process.stdout.write('\x1B[2J\x1B[0f')
|
||||
console.log(`\n\n${results}`)
|
||||
console.log(`${okayLog}take it away ${chalk.yellow('`electron-builder`')}\n`)
|
||||
process.exit()
|
||||
})
|
||||
|
||||
pack(mainConfig).then(result => {
|
||||
results += result + '\n\n'
|
||||
m.success('main')
|
||||
}).catch(err => {
|
||||
m.error('main')
|
||||
console.log(`\n ${errorLog}failed to build main process`)
|
||||
console.error(`\n${err}\n`)
|
||||
process.exit(1)
|
||||
})
|
||||
|
||||
pack(rendererConfig).then(result => {
|
||||
results += result + '\n\n'
|
||||
m.success('renderer')
|
||||
}).catch(err => {
|
||||
m.error('renderer')
|
||||
console.log(`\n ${errorLog}failed to build renderer process`)
|
||||
console.error(`\n${err}\n`)
|
||||
process.exit(1)
|
||||
})
|
||||
}
|
||||
|
||||
function pack (config) {
|
||||
return new Promise((resolve, reject) => {
|
||||
config.mode = 'production'
|
||||
webpack(config, (err, stats) => {
|
||||
if (err) reject(err.stack || err)
|
||||
else if (stats.hasErrors()) {
|
||||
let err = ''
|
||||
|
||||
stats.toString({
|
||||
chunks: false,
|
||||
colors: true
|
||||
})
|
||||
.split(/\r?\n/)
|
||||
.forEach(line => {
|
||||
err += ` ${line}\n`
|
||||
})
|
||||
|
||||
reject(err)
|
||||
} else {
|
||||
resolve(stats.toString({
|
||||
chunks: false,
|
||||
colors: true
|
||||
}))
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function web () {
|
||||
del.sync(['dist/web/*', '!.gitkeep'])
|
||||
webConfig.mode = 'production'
|
||||
webpack(webConfig, (err, stats) => {
|
||||
if (err || stats.hasErrors()) console.log(err)
|
||||
|
||||
console.log(stats.toString({
|
||||
chunks: false,
|
||||
colors: true
|
||||
}))
|
||||
|
||||
process.exit()
|
||||
})
|
||||
}
|
||||
|
||||
function greeting () {
|
||||
const cols = process.stdout.columns
|
||||
let text = ''
|
||||
|
||||
if (cols > 85) text = 'lets-build'
|
||||
else if (cols > 60) text = 'lets-|build'
|
||||
else text = false
|
||||
|
||||
if (text && !isCI) {
|
||||
say(text, {
|
||||
colors: ['yellow'],
|
||||
font: 'simple3d',
|
||||
space: false
|
||||
})
|
||||
} else console.log(chalk.yellow.bold('\n lets-build'))
|
||||
console.log()
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
const hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true')
|
||||
|
||||
hotClient.subscribe(event => {
|
||||
/**
|
||||
* Reload browser when HTMLWebpackPlugin emits a new index.html
|
||||
*
|
||||
* Currently disabled until jantimon/html-webpack-plugin#680 is resolved.
|
||||
* https://github.com/SimulatedGREG/electron-vue/issues/437
|
||||
* https://github.com/jantimon/html-webpack-plugin/issues/680
|
||||
*/
|
||||
// if (event.action === 'reload') {
|
||||
// window.location.reload()
|
||||
// }
|
||||
|
||||
/**
|
||||
* Notify `mainWindow` when `main` process is compiling,
|
||||
* giving notice for an expected reload of the `electron` process
|
||||
*/
|
||||
if (event.action === 'compiling') {
|
||||
document.body.innerHTML += `
|
||||
<style>
|
||||
#dev-client {
|
||||
background: #4fc08d;
|
||||
border-radius: 4px;
|
||||
bottom: 20px;
|
||||
box-shadow: 0 4px 5px 0 rgba(0, 0, 0, 0.14), 0 1px 10px 0 rgba(0, 0, 0, 0.12), 0 2px 4px -1px rgba(0, 0, 0, 0.3);
|
||||
color: #fff;
|
||||
font-family: 'Source Sans Pro', sans-serif;
|
||||
left: 20px;
|
||||
padding: 8px 12px;
|
||||
position: absolute;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="dev-client">
|
||||
Compiling Main Process...
|
||||
</div>
|
||||
`
|
||||
}
|
||||
})
|
||||
@@ -1,191 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const chalk = require('chalk')
|
||||
const electron = require('electron')
|
||||
const path = require('path')
|
||||
const { say } = require('cfonts')
|
||||
const { spawn } = require('child_process')
|
||||
const webpack = require('webpack')
|
||||
const WebpackDevServer = require('webpack-dev-server')
|
||||
const webpackHotMiddleware = require('webpack-hot-middleware')
|
||||
|
||||
const mainConfig = require('./webpack.main.config')
|
||||
const rendererConfig = require('./webpack.renderer.config')
|
||||
|
||||
let electronProcess = null
|
||||
let manualRestart = false
|
||||
let hotMiddleware
|
||||
|
||||
function logStats (proc, data) {
|
||||
let log = ''
|
||||
|
||||
log += chalk.yellow.bold(`┏ ${proc} Process ${new Array((19 - proc.length) + 1).join('-')}`)
|
||||
log += '\n\n'
|
||||
|
||||
if (typeof data === 'object') {
|
||||
data.toString({
|
||||
colors: true,
|
||||
chunks: false
|
||||
}).split(/\r?\n/).forEach(line => {
|
||||
log += ' ' + line + '\n'
|
||||
})
|
||||
} else {
|
||||
log += ` ${data}\n`
|
||||
}
|
||||
|
||||
log += '\n' + chalk.yellow.bold(`┗ ${new Array(28 + 1).join('-')}`) + '\n'
|
||||
|
||||
console.log(log)
|
||||
}
|
||||
|
||||
function startRenderer () {
|
||||
return new Promise((resolve, reject) => {
|
||||
rendererConfig.entry.renderer = [path.join(__dirname, 'dev-client')].concat(rendererConfig.entry.renderer)
|
||||
rendererConfig.mode = 'development'
|
||||
const compiler = webpack(rendererConfig)
|
||||
hotMiddleware = webpackHotMiddleware(compiler, {
|
||||
log: false,
|
||||
heartbeat: 2500
|
||||
})
|
||||
|
||||
compiler.hooks.compilation.tap('compilation', compilation => {
|
||||
compilation.hooks.htmlWebpackPluginAfterEmit.tapAsync('html-webpack-plugin-after-emit', (data, cb) => {
|
||||
hotMiddleware.publish({ action: 'reload' })
|
||||
cb()
|
||||
})
|
||||
})
|
||||
|
||||
compiler.hooks.done.tap('done', stats => {
|
||||
logStats('Renderer', stats)
|
||||
})
|
||||
|
||||
const server = new WebpackDevServer(
|
||||
compiler,
|
||||
{
|
||||
contentBase: path.join(__dirname, '../'),
|
||||
quiet: true,
|
||||
hot: true,
|
||||
before (app, ctx) {
|
||||
// app.use(hotMiddleware)
|
||||
ctx.middleware.waitUntilValid(() => {
|
||||
resolve()
|
||||
})
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
server.listen(9080)
|
||||
})
|
||||
}
|
||||
|
||||
function startMain () {
|
||||
return new Promise((resolve, reject) => {
|
||||
mainConfig.entry.main = [path.join(__dirname, '../src/main/index.dev.js')].concat(mainConfig.entry.main)
|
||||
mainConfig.mode = 'development'
|
||||
const compiler = webpack(mainConfig)
|
||||
|
||||
compiler.hooks.watchRun.tapAsync('watch-run', (compilation, done) => {
|
||||
logStats('Main', chalk.white.bold('compiling...'))
|
||||
hotMiddleware.publish({ action: 'compiling' })
|
||||
done()
|
||||
})
|
||||
|
||||
compiler.watch({}, (err, stats) => {
|
||||
if (err) {
|
||||
console.log(err)
|
||||
return
|
||||
}
|
||||
|
||||
logStats('Main', stats)
|
||||
|
||||
if (electronProcess && electronProcess.kill) {
|
||||
manualRestart = true
|
||||
process.kill(electronProcess.pid)
|
||||
electronProcess = null
|
||||
startElectron()
|
||||
|
||||
setTimeout(() => {
|
||||
manualRestart = false
|
||||
}, 5000)
|
||||
}
|
||||
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function startElectron () {
|
||||
var args = [
|
||||
'--inspect=5858',
|
||||
path.join(__dirname, '../dist/electron/main.js')
|
||||
]
|
||||
|
||||
// detect yarn or npm and process commandline args accordingly
|
||||
if (process.env.npm_execpath.endsWith('yarn.js')) {
|
||||
args = args.concat(process.argv.slice(3))
|
||||
} else if (process.env.npm_execpath.endsWith('npm-cli.js')) {
|
||||
args = args.concat(process.argv.slice(2))
|
||||
}
|
||||
|
||||
electronProcess = spawn(electron, args)
|
||||
|
||||
electronProcess.stdout.on('data', data => {
|
||||
electronLog(data, 'blue')
|
||||
})
|
||||
electronProcess.stderr.on('data', data => {
|
||||
electronLog(data, 'red')
|
||||
})
|
||||
|
||||
electronProcess.on('close', () => {
|
||||
if (!manualRestart) process.exit()
|
||||
})
|
||||
}
|
||||
|
||||
function electronLog (data, color) {
|
||||
let log = ''
|
||||
data = data.toString().split(/\r?\n/)
|
||||
data.forEach(line => {
|
||||
log += ` ${line}\n`
|
||||
})
|
||||
if (/[0-9A-z]+/.test(log)) {
|
||||
console.log(
|
||||
chalk[color].bold('┏ Electron -------------------') +
|
||||
'\n\n' +
|
||||
log +
|
||||
chalk[color].bold('┗ ----------------------------') +
|
||||
'\n'
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
function greeting () {
|
||||
const cols = process.stdout.columns
|
||||
let text = ''
|
||||
|
||||
if (cols > 104) text = 'electron-vue'
|
||||
else if (cols > 76) text = 'electron-|vue'
|
||||
else text = false
|
||||
|
||||
if (text) {
|
||||
say(text, {
|
||||
colors: ['yellow'],
|
||||
font: 'simple3d',
|
||||
space: false
|
||||
})
|
||||
} else console.log(chalk.yellow.bold('\n electron-vue'))
|
||||
console.log(chalk.blue(' getting ready...') + '\n')
|
||||
}
|
||||
|
||||
function init () {
|
||||
greeting()
|
||||
|
||||
Promise.all([startRenderer(), startMain()])
|
||||
.then(() => {
|
||||
startElectron()
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err)
|
||||
})
|
||||
}
|
||||
|
||||
init()
|
||||
@@ -1,82 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
process.env.BABEL_ENV = 'main'
|
||||
|
||||
const path = require('path')
|
||||
const { dependencies } = require('../package.json')
|
||||
const webpack = require('webpack')
|
||||
|
||||
const MinifyPlugin = require("babel-minify-webpack-plugin")
|
||||
|
||||
let mainConfig = {
|
||||
entry: {
|
||||
main: path.join(__dirname, '../src/main/index.js')
|
||||
},
|
||||
externals: [
|
||||
...Object.keys(dependencies || {})
|
||||
],
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.js$/,
|
||||
use: 'babel-loader',
|
||||
exclude: /node_modules/
|
||||
},
|
||||
{
|
||||
test: /\.node$/,
|
||||
use: 'node-loader'
|
||||
},
|
||||
{
|
||||
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
|
||||
use: {
|
||||
loader: 'url-loader',
|
||||
query: {
|
||||
limit: 10000,
|
||||
name: 'imgs/[name]--[folder].[ext]'
|
||||
}
|
||||
}
|
||||
},
|
||||
]
|
||||
},
|
||||
node: {
|
||||
__dirname: process.env.NODE_ENV !== 'production',
|
||||
__filename: process.env.NODE_ENV !== 'production'
|
||||
},
|
||||
output: {
|
||||
filename: '[name].js',
|
||||
libraryTarget: 'commonjs2',
|
||||
path: path.join(__dirname, '../dist/electron')
|
||||
},
|
||||
plugins: [
|
||||
new webpack.NoEmitOnErrorsPlugin()
|
||||
],
|
||||
resolve: {
|
||||
extensions: ['.js', '.json', '.node']
|
||||
},
|
||||
target: 'electron-main'
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust mainConfig for development settings
|
||||
*/
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
mainConfig.plugins.push(
|
||||
new webpack.DefinePlugin({
|
||||
'__static': `"${path.join(__dirname, '../static').replace(/\\/g, '\\\\')}"`
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust mainConfig for production settings
|
||||
*/
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
mainConfig.plugins.push(
|
||||
new MinifyPlugin(),
|
||||
new webpack.DefinePlugin({
|
||||
'process.env.NODE_ENV': '"production"'
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
module.exports = mainConfig
|
||||
@@ -1,191 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
process.env.BABEL_ENV = 'renderer'
|
||||
|
||||
const path = require('path')
|
||||
const { dependencies } = require('../package.json')
|
||||
const webpack = require('webpack')
|
||||
|
||||
const MinifyPlugin = require("babel-minify-webpack-plugin")
|
||||
const CopyWebpackPlugin = require('copy-webpack-plugin')
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin')
|
||||
const { VueLoaderPlugin } = require('vue-loader')
|
||||
|
||||
/**
|
||||
* List of node_modules to include in webpack bundle
|
||||
*
|
||||
* Required for specific packages like Vue UI libraries
|
||||
* that provide pure *.vue files that need compiling
|
||||
* https://simulatedgreg.gitbooks.io/electron-vue/content/en/webpack-configurations.html#white-listing-externals
|
||||
*/
|
||||
let whiteListedModules = ['vue']
|
||||
|
||||
let rendererConfig = {
|
||||
devtool: '#cheap-module-eval-source-map',
|
||||
entry: {
|
||||
renderer: path.join(__dirname, '../src/renderer/main.js')
|
||||
},
|
||||
externals: [
|
||||
...Object.keys(dependencies || {}).filter(d => !whiteListedModules.includes(d))
|
||||
],
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.scss$/,
|
||||
use: ['vue-style-loader', 'css-loader', 'sass-loader']
|
||||
},
|
||||
{
|
||||
test: /\.sass$/,
|
||||
use: ['vue-style-loader', 'css-loader', 'sass-loader?indentedSyntax']
|
||||
},
|
||||
{
|
||||
test: /\.less$/,
|
||||
use: ['vue-style-loader', 'css-loader', 'less-loader']
|
||||
},
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: ['vue-style-loader', 'css-loader']
|
||||
},
|
||||
{
|
||||
test: /\.html$/,
|
||||
use: 'vue-html-loader'
|
||||
},
|
||||
{
|
||||
test: /\.js$/,
|
||||
use: 'babel-loader',
|
||||
exclude: /node_modules/
|
||||
},
|
||||
{
|
||||
test: /\.node$/,
|
||||
use: 'node-loader'
|
||||
},
|
||||
{
|
||||
test: /\.vue$/,
|
||||
use: {
|
||||
loader: 'vue-loader',
|
||||
options: {
|
||||
extractCSS: process.env.NODE_ENV === 'production',
|
||||
loaders: {
|
||||
sass: 'vue-style-loader!css-loader!sass-loader?indentedSyntax=1',
|
||||
scss: 'vue-style-loader!css-loader!sass-loader',
|
||||
less: 'vue-style-loader!css-loader!less-loader'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
|
||||
use: {
|
||||
loader: 'url-loader',
|
||||
query: {
|
||||
limit: 10000,
|
||||
name: 'imgs/[name]--[folder].[ext]'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
|
||||
loader: 'url-loader',
|
||||
options: {
|
||||
limit: 10000,
|
||||
name: 'media/[name]--[folder].[ext]'
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
|
||||
use: {
|
||||
loader: 'url-loader',
|
||||
query: {
|
||||
limit: 10000,
|
||||
name: 'fonts/[name]--[folder].[ext]'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
node: {
|
||||
__dirname: process.env.NODE_ENV !== 'production',
|
||||
__filename: process.env.NODE_ENV !== 'production'
|
||||
},
|
||||
plugins: [
|
||||
new VueLoaderPlugin(),
|
||||
new MiniCssExtractPlugin({filename: 'styles.css'}),
|
||||
new HtmlWebpackPlugin({
|
||||
filename: 'index.html',
|
||||
template: path.resolve(__dirname, '../src/index.ejs'),
|
||||
templateParameters(compilation, assets, options) {
|
||||
return {
|
||||
compilation: compilation,
|
||||
webpack: compilation.getStats().toJson(),
|
||||
webpackConfig: compilation.options,
|
||||
htmlWebpackPlugin: {
|
||||
files: assets,
|
||||
options: options,
|
||||
},
|
||||
process,
|
||||
};
|
||||
},
|
||||
minify: {
|
||||
collapseWhitespace: true,
|
||||
removeAttributeQuotes: true,
|
||||
removeComments: true
|
||||
},
|
||||
nodeModules: process.env.NODE_ENV !== 'production'
|
||||
? path.resolve(__dirname, '../node_modules')
|
||||
: false
|
||||
}),
|
||||
new webpack.NoEmitOnErrorsPlugin()
|
||||
],
|
||||
output: {
|
||||
filename: '[name].js',
|
||||
libraryTarget: 'commonjs2',
|
||||
path: path.join(__dirname, '../dist/electron')
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': path.join(__dirname, '../src/renderer'),
|
||||
'vue$': 'vue/dist/vue.esm.js'
|
||||
},
|
||||
extensions: ['.js', '.vue', '.json', '.css', '.node']
|
||||
},
|
||||
target: 'electron-renderer'
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust rendererConfig for development settings
|
||||
*/
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
rendererConfig.plugins.push(
|
||||
new webpack.HotModuleReplacementPlugin(),
|
||||
new webpack.DefinePlugin({
|
||||
'__static': `"${path.join(__dirname, '../static').replace(/\\/g, '\\\\')}"`
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust rendererConfig for production settings
|
||||
*/
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
rendererConfig.devtool = ''
|
||||
|
||||
rendererConfig.plugins.push(
|
||||
new MinifyPlugin(),
|
||||
new CopyWebpackPlugin([
|
||||
{
|
||||
from: path.join(__dirname, '../static'),
|
||||
to: path.join(__dirname, '../dist/electron/static'),
|
||||
ignore: ['.*']
|
||||
}
|
||||
]),
|
||||
new webpack.DefinePlugin({
|
||||
'process.env.NODE_ENV': '"production"'
|
||||
}),
|
||||
new webpack.LoaderOptionsPlugin({
|
||||
minimize: true
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
module.exports = rendererConfig
|
||||
@@ -1,152 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
process.env.BABEL_ENV = 'web'
|
||||
|
||||
const path = require('path')
|
||||
const webpack = require('webpack')
|
||||
|
||||
const MinifyPlugin = require("babel-minify-webpack-plugin")
|
||||
const CopyWebpackPlugin = require('copy-webpack-plugin')
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin')
|
||||
const { VueLoaderPlugin } = require('vue-loader')
|
||||
|
||||
let webConfig = {
|
||||
devtool: '#cheap-module-eval-source-map',
|
||||
entry: {
|
||||
web: path.join(__dirname, '../src/renderer/main.js')
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.scss$/,
|
||||
use: ['vue-style-loader', 'css-loader', 'sass-loader']
|
||||
},
|
||||
{
|
||||
test: /\.sass$/,
|
||||
use: ['vue-style-loader', 'css-loader', 'sass-loader?indentedSyntax']
|
||||
},
|
||||
{
|
||||
test: /\.less$/,
|
||||
use: ['vue-style-loader', 'css-loader', 'less-loader']
|
||||
},
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: ['vue-style-loader', 'css-loader']
|
||||
},
|
||||
{
|
||||
test: /\.html$/,
|
||||
use: 'vue-html-loader'
|
||||
},
|
||||
{
|
||||
test: /\.js$/,
|
||||
use: 'babel-loader',
|
||||
include: [ path.resolve(__dirname, '../src/renderer') ],
|
||||
exclude: /node_modules/
|
||||
},
|
||||
{
|
||||
test: /\.vue$/,
|
||||
use: {
|
||||
loader: 'vue-loader',
|
||||
options: {
|
||||
extractCSS: true,
|
||||
loaders: {
|
||||
sass: 'vue-style-loader!css-loader!sass-loader?indentedSyntax=1',
|
||||
scss: 'vue-style-loader!css-loader!sass-loader',
|
||||
less: 'vue-style-loader!css-loader!less-loader'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
|
||||
use: {
|
||||
loader: 'url-loader',
|
||||
query: {
|
||||
limit: 10000,
|
||||
name: 'imgs/[name].[ext]'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
|
||||
use: {
|
||||
loader: 'url-loader',
|
||||
query: {
|
||||
limit: 10000,
|
||||
name: 'fonts/[name].[ext]'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
plugins: [
|
||||
new VueLoaderPlugin(),
|
||||
new MiniCssExtractPlugin({filename: 'styles.css'}),
|
||||
new HtmlWebpackPlugin({
|
||||
filename: 'index.html',
|
||||
template: path.resolve(__dirname, '../src/index.ejs'),
|
||||
templateParameters(compilation, assets, options) {
|
||||
return {
|
||||
compilation: compilation,
|
||||
webpack: compilation.getStats().toJson(),
|
||||
webpackConfig: compilation.options,
|
||||
htmlWebpackPlugin: {
|
||||
files: assets,
|
||||
options: options,
|
||||
},
|
||||
process,
|
||||
};
|
||||
},
|
||||
minify: {
|
||||
collapseWhitespace: true,
|
||||
removeAttributeQuotes: true,
|
||||
removeComments: true
|
||||
},
|
||||
nodeModules: false
|
||||
}),
|
||||
new webpack.DefinePlugin({
|
||||
'process.env.IS_WEB': 'true'
|
||||
}),
|
||||
new webpack.HotModuleReplacementPlugin(),
|
||||
new webpack.NoEmitOnErrorsPlugin()
|
||||
],
|
||||
output: {
|
||||
filename: '[name].js',
|
||||
path: path.join(__dirname, '../dist/web')
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': path.join(__dirname, '../src/renderer'),
|
||||
'vue$': 'vue/dist/vue.esm.js'
|
||||
},
|
||||
extensions: ['.js', '.vue', '.json', '.css']
|
||||
},
|
||||
target: 'web'
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust webConfig for production settings
|
||||
*/
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
webConfig.devtool = ''
|
||||
|
||||
webConfig.plugins.push(
|
||||
new MinifyPlugin(),
|
||||
new CopyWebpackPlugin([
|
||||
{
|
||||
from: path.join(__dirname, '../static'),
|
||||
to: path.join(__dirname, '../dist/web/static'),
|
||||
ignore: ['.*']
|
||||
}
|
||||
]),
|
||||
new webpack.DefinePlugin({
|
||||
'process.env.NODE_ENV': '"production"'
|
||||
}),
|
||||
new webpack.LoaderOptionsPlugin({
|
||||
minimize: true
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
module.exports = webConfig
|
||||
26
.eslintrc.js
Normal file
@@ -0,0 +1,26 @@
|
||||
module.exports = {
|
||||
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: {
|
||||
'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']
|
||||
|
||||
24
.github/workflows/main.yml
vendored
@@ -23,10 +23,14 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-latest, windows-2019]
|
||||
os: [macos-latest, windows-2019, ubuntu-latest]
|
||||
|
||||
# create steps
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.10'
|
||||
# step1: check out repository
|
||||
- name: Check out git repository
|
||||
uses: actions/checkout@v2
|
||||
@@ -35,27 +39,25 @@ 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'
|
||||
run: |
|
||||
sudo apt-get install libxtst-dev libpng++-dev
|
||||
sudo apt-get install --no-install-recommends -y icnsutils graphicsmagick xz-utils
|
||||
sudo snap install snapcraft --classic
|
||||
# step3: yarn
|
||||
- name: macos Yarn install
|
||||
if: ${{runner.os == 'macOS'}}
|
||||
- name: Yarn install
|
||||
run: |
|
||||
yarn
|
||||
yarn global add xvfb-maybe
|
||||
npm run rebuild
|
||||
|
||||
- name: windows Yarn install
|
||||
if: ${{runner.os == 'Windows'}}
|
||||
yarn global add @vue/cli
|
||||
- name: Build feature
|
||||
run: |
|
||||
cd ./feature
|
||||
yarn
|
||||
yarn global add xvfb-maybe
|
||||
npm run rebuild_win
|
||||
|
||||
npm run build
|
||||
- name: Build & release app
|
||||
run: |
|
||||
npm run release
|
||||
|
||||
33
.gitignore
vendored
@@ -1,12 +1,27 @@
|
||||
.DS_Store
|
||||
dist/electron/*
|
||||
dist/web/*
|
||||
node_modules
|
||||
build/*
|
||||
!build/icons/
|
||||
node_modules/
|
||||
npm-debug.log
|
||||
npm-debug.log.*
|
||||
thumbs.db
|
||||
!.gitkeep
|
||||
!build/icons
|
||||
|
||||
|
||||
# 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
|
||||
dist/
|
||||
.vscode
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
#Electron-builder output
|
||||
/dist_electron
|
||||
|
||||
1
.npmrc
Normal file
@@ -0,0 +1 @@
|
||||
electron_mirror=https://npmmirror.com/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"
|
||||
}
|
||||
40
.travis.yml
@@ -1,40 +0,0 @@
|
||||
# Commented sections below can be used to run tests on the CI server
|
||||
# https://simulatedgreg.gitbooks.io/electron-vue/content/en/testing.html#on-the-subject-of-ci-testing
|
||||
osx_image: xcode8.3
|
||||
sudo: required
|
||||
dist: trusty
|
||||
language: c
|
||||
matrix:
|
||||
include:
|
||||
- os: osx
|
||||
# - os: linux
|
||||
env: CC=clang CXX=clang++ npm_config_clang=1
|
||||
compiler: clang
|
||||
cache:
|
||||
directories:
|
||||
- node_modules
|
||||
- "$HOME/.electron"
|
||||
- "$HOME/.cache"
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- libgnome-keyring-dev
|
||||
- icnsutils
|
||||
before_install:
|
||||
- mkdir -p /tmp/git-lfs && curl -L https://github.com/github/git-lfs/releases/download/v1.2.1/git-lfs-$([
|
||||
"$TRAVIS_OS_NAME" == "linux" ] && echo "linux" || echo "darwin")-amd64-1.2.1.tar.gz
|
||||
| tar -xz -C /tmp/git-lfs --strip-components 1 && /tmp/git-lfs/git-lfs pull
|
||||
install:
|
||||
- nvm install 8.9
|
||||
- curl -o- -L https://yarnpkg.com/install.sh | bash
|
||||
- source ~/.bashrc
|
||||
- npm install -g xvfb-maybe
|
||||
- yarn
|
||||
- cd docs
|
||||
- yarn
|
||||
script:
|
||||
- npm run release
|
||||
- sh deploy.sh
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
137
README.md
@@ -1,95 +1,118 @@
|
||||
English | [简体中文](./README.zh-CN.md)
|
||||
|
||||
|
||||
<div align= "center">
|
||||
<img align="center" width=200 src="https://user-images.githubusercontent.com/21073039/128333805-73e086f0-5523-46a3-a096-cba80b904c46.png" />
|
||||
<img align="center" width=200 src="./public/logo.png" />
|
||||
</div>
|
||||
|
||||
|
||||
<div align= "center">
|
||||
<h1>Rubick</h1>
|
||||
|
||||
<img alt="release" src="https://img.shields.io/github/downloads/clouDr-f2e/rubick/total" />
|
||||
<a href="https://github.com/clouDr-f2e/rubick/releases">
|
||||
<img alt="release" src="https://img.shields.io/github/package-json/v/clouDr-f2e/rubick" />
|
||||
</a>
|
||||
<a href="https://github.com/clouDr-f2e/rubick/actions">
|
||||
<img alt=building src=https://img.shields.io/github/workflow/status/clouDr-f2e/rubick/Build>
|
||||
</a>
|
||||
<a href="https://github.com/clouDr-f2e/rubick/blob/master/LICENSE">
|
||||
<img alt="npm" src="https://img.shields.io/github/license/clouDr-f2e/rubick" />
|
||||
</a>
|
||||
<img alt="star" src="https://img.shields.io/github/stars/clouDr-f2e/rubick?style=social"></a>
|
||||
|
||||
<img alt="release" src="https://img.shields.io/github/downloads/rubickCenter/rubick/total" />
|
||||
<a href="https://github.com/rubickCenter/rubick/releases">
|
||||
<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/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" />
|
||||
</a>
|
||||
<a href="https://github.com/rubickCenter/rubick/stargazers">
|
||||
<img alt="star" src="https://img.shields.io/github/stars/rubickCenter/rubick?style=social">
|
||||
</a>
|
||||
<a href="https://gitee.com/monkeyWang/rubick">
|
||||
<img alt="码云" src="https://img.shields.io/badge/Gitee--yellow.svg?style=social&logo=data:image/svg+xml;base64,PHN2ZyB0PSIxNTc0ODM3MTM4ODM3IiBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHAtaWQ9IjE3NzAiICAgICB3aWR0aD0iMTYiIGhlaWdodD0iMTYiPiAgICA8cGF0aCBkPSJNODkxIDQyOC44SDQ2NS44Yy0yMC40IDAtMzcgMTYuNS0zNyAzN3Y5Mi40YzAgMjAuNCAxNi41IDM3IDM3IDM3aDI1OC45YzIwLjQgMCAzNyAxNi42IDM3IDM3djE4LjRjMCA2MS4zLTQ5LjcgMTEwLjktMTEwLjkgMTEwLjlIMjk5LjRjLTIwLjQgMC0zNy0xNi42LTM3LTM3VjM3My4yYzAtNjEuMyA0OS43LTExMC45IDExMC45LTExMC45aDUxNy42YzIwLjQgMCAzNy0xNi41IDM3LTM3bDAuMS05Mi4zYzAtMjAuNC0xNi41LTM3LTM3LTM3SDM3My4zQzIyMC4yIDk2IDk2IDIyMC4yIDk2IDM3My4zVjg5MWMwIDIwLjQgMTYuNiAzNyAzNyAzN2g1NDUuNEM4MTYuMiA5MjggOTI4IDgxNi4zIDkyOCA2NzguNFY0NjUuOGMwLTIwLjQtMTYuNi0zNy0zNy0zN3oiICAgICAgICAgIGZpbGw9IiNkODFlMDYiIHAtaWQ9IjE3NzEiPjwvcGF0aD48L3N2Zz4="/>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div align= "center">
|
||||
<img align="center" src="https://picx.zhimg.com/80/v2-f8fe09ef125dac5fdcbef3fe00f92b21_720w.png" />
|
||||
</div>
|
||||
|
||||
基于 electron 的开源工具箱,自由集成丰富插件,打造极致的桌面端效能工具。Rubick(拉比克) 是 dota 里面的英雄之一,其核心技能是插件化使用其他英雄的技能,用完即走。非常符合本工具的设计理念,所以取名 Rubick。
|
||||
Open-source plugin-based desktop efficiency toolbox. The plugins are installed and uninstalled based on npm, which is very lightweight. The plugin data supports webdav multi-terminal synchronization, which is very secure. It supports internal network deployment and can be customized for further development, which is very flexible.
|
||||
|
||||
## 安装包
|
||||
* [Rubick Mac OS](https://github.com/clouDr-f2e/rubick/releases)
|
||||
* [Rubick Windows](https://github.com/clouDr-f2e/rubick/releases)
|
||||
## Get Rubick
|
||||
Download the latest release:
|
||||
* [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] 支持远程下载安装插件,支持插件开发者模式
|
||||
- [x] 支持插件分离
|
||||
- [x] 支持系统命令取色、截屏、帮助
|
||||
- [x] 支持超级面板,长按右击呼出
|
||||
- [x] 支持全局快捷键设置
|
||||
- [x] 支持搜索本地已安装 app 或 偏好设置
|
||||
- [x] macos touchBar 唤起插件
|
||||
- [x] 支持 Windows(目前是 mac 的 alpha 版本,功能尚不全,正在迁移中)
|
||||
- [ ] 支持 Linux
|
||||
## Docs
|
||||
|
||||
[Rubick website](https://rubick.vip)
|
||||
|
||||
[Rubick Docs](https://rubickCenter.github.io/docs/)
|
||||
|
||||

|
||||
## How To Use Rubick
|
||||
After installing rubick, you can quickly launch the main program by pressing the shortcut keys Alt/Option+R. Entering keywords in the main program input box can search for corresponding apps, plugins, files...
|
||||
Select the ones you want and use them.
|
||||
|
||||
## 使用文档
|
||||
If you don't want the function, you can click the logo on the left to enter the plugin market and find the ones you want to install.
|
||||
|
||||
[Rubick Docs](https://cloudr-f2e.github.io/rubick/)
|
||||
## Feature list
|
||||
- [x] Plugin management based on the npm package pattern, installing plugins is as simple as installing npm packages.
|
||||
- [x] Supports WebDAV for multi-device data synchronization, ensuring true data security synchronization.
|
||||
- [x] A unique system plugin mode that allows plugins to become an integral part of Rubick.
|
||||
- [x] Supports the quick launch of local apps, files, and folders.
|
||||
- [x] Supports enterprise-level intranet deployment.
|
||||
- [x] Supports multiple languages.
|
||||
|
||||
## Core functionality showcase.
|
||||
### 1. Search system application
|
||||
Support pinyin and abbreviations to search system applications:
|
||||
|
||||
## 使用问题
|
||||
1. 依赖于 `robotjs` dev 环境运行请在 `install` 后执行 `npm run rebuild`
|
||||
2. windows 版本目前有了一个最基础的可用版,代码在 [feat-win](https://github.com/clouDr-f2e/rubick/tree/feat-win) 分支。完整版正在开发中,敬请期待
|
||||

|
||||
|
||||
## 目前支持能力
|
||||
### 2. UI plug-in installation
|
||||
Click the `rubick` icon on the right side of the search box to enter the plug-in market, select the desired plug-in, and click the download button to download. After the download is complete, you can find the installed plug-in under the Installed tab
|
||||
|
||||
### touchBar 唤起插件
|
||||
macOS 支持 touchbar 快速唤起插件
|
||||
After the installation is complete, enter the plug-in call up command to use the corresponding plug-in:
|
||||
|
||||

|
||||

|
||||
|
||||
### 3. System plug-in installation
|
||||
The system plug-in installation method is the same as that of the UI category. In the plug-in market, select the `system category` and find the system plug-in that suits you to install it.
|
||||
```
|
||||
After the system plug-in is installed successfully, rubick needs to be restarted to take effect
|
||||
```
|
||||
|
||||
### 超级面板
|
||||
长按鼠标右键,即可呼起超级面板,可以根据当前鼠标选择内容,匹配对应插件能力。比如当前选择图片后长按右击,则会呼起上传图床插件:
|
||||
### 4. Multi-device data synchronization based on WebDAV.
|
||||
In "Rubick," search for "Preferences," go to "Account and Settings," and then select "Multi-Device Data Synchronization." You can export and import data for the use of Rubick plugins.
|
||||
|
||||

|
||||

|
||||
|
||||
### 模板
|
||||
模板即是一个内置 UI 样式的功能插件。
|
||||
## Related Repositories
|
||||
|
||||
<img src=https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0b113ad547974699b9c73c28bc09b9b1~tplv-k3u1fbpfcp-watermark.image width=500 />
|
||||
[Rubick Plugins Repositories](https://gitee.com/rubick-center)
|
||||
|
||||
### 系统命令
|
||||
#### 取色
|
||||
基于 `robot.js` 以及 `iohook` 实现。未使用 C++ 扩展。
|
||||
[Rubick Plugins Database](https://gitcode.net/rubickcenter/rubick-database)
|
||||
|
||||

|
||||
[Rubick Plugin CLI](https://github.com/rubickCenter/rubick-plugin-cli)
|
||||
|
||||
#### 截屏
|
||||
## Sponsor
|
||||
### 1. Join the Knowledge Planet
|
||||
We have accumulated a lot of knowledge and common issues about rubick on the Knowledge Planet. You can pay to join our knowledge community to discuss with us. We will answer at any time!
|
||||
|
||||
<img src=https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/18023dab52e1420c9e87362cefddb2a1~tplv-k3u1fbpfcp-watermark.image width=500 />
|
||||
<img width=400 src=https://picx.zhimg.com/80/v2-6deabf65175d18080439ef813102d18c_720w.png />
|
||||
|
||||
### 2. Buy me a cup of coffee
|
||||
If the project is helpful to you, you can buy me a cup of coffee as a reward!
|
||||
<div align= "left">
|
||||
<img width="180" src="https://picx.zhimg.com/80/v2-911d249dc454f3460451a4e1ecceeb14_720w.png">
|
||||
<img width="180" src="https://picx.zhimg.com/80/v2-3160247d6099053405e6cd2cb6afb5e5_720w.png">
|
||||
</div>
|
||||
|
||||
#### 全局快捷键
|
||||
|
||||
<img src=https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/62cc424eacac4c9eb178f0e055e87d9a~tplv-k3u1fbpfcp-watermark.image width=500 />
|
||||
|
||||
### 最后
|
||||
对本项目有兴趣或者想要交流学习的同学可以扫码加下面的微信,备注 rubick,帮助我们更好的成长:
|
||||
## Feedback
|
||||
Those who are interested in this project or want to exchange and learn can scan the QR code and add the following WeChat, with the comment rubick, to help us grow better.
|
||||
|
||||

|
||||
|
||||
<a href="https://hellogithub.com/repository/0a3e2484b44e481e9dcf1850e45193cd" target="_blank"><img src="https://api.hellogithub.com/v1/widgets/recommend.svg?rid=0a3e2484b44e481e9dcf1850e45193cd&claim_uid=vXGwjpmYNsBex0C" alt="Featured|HelloGitHub" style="width: 250px; height: 54px;" width="250" height="54" /></a>
|
||||
|
||||
## Contribute
|
||||
This project exists thanks to all the people who contribute. [[Contribute](https://github.com/rubickCenter/rubick/graphs/contributors)]. <a href="https://github.com/rubickCenter/rubick/graphs/contributors"><img src="https://opencollective.com/rubick/contributors.svg?width=890&button=false" /></a>
|
||||
|
||||
## License
|
||||
This project is licensed under the MIT License - see the [LICENSE.md](https://github.com/clouDr-f2e/rubick/blob/master/LICENSE) file for details.
|
||||
|
||||
This project is licensed under the MIT License - see the [LICENSE](https://github.com/rubickCenter/rubick/blob/master/LICENSE) file for details.
|
||||
|
||||
117
README.zh-CN.md
Normal file
@@ -0,0 +1,117 @@
|
||||
[English](./README.md) | 简体中文
|
||||
|
||||
|
||||
<div align= "center">
|
||||
<img align="center" width=200 src="./public/logo.png" />
|
||||
</div>
|
||||
|
||||
<div align= "center">
|
||||
<h1>Rubick</h1>
|
||||
|
||||
<img alt="release" src="https://img.shields.io/github/downloads/rubickCenter/rubick/total" />
|
||||
<a href="https://github.com/rubickCenter/rubick/releases">
|
||||
<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/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" />
|
||||
</a>
|
||||
<a href="https://github.com/rubickCenter/rubick/stargazers">
|
||||
<img alt="star" src="https://img.shields.io/github/stars/rubickCenter/rubick?style=social">
|
||||
</a>
|
||||
<a href="https://gitee.com/monkeyWang/rubick">
|
||||
<img alt="码云" src="https://img.shields.io/badge/Gitee--yellow.svg?style=social&logo=data:image/svg+xml;base64,PHN2ZyB0PSIxNTc0ODM3MTM4ODM3IiBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHAtaWQ9IjE3NzAiICAgICB3aWR0aD0iMTYiIGhlaWdodD0iMTYiPiAgICA8cGF0aCBkPSJNODkxIDQyOC44SDQ2NS44Yy0yMC40IDAtMzcgMTYuNS0zNyAzN3Y5Mi40YzAgMjAuNCAxNi41IDM3IDM3IDM3aDI1OC45YzIwLjQgMCAzNyAxNi42IDM3IDM3djE4LjRjMCA2MS4zLTQ5LjcgMTEwLjktMTEwLjkgMTEwLjlIMjk5LjRjLTIwLjQgMC0zNy0xNi42LTM3LTM3VjM3My4yYzAtNjEuMyA0OS43LTExMC45IDExMC45LTExMC45aDUxNy42YzIwLjQgMCAzNy0xNi41IDM3LTM3bDAuMS05Mi4zYzAtMjAuNC0xNi41LTM3LTM3LTM3SDM3My4zQzIyMC4yIDk2IDk2IDIyMC4yIDk2IDM3My4zVjg5MWMwIDIwLjQgMTYuNiAzNyAzNyAzN2g1NDUuNEM4MTYuMiA5MjggOTI4IDgxNi4zIDkyOCA2NzguNFY0NjUuOGMwLTIwLjQtMTYuNi0zNy0zNy0zN3oiICAgICAgICAgIGZpbGw9IiNkODFlMDYiIHAtaWQ9IjE3NzEiPjwvcGF0aD48L3N2Zz4="/>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div align= "center">
|
||||
<img align="center" src="https://picx.zhimg.com/80/v2-f8fe09ef125dac5fdcbef3fe00f92b21_720w.png" />
|
||||
</div>
|
||||
|
||||
开源的插件化桌面端效率工具箱。插件是基于 npm 进行安装和卸载,非常轻便。插件数据支持 webdav 多端同步,非常安全。支持内网部署,可二次定制化开发,非常灵活。
|
||||
|
||||
## 获取 rubick
|
||||
下载最新的安装包:
|
||||
|
||||
* [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)
|
||||
|
||||
## 使用文档
|
||||
|
||||
[Rubick 官网](https://rubick.vip)
|
||||
|
||||
[Rubick Docs](https://rubickCenter.github.io/rubick/)
|
||||
|
||||
## 如何使用 rubick
|
||||
|
||||
安装完成 rubick 后,可以通过快捷键 Alt/Option+R 可以快速呼起主程序。主程序输入框内输入关键词可以搜索出对应的 App、插件、文件... 选择即可使用。如果没有想要的功能,可以点击左侧的 logo 进入插件市场寻找自己想要的插件进行安装。
|
||||
|
||||
## 支持能力
|
||||
- [x] 基于 npm 包模式的插件管理,安装插件和安装 npm 包一样简单
|
||||
- [x] 支持 webdav 多端数据同步,真正的数据安全同步
|
||||
- [x] 独一无二的系统插件模式,让插件成为 rubick 的一部分
|
||||
- [x] 支持快速启动本地 app、文件、文件夹
|
||||
- [x] 支持企业化内网部署
|
||||
- [x] 支持多语言
|
||||
|
||||
|
||||
## 核心功能展示
|
||||
### 1. 搜索系统应用
|
||||
支持拼音和缩写来搜索系统安装应用:
|
||||
|
||||

|
||||
|
||||
### 2. UI类插件安装
|
||||
点击搜索框右侧 `rubick` 图标,进入插件市场,选择所需插件,点击下载按钮即可下载,下载完成后在已安装 tab 下可以找到安装插件。
|
||||
安装完成后,输入插件呼起命令即可使用对应插件:
|
||||
|
||||

|
||||
|
||||
### 3. 系统类插件安装
|
||||
系统插件安装方式和UI类一样,在插件市场选择`系统分类`,寻找适合自己的系统插件安装即可。
|
||||
|
||||
```
|
||||
系统插件安装成功后,需要重启 rubick 才能生效
|
||||
```
|
||||
|
||||
### 4. 基于 webdav 的多端数据同步
|
||||
在 `rubick` 内搜索`偏好设置` 进入 `账户和设置` -> `多端数据同步`;即可对 `rubick` 插件使用数据进行 `导出` 和 `导入`。
|
||||
|
||||

|
||||
|
||||
## 关联仓库
|
||||
|
||||
[Rubick 插件仓库](https://gitee.com/rubick-center)
|
||||
|
||||
[Rubick 插件数据库](https://gitcode.net/rubickcenter/rubick-database)
|
||||
|
||||
[Rubick Plugin CLI](https://github.com/rubickCenter/rubick-plugin-cli)
|
||||
|
||||
## 赞助
|
||||
### 1. 加入知识星球
|
||||
我们在知识星球积累了大量的关于 rubick 的知识和常见问题,您可以付费加入我们的知识星球来一起讨论。我们将随时解答!
|
||||
|
||||
<img width=400 src=https://picx.zhimg.com/80/v2-6deabf65175d18080439ef813102d18c_720w.png />
|
||||
|
||||
### 2. 打赏喝杯咖啡
|
||||
如果项目对你有帮助,可以请我喝杯咖啡赞赏!
|
||||
|
||||
<div align= "left">
|
||||
<img width="180" src="https://picx.zhimg.com/80/v2-911d249dc454f3460451a4e1ecceeb14_720w.png">
|
||||
<img width="180" src="https://picx.zhimg.com/80/v2-3160247d6099053405e6cd2cb6afb5e5_720w.png">
|
||||
</div>
|
||||
|
||||
## 反馈
|
||||
对本项目有兴趣或者想要交流学习的同学可以扫码加下面的微信,备注 rubick,帮助我们更好的成长:
|
||||
|
||||

|
||||
|
||||
## 贡献
|
||||
This project exists thanks to all the people who contribute. [[Contribute](https://github.com/rubickCenter/rubick/graphs/contributors)]. <a href="https://github.com/rubickCenter/rubick/graphs/contributors"><img src="https://opencollective.com/rubick/contributors.svg?width=890&button=false" /></a>
|
||||
|
||||
## License
|
||||
This project is licensed under the MIT License - see the [LICENSE](https://github.com/rubickCenter/rubick/blob/master/LICENSE) file for details.
|
||||
|
||||
29
appveyor.yml
@@ -1,29 +0,0 @@
|
||||
version: 0.1.{build}
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
|
||||
image: Visual Studio 2017
|
||||
platform:
|
||||
- x64
|
||||
|
||||
cache:
|
||||
- node_modules
|
||||
- '%APPDATA%\npm-cache'
|
||||
- '%USERPROFILE%\.electron'
|
||||
- '%USERPROFILE%\AppData\Local\Yarn\cache'
|
||||
|
||||
init:
|
||||
- git config --global core.autocrlf input
|
||||
|
||||
install:
|
||||
- ps: Install-Product node 8 x64
|
||||
- git reset --hard HEAD
|
||||
- yarn
|
||||
- node --version
|
||||
|
||||
build_script:
|
||||
- yarn build
|
||||
|
||||
test: off
|
||||
23
babel.config.js
Normal file
@@ -0,0 +1,23 @@
|
||||
module.exports = {
|
||||
presets: ['@vue/cli-plugin-babel/preset'],
|
||||
plugins: [
|
||||
[
|
||||
'import',
|
||||
{
|
||||
libraryName: 'ant-design-vue',
|
||||
libraryDirectory: 'es',
|
||||
style: 'css', // or 'css'
|
||||
},
|
||||
'ant-design-vue',
|
||||
],
|
||||
[
|
||||
'import',
|
||||
{
|
||||
libraryName: '@ant-design/icons-vue',
|
||||
libraryDirectory: 'lib/icons',
|
||||
camel2DashComponentName: false,
|
||||
},
|
||||
'@ant-design/icons-vue',
|
||||
],
|
||||
],
|
||||
};
|
||||
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 15 KiB |
24
deploy.sh
@@ -1,24 +0,0 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# 确保脚本抛出遇到的错误
|
||||
set -e
|
||||
|
||||
# 生成静态文件
|
||||
cd docs && npm run docs:build
|
||||
# 进入生成的文件夹
|
||||
cd docs/.vuepress/dist
|
||||
|
||||
# 如果是发布到自定义域名
|
||||
# echo 'www.example.com' > CNAME
|
||||
|
||||
git init
|
||||
git add -A
|
||||
git commit -m 'deploy'
|
||||
|
||||
# 如果发布到 https://<USERNAME>.github.io
|
||||
# git push -f git@github.com:<USERNAME>/<USERNAME>.github.io.git master
|
||||
|
||||
# 如果发布到 https://<USERNAME>.github.io/<REPO>
|
||||
git push -f git@github.com:clouDr-f2e/rubick.git master:gh-pages
|
||||
|
||||
cd -
|
||||
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></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>
|
||||
262
detach/src/App.vue
Normal file
@@ -0,0 +1,262 @@
|
||||
<template>
|
||||
<div :class="[process.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="process.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 process = window.require('process');
|
||||
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;
|
||||
},
|
||||
});
|
||||
|
||||
window.enterFullScreenTrigger = () => {
|
||||
document.querySelector('.detach').classList.remove('darwin');
|
||||
};
|
||||
window.leaveFullScreenTrigger = () => {
|
||||
const titleDom = document.querySelector('.detach');
|
||||
if (!titleDom.classList.contains('darwin')) {
|
||||
titleDom.classList.add('darwin');
|
||||
}
|
||||
};
|
||||
|
||||
window.maximizeTrigger = () => {
|
||||
const btnMaximize = document.querySelector('.maximize')
|
||||
if (!btnMaximize || btnMaximize.classList.contains('unmaximize')) return;
|
||||
btnMaximize.classList.add('unmaximize');
|
||||
};
|
||||
|
||||
window.unmaximizeTrigger = () => {
|
||||
const btnMaximize = document.querySelector('.maximize');
|
||||
if (!btnMaximize) return;
|
||||
btnMaximize.classList.remove('unmaximize');
|
||||
};
|
||||
|
||||
if (process.platform === 'darwin') {
|
||||
window.onkeydown = (e) => {
|
||||
if (e.code === 'Escape') {
|
||||
ipcRenderer.send('detach:service', { type: 'endFullScreen' });
|
||||
return;
|
||||
}
|
||||
if (e.metaKey && (e.code === 'KeyW' || e.code === 'KeyQ')) {
|
||||
window.handle.close()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
window.onkeydown = (e) => {
|
||||
if (e.ctrlKey && e.code === 'KeyW') {
|
||||
window.handle.close()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
</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"
|
||||
]
|
||||
}
|
||||
17
detach/vue.config.js
Normal file
@@ -0,0 +1,17 @@
|
||||
const path = require('path');
|
||||
|
||||
module.exports = {
|
||||
css: {
|
||||
// 配置css模块
|
||||
loaderOptions: {
|
||||
// 向预处理器 Loader 传递配置选项
|
||||
less: {
|
||||
// 配置less(其他样式解析用法一致)
|
||||
javascriptEnabled: true, // 设置为true
|
||||
},
|
||||
},
|
||||
},
|
||||
productionSourceMap: false,
|
||||
outputDir: path.join(__dirname, '../public/detach'),
|
||||
publicPath: process.env.NODE_ENV === 'production' ? '' : '/',
|
||||
};
|
||||
9401
detach/yarn.lock
Normal file
@@ -1,60 +0,0 @@
|
||||
module.exports = {
|
||||
title: 'Rubick',
|
||||
description: '你的开源桌面插件应用',
|
||||
base: '/rubick/',
|
||||
themeConfig: {
|
||||
themeColor: {
|
||||
blue: "#2196f3",
|
||||
red: "#2196f3",
|
||||
green: "#2196f3",
|
||||
orange: "#2196f3",
|
||||
},
|
||||
logo: '/images/logo.png',
|
||||
nav: [
|
||||
{ text: '使用文档', link: '/guide/' },
|
||||
{ text: '开发者', link: '/dev/' },
|
||||
],
|
||||
sidebar: [
|
||||
{
|
||||
title: '使用文档', // 必要的
|
||||
path: '/guide/', // 可选的, 标题的跳转链接,应为绝对路径且必须存在
|
||||
sidebarDepth: 1, // 可选的, 默认值是 1
|
||||
},
|
||||
{
|
||||
title: '开发者',
|
||||
path: '/dev/',
|
||||
},
|
||||
{
|
||||
title: '常见问题',
|
||||
path: '/qs/',
|
||||
},
|
||||
{
|
||||
title: 'TODO: 原理解析',
|
||||
children: [
|
||||
{
|
||||
title: '插件化实现原理',
|
||||
path: '/blogs/plugin/',
|
||||
},
|
||||
{
|
||||
title: '右击增强实现原理'
|
||||
},
|
||||
{
|
||||
title: '系统插件实现原理'
|
||||
},
|
||||
{
|
||||
title: '文件检索实现原理'
|
||||
},
|
||||
]
|
||||
},
|
||||
],
|
||||
// 假定是 GitHub. 同时也可以是一个完整的 GitLab URL
|
||||
repo: 'https://github.com/clouDr-f2e/rubick',
|
||||
// 自定义仓库链接文字。默认从 `themeConfig.repo` 中自动推断为
|
||||
// "GitHub"/"GitLab"/"Bitbucket" 其中之一,或是 "Source"。
|
||||
repoLabel: 'Github',
|
||||
// 默认是 false, 设置为 true 来启用
|
||||
editLinks: true,
|
||||
// 默认为 "Edit this page"
|
||||
editLinkText: '帮助我们改善此页面!'
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 77 KiB |
|
Before Width: | Height: | Size: 471 KiB |
|
Before Width: | Height: | Size: 749 KiB |
|
Before Width: | Height: | Size: 2.7 MiB |
|
Before Width: | Height: | Size: 452 KiB |
|
Before Width: | Height: | Size: 54 KiB |
|
Before Width: | Height: | Size: 47 KiB |
@@ -1,7 +0,0 @@
|
||||
$accentColor = #ff4ea4//默认主题颜色
|
||||
$codeBgColor = #282c34//默认背景颜色
|
||||
|
||||
//示例修改相关样式f12找到需要修改的地方找到对应class类拿过来直接用就行了
|
||||
.sidebar-group.is-sub-group > .sidebar-heading:not(.clickable){
|
||||
opacity :1
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
---
|
||||
home: true
|
||||
heroImage: /images/logo.png
|
||||
heroText: Rubick
|
||||
tagline: 基于 Electron 开源的插件化工具箱
|
||||
actionText: 快速上手 →
|
||||
actionLink: /guide/
|
||||
features:
|
||||
- title: 开箱即用
|
||||
details: 支持快速检索系统应用
|
||||
- title: 自由定制
|
||||
details: 支持自定义插件开发
|
||||
- title: 海量示例
|
||||
details: 新版文档 code Demo & playground 一应俱全
|
||||
footer: MIT Licensed | Copyright (c) 2021 muwoo
|
||||
---
|
||||
@@ -1,167 +0,0 @@
|
||||
## 插件化原理
|
||||
浏览器是打开不同网页进行浏览就是一个天然的插件,我们在做 `hybird` 混合开发的时候,App 内的 H5 页面也是可以类比成一个个
|
||||
插件。微信小程序在微信环境内运行也可以看做一个插件。他们都有一个共性:**在宿主环境内运行插件页面,需要使用宿主能力时
|
||||
调用宿主提供的API来完成自身能力的增强**。
|
||||
|
||||
所以 electron 也可以看做一个移动端 APP,我们通过 `webview` 来加载 `H5` 页面,`H5` 页面调用 `electron App` 内置 API
|
||||
完成功能增强。所以这就是我们核心的原理思想。
|
||||
|
||||
## electron webview 方式
|
||||
### 1. electron 中使用 webview
|
||||
|
||||
```html
|
||||
<webview src="https://xxx.xx.com/index.html" preload="preload.js" />
|
||||
```
|
||||
|
||||
### 2. 实现 `bridge`
|
||||
```js
|
||||
// preload.js
|
||||
window.rubickBridge = {
|
||||
sayHello() {
|
||||
console.log('hello world')
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 插件借助 `bridge` 调用 `electron` 的能力
|
||||
|
||||
```html
|
||||
<html>
|
||||
<body>
|
||||
<div>这是一个插件<div>
|
||||
</body>
|
||||
<script>
|
||||
window.rubickBridge.sayHello()
|
||||
</script>
|
||||
</html>
|
||||
```
|
||||
|
||||
### 4. 通信
|
||||
因为 `proload.js` 是 `electron` 的 `renderer` 进程的,所以如果需要使用部分 `main` 进程的能力,则需要使用通信机制:
|
||||
```js
|
||||
// main process
|
||||
ipcMain.on('msg-trigger', async (event, arg) => {
|
||||
const window = arg.winId ? BrowserWindow.fromId(arg.winId) : mainWindow
|
||||
const operators = arg.type.split('.');
|
||||
let fn = Api;
|
||||
operators.forEach((op) => {
|
||||
fn = fn[op];
|
||||
});
|
||||
const data = await fn(arg, window);
|
||||
event.sender.send(`msg-back-${arg.type}`, data);
|
||||
});
|
||||
|
||||
// renderer process
|
||||
ipcRenderer.send('msg-trigger', {
|
||||
type: 'getPath',
|
||||
name,
|
||||
});
|
||||
ipcRenderer.on(`msg-back-getPath`, (e, result) => {
|
||||
console.log(result)
|
||||
});
|
||||
```
|
||||
|
||||
## 插件加载原理
|
||||
### rubick 使用插件
|
||||
首先我们需要实现一个插件,必须要有个 `plugin.json`,这玩意就是用来告诉 `rubick` 插件的信息。
|
||||
```json
|
||||
{
|
||||
"pluginName": "helloWorld",
|
||||
"description": "我的第一个uTools插件",
|
||||
"main": "index.html",
|
||||
"version": "0.0.1",
|
||||
"logo": "logo.png",
|
||||
"features": [
|
||||
{
|
||||
"code": "hello",
|
||||
"explain": "hello world",
|
||||
"cmds":["hello", "你好"]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
接下来是将写好的插件用 `rubick` 跑起来,复制 `plugin.json` 到 `rubick` 搜索框即可,所以当 `rubick` 检测到输入框内执行
|
||||
`ctrl/command + c` 时,读取剪切板内容,如果剪切板复制的是文件类型的 `plugin.json`,那么就将构造插件的 `pluginConfig` 配置文件,用于后续搜索
|
||||
时使用。
|
||||
|
||||
```js
|
||||
// 监听 input change
|
||||
// 读取剪切板内容
|
||||
const fileUrl = clipboard.read('public.file-url').replace('file://', '');
|
||||
// 复制文件
|
||||
if (fileUrl && value === 'plugin.json') {
|
||||
// 读取 plugin.json 配置
|
||||
const config = JSON.parse(fs.readFileSync(fileUrl, 'utf-8'));
|
||||
const pluginConfig = {
|
||||
...config,
|
||||
// index.html 文件位置,用于webview加载
|
||||
sourceFile: path.join(fileUrl, `../${config.main || 'index.html'}`),
|
||||
id: uuidv4(),
|
||||
type: 'dev',
|
||||
icon: 'image://' + path.join(fileUrl, `../${config.logo}`),
|
||||
subType: (() => {
|
||||
if (config.main) {
|
||||
return ''
|
||||
}
|
||||
return 'template';
|
||||
})()
|
||||
};
|
||||
}
|
||||
```
|
||||
实现效果如下:
|
||||
|
||||
|
||||

|
||||
|
||||
### rubick 内搜索插件原理
|
||||
|
||||
接下来就是进行命令搜索插件:
|
||||
|
||||
|
||||

|
||||
|
||||
实现这个功能其实也就是对之前存储的`pluginConfig`的里面的 `features` 进行遍历,找到相应的 `cmd` 后进行下拉框展示即可。
|
||||
|
||||
```js
|
||||
state.devPlugins.forEach((plugin) => {
|
||||
// dev 插件未开启
|
||||
if (plugin.type === 'dev' && !plugin.status) return;
|
||||
const feature = plugin.features;
|
||||
feature.forEach((fe) => {
|
||||
// fe.cmds: 所有插件的命令; value: 当前输入框内搜索的名称
|
||||
const cmds = searchKeyValues(fe.cmds, value);
|
||||
options = [
|
||||
...options,
|
||||
...cmds.map((cmd) => ({
|
||||
name: cmd,
|
||||
value: 'plugin',
|
||||
icon: plugin.sourceFile ? 'image://' + path.join(plugin.sourceFile, `../${plugin.logo}`) : plugin.logo,
|
||||
desc: fe.explain,
|
||||
type: plugin.type,
|
||||
click: (router) => {
|
||||
// 跳转到指定插件页面
|
||||
actions.openPlugin({ commit }, { cmd, plugin, feature: fe, router });
|
||||
}
|
||||
}))
|
||||
];
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
当点击 input 内插件时,需要跳转到插件 `webview` 加载页面:
|
||||
|
||||
```js
|
||||
// actions.openPlugin
|
||||
router.push({
|
||||
path: '/plugin',
|
||||
query: {
|
||||
...plugin,
|
||||
_modify: Date.now(),
|
||||
detail: JSON.stringify(feature)
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||

|
||||
|
||||
本页写的插件demo已上传 [github](https://github.com/clouDr-f2e/rubick-plugin-demo)
|
||||
@@ -1,81 +0,0 @@
|
||||
## 开发一个最基础的插件
|
||||
一个最基础插件的目录是这样的:
|
||||
```
|
||||
rubick-plugin-demo
|
||||
|-- index.html
|
||||
|-- logo.png
|
||||
|-- plugin.json
|
||||
|-- preload.js
|
||||
```
|
||||
## 文件说明
|
||||
### plugin.json
|
||||
用于指定插件最基础的配置,一个最基础的配置信息如下:
|
||||
```json
|
||||
{
|
||||
"pluginName": "测试插件",
|
||||
"author": "muwoo",
|
||||
"description": "我的第一个 rubick 插件",
|
||||
"main": "index.html",
|
||||
"version": "0.0.2",
|
||||
"logo": "logo.png",
|
||||
"name": "rubick-plugin-demo",
|
||||
"features": [
|
||||
{
|
||||
"code": "hello",
|
||||
"explain": "这是一个测试的插件",
|
||||
"cmds":["hello", "你好"]
|
||||
}
|
||||
],
|
||||
"preload": "preload.js"
|
||||
}
|
||||
```
|
||||
核心字段说明:
|
||||
|
||||
* name 插件仓库名称,需要保持和git仓库同名,不要随意变更
|
||||
* pluginName 插件显示名称,用于展示给使用者
|
||||
* description 插件描述,描述这个插件的作用
|
||||
* main 入口文件,一般为 `index.html`
|
||||
* version 插件的版本
|
||||
* features 插件核心功能列表
|
||||
* features.code 插件某个功能的识别码,可用于区分不同的功能
|
||||
* features.cmds 输入框内搜索该 cmd 进入插件
|
||||
|
||||
### index.html
|
||||
插件的入口文件,用于展示插件的样式,一个最基础的 `html` 结构可以是这样:
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
hello Rubick
|
||||
<button id="showNotification">通知</button>
|
||||
</body>
|
||||
<script>
|
||||
document.getElementById('showNotification').addEventListener('click', () => {
|
||||
window.showNotification();
|
||||
})
|
||||
</script>
|
||||
</html>
|
||||
```
|
||||
|
||||
### preload.js
|
||||
细心的同学可能已经注意到上面的 `index.html` 使用了一个全局函数 `showNotification` 那么这个函数是在哪里定义的呢?
|
||||
答案就是在 `preload.js` 里面。我们知道 `electron` 是可以再渲染进程中执行 `node.js` 的,所以 `preload.js` 是既可以
|
||||
执行 `node.js` 以及执行 `Rubick` 提供的系统命令的位置:
|
||||
```js
|
||||
window.showNotification = function () {
|
||||
rubick.showNotification('HI, rubick')
|
||||
}
|
||||
```
|
||||
rubick 更多支持 API 能力参考:[rubick 全局API](https://github.com/clouDr-f2e/rubick/blob/master/static/preload.js#L49)
|
||||
|
||||
### logo.png
|
||||
当前插件的logo图标,建议是 200 x 200 方形图标
|
||||
|
||||
## 测试插件
|
||||
复制 `plugin.json` 文件,在 `rubick` 主窗口执行 `ctrl/command + v` 即可唤起安装插件的功能,选择`新建rubick插件`,进入插件主界面,
|
||||
开启插件后,在插件主窗口即可通过命令打开插件:
|
||||
|
||||

|
||||
|
||||
本小节所有代码:[rubcik-plugin-demo](https://github.com/clouDr-f2e/rubick-plugin-demo)
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
## 下载 rubick
|
||||
[rubick 下载安装地址](https://github.com/clouDr-f2e/rubick/releases)
|
||||
|
||||
安装完成后打开 rubick 即可看到主搜索界面:
|
||||
|
||||

|
||||
|
||||
目前支持 windows 和 macos。linux 小伙伴正在开发中
|
||||
|
||||
## 功能说明
|
||||
接下来详细介绍 rubick 所包含和支持的功能
|
||||
|
||||
### 1. 搜索系统应用
|
||||
`macos` 下支持搜索当前电脑内所安装的所有 app 和一些偏好设置,目前可搜索路径为:
|
||||
```json
|
||||
[
|
||||
"/System/Applications",
|
||||
"/Applications",
|
||||
"/System/Library/PreferencePanes"
|
||||
]
|
||||
```
|
||||
也就是说只要当前系统软件安装到这些目录才会被检索到。支持中文搜索和拼音、拼音首字母搜索:
|
||||
|
||||

|
||||
|
||||
`Windows` 内由于安装目录太多不确定,有的在 C盘,有的在D盘,还有的在自定义其他位置,所以该功能还在设计中,如果您有好的方案也欢迎提供:[issues](https://github.com/clouDr-f2e/rubick/issues)
|
||||
|
||||
### 2. rubick 内置功能
|
||||
|
||||
`rubick` 参考了钉钉、微信等 App 的基础功能,也设计内置了 `截图`、`取色`、`锁屏` 基础功能,通过搜索框输入对应关键词呼起。
|
||||
|
||||
#### 截屏
|
||||
输入:`'截屏'` 或者 `'shortCut'` 或者 `'jp'`。
|
||||
|
||||
#### 取色
|
||||
输入:`'取色'` 或者 `'拾色'` 或者 `'Pick color'` 、`'qs'`、`'ss'`。
|
||||
|
||||
#### 锁屏
|
||||
输入:`'锁屏'` 或者 `'lock screen'` 或者 `'sp'`。
|
||||
|
||||
### 3. 使用插件
|
||||
点击搜索框右侧 rubick 图标,进入插件市场,选择所需插件,点击下载按钮即可下载,下载完成后在已安装 tab 下可以找到安装插件。
|
||||
安装完成后,输入插件呼起命令即可使用对应插件:
|
||||
|
||||

|
||||
|
||||
### 4. 右击增强
|
||||
通常我们需要使用鼠标右击来对桌面属性进行拓展,`Rubick` 支持对右击属性进行增强功能,长按鼠标右键即可呼起。如果安装的插件支持
|
||||
特殊类型的文件操作,还可以在右键中唤起插件:
|
||||
|
||||

|
||||
|
||||
### 更多功能
|
||||
如果您还需要更多功能,欢迎来这里给我们提建议:[issues](https://github.com/clouDr-f2e/rubick/issues/20)
|
||||
有价值的想法我们会加入到后期的开发当中。同时也欢迎一起加入共建。
|
||||
|
||||
|
Before Width: | Height: | Size: 92 KiB |
@@ -1,99 +0,0 @@
|
||||
## windows 本地启动项目
|
||||
**windows 项目地址目前在 `feat-win` 分支,需要切换到 `feat-win`。**
|
||||
如果您是在 `windows` 系统下使用本项目进行启动的话,如果出现了一些跑不起的情况,下面的一些经验或许可以帮助您。
|
||||
|
||||
### 安装依赖
|
||||
项目是基于 `electron-vue` 的,所以需要本地已经安装好 `nodejs`。当 `clone` 好项目到本地的时候,需要对项目依赖
|
||||
进行手动安装:
|
||||
```bash
|
||||
$ cd rubick
|
||||
$ npm install
|
||||
```
|
||||
由于本项目依赖 [iohook](https://wilix-team.github.io/iohook/) 和 [robotjs](http://robotjs.io/)
|
||||
而这2个项目在安装时,依赖 node gyp 的编译,所以你可能会遇到一些环境问题或者网络问题。
|
||||
### iohook 安装
|
||||
首先,我们先来安装 `iohook`,按照 `iohook` 的文档所示,安装前需要先确定当前 `electron` 的版本以及 `abi` 的版本,
|
||||
现在我们使用的 `electron` 版本是 `v11.0.2` 所以只需要在 `package,json` 中加上以下配置,指定安装特点的`.node` 文件
|
||||
|
||||
```json
|
||||
{
|
||||
"iohook": {
|
||||
"targets": [
|
||||
"node-83",
|
||||
"electron-85"
|
||||
],
|
||||
"platforms": [
|
||||
"win32"
|
||||
],
|
||||
"arches": [
|
||||
"x64",
|
||||
"ia32"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
接下来执行安装操作:
|
||||
```shell
|
||||
$ npm i iohook
|
||||
```
|
||||
|
||||
如果此时一直停留在 `node install` 进度上,说明可能需要翻墙,这里就不介绍如何翻墙了。此时虽然 `.node` 文件没有下载成功,但是 `iohook` 源文件
|
||||
已经安装成功,如果因为翻墙问题导致的安装失败,我们解决好翻墙问题后,可以接着运行一下:
|
||||
|
||||
```shell
|
||||
$ npm run rebuild_win
|
||||
```
|
||||
到这里 `iohook` 应该就安装好了
|
||||
|
||||
### 安装 robotjs
|
||||
和 iohook 不同, `robotjs` 需要 `node gyp` 重新编译 `C++`。所以第一步是先安装源文件:
|
||||
```shell
|
||||
npm i robotjs@git+https://github.com/Toinane/robotjs.git
|
||||
```
|
||||
此时如果报错,大多还是因为墙的问题。不管包不报错,我们接下来都需要执行一下下面的编译操作:
|
||||
|
||||
```shell
|
||||
npm run rebuild_win
|
||||
```
|
||||
此时,可能会出现下这个错:
|
||||
|
||||
```text
|
||||
gyp ERR! find VS msvs_version not set from command line or npm config
|
||||
// ...
|
||||
```
|
||||
google 了一圈,大多数是说缺少 `visual studio`。需要安装,所以可以执行这个命令:
|
||||
|
||||
```shell
|
||||
$ npm install --global --production windows-build-tools
|
||||
```
|
||||
到这里会进入正常的安装流程,理论上会一部到底,如果你卡在了 `Successfully installed Python 2.7` 不动了
|
||||
可以去一下 `C:\Users\you username\.windows-build-tools` 找一下看看应该会有一个 `vs_BuildTools` 文件
|
||||
双击后,会出现以下弹窗:
|
||||
|
||||

|
||||
|
||||
点击启动,如果一切正常那么可以方向关掉你的命令行了,此时 vs 已经安装成功,接下来要配置一下编译工具:
|
||||
```shell
|
||||
$ npm config set python python3.9
|
||||
$ npm config set msvs_version 2017
|
||||
```
|
||||
到这里终于完事了,再执行一下 `npm run rebuild_win` 此时已经安装成功!
|
||||
|
||||
## macos
|
||||
macos 下安装就简单不少了,首先先解决翻墙的问题,然后:
|
||||
```shell
|
||||
$ npm i
|
||||
```
|
||||
|
||||
最后执行
|
||||
|
||||
```shell
|
||||
$npm run rebuild
|
||||
```
|
||||
|
||||
## 最后
|
||||
如果您在启动过程中还有其他的问题,欢迎随时给我们反馈,我们会在第一时间回复:[issues](https://github.com/clouDr-f2e/rubick/issues/20)
|
||||
|
||||
|
||||
|
||||
|
||||
24918
docs/package-lock.json
generated
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"name": "rubick-docs",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"docs:dev": "vuepress dev docs",
|
||||
"docs:build": "vuepress build docs"
|
||||
},
|
||||
"author": "muwoo",
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"vuepress": "^1.8.2"
|
||||
}
|
||||
}
|
||||
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/
|
||||
23
feature/.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
feature/README.md
Normal file
@@ -0,0 +1,24 @@
|
||||
# feature
|
||||
|
||||
## 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/).
|
||||
22
feature/babel.config.js
Normal file
@@ -0,0 +1,22 @@
|
||||
module.exports = {
|
||||
presets: ['@vue/cli-plugin-babel/preset'],
|
||||
plugins: [
|
||||
[
|
||||
'import',
|
||||
{
|
||||
libraryName: 'ant-design-vue',
|
||||
style: 'css', // or 'css'
|
||||
},
|
||||
'ant-design-vue',
|
||||
],
|
||||
[
|
||||
'import',
|
||||
{
|
||||
libraryName: '@ant-design/icons-vue',
|
||||
libraryDirectory: 'lib/icons',
|
||||
camel2DashComponentName: false,
|
||||
},
|
||||
'@ant-design/icons-vue',
|
||||
],
|
||||
],
|
||||
};
|
||||
71
feature/package.json
Normal file
@@ -0,0 +1,71 @@
|
||||
{
|
||||
"name": "feature",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"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",
|
||||
"@vue/cli-service": "~4.5.0",
|
||||
"ant-design-vue": "3.2.14",
|
||||
"axios": "^0.24.0",
|
||||
"babel-plugin-import": "^1.13.8",
|
||||
"core-js": "^3.6.5",
|
||||
"lodash.debounce": "^4.0.8",
|
||||
"lodash.throttle": "^4.1.1",
|
||||
"markdown-it": "^12.2.0",
|
||||
"nanoid": "^4.0.2",
|
||||
"vue": "3.2.45",
|
||||
"vue-i18n": "9.2.2",
|
||||
"vue-router": "^4.0.0-0",
|
||||
"vue3-carousel": "^0.3.1",
|
||||
"vue3-lottie": "^3.1.0",
|
||||
"vuex": "^4.0.0-0",
|
||||
"webpack-bundle-analyzer": "^4.9.1"
|
||||
},
|
||||
"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",
|
||||
"less": "^4.1.3",
|
||||
"less-loader": "5.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
feature/public/favicon.ico
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
17
feature/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>
|
||||
31
feature/public/package.json
Normal file
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"name": "rubick-system-feature",
|
||||
"pluginName": "系统菜单",
|
||||
"description": "系统菜单",
|
||||
"main": "index.html",
|
||||
"logo": "https://pic1.zhimg.com/80/v2-29152fe716010751db835adf591421f8_720w.png",
|
||||
"version": "0.0.0",
|
||||
"preload":"preload.js",
|
||||
"pluginType": "ui",
|
||||
"features": [
|
||||
{
|
||||
"code": "finder",
|
||||
"explain": "插件市场",
|
||||
"cmds":[
|
||||
"插件市场"
|
||||
]
|
||||
},{
|
||||
"code": "installed",
|
||||
"explain": "已安装插件",
|
||||
"cmds":[
|
||||
"已安装插件", "installed"
|
||||
]
|
||||
},{
|
||||
"code": "settings",
|
||||
"explain": "偏好设置",
|
||||
"cmds":[
|
||||
"偏好设置"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
46
feature/public/preload.js
Normal file
@@ -0,0 +1,46 @@
|
||||
const remote = require('@electron/remote');
|
||||
const { ipcRenderer } = require('electron');
|
||||
|
||||
const ipcSendSync = (type, data) => {
|
||||
const returnValue = ipcRenderer.sendSync('msg-trigger', {
|
||||
type,
|
||||
data,
|
||||
});
|
||||
if (returnValue instanceof Error) throw returnValue;
|
||||
return returnValue;
|
||||
};
|
||||
|
||||
const ipcSend = (type, data) => {
|
||||
ipcRenderer.send('msg-trigger', {
|
||||
type,
|
||||
data,
|
||||
});
|
||||
};
|
||||
|
||||
window.market = {
|
||||
getLocalPlugins() {
|
||||
return remote.getGlobal('LOCAL_PLUGINS').getLocalPlugins();
|
||||
},
|
||||
downloadPlugin(plugin) {
|
||||
return remote.getGlobal('LOCAL_PLUGINS').downloadPlugin(plugin);
|
||||
},
|
||||
deletePlugin(plugin) {
|
||||
return remote.getGlobal('LOCAL_PLUGINS').deletePlugin(plugin);
|
||||
},
|
||||
refreshPlugin(plugin) {
|
||||
return remote.getGlobal('LOCAL_PLUGINS').refreshPlugin(plugin);
|
||||
},
|
||||
addLocalStartPlugin(plugin) {
|
||||
ipcSend('addLocalStartPlugin', { plugin });
|
||||
},
|
||||
removeLocalStartPlugin(plugin) {
|
||||
ipcSend('removeLocalStartPlugin', { plugin });
|
||||
},
|
||||
dbDump(target) {
|
||||
ipcSend('dbDump', { target });
|
||||
},
|
||||
|
||||
dbImport(target) {
|
||||
ipcSend('dbImport', { target });
|
||||
},
|
||||
};
|
||||
256
feature/src/App.vue
Normal file
@@ -0,0 +1,256 @@
|
||||
<template>
|
||||
<div class="main-container">
|
||||
<div class="left-menu">
|
||||
<a-menu
|
||||
@select="({ key }) => changeMenu(key)"
|
||||
:selectedKeys="active"
|
||||
mode="vertical"
|
||||
>
|
||||
<a-menu-item key="finder">
|
||||
<template #icon>
|
||||
<StarOutlined style="font-size: 16px" />
|
||||
</template>
|
||||
{{ $t('feature.market.explore') }}
|
||||
</a-menu-item>
|
||||
<a-menu-item key="worker">
|
||||
<template #icon>
|
||||
<SendOutlined style="transform: rotate(-45deg); font-size: 16px" />
|
||||
</template>
|
||||
{{ $t('feature.market.efficiency') }}
|
||||
</a-menu-item>
|
||||
<a-menu-item key="tools">
|
||||
<template #icon>
|
||||
<SearchOutlined style="font-size: 16px" />
|
||||
</template>
|
||||
{{ $t('feature.market.searchTool') }}
|
||||
</a-menu-item>
|
||||
<a-menu-item key="image">
|
||||
<template #icon>
|
||||
<FileImageOutlined style="font-size: 16px" />
|
||||
</template>
|
||||
{{ $t('feature.market.imageTool') }}
|
||||
</a-menu-item>
|
||||
<a-menu-item key="devPlugin">
|
||||
<template #icon>
|
||||
<CodeOutlined style="font-size: 16px" />
|
||||
</template>
|
||||
{{ $t('feature.market.developTool') }}
|
||||
</a-menu-item>
|
||||
<a-menu-item key="system">
|
||||
<template #icon>
|
||||
<DatabaseOutlined style="font-size: 16px" />
|
||||
</template>
|
||||
{{ $t('feature.market.systemTool') }}
|
||||
</a-menu-item>
|
||||
<a-sub-menu class="user-info">
|
||||
<template #icon>
|
||||
<a-avatar :size="32">
|
||||
<template #icon>
|
||||
<img :src="perf.custom.logo" />
|
||||
</template>
|
||||
</a-avatar>
|
||||
</template>
|
||||
<template #title>{{ perf.custom.username }}</template>
|
||||
<a-menu-item key="settings">
|
||||
<template #icon>
|
||||
<SettingOutlined />
|
||||
</template>
|
||||
{{ $t('feature.settings.title') }}
|
||||
</a-menu-item>
|
||||
<a-menu-item key="installed">
|
||||
<template #icon>
|
||||
<HeartOutlined />
|
||||
</template>
|
||||
{{ $t('feature.installed.title') }}
|
||||
</a-menu-item>
|
||||
<a-menu-item key="dev">
|
||||
<template #icon>
|
||||
<BugOutlined />
|
||||
</template>
|
||||
{{ $t('feature.dev.title') }}
|
||||
</a-menu-item>
|
||||
</a-sub-menu>
|
||||
</a-menu>
|
||||
</div>
|
||||
<div
|
||||
:class="
|
||||
[
|
||||
'finder',
|
||||
'result',
|
||||
'devPlugin',
|
||||
'image',
|
||||
'tools',
|
||||
'worker',
|
||||
'system',
|
||||
].includes(active[0])
|
||||
? 'container'
|
||||
: 'more'
|
||||
"
|
||||
>
|
||||
<keep-alive>
|
||||
<router-view />
|
||||
</keep-alive>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import {
|
||||
StarOutlined,
|
||||
SendOutlined,
|
||||
SearchOutlined,
|
||||
FileImageOutlined,
|
||||
DatabaseOutlined,
|
||||
CodeOutlined,
|
||||
SettingOutlined,
|
||||
HeartOutlined,
|
||||
BugOutlined,
|
||||
} from '@ant-design/icons-vue';
|
||||
import { useStore } from 'vuex';
|
||||
import localConfig from '@/confOp';
|
||||
|
||||
const store = useStore();
|
||||
const router = useRouter();
|
||||
const active = computed(() => store.state.active);
|
||||
const { perf } = localConfig.getConfig();
|
||||
|
||||
const changeMenu = (key: any) => {
|
||||
store.commit('commonUpdate', { active: [key] });
|
||||
router.push(key);
|
||||
};
|
||||
|
||||
window.rubick.onPluginEnter(({ code }: { code: string }) => {
|
||||
code = code === '已安装插件' ? 'installed' : code;
|
||||
changeMenu(code);
|
||||
store.commit('commonUpdate', { active: [code] });
|
||||
});
|
||||
|
||||
window.rubick.setSubInput((e: any) => {
|
||||
if (
|
||||
[
|
||||
'finder',
|
||||
'result',
|
||||
'devPlugin',
|
||||
'image',
|
||||
'tools',
|
||||
'worker',
|
||||
'system',
|
||||
].includes(active.value[0])
|
||||
) {
|
||||
if (e.text) {
|
||||
store.commit('setSearchValue', e.text);
|
||||
router.push('result');
|
||||
} else {
|
||||
store.commit('commonUpdate', { active: ['finder'] });
|
||||
router.push('finder');
|
||||
}
|
||||
}
|
||||
}, '搜索插件');
|
||||
|
||||
const init = () => store.dispatch('init');
|
||||
init();
|
||||
</script>
|
||||
<style lang="less">
|
||||
.ant-menu-submenu-popup {
|
||||
.ant-menu {
|
||||
background: var(--color-body-bg2) !important;
|
||||
height: 100%;
|
||||
border-right: none;
|
||||
.ant-menu-item,
|
||||
.ant-menu-submenu,
|
||||
.ant-menu-submenu-arrow {
|
||||
color: var(--color-text-content);
|
||||
&:active {
|
||||
background: none;
|
||||
}
|
||||
}
|
||||
.ant-menu-item-selected,
|
||||
.ant-menu-submenu-selected {
|
||||
background-color: var(--color-list-hover);
|
||||
color: var(--ant-primary-color);
|
||||
.ant-menu-submenu-arrow {
|
||||
color: var(--ant-primary-color);
|
||||
}
|
||||
&:after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style lang="less" scoped>
|
||||
@import '~@/assets/common.less';
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.main-container {
|
||||
-webkit-app-region: no-drag;
|
||||
display: flex;
|
||||
background: var(--color-body-bg);
|
||||
border-top: 1px solid var(--color-border-light);
|
||||
height: 100vh;
|
||||
box-sizing: border-box;
|
||||
align-items: flex-start;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
background: var(--color-menu-bg);
|
||||
.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,
|
||||
.more {
|
||||
background: var(--color-body-bg);
|
||||
width: calc(~'100% - 183px');
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
padding: 16px;
|
||||
position: relative;
|
||||
overflow: auto;
|
||||
}
|
||||
.more {
|
||||
background: var(--color-body-bg2);
|
||||
}
|
||||
.left-menu {
|
||||
padding: 16px;
|
||||
position: relative;
|
||||
height: 100vh;
|
||||
:deep(.ant-menu) {
|
||||
width: 100%;
|
||||
}
|
||||
:deep(.ant-menu-item) {
|
||||
padding-left: 12px !important;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
:deep(.ant-menu-item-selected),
|
||||
:deep(.ant-menu-submenu-selected) {
|
||||
background-color: var(--color-list-hover);
|
||||
border-radius: 6px;
|
||||
color: var(--ant-primary-color);
|
||||
}
|
||||
:deep(.user-info) {
|
||||
position: absolute;
|
||||
bottom: 16px;
|
||||
width: calc(100% - 32px);
|
||||
.ant-menu-submenu-title {
|
||||
padding: 0 32px 0 8px;
|
||||
.ant-menu-title-content {
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
:deep(.ant-avatar) {
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
31
feature/src/assets/ant-reset.less
Normal file
@@ -0,0 +1,31 @@
|
||||
: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-bg2: #eee;
|
||||
--color-body-bg: #fff;
|
||||
--color-menu-bg: rgba(248, 248, 248, 1);
|
||||
--color-list-hover: rgba(233, 233, 233, 1);
|
||||
--color-input-hover: #fff;
|
||||
// 边框
|
||||
--color-border-light: #f0f0f0;
|
||||
// 输入框附带icon
|
||||
--color-action-color: rgba(0, 0, 0, 0.25);;
|
||||
}
|
||||
|
||||
.dark {
|
||||
--color-text-primary: #e8e8f0;
|
||||
--color-text-content: #ccccd8;
|
||||
--color-text-desc: #8f8fa6;
|
||||
// 背景色
|
||||
--color-body-bg: #1c1c28;
|
||||
--color-body-bg2: #2c2f3b;
|
||||
--color-menu-bg: #1c1c28;
|
||||
--color-list-hover: #2c2f3b;
|
||||
--color-input-hover: #444d;
|
||||
// 边框
|
||||
--color-border-light: #444d;
|
||||
// 输入框附带icon
|
||||
--color-action-color: #ffffff4d;
|
||||
}
|
||||
40
feature/src/assets/common.less
Normal file
@@ -0,0 +1,40 @@
|
||||
.left-menu {
|
||||
width: 183px;
|
||||
// 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, .ant-menu-submenu, .ant-menu-submenu-arrow {
|
||||
color: var(--color-text-content);
|
||||
&:active {
|
||||
background: none;
|
||||
}
|
||||
}
|
||||
.ant-menu-item-selected, .ant-menu-submenu-selected {
|
||||
background-color: var(--color-list-hover);
|
||||
color: var(--ant-primary-color);
|
||||
.ant-menu-submenu-arrow {
|
||||
color: var(--ant-primary-color);
|
||||
}
|
||||
&:after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
35
feature/src/assets/constans.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
export const SPRING = {
|
||||
theme: 'SPRING',
|
||||
primaryColor: '#ff4ea4',
|
||||
errorColor: '#ed6d46',
|
||||
warningColor: '#e5a84b',
|
||||
successColor: '#c0d695',
|
||||
infoColor: '#aa8eeB',
|
||||
};
|
||||
|
||||
export const SUMMER = {
|
||||
theme: 'SUMMER',
|
||||
primaryColor: '#6078ea',
|
||||
errorColor: '#ed6d46',
|
||||
warningColor: '#e5a84b',
|
||||
successColor: '#c0d695',
|
||||
infoColor: '#aa8eeB',
|
||||
};
|
||||
|
||||
export const AUTUMN = {
|
||||
theme: 'AUTUMN',
|
||||
primaryColor: '#f55555',
|
||||
errorColor: '#ed6d46',
|
||||
warningColor: '#e5a84b',
|
||||
successColor: '#c0d695',
|
||||
infoColor: '#aa8eeB',
|
||||
};
|
||||
|
||||
export const WINTER = {
|
||||
theme: 'WINTER',
|
||||
primaryColor: '#00b294',
|
||||
errorColor: '#e94829',
|
||||
warningColor: '#ed6d3d',
|
||||
successColor: '#c3d94e',
|
||||
infoColor: '#bfa782',
|
||||
};
|
||||
BIN
feature/src/assets/delete.png
Normal file
|
After Width: | Height: | Size: 845 B |
BIN
feature/src/assets/error.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
feature/src/assets/logo.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
1
feature/src/assets/lottie/404.json
Normal file
1
feature/src/assets/lottie/empty.json
Normal file
100
feature/src/assets/request/index.ts
Normal file
@@ -0,0 +1,100 @@
|
||||
import axios from 'axios';
|
||||
|
||||
let baseURL = 'https://gitee.com/monkeyWang/rubickdatabase/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({
|
||||
timeout: 4000,
|
||||
baseURL:
|
||||
baseURL || 'https://gitee.com/monkeyWang/rubickdatabase/raw/master',
|
||||
});
|
||||
|
||||
export default {
|
||||
async getTotalPlugins() {
|
||||
let targetPath = 'plugins/total-plugins.json';
|
||||
if (access_token) {
|
||||
targetPath = `${encodeURIComponent(
|
||||
targetPath
|
||||
)}?access_token=${access_token}&ref=master`;
|
||||
}
|
||||
const res = await instance.get(targetPath);
|
||||
console.log('total plugsin', res);
|
||||
return res.data;
|
||||
},
|
||||
|
||||
async getFinderDetail() {
|
||||
let targetPath = 'plugins/finder.json';
|
||||
if (access_token) {
|
||||
targetPath = `${encodeURIComponent(
|
||||
targetPath
|
||||
)}?access_token=${access_token}&ref=master`;
|
||||
}
|
||||
const res = await instance.get(targetPath);
|
||||
return res.data;
|
||||
},
|
||||
|
||||
async getSystemDetail() {
|
||||
let targetPath = 'plugins/system.json';
|
||||
if (access_token) {
|
||||
targetPath = `${encodeURIComponent(
|
||||
targetPath
|
||||
)}?access_token=${access_token}&ref=master`;
|
||||
}
|
||||
const res = await instance.get(targetPath);
|
||||
return res.data;
|
||||
},
|
||||
async getWorkerDetail() {
|
||||
let targetPath = 'plugins/worker.json';
|
||||
if (access_token) {
|
||||
targetPath = `${encodeURIComponent(
|
||||
targetPath
|
||||
)}?access_token=${access_token}&ref=master`;
|
||||
}
|
||||
const res = await instance.get(targetPath);
|
||||
return res.data;
|
||||
},
|
||||
|
||||
async getPluginDetail(url: string) {
|
||||
const res = await instance.get(url);
|
||||
return res.data;
|
||||
},
|
||||
|
||||
async getSearchDetail() {
|
||||
let targetPath = 'plugins/search.json';
|
||||
if (access_token) {
|
||||
targetPath = `${encodeURIComponent(
|
||||
targetPath
|
||||
)}?access_token=${access_token}&ref=master`;
|
||||
}
|
||||
const res = await instance.get(targetPath);
|
||||
return res.data;
|
||||
},
|
||||
async getDevDetail() {
|
||||
let targetPath = 'plugins/dev.json';
|
||||
if (access_token) {
|
||||
targetPath = `${encodeURIComponent(
|
||||
targetPath
|
||||
)}?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
|
||||
)}?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;
|
||||
},
|
||||
};
|
||||
22
feature/src/confOp.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
const LOCAL_CONFIG_KEY = 'rubick-local-config';
|
||||
|
||||
const localConfig = {
|
||||
getConfig(): Promise<any> {
|
||||
const data: any = window.rubick.db.get(LOCAL_CONFIG_KEY) || {};
|
||||
return data.data;
|
||||
},
|
||||
|
||||
setConfig(data: any) {
|
||||
const localConfig: any = window.rubick.db.get(LOCAL_CONFIG_KEY) || {};
|
||||
window.rubick.db.put({
|
||||
_id: LOCAL_CONFIG_KEY,
|
||||
_rev: localConfig._rev,
|
||||
data: {
|
||||
...localConfig.data,
|
||||
...data,
|
||||
},
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
export default localConfig;
|
||||
16
feature/src/languages/i18n.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { createI18n } from 'vue-i18n';
|
||||
import messages from './langs';
|
||||
import localConfig from '@/confOp';
|
||||
const { perf }: any = localConfig.getConfig();
|
||||
|
||||
// 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;
|
||||
119
feature/src/languages/langs/en-US.ts
Normal file
@@ -0,0 +1,119 @@
|
||||
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: {
|
||||
must: 'Necessary',
|
||||
recommended: 'Recommended',
|
||||
lastUpdated: 'Total',
|
||||
},
|
||||
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 Setting',
|
||||
spring: 'Spring',
|
||||
summer: 'Summer',
|
||||
autumn: 'Autumn',
|
||||
winter: 'Winter',
|
||||
personalized: 'Personalized',
|
||||
greeting: 'Search Box Greeting',
|
||||
logo: 'Avatar',
|
||||
replace: 'Repalce Logo',
|
||||
reset: 'Reset Default',
|
||||
name: 'User Name',
|
||||
},
|
||||
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',
|
||||
history: 'keywords search history',
|
||||
},
|
||||
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',
|
||||
},
|
||||
localstart: {
|
||||
title: 'Local Start',
|
||||
},
|
||||
database: {
|
||||
title: 'Data Synchronization',
|
||||
},
|
||||
},
|
||||
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;
|
||||
117
feature/src/languages/langs/zh-CN.ts
Normal file
@@ -0,0 +1,117 @@
|
||||
export default {
|
||||
'zh-CN': {
|
||||
feature: {
|
||||
market: {
|
||||
title: '插件市场',
|
||||
search: '搜索插件',
|
||||
searchResult: '搜索结果',
|
||||
explore: '探索',
|
||||
efficiency: '效率',
|
||||
searchTool: '搜索工具',
|
||||
imageTool: '图像',
|
||||
developTool: '开发者',
|
||||
systemTool: '系统',
|
||||
finder: {
|
||||
must: '必备',
|
||||
recommended: '推荐',
|
||||
lastUpdated: '全部',
|
||||
},
|
||||
install: '安装',
|
||||
},
|
||||
installed: {
|
||||
title: '已安装',
|
||||
tips1: '暂无任何插件',
|
||||
tips2: '去插件市场选择安装合适的插件吧!',
|
||||
developer: '开发者',
|
||||
unknown: '未知',
|
||||
remove: '移除',
|
||||
functionKey: '功能关键字',
|
||||
detailInfo: '详情介绍',
|
||||
addToPanel: '点击+号,固定关键词到超级面板',
|
||||
removeFromPanel: '点击-号,从超级面板移除关键词',
|
||||
},
|
||||
settings: {
|
||||
title: '账户和设置',
|
||||
account: {
|
||||
accountInfo: '账户信息',
|
||||
tips1: 'rubick 用户',
|
||||
tips2: '软件偏好设置完成后需重启软件,头像和昵称请前往小程序设置',
|
||||
themeColor: '主题设置',
|
||||
spring: '立春',
|
||||
summer: '立夏',
|
||||
autumn: '立秋',
|
||||
winter: '立冬',
|
||||
personalized: '用户设置',
|
||||
greeting: '搜索框欢迎语',
|
||||
logo: '头像',
|
||||
replace: '替换',
|
||||
reset: '恢复默认设置',
|
||||
name: '用户名',
|
||||
},
|
||||
basic: {
|
||||
title: '基本设置',
|
||||
shortcutKey: '快捷键',
|
||||
showOrHiddle: '显示/隐藏快捷键',
|
||||
screenCapture: '截屏',
|
||||
common: '通用',
|
||||
autoPaste: '输入框自动粘贴',
|
||||
autoBoot: '开机启动',
|
||||
spaceExec: '空格执行',
|
||||
on: '开',
|
||||
off: '关',
|
||||
theme: '主题',
|
||||
darkMode: '暗黑模式',
|
||||
language: '语言',
|
||||
changeLang: '切换语言',
|
||||
cn: '简体中文',
|
||||
en: 'English',
|
||||
history: '关键词搜索记录',
|
||||
},
|
||||
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仓库必填',
|
||||
},
|
||||
localstart: {
|
||||
title: '本地启动',
|
||||
},
|
||||
database: {
|
||||
title: '多端数据同步',
|
||||
},
|
||||
},
|
||||
dev: {
|
||||
title: '开发者',
|
||||
tips: 'rubick 插件系统依托于 npm 管理,本地调试需要先在本地插件当前目录执行 npm link',
|
||||
pluginName: '插件名称',
|
||||
install: '安装',
|
||||
refreshPlugins: '刷新插件',
|
||||
installSuccess: '{pluginName}安装成功!',
|
||||
refreshSuccess: '{pluginName}刷新成功!',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
78
feature/src/main.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import { createApp } from 'vue';
|
||||
import Vue3Lottie from 'vue3-lottie';
|
||||
import {
|
||||
ConfigProvider,
|
||||
Button,
|
||||
Divider,
|
||||
Row,
|
||||
Col,
|
||||
Dropdown,
|
||||
Menu,
|
||||
Form,
|
||||
Input,
|
||||
Radio,
|
||||
Select,
|
||||
Switch,
|
||||
Avatar,
|
||||
Collapse,
|
||||
List,
|
||||
Tooltip,
|
||||
Alert,
|
||||
Drawer,
|
||||
Modal,
|
||||
Result,
|
||||
Spin,
|
||||
} 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';
|
||||
import localConfig from './confOp';
|
||||
|
||||
const config: any = localConfig.getConfig();
|
||||
|
||||
// 暗夜模式
|
||||
if (config.perf.common.darkMode) {
|
||||
document.body.classList.add('dark');
|
||||
window.rubick.theme = 'dark';
|
||||
}
|
||||
|
||||
ConfigProvider.config({
|
||||
theme: config.perf.custom || {},
|
||||
});
|
||||
|
||||
window.rubick.changeTheme = () => {
|
||||
const config: any = localConfig.getConfig();
|
||||
ConfigProvider.config({
|
||||
theme: config.perf.custom || {},
|
||||
});
|
||||
};
|
||||
|
||||
createApp(App)
|
||||
.use(registerI18n)
|
||||
.use(store)
|
||||
.use(Button)
|
||||
.use(Divider)
|
||||
.use(Row)
|
||||
.use(Col)
|
||||
.use(Dropdown)
|
||||
.use(Menu)
|
||||
.use(Form)
|
||||
.use(Input)
|
||||
.use(Radio)
|
||||
.use(Select)
|
||||
.use(Switch)
|
||||
.use(Avatar)
|
||||
.use(Collapse)
|
||||
.use(List)
|
||||
.use(Tooltip)
|
||||
.use(Alert)
|
||||
.use(Drawer)
|
||||
.use(Modal)
|
||||
.use(Result)
|
||||
.use(Spin)
|
||||
.use(router)
|
||||
.use(Vue3Lottie)
|
||||
.mount('#app');
|
||||
71
feature/src/router/index.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router';
|
||||
|
||||
const routes: Array<RouteRecordRaw> = [
|
||||
{
|
||||
path: '/result',
|
||||
name: 'result',
|
||||
component: () => import('../views/market/components/result.vue'),
|
||||
},
|
||||
{
|
||||
path: '/devPlugin',
|
||||
name: 'devPlugin',
|
||||
component: () => import('../views/market/components/devlopment.vue'),
|
||||
},
|
||||
{
|
||||
path: '/image',
|
||||
name: 'image',
|
||||
component: () => import('../views/market/components/image.vue'),
|
||||
},
|
||||
{
|
||||
path: '/tools',
|
||||
name: 'tools',
|
||||
component: () => import('../views/market/components/tools.vue'),
|
||||
},
|
||||
{
|
||||
path: '/worker',
|
||||
name: 'worker',
|
||||
component: () => import('../views/market/components/worker.vue'),
|
||||
},
|
||||
{
|
||||
path: '/system',
|
||||
name: 'system',
|
||||
component: () => import('../views/market/components/system.vue'),
|
||||
},
|
||||
{
|
||||
path: '/finder',
|
||||
name: 'finder',
|
||||
component: () => import('../views/market/components/finder.vue'),
|
||||
},
|
||||
{
|
||||
path: '/installed',
|
||||
name: 'installed',
|
||||
component: () => import('../views/installed/index.vue'),
|
||||
},
|
||||
{
|
||||
path: '/account',
|
||||
name: 'account',
|
||||
component: () => import('../views/account/index.vue'),
|
||||
},
|
||||
{
|
||||
path: '/settings',
|
||||
name: 'settings',
|
||||
component: () => import('../views/settings/user.vue'),
|
||||
},
|
||||
{
|
||||
path: '/dev',
|
||||
name: 'dev',
|
||||
component: () => import('../views/dev/index.vue'),
|
||||
},
|
||||
{
|
||||
path: '/:catchAll(.*)',
|
||||
name: 'finder',
|
||||
component: () => import('../views/market/components/finder.vue'),
|
||||
},
|
||||
];
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHashHistory(),
|
||||
routes,
|
||||
});
|
||||
|
||||
export default router;
|
||||
21
feature/src/shims-vue.d.ts
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
/* eslint-disable */
|
||||
declare module '*.vue' {
|
||||
import type { DefineComponent } from 'vue'
|
||||
const component: DefineComponent<{}, {}, any>
|
||||
export default component
|
||||
}
|
||||
|
||||
declare module 'axios'
|
||||
|
||||
interface Window {
|
||||
rubick: any;
|
||||
market: any
|
||||
}
|
||||
|
||||
namespace Market {
|
||||
interface Plugin {
|
||||
isdownload?: boolean;
|
||||
name?: string;
|
||||
isloading: boolean
|
||||
}
|
||||
}
|
||||
121
feature/src/store/index.ts
Normal file
@@ -0,0 +1,121 @@
|
||||
import { createStore } from 'vuex';
|
||||
import request from '@/assets/request';
|
||||
|
||||
const isDownload = (item: Market.Plugin, targets: any[]) => {
|
||||
let isDownload = false;
|
||||
targets.some((plugin) => {
|
||||
if (plugin.name === item.name) {
|
||||
isDownload = true;
|
||||
}
|
||||
return isDownload;
|
||||
});
|
||||
return isDownload;
|
||||
};
|
||||
|
||||
export default createStore({
|
||||
state: {
|
||||
totalPlugins: [],
|
||||
localPlugins: [],
|
||||
searchValue: '',
|
||||
active: ['finder'],
|
||||
},
|
||||
mutations: {
|
||||
commonUpdate(state: any, payload) {
|
||||
Object.keys(payload).forEach((key) => {
|
||||
state[key] = payload[key];
|
||||
});
|
||||
},
|
||||
setSearchValue(state: any, payload) {
|
||||
state.searchValue = payload;
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
async init({ commit }) {
|
||||
const totalPlugins = await request.getTotalPlugins();
|
||||
const localPlugins = window.market.getLocalPlugins();
|
||||
|
||||
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: Market.Plugin) => {
|
||||
if (origin.name === name) {
|
||||
origin.isloading = true;
|
||||
}
|
||||
});
|
||||
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: Market.Plugin) => {
|
||||
if (origin.name === name) {
|
||||
origin.isloading = false;
|
||||
origin.isdownload = true;
|
||||
}
|
||||
});
|
||||
const localPlugins = window.market.getLocalPlugins();
|
||||
|
||||
commit('commonUpdate', {
|
||||
totalPlugins,
|
||||
localPlugins,
|
||||
});
|
||||
},
|
||||
|
||||
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,
|
||||
});
|
||||
},
|
||||
},
|
||||
modules: {},
|
||||
});
|
||||
85
feature/src/views/account/index.vue
Normal file
@@ -0,0 +1,85 @@
|
||||
<template>
|
||||
<div class="account">
|
||||
<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 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" 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>
|
||||
110
feature/src/views/dev/index.vue
Normal file
@@ -0,0 +1,110 @@
|
||||
<template>
|
||||
<div class="dev">
|
||||
<div class="view-title">{{ $t('feature.dev.title') }}</div>
|
||||
<div class="view-container">
|
||||
<a-alert
|
||||
style="margin-bottom: 40px"
|
||||
:message="$t('feature.dev.tips')"
|
||||
type="warning"
|
||||
/>
|
||||
<a-form
|
||||
ref="formRef"
|
||||
:model="formState"
|
||||
:rules="rules"
|
||||
:label-col="labelCol"
|
||||
:wrapper-col="wrapperCol"
|
||||
>
|
||||
<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">
|
||||
{{ $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>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
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({
|
||||
name: undefined,
|
||||
});
|
||||
const rules = {
|
||||
name: {
|
||||
required: true,
|
||||
message: 'Please input name',
|
||||
},
|
||||
};
|
||||
const onSubmit = () => {
|
||||
formRef.value.validate().then(() => {
|
||||
downloadPlugin(formState.name);
|
||||
});
|
||||
};
|
||||
|
||||
const loading = ref(false);
|
||||
const downloadPlugin = async (pluginName) => {
|
||||
loading.value = true;
|
||||
await window.market.downloadPlugin({
|
||||
name: pluginName,
|
||||
isDev: true,
|
||||
});
|
||||
message.success(t('feature.dev.installSuccess', { pluginName: pluginName }));
|
||||
loading.value = false;
|
||||
};
|
||||
|
||||
const refresh = () => {
|
||||
formRef.value.validate().then(() => {
|
||||
window.market.refreshPlugin({
|
||||
name: formState.name,
|
||||
});
|
||||
message.success(
|
||||
t('feature.dev.refreshSuccess', { pluginName: formState.name })
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
const labelCol = { span: 4 };
|
||||
const wrapperCol = { span: 14 };
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.dev {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
overflow-x: hidden;
|
||||
height: calc(~'100vh - 34px');
|
||||
.view-title {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
margin-bottom: 16px;
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
.view-container {
|
||||
padding: 10px;
|
||||
box-sizing: border-box;
|
||||
border-radius: 8px;
|
||||
background: var(--color-body-bg);
|
||||
overflow: auto;
|
||||
height: calc(~'100vh - 84px');
|
||||
}
|
||||
:deep(label) {
|
||||
color: var(--color-text-content);
|
||||
}
|
||||
:deep(.ant-input) {
|
||||
background: var(--color-input-hover) !important;
|
||||
color: var(--color-text-content);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
397
feature/src/views/installed/index.vue
Normal file
@@ -0,0 +1,397 @@
|
||||
<template>
|
||||
<div class="installed">
|
||||
<div class="view-title">{{ $t('feature.installed.title') }}</div>
|
||||
<div class="view-container">
|
||||
<div v-if="!localPlugins.length">
|
||||
<a-result
|
||||
class="error-content"
|
||||
sub-title="哎呀,暂时还没有安装任何插件!"
|
||||
>
|
||||
<template #icon>
|
||||
<Vue3Lottie :animationData="emptyJson" :height="240" :width="240" />
|
||||
</template>
|
||||
<template #extra>
|
||||
<a-button @click="gotoFinder" key="console" type="primary">去插件市场看看吧</a-button>
|
||||
</template>
|
||||
</a-result>
|
||||
</div>
|
||||
<div class="container" v-else>
|
||||
<div class="installed-list">
|
||||
<div
|
||||
:class="currentSelect[0] === plugin.name ? 'item active' : 'item'"
|
||||
:key="index"
|
||||
@click="currentSelect = [plugin.name]"
|
||||
v-for="(plugin, index) in localPlugins"
|
||||
>
|
||||
<img :src="plugin.logo" />
|
||||
<div class="info">
|
||||
<div class="title">
|
||||
{{ plugin.pluginName }}
|
||||
</div>
|
||||
<div class="desc">{{ plugin.description }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="plugin-detail">
|
||||
<div class="plugin-top">
|
||||
<div class="left">
|
||||
<div class="title">
|
||||
{{ pluginDetail.pluginName }}
|
||||
<a-tag>{{ pluginDetail.version }}</a-tag>
|
||||
</div>
|
||||
<div class="desc">
|
||||
{{ $t('feature.installed.developer') }}:{{
|
||||
`${pluginDetail.author || $t('feature.installed.unknown')}`
|
||||
}}
|
||||
</div>
|
||||
<div class="desc">
|
||||
{{ pluginDetail.description }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<a-button
|
||||
type="primary"
|
||||
size="small"
|
||||
shape="round"
|
||||
:loading="pluginDetail.isloading"
|
||||
@click="deletePlugin(pluginDetail)"
|
||||
>
|
||||
{{ $t('feature.installed.remove') }}
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="feature-container">
|
||||
<template
|
||||
:key="index"
|
||||
v-for="(item, index) in pluginDetail.features"
|
||||
>
|
||||
<div
|
||||
class="desc-item"
|
||||
v-if="item.cmds.filter(cmd => !cmd.label).length > 0"
|
||||
>
|
||||
<div>{{ item.explain }}</div>
|
||||
<template :key="cmd" v-for="cmd in item.cmds">
|
||||
<a-dropdown
|
||||
v-if="!cmd.label"
|
||||
:class="{ executable: !cmd.label }"
|
||||
>
|
||||
<template #overlay>
|
||||
<a-menu @click="({key}) => handleMenuClick(key, item, cmd)">
|
||||
<a-menu-item key="open">
|
||||
<CaretRightOutlined />
|
||||
运行
|
||||
</a-menu-item>
|
||||
<a-menu-item v-if="!hasAdded(cmd)" key="add">
|
||||
<PushpinOutlined />
|
||||
固定到超级面板
|
||||
</a-menu-item>
|
||||
<a-menu-item v-else key="remove">
|
||||
<PushpinFilled />
|
||||
从超级面板中取消固定
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
<a-button size="small" class="keyword-tag">
|
||||
{{ cmd.label || cmd }}
|
||||
<DownOutlined />
|
||||
</a-button>
|
||||
</a-dropdown>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useStore } from 'vuex';
|
||||
import { computed, ref, toRaw, watch } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import path from 'path';
|
||||
import {
|
||||
PushpinOutlined,
|
||||
PushpinFilled,
|
||||
CaretRightOutlined,
|
||||
DownOutlined,
|
||||
} from '@ant-design/icons-vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
|
||||
import emptyJson from '@/assets/lottie/empty.json';
|
||||
|
||||
const { ipcRenderer } = window.require('electron');
|
||||
|
||||
const remote = window.require('@electron/remote');
|
||||
const fs = window.require('fs');
|
||||
|
||||
const appPath = remote.app.getPath('userData');
|
||||
const baseDir = path.join(appPath, './rubick-plugins');
|
||||
|
||||
const store = useStore();
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
|
||||
const localPlugins = computed(() =>
|
||||
store.state.localPlugins.filter(
|
||||
(plugin) => plugin.name !== 'rubick-system-feature'
|
||||
)
|
||||
);
|
||||
const updateLocalPlugin = () => store.dispatch('updateLocalPlugin');
|
||||
const startUnDownload = (name) => store.dispatch('startUnDownload', name);
|
||||
const errorUnDownload = (name) => store.dispatch('errorUnDownload', name);
|
||||
|
||||
const currentSelect = ref([route.query.plugin || localPlugins?.value[0]?.name]);
|
||||
|
||||
watch(localPlugins, () => {
|
||||
currentSelect.value = [localPlugins?.value[0]?.name];
|
||||
});
|
||||
|
||||
const pluginDetail = computed(() => {
|
||||
return (
|
||||
localPlugins.value.find((v) => v.name === currentSelect.value[0]) || {}
|
||||
);
|
||||
});
|
||||
|
||||
const superPanelPlugins = ref(
|
||||
window.rubick.db.get('super-panel-user-plugins') || {
|
||||
data: [],
|
||||
_id: 'super-panel-user-plugins',
|
||||
}
|
||||
);
|
||||
|
||||
const handleMenuClick = (key, item, cmd) => {
|
||||
if(key === 'open') {
|
||||
openPlugin({
|
||||
code: item.code,
|
||||
cmd,
|
||||
});
|
||||
} else if (key === 'add') {
|
||||
addCmdToSuperPanel({cmd, code: item.code});
|
||||
} else {
|
||||
removePluginToSuperPanel({cmd, name: item.name})
|
||||
}
|
||||
};
|
||||
|
||||
const addCmdToSuperPanel = ({ cmd, code }) => {
|
||||
const plugin = {
|
||||
...toRaw(pluginDetail.value),
|
||||
cmd,
|
||||
ext: {
|
||||
code,
|
||||
type: 'text',
|
||||
payload: null,
|
||||
},
|
||||
};
|
||||
superPanelPlugins.value.data.push(plugin);
|
||||
const { rev } = window.rubick.db.put(JSON.parse(JSON.stringify(superPanelPlugins.value)));
|
||||
superPanelPlugins.value._rev = rev;
|
||||
};
|
||||
|
||||
const removePluginToSuperPanel = ({ cmd, name }) => {
|
||||
superPanelPlugins.value.data = toRaw(superPanelPlugins.value).data.filter(
|
||||
(item) => {
|
||||
if (name) return item.name !== name;
|
||||
return item.cmd !== cmd;
|
||||
}
|
||||
);
|
||||
const { rev } = window.rubick.db.put(toRaw(superPanelPlugins.value));
|
||||
superPanelPlugins.value._rev = rev;
|
||||
};
|
||||
|
||||
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 deletePlugin = async (plugin) => {
|
||||
startUnDownload(plugin.name);
|
||||
const timer = setTimeout(() => {
|
||||
errorUnDownload(plugin.name);
|
||||
message.error('卸载超时,请重试!');
|
||||
}, 20000);
|
||||
await window.market.deletePlugin(plugin);
|
||||
removePluginToSuperPanel({ name: plugin.name });
|
||||
updateLocalPlugin();
|
||||
clearTimeout(timer);
|
||||
};
|
||||
|
||||
const gotoFinder = () => {
|
||||
router.push('/finder');
|
||||
store.commit('commonUpdate', { active: ['finder'] });
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.installed {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
height: calc(~'100vh - 34px');
|
||||
.view-title {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
margin-bottom: 16px;
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
.view-container {
|
||||
border-radius: 8px;
|
||||
background: var(--color-body-bg);
|
||||
overflow: auto;
|
||||
height: calc(~'100vh - 84px');
|
||||
}
|
||||
:deep(.ant-result-title) {
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
:deep(.ant-result-subtitle) {
|
||||
color: var(--color-text-desc);
|
||||
}
|
||||
.keyword-tag {
|
||||
font-size: 13px;
|
||||
margin: 4px;
|
||||
}
|
||||
|
||||
.container {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
background: #f3efef;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.installed-list {
|
||||
width: 38%;
|
||||
background: var(--color-body-bg);
|
||||
height: 100%;
|
||||
padding: 10px 0;
|
||||
border-right: 1px solid var(--color-border-light);
|
||||
overflow: auto;
|
||||
|
||||
.item {
|
||||
padding: 10px 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: var(--color-text-content);
|
||||
border-bottom: 1px dashed var(--color-border-light);
|
||||
cursor: pointer;
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
img {
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
.desc {
|
||||
font-size: 12px;
|
||||
color: var(--color-text-desc);
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
-webkit-line-clamp: 2;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
&.active {
|
||||
color: var(--ant-primary-color);
|
||||
background: var(--color-list-hover);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.plugin-detail {
|
||||
padding: 20px 20px 0 20px;
|
||||
box-sizing: border-box;
|
||||
width: 62%;
|
||||
height: 100%;
|
||||
background: var(--color-body-bg);
|
||||
.plugin-top {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
border-bottom: 1px solid #eee;
|
||||
padding-bottom: 12px;
|
||||
margin-bottom: 12px;
|
||||
.title {
|
||||
font-size: 16px;
|
||||
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: var(--color-text-desc);
|
||||
}
|
||||
}
|
||||
|
||||
.detail-container,
|
||||
.feature-container {
|
||||
height: 380px;
|
||||
overflow: auto;
|
||||
color: var(--color-text-content);
|
||||
img {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.desc-item {
|
||||
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: var(--color-text-desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
48
feature/src/views/market/components/devlopment.vue
Normal file
@@ -0,0 +1,48 @@
|
||||
<template>
|
||||
<div class="system">
|
||||
<PluginList
|
||||
v-if="dev && !!dev.length"
|
||||
@downloadSuccess="downloadSuccess"
|
||||
: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 { useStore } from 'vuex';
|
||||
const store = useStore();
|
||||
const totalPlugins = computed(() => store.state.totalPlugins);
|
||||
|
||||
const data = ref([]);
|
||||
|
||||
onBeforeMount(async () => {
|
||||
data.value = await request.getDevDetail();
|
||||
});
|
||||
|
||||
const dev = 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 lang="less">
|
||||
.system {
|
||||
width: 100%;
|
||||
overflow-x: hidden;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
</style>
|
||||