Compare commits

...

190 Commits

Author SHA1 Message Date
muwoo
62bcc345da 🐛 修复插件安装镜像地址问题:https://zhuanlan.zhihu.com/p/432578145 2023-08-18 14:42:55 +08:00
muwoo
637c1238ae 🐛 修复图片cdn加载问题 2023-08-18 10:43:46 +08:00
muwoo
2008b62a45 支持新API:getCopyFiles simulateKeyboardTap 2023-08-16 17:57:25 +08:00
木偶
c2a23f0c6c Merge pull request #217 from 1129921824/master
实现简易的搜索功能
2023-08-11 10:28:43 +08:00
sunyuqiang
4e266d4d92 Merge branch 'master' of https://github.com/rubickCenter/rubick 2023-08-10 22:09:28 +08:00
sunyuqiang
5857af30b9 实现简易的搜索功能 2023-08-10 22:09:04 +08:00
muwoo
4ef93e8f6d 🐛 2023-08-08 10:52:11 +08:00
璃白
113cd3dfbc Merge pull request #214 from 1129921824/master
特性-市场插件的国际化支持
2023-08-06 00:40:24 +08:00
sunyuqiang
84d15cd20f Merge branch 'master' into master 2023-08-03 10:21:40 +08:00
muwoo
a2f0908d38 📝 更新文档 2023-08-02 16:07:20 +08:00
muwoo
a5fb7f05a5 ⬇️ 更新文档 2023-08-02 16:03:20 +08:00
muwoo
e3b10d53e2 增加新手引导
git push
2023-08-02 14:03:07 +08:00
muwoo
6cbd5fe15b 增加新手引导 2023-08-02 14:02:30 +08:00
sunyuqiang
06d2d9bfbc Merge branch 'master' of https://github.com/rubickCenter/rubick 2023-08-01 18:24:24 +08:00
sunyuqiang
e9f45cf3af 主界面语言选择 2023-08-01 17:54:29 +08:00
muwoo
2cdfcbbbae 🚑 修复颜色问题导致的下载按钮不可点击 2023-08-01 16:39:51 +08:00
muwoo
eef24dbb76 🐛 fix #210 2023-08-01 14:58:42 +08:00
sunyuqiang
1080f6e960 语言固化 2023-08-01 14:16:58 +08:00
sunyuqiang
6339228c47 Merge branch 'master' of https://github.com/rubickCenter/rubick
# Conflicts:
#	feature/src/App.vue
#	feature/src/views/market/index.vue
#	feature/src/views/settings/index.vue
2023-08-01 14:10:25 +08:00
sunyuqiang
36afdae707 lock文件 2023-08-01 14:06:51 +08:00
sunyuqiang
a2f9e1d01c 特性-市场插件的国际化支持 2023-08-01 14:01:19 +08:00
muwoo
7a96bf395a 💄 detach 窗口样式修复 2023-08-01 12:14:52 +08:00
muwoo
676c2b9c6a 🐛 fix #212 2023-08-01 11:41:43 +08:00
muwoo
6516042809 🐛 修复 #212 2023-08-01 11:41:18 +08:00
muwoo
f72ae23691 🐛 fix #212 2023-07-31 18:09:33 +08:00
muwoo
5946e06693 🐛 fix #212 2023-07-31 17:45:22 +08:00
muwoo
cc6098258c Merge branch 'master' of github.com:rubickCenter/rubick 2023-07-19 09:44:07 +08:00
muwoo
47bada5c01 增加用户体系 2023-07-19 09:43:48 +08:00
木偶
e236ee15b2 Merge pull request #199 from du00cs/du00cs-patch-1
Update README.md
2023-07-03 10:26:26 +08:00
Ninglin Du
6dcec6cede Update README.md 2023-07-02 01:58:58 +08:00
muwoo
ca6629988a 💚 修复 ci 构建问题
git push
2023-06-26 15:07:29 +08:00
muwoo
40c92dbd99 💚 修复macos electron-builder 构建问题:https://github.com/nklayman/vue-cli-plugin-electron-builder/issues/1701 2023-06-26 14:44:48 +08:00
muwoo
a827438dbe 🐛 fix #185 2023-06-26 10:18:06 +08:00
layyback
e2ea081d25 init mac codesign 2023-06-25 14:21:18 +08:00
璃白
46eeb8d320 Merge pull request #195 from rubickCenter/feature/update
🔨 resolve packages
2023-06-24 23:26:45 +08:00
layyback
16e8d90141 🔨 resolve packages 2023-06-24 23:26:01 +08:00
璃白
867a7b1fec Merge pull request #194 from rubickCenter/feature/update
 add windows auto-update feature
2023-06-24 23:03:39 +08:00
layyback
d7d7e1423e 📝 add release notes 2023-06-24 23:01:56 +08:00
layyback
1fc3d00f9c 📝 add release notes 2023-06-24 22:57:38 +08:00
layyback
6ea706127d add windows auto-update feature 2023-06-24 22:49:22 +08:00
木偶
53ec3a8bb2 Merge pull request #193 from 1129921824/master
优化-全局快捷键优化及提示信息更正错别字
2023-06-24 15:04:13 +08:00
sunyuqiang
7802d359c4 优化-全局快捷键优化及提示信息更正错别字 2023-06-24 11:35:03 +08:00
muwoo
2eff73f581 🐛 主程序支持 type: over 类型 2023-06-21 16:10:49 +08:00
木偶
a7926aff60 Merge pull request #192 from 1129921824/master
优化-快捷键支持三键
2023-06-21 11:29:47 +08:00
sunyuqiang
1dfb39c2e7 优化-快捷键支持三键 2023-06-20 18:30:59 +08:00
木偶
5d7e2e97c2 Merge pull request #190 from 1129921824/master
本地启动固定端口
2023-06-20 09:59:10 +08:00
sunyuqiang
b6b1c2eb08 本地启动固定端口 2023-06-16 15:25:14 +08:00
layyback
e52d3bbbc9 🏁 fix #180 2023-05-30 19:07:13 +08:00
muwoo
de7fee6a23 feat: 增加 getFileIcon api 2023-05-26 09:43:06 +08:00
木偶
971ad0e3e2 Update package.json 2023-05-15 09:51:17 +08:00
木偶
a1296953e9 ♻️ 修复插件呼起状态通过超级面板再次呼起的bug 2023-05-15 09:50:36 +08:00
木偶
e8d69214b7 ♻️ 系统插件钩子函数传入 api 参数 2023-05-15 09:47:33 +08:00
muwoo
668a470276 🐛 修复插件窗口打开尺寸偏小的bug 2023-04-21 13:52:00 +08:00
muwoo
9f81854139 🐛 fix [#179] 2023-04-18 10:51:38 +08:00
muwoo
296e3a164a 🔖 v2.2.2 2023-04-11 11:34:19 +08:00
muwoo
6e30f330d3 Merge branch 'feat/v2.2.1' 2023-04-11 11:33:03 +08:00
muwoo
d64eed6f7f 截图功能优化 2023-04-10 14:30:51 +08:00
layyback
794235c72d 🔨 设置页适配暗黑 2023-04-08 20:30:01 +08:00
layyback
edbc4d0749 🔨 优化mac拖拽 2023-04-08 20:13:48 +08:00
muwoo
2cd70bd386 :spark: 支持系统截屏功能 2023-04-04 11:13:38 +08:00
muwoo
9ee8d78b1b 支持拼音首字母检索 #174 2023-04-03 09:55:00 +08:00
璃白
6f02359727 Merge pull request #176 from rubickCenter/feature/drag
Feature/drag
2023-04-01 23:10:50 +08:00
layyback
529f46dafe windows适配拖拽 2023-04-01 23:09:54 +08:00
layyback
5eb07118b0 🔨 适配windows 125%下窗口异常 2023-04-01 23:08:50 +08:00
璃白
215b4895fb Merge pull request #175 from rubickCenter/feature/drag
Feature/drag
2023-04-01 22:45:01 +08:00
layyback
cffbbaf0dc 优化窗口拖拽 2023-04-01 22:42:35 +08:00
layyback
b42bc6461d 🔨 优化拖拽方案 2023-04-01 16:59:48 +08:00
muwoo
1fa0b9fb9c 🐛 修复package.json 报错
git push
2023-04-01 10:43:36 +08:00
muwoo
35c9a32604 支持图像分类插件查看 2023-04-01 10:26:17 +08:00
muwoo
a8006ec199 💚 修复win 构建问题 2023-03-28 14:22:41 +08:00
muwoo
283542df21 💚 修复构建问题 2023-03-28 11:35:37 +08:00
muwoo
2341d75533 支持插件自动更新 2023-03-28 10:41:01 +08:00
muwoo
57781e7b5a :spark: 支持插件自动更新 2023-03-28 10:26:33 +08:00
muwoo
bfbbf3463e 📝 更新 CI 状态徽章 2023-03-27 09:47:24 +08:00
layyback
9c47c4e6a6 add dark mode 2023-03-26 23:01:40 +08:00
layyback
d5a532218a add dark mode 2023-03-26 22:37:35 +08:00
layyback
39f511e548 add dark mode 2023-03-26 22:35:32 +08:00
layyback
adf3e8807e add dark mode 2023-03-26 22:20:05 +08:00
璃白
afbe7dc385 Merge pull request #173 from rubickCenter/feature/darkmode
 add dark mode
2023-03-26 19:49:51 +08:00
layyback
1f391c7cb5 add dark mode 2023-03-26 19:49:04 +08:00
layyback
12a1961405 🔨 resolve conflicts 2023-03-26 19:46:46 +08:00
layyback
4115051bad 🎨 fit reset pages 2023-03-26 19:37:25 +08:00
layyback
e156642684 🎨 fit dev page style 2023-03-26 19:36:58 +08:00
layyback
47eacb86cb 🎨 fit installed page style 2023-03-26 19:36:22 +08:00
layyback
f766ea3bde 🎨 fit market style 2023-03-26 19:35:47 +08:00
layyback
9e2b6f52a4 init dark mode 2023-03-26 19:35:07 +08:00
layyback
958e20fef9 🎨 fit result style 2023-03-26 19:34:18 +08:00
layyback
77d3d00f7a 🎨 fit search input style 2023-03-26 19:33:50 +08:00
layyback
3fded762df 🎨 fit menu style 2023-03-26 19:33:13 +08:00
layyback
19d98ec07c :feature: add css variable 2023-03-26 19:30:49 +08:00
layyback
1736037411 🔨 减少设置防抖时间 2023-03-26 19:29:08 +08:00
muwoo
e6af7f30ee 修复插件缓存更新问题 2023-03-22 15:52:03 +08:00
muwoo
433e7c9850 :feature: 日常更新 2023-03-22 11:19:39 +08:00
muwoo
dc74251bd0 🚨 增加 prettier 2023-03-16 14:45:53 +08:00
muwoo
4f58bfdc4f 💚 修复github actions 构建问题 2023-03-14 16:17:19 +08:00
muwoo
a407f84981 💚 修复github actions 构建问题 2023-03-14 15:59:03 +08:00
muwoo
c16f703cef 💚 修复github actions 构建问题 2023-03-14 15:50:36 +08:00
muwoo
9b02915e44 💚 修复github actions 构建问题 2023-03-14 12:09:36 +08:00
muwoo
ce46d0b37f 💚 修复github actions 构建问题 2023-03-14 12:02:23 +08:00
muwoo
7909475ed3 🐛 修复超级面板问题#170,修复#123 2023-03-14 11:53:50 +08:00
璃白
5a038031e7 Merge pull request #167 from rubickCenter/feature/settings
Feature/settings
2023-03-11 10:35:38 +08:00
layyback
7f4203aeb1 open settings with tray 2023-03-11 10:32:26 +08:00
layyback
36b1fd5588 open settings with tray 2023-03-11 10:31:18 +08:00
璃白
f69bc59130 Merge pull request #163 from rubickCenter/feature/esc
 toggle visibility with hotkey
2023-03-10 16:10:02 +08:00
layyback
391c9f2952 toggle visibility with hotkey 2023-03-10 16:02:13 +08:00
璃白
3846489611 Merge pull request #161 from rubickCenter/feature/esc
:spakles: close with esc
2023-03-10 15:56:15 +08:00
layyback
ac1b202f44 :spakles: close with esc 2023-03-10 15:55:00 +08:00
璃白
9f21823792 Merge pull request #160 from rubickCenter/fix/apiclass
🐛 fix apiclass & add some feature
2023-03-10 15:15:06 +08:00
layyback
6b0f00f71a 🐛 fix apiclass & add some feature 2023-03-10 15:13:20 +08:00
木偶
5d0aca0e4a Merge pull request #142 from AdamCaoQAQ/master
bugfix: 修复mac环境下因对extract-file-icon的错误依赖导致的构建报错
2022-10-20 17:31:01 +08:00
木偶
6608f02467 Merge pull request #141 from knoxnoe/dev
chore: API改为类,成员函数变量增加static关键字 & yarn lint
2022-10-14 11:48:05 +08:00
AdamCaoQAQ
1cdd50d62d bugfix: 修复mac环境下因对extract-file-icon的错误依赖导致的构建报错 2022-10-12 11:54:39 +08:00
noe
cfc10a6aee chore: API改为类,成员函数变量增加static关键字 & yarn lint 2022-09-24 11:44:04 +08:00
木偶
17436b0e9a Merge pull request #118 from zqhong/patch-1
updated:更新中文 README.md,添加支持 Linux 的说明
2022-08-15 09:17:47 +08:00
zqhong
68cfa14100 updated:更新中文 README.md,添加支持 Linux 的说明 2022-08-14 22:46:09 +08:00
木偶
d3cbae7223 Update package.json 2022-08-08 18:01:42 +08:00
muwoo
f33941446d Merge remote-tracking branch 'origin/master' 2022-08-08 17:04:51 +08:00
muwoo
976075d1c6 🚑 修复 [#107] 2022-08-08 17:04:30 +08:00
muwoo
5b6995febe 🚑 修复 [#107] 2022-08-08 17:04:10 +08:00
muwoo
8acaff15f2 fix: #91 修复win下 ctrl+d 热键冲突问题 2022-06-29 16:55:22 +08:00
Layyback
b43c2c0091 🚑 reset the default database path 2022-06-01 00:25:45 +08:00
璃白
900a568ddf Merge pull request #110 from rubickCenter/feature/cherry-pick
🔨 cherry pick
2022-05-29 14:21:02 +08:00
layyback
8d3d55bdd8 🔨 cherry pick 2022-05-29 14:14:24 +08:00
muwoo
310dba0aa3 支持新的api 2022-05-09 11:21:03 +08:00
muwoo
343079d24f 支持新的api 2022-05-09 11:04:23 +08:00
layyback
c49b55992c 🐛 fix style 2022-04-15 11:46:07 +08:00
layyback
d562d88768 🐛 fix style 2022-04-15 11:36:07 +08:00
璃白
554b208f80 Merge pull request #102 from rubickCenter/feature/delkey
Feature/delkey
2022-04-15 11:17:23 +08:00
layyback
ef563717a3 add remove hotkey button 2022-04-15 11:15:26 +08:00
layyback
173a3a93ba add remove hotkey button 2022-04-15 11:00:20 +08:00
木偶
cdc4fa3a09 更新版本
社区维护了一些内容,更新一个beta版
2022-04-06 10:34:50 +08:00
layyback
a2d7c9b9c4 🔧 run the pages-build-deployment 2022-04-03 14:04:17 +08:00
璃白
915288499e Merge pull request #100 from rubickCenter/feature/space
🚀 run plugins with the space key
2022-04-03 13:38:40 +08:00
layyback
e1ccbb69a5 🚀 run plugins with the space key 2022-04-03 13:36:39 +08:00
layyback
9613c24deb 🚀 run plugins with the space key 2022-04-03 13:30:27 +08:00
木偶
91b075a439 Update README.md 2022-04-02 16:58:03 +08:00
木偶
6cecfbf77d Update package.json 2022-04-02 16:54:33 +08:00
木偶
aada416790 Update package.json
update img
2022-04-02 16:53:28 +08:00
璃白
65932ca22a Merge pull request #98 from rubickCenter/feature/hotkey-tips
🚀 添加快捷键修改提示
2022-04-02 10:57:10 +08:00
layyback
419dc21618 🚀 添加快捷键修改提示 2022-04-02 10:54:57 +08:00
木偶
313142e6f0 Merge pull request #97 from layyback/fix/hotkey
fix:修复ctrl等热键修改不生效的问题
2022-03-24 20:31:14 +08:00
木偶
039b69f4be Merge pull request #96 from layyback/master
fix:修复Tray菜单唤起热键不更新的问题
2022-03-23 21:43:23 +08:00
layyback
e0d0de4baf 🐛 fix:修复ctrl等热键修改不生效的问题 2022-03-23 11:11:35 +08:00
layyback
4d621c7521 🐛 fix:修复Tray菜单唤起热键不更新的问题 2022-03-22 14:53:46 +08:00
木偶
cd4036a805 Merge pull request #95 from layyback/feature/style
feat:提取公共样式
2022-03-21 22:50:39 +08:00
木偶
3e3c198a7f Merge pull request #94 from layyback/master
feat:Declare the interface of plugin in the market
2022-03-21 22:49:00 +08:00
layyback
02dcc34a4b feat:提取公共样式 2022-03-21 22:43:05 +08:00
layyback
ba0ccbb8ff feat:声明插件接口类型,剔除冗余代码 2022-03-21 22:22:12 +08:00
木偶
56b6ca9e89 Merge pull request #93 from layyback/master
fix:typo
2022-03-21 19:17:55 +08:00
layyback
9869d9fecf fix:typo 2022-03-21 16:13:53 +08:00
muwoo
1e4757f70d Merge remote-tracking branch 'origin/master' 2022-02-18 11:43:45 +08:00
muwoo
6adf25dbee 🐛 修复 allDocs 问题,新增 shellShowItemInFolder API 2022-02-18 11:43:30 +08:00
木偶
7fbb12d04b Merge pull request #90 from renmu123/master
fix typo
2022-02-17 19:29:00 +08:00
renmu123
ded16b9580 fix typo 2022-02-17 16:07:07 +08:00
Starry North
d379c58082 Merge pull request #87 from gclm/dev-gclm-85
feat: 新增mac打包为dmg
feat: 给rubick 配置一个专门的应用目录
2022-02-12 13:55:40 +08:00
gclm
8a536374ea feat: 给rubick 配置一个专门的应用目录 2022-02-11 15:15:40 +08:00
gclm
bcfc968c9d feat: 新增mac打包为dmg 2022-02-11 14:41:47 +08:00
木偶
4bf3f3a602 Update README.md 2022-01-24 15:26:00 +08:00
muwoo
497de040cf suport linux 2022-01-24 14:57:13 +08:00
muwoo
a22a78fa0a suport linux 2022-01-24 14:42:49 +08:00
muwoo
d2894c66ba suport linux 2022-01-24 14:24:52 +08:00
muwoo
ff7473deb2 suport linux 2022-01-24 14:16:01 +08:00
muwoo
842a44a6d1 suport linux 2022-01-24 13:40:24 +08:00
muwoo
751c73b3a6 ♻️ 优化插件中心功能 2022-01-17 20:32:08 +08:00
muwoo
240175c571 🐛 修复系统插件无法打开ui界面问题 2022-01-17 16:00:23 +08:00
muwoo
8107d74537 👷 构建问题 2022-01-14 10:21:58 +08:00
muwoo
861950145f Merge remote-tracking branch 'origin/master' 2022-01-14 10:12:10 +08:00
muwoo
7b320c9dd1 👷 构建问题 2022-01-14 10:11:52 +08:00
木偶
6640d66fac Update FUNDING.yml 2022-01-13 20:53:54 +08:00
muwoo
357846d2e6 👷 构建问题 2022-01-13 20:38:59 +08:00
muwoo
3b3ddf224c 👷 构建问题 2022-01-13 20:32:55 +08:00
muwoo
4439d0548f 👷 构建问题 2022-01-13 20:29:17 +08:00
muwoo
21163b2277 👷 构建问题 2022-01-13 20:13:50 +08:00
muwoo
480aaf2970 👷 构建问题 2022-01-13 20:12:27 +08:00
muwoo
06596d87ae 👷 构建问题 2022-01-13 19:57:17 +08:00
muwoo
1008e86fbb 👷 构建问题 2022-01-13 19:17:08 +08:00
muwoo
62ec316337 :ci: 构建问题 2022-01-13 18:59:57 +08:00
木偶
735a450260 Merge pull request #81 from rubickCenter/feat-dev
LGTM
2022-01-13 18:41:08 +08:00
muwoo
417ab071df 🐛 #80 修复 win depd bug 2022-01-13 18:40:04 +08:00
muwoo
1e73ab5ee6 🐛 #80 修复 win depd bug 2022-01-13 18:38:44 +08:00
muwoo
e5ff219685 ref: 修复win下多文件复制 2022-01-13 13:48:20 +08:00
muwoo
2beac06e7c ref: 修复win下多文件复制 2022-01-13 13:47:55 +08:00
muwoo
6b96df3da5 🐛 修复复制文件bug 2022-01-13 12:04:53 +08:00
muwoo
8521262344 Merge remote-tracking branch 'origin/master' 2022-01-11 19:39:12 +08:00
muwoo
4cf00f9270 支持 removePlugin API 2022-01-11 19:38:52 +08:00
muwoo
bdae8c280b ref: 支持win搜索快捷启动 2022-01-11 12:18:08 +08:00
muwoo
04e674d1cd 支持内网部署配置能力 2022-01-11 10:17:41 +08:00
muwoo
371565744e 支持内网部署配置能力 2022-01-10 19:13:26 +08:00
muwoo
58aabb9f1e 增加首屏打开速度 2022-01-05 19:41:14 +08:00
muwoo
19cd77b26c 支持插件分离,增加开发者工具功能 2022-01-04 14:03:25 +08:00
190 changed files with 88097 additions and 40749 deletions

View File

@@ -4,17 +4,23 @@ module.exports = {
node: true,
},
extends: [
"plugin:vue/vue3-essential",
"eslint:recommended",
"@vue/typescript/recommended",
"@vue/prettier",
"@vue/prettier/@typescript-eslint",
'plugin:vue/vue3-essential',
'eslint:recommended',
'@vue/typescript/recommended',
'@vue/prettier',
'@vue/prettier/@typescript-eslint',
],
parserOptions: {
ecmaVersion: 2020,
},
rules: {
"no-console": process.env.NODE_ENV === "production" ? "warn" : "off",
"no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off"
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'prettier/prettier': [
'warn',
{
singleQuote: true,
},
],
},
};

2
.github/FUNDING.yml vendored
View File

@@ -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']

View File

@@ -23,7 +23,7 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [macos-latest, windows-2019]
os: [macos-latest, windows-2019, ubuntu-latest]
# create steps
steps:
@@ -35,7 +35,7 @@ jobs:
- name: Install Node.js
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node }}
node-version: 16.x
- name: Install system deps
if: matrix.os == 'ubuntu-latest'
@@ -47,7 +47,12 @@ jobs:
run: |
yarn
yarn global add xvfb-maybe
yarn global add @vue/cli
- name: Build feature
run: |
cd ./feature
yarn
npm run build
- name: Build & release app
run: |
npm run release

1
.npmrc Normal file
View File

@@ -0,0 +1 @@
electron_mirror=https://npm.taobao.org/mirrors/electron/

19
.prettierrc Normal file
View 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"
}

View File

@@ -14,7 +14,7 @@ English | [简体中文](./README.zh-CN.md)
<img alt="release" src="https://img.shields.io/github/package-json/v/rubickCenter/rubick" />
</a>
<a href="https://github.com/rubickCenter/rubick/actions">
<img alt=building src=https://img.shields.io/github/workflow/status/rubickCenter/rubick/Build>
<img alt=building src=https://img.shields.io/github/actions/workflow/status/rubickCenter/rubick/main.yml>
</a>
<a href="https://github.com/rubickCenter/rubick/blob/master/LICENSE">
<img alt="npm" src="https://img.shields.io/github/license/rubickCenter/rubick" />
@@ -29,9 +29,18 @@ English | [简体中文](./README.zh-CN.md)
Based on electron open source toolbox, free integration of rich plug-ins, to create the ultimate desktop efficiency tool。Rubick is one of the heroes of Dota The core skill is the ability to use other heroes as plug-insFinished the walk 。Very consistent with the design concept of this toolSo named Rubick。
## Sponsor
我们通过有偿的方式积累高质量的常见问题、最佳实践文档,加入星球后可以和作者进行互动和答疑。我们提供技术支持、答疑解惑、定制化插件开发、二次定制化开发 rubick 等等官方服务。
权益明细可以参考文档:[权益明细](https://rubickcenter.github.io/rubick/super/)
<img width=400 src=https://picx.zhimg.com/80/v2-6deabf65175d18080439ef813102d18c_720w.png />
## Installation package
* [Rubick Mac OS](https://github.com/rubickCenter/rubick/releases)
* [Rubick Windows](https://github.com/rubickCenter/rubick/releases)
* [Rubick Linux](https://github.com/rubickCenter/rubick/releases)
## Feature list
- [x] Plug-in management based on npm package mode, installing plugins is as easy as installing npm packages.
@@ -41,7 +50,7 @@ Based on electron open source toolbox, free integration of rich plug-ins, to cre
- [x] Support searching for locally installed apps or preferences
- [x] Support MacOS
- [x] Support Windows
- [x] Support Linux
## Docs
@@ -76,12 +85,6 @@ Search for `Preferences` in `rubick`, and then turn on the `Auto Paste` function
If you need more features, please come here to give us suggestions[issues](https://github.com/rubickCenter/rubick/issues) 。
We will add valuable ideas to the later development. At the same time, welcome to join and build together。
## Sponsor
开源不容易,如果该项目对你有用的话,可以打赏我们喝杯 coffee ☕️.
<img width=200 src=https://pic1.zhimg.com/80/v2-688385687a37e962fe32daf136139feb_720w.png />
<img width=200 src=https://pica.zhimg.com/80/v2-1ba296fd2cece45ee1094ee7c259035c_720w.png />
## 贡献
This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)]. <a href="https://github.com/rubickCenter/rubick/graphs/contributors"><img src="https://opencollective.com/rubick/contributors.svg?width=890&button=false" /></a>

View File

@@ -30,9 +30,17 @@
基于 electron 的开源工具箱自由集成丰富插件打造极致的桌面端效能工具。Rubick(拉比克) 是 dota 里面的英雄之一,其核心技能是插件化使用其他英雄的技能,用完即走。非常符合本工具的设计理念,所以取名 Rubick。
## 赞助和服务
我们通过有偿的方式积累高质量的常见问题、最佳实践文档,加入星球后可以和作者进行互动和答疑。我们提供技术支持、答疑解惑、定制化插件开发、二次定制化开发 rubick 等等官方服务。
权益明细可以参考文档:[权益明细](https://rubickcenter.github.io/rubick/super/)
<img width=400 src=https://picx.zhimg.com/80/v2-6deabf65175d18080439ef813102d18c_720w.png />
## 安装包
* [Rubick Mac OS](https://github.com/rubickCenter/rubick/releases)
* [Rubick Windows](https://github.com/rubickCenter/rubick/releases)
* [Rubick Linux](https://github.com/rubickCenter/rubick/releases)
## 支持能力
- [x] 基于 npm 包模式的插件管理,安装插件和安装 npm 包一样简单
@@ -42,7 +50,7 @@
- [x] 支持搜索本地已安装 app 或 偏好设置
- [x] 支持 MacOS
- [x] 支持 Windows
- [x] 支持 Linux
## 使用文档
@@ -77,12 +85,6 @@
如果您还需要更多功能,欢迎来这里给我们提建议:[issues](https://github.com/rubickCenter/rubick/issues) 。
有价值的想法我们会加入到后期的开发当中。同时也欢迎一起加入共建。
## 赞助
开源不容易,如果该项目对你有用的话,可以打赏我们喝杯 coffee ☕️.
<img width=200 src=https://pic1.zhimg.com/80/v2-688385687a37e962fe32daf136139feb_720w.png />
<img width=200 src=https://pica.zhimg.com/80/v2-1ba296fd2cece45ee1094ee7c259035c_720w.png />
## 贡献
This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)]. <a href="https://github.com/rubickCenter/rubick/graphs/contributors"><img src="https://opencollective.com/rubick/contributors.svg?width=890&button=false" /></a>

View File

@@ -1,3 +1,9 @@
module.exports = {
presets: ["@vue/cli-plugin-babel/preset"],
plugins: [
[
"import",
{ libraryName: "ant-design-vue", libraryDirectory: "es", style: "css" },
], // `style: true` 会加载 less 文件
],
};

23
detach/.gitignore vendored Normal file
View 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
View 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
View File

@@ -0,0 +1,3 @@
module.exports = {
presets: ["@vue/cli-plugin-babel/preset"],
};

13238
detach/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

57
detach/package.json Normal file
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

17
detach/public/index.html Normal file
View File

@@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>

221
detach/src/App.vue Normal file
View File

@@ -0,0 +1,221 @@
<template>
<div :class="[platform, 'detach']">
<div class="info">
<img :src="plugInfo.logo"/>
<input
autofocus
@input="changeValue"
v-if="showInput"
:value="plugInfo.subInput?.value"
:placeholder="plugInfo.subInput?.placeholder"
/>
<span v-else>{{ plugInfo.pluginName }}</span>
</div>
<div class="handle-container">
<div class="handle">
<div class="devtool" @click="openDevTool" title="开发者工具"></div>
</div>
<div class="window-handle" v-if="platform !== 'darwin'">
<div class="minimize" @click="minimize"></div>
<div class="maximize" @click="maximize"></div>
<div class="close" @click="close"></div>
</div>
</div>
</div>
</template>
<script setup>
import throttle from 'lodash.throttle';
import { ref } from 'vue';
const { ipcRenderer } = window.require('electron');
const platform = ref(window.process.platform);
const showInput = ref(false);
const storeInfo = localStorage.getItem('rubick-system-detach') || '{}';
const plugInfo = ref({});
window.initDetach = (pluginInfo) => {
plugInfo.value = pluginInfo;
showInput.value =
pluginInfo.subInput &&
(!!pluginInfo.subInput.value || !!pluginInfo.subInput.placeholder);
localStorage.setItem('rubick-system-detach', JSON.stringify(pluginInfo));
};
try {
window.initDetach(JSON.parse(storeInfo));
} catch (e) {
// ...
}
const changeValue = throttle((e) => {
ipcRenderer.send('msg-trigger', {
type: 'detachInputChange',
data: {
text: e.target.value,
},
});
}, 500);
const openDevTool = () => {
ipcRenderer.send('msg-trigger', { type: 'openPluginDevTools' });
};
const minimize = () => {
ipcRenderer.send('detach:service', { type: 'minimize' });
};
const maximize = () => {
ipcRenderer.send('detach:service', { type: 'maximize' });
};
const close = () => {
ipcRenderer.send('detach:service', { type: 'close' });
};
Object.assign(window, {
setSubInputValue: ({ value }) => {
plugInfo.value.subInput.value = value;
},
setSubInput: (placeholder) => {
plugInfo.value.subInput.placeholder = placeholder;
},
removeSubInput: () => {
plugInfo.value.subInput = null;
},
});
</script>
<style>
html, body {
margin: 0;
padding: 0;
font-family: system-ui, "PingFang SC", "Helvetica Neue", "Microsoft Yahei", sans-serif;
user-select: none;
overflow: hidden;
}
.detach {
width: 100%;
height: 60px;
display: flex;
align-items: center;
color: var(--color-text-primary);
}
.detach {
flex: 1;
display: flex;
align-items: center;
font-size: 18px;
padding-left: 10px;
font-weight: 500;
box-sizing: border-box;
justify-content: space-between;
}
.detach.darwin {
padding-left: 80px;
-webkit-app-region: drag;
}
.detach.win32 {
-webkit-app-region: drag;
}
.detach img {
width: 36px;
height: 36px;
margin-right: 10px;
}
.detach input {
background-color: var(--color-body-bg);
color: var(--color-text-primary);
width: 360px;
height: 36px;
line-height: 36px;
border-radius: 4px;
font-size: 14px;
border: none;
padding: 0 10px;
outline: none;
-webkit-app-region: no-drag;
}
.detach input::-webkit-input-placeholder {
color: #aaa;
user-select: none;
}
.detach .info {
display: flex;
align-items: center;
}
.handle {
display: flex;
-webkit-app-region: no-drag;
}
.handle > div {
width: 36px;
height: 36px;
border-radius: 18px;
cursor: pointer;
margin-right: 6px;
}
.handle > div:hover {
background-color: #dee2e6;
}
.handle .devtool {
background: center no-repeat url("./assets/tool.svg")
}
.handle-container {
display: flex;
align-items: center;
}
.window-handle {
display: flex;
align-items: center;
-webkit-app-region: no-drag;
}
.window-handle > div {
width: 48px;
height: 56px;
cursor: pointer;
}
.window-handle > div:hover {
background-color: #dee2e6;
}
.window-handle .minimize {
background: center / 20px no-repeat url("./assets/minimize.svg");
}
.window-handle .maximize {
background: center / 20px no-repeat url("./assets/maximize.svg");
}
.window-handle .unmaximize {
background: center / 20px no-repeat url("./assets/unmaximize.svg");
}
.window-handle .close {
background: center / 20px no-repeat url("./assets/close.svg");
}
.window-handle .close:hover {
background-color: #e53935 !important;
background-image: url("./assets/close-hover.svg") !important;
}
</style>

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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;
}

View 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
View 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
View 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
View File

@@ -0,0 +1,39 @@
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"strict": true,
"jsx": "preserve",
"importHelpers": true,
"moduleResolution": "node",
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"sourceMap": true,
"baseUrl": ".",
"types": [
"webpack-env"
],
"paths": {
"@/*": [
"src/*"
]
},
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
},
"include": [
"src/**/*.ts",
"src/**/*.tsx",
"src/**/*.vue",
"tests/**/*.ts",
"tests/**/*.tsx"
],
"exclude": [
"node_modules"
]
}

13
detach/vue.config.js Normal file
View File

@@ -0,0 +1,13 @@
const path = require("path");
module.exports = {
css: { // 配置css模块
loaderOptions: { // 向预处理器 Loader 传递配置选项
less: { // 配置less其他样式解析用法一致
javascriptEnabled: true, // 设置为true
},
},
},
outputDir: path.join(__dirname, "../public/detach"),
publicPath: process.env.NODE_ENV === "production" ? "" : "/",
};

9401
detach/yarn.lock Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -24,6 +24,10 @@ module.exports = {
title: '插件开发',
path: '/dev/',
},
{
title: '特殊服务',
path: '/super/',
},
{
title: 'API',
path: '/api/',

Submodule docs/docs/.vuepress/dist added at 7b52f0fb4a

View File

@@ -23,7 +23,7 @@
#### 示例
```js
rubcik.onPluginReady(({ code, type, payload }) => {
rubick.onPluginReady(({ code, type, payload }) => {
console.log('插件装配完成,已准备好')
})
/*

View File

@@ -113,7 +113,7 @@ rubick-system-plugin-demo
"version": "0.0.0",
"description": "rubick 系统插件demo",
"entry": "index.js",
"logo": "httpss://static.91jkys.com/upload/202112/08/5bac90649c5343cabb63930b131cf8e6.png",
"logo": "https://xxxx/upload/202112/08/5bac90649c5343cabb63930b131cf8e6.png",
"pluginType": "system",
"author": "muwoo",
"homepage": ""
@@ -171,6 +171,6 @@ $ npm link
$ npm publish
```
然后再给 [rubick-database/plugins/total-plugins.json](https://gitee.com/monkeyWang/rubick-database/blob/master/plugins/total-plugins.json) 仓库提个 `pull request`, 把你的 `package.json` 信息加入 `json` 文件内,等我们 merge 了您的提交,插件将会自动上架。
然后再给 [rubick-database/plugins/total-plugins.json](https://gitcode.net/rubickcenter/rubick-database/-/blob/master/plugins/total-plugins.json) 仓库提个 `pull request`, 把你的 `package.json` 信息加入 `json` 文件内,等我们 merge 了您的提交,插件将会自动上架。

View File

@@ -18,13 +18,11 @@ rubick 之前的插件管理,依托于云服务器存储,我们需要为服
## 下载 rubick
[rubick 下载安装地址](https://github.com/rubickCenter/rubick/releases)
macos 选择 `pkg` 文件windows 选择 `exe` 文件。
macos 选择 `pkg` 文件windows 选择 `exe` 文件Debian/Ubuntu选择`deb`
安装完成后打开 rubick 即可看到主搜索界面:
![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/26f0fbe2c69246b6a3ed139b0df1ca0b~tplv-k3u1fbpfcp-watermark.image)
目前支持 windows 和 macos。linux 小伙伴正在开发中
## 功能说明
接下来详细介绍 rubick 所包含和支持的功能
@@ -50,6 +48,27 @@ macos 选择 `pkg` 文件windows 选择 `exe` 文件。
![](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/01ef50fbfa064ba9a88bebe1531eacd4~tplv-k3u1fbpfcp-watermark.image)
### 内网部署
::: tip
如果把插件发布到公网 `npm` 如果不符合您的公司安全要求,`rubick` 支持内网私有源和私有插件库,如果您需要内网部署使用,可以自行配置以下规则。
:::
`rubick` 依赖 `npm` 仓库做插件管理,依赖 `gitcode` 做插件数据存储所以如果要进行内网部署主要需要替换这2个设置。详细设置
`插件市场 -> 设置 -> 内网部署设置`
![image.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1319b177fb544017ae10b4a703e8efa6~tplv-k3u1fbpfcp-watermark.image?)
#### 1. 替换 npm 源
插件发布到私有 `npm` 源即可。
#### 2. 替换 `gitcode` 源为内网 `gitlab`: database url
* clone 下载 rubick 插件库:[https://gitcode.net/rubickcenter/rubick-database](https://gitcode.net/rubickcenter/rubick-database)
* 提交仓库到私有 `gitlab` 库。
替换格式:`https://gitlab.xxx.com/api/v4/projects/{projectId}/repository/files/` 。因为接口为 `gitlab openAPI`,所以需要填写仓库 `access_token`
### 更多功能
如果您还需要更多功能,欢迎来这里给我们提建议:[issues](https://github.com/rubickCenter/rubick/issues) 。
有价值的想法我们会加入到后期的开发当中。同时也欢迎一起加入共建。

View File

@@ -101,5 +101,3 @@ $ npm run electron:build
5. Make sure that running npm run prepublish outputs the correct files.
6. Rebase before creating a PR to keep commit history clear. (Merge request to branch dev)
7. Provide some description about your PR.

19
docs/docs/super/README.md Normal file
View File

@@ -0,0 +1,19 @@
# 特殊服务
## 说明
`rubick` 一直坚持开源免费,现在不会变,以后也不会变。但是纯开源 `MIT` 模式下,是一种 0 收入用爱发电的,完全依靠
作者自己的爱好和激情。但这种用爱发电的模式很难持续维持,为了更好的持续迭代和发展壮大 `rubick`, 我们需要一定的现金持续激励 `rubick` 的核心开发者们,让更多的人成为 `rubick`
的核心开发者。所以 `rubick` 开启了一个新的模式尝试,那是服务付费:`rubick` 用户可以购买我们提供技术支持、答疑解惑、定制化插件开发、二次定制化开发 `rubick` 等等官方服务...
## 可以提供哪些服务?
我们收集了大量用户的问题,目前约定可以支持到的服务有:
1. 二次定制化开发 `rubick`
2. 轻量级插件开发
3. `rubick` 实现原理手把手介绍
4. `rubick` 使用答疑
5. `rubick` 内网部署一条龙服务
6. 前端圈各种技术支持(作者分别是前蚂蚁集团和字节跳动的前端技术专家)
7. 未来能提供的一切...
## 如何加入特殊服务?
扫描下方的二维码,加入知识星球即可:
<img width=400 src=https://picx.zhimg.com/80/v2-6deabf65175d18080439ef813102d18c_720w.png />

24918
docs/package-lock.json generated

File diff suppressed because it is too large Load Diff

10220
docs/pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

8688
docs/yarn.lock Normal file

File diff suppressed because it is too large Load Diff

1
feature/.env.development Normal file
View File

@@ -0,0 +1 @@
VUE_APP_API_BASE=http://localhost:7001/

1
feature/.env.production Normal file
View File

@@ -0,0 +1 @@
VUE_APP_API_BASE=https://rubick.vip/api/

7339
feature/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -3,19 +3,22 @@
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"serve": "vue-cli-service serve --port 8081",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"@ant-design/icons-vue": "^6.0.1",
"ant-design-vue": "^2.2.8",
"@vue/cli-service": "~4.5.0",
"ant-design-vue": "3.2.14",
"axios": "^0.24.0",
"core-js": "^3.6.5",
"lodash.debounce": "^4.0.8",
"lodash.throttle": "^4.1.1",
"markdown-it": "^12.2.0",
"vue": "^3.0.0",
"nanoid": "^4.0.2",
"vue": "3.2.45",
"vue-i18n": "^9.2.2",
"vue-router": "^4.0.0-0",
"vuex": "^4.0.0-0"
},
@@ -34,6 +37,8 @@
"eslint": "^6.7.2",
"eslint-plugin-prettier": "^3.3.1",
"eslint-plugin-vue": "^7.0.0",
"less": "^4.1.3",
"less-loader": "5.0.0",
"prettier": "^2.2.1",
"typescript": "~4.1.5"
},

View File

@@ -3,7 +3,7 @@
"pluginName": "rubick 系统菜单",
"description": "rubick 系统菜单",
"main": "index.html",
"logo": "https://static.91jkys.com/upload/202112/08/8a1abbb051bf4b05bbc9bbf66ade63f2.png",
"logo": "https://pic1.zhimg.com/80/v2-c09780808301668a82e6646cb42f0806_720w.png",
"version": "0.0.0",
"preload":"preload.js",
"pluginType": "ui",

View File

@@ -1,36 +1,34 @@
<template>
<div class="main-container">
<div class="slider-bar">
<a-menu v-model:selectedKeys="active" mode="horizontal" @select="({key}) => changeMenu(key)">
<a-menu
v-model:selectedKeys="active"
mode="horizontal"
@select="({ key }) => changeMenu(key)"
>
<a-menu-item key="market">
<template #icon>
<AppstoreOutlined />
</template>
插件市场
{{ $t('feature.market.title') }}
</a-menu-item>
<a-menu-item key="installed">
<template #icon>
<HeartOutlined />
</template>
已安装
{{ $t('feature.installed.title') }}
</a-menu-item>
<a-menu-item key="settings">
<template #icon>
<SettingOutlined />
</template>
设置
</a-menu-item>
<a-menu-item key="account">
<template #icon>
<UserOutlined />
</template>
账户
{{ $t('feature.settings.title') }}
</a-menu-item>
<a-menu-item key="dev">
<template #icon>
<BugOutlined />
</template>
开发者
{{ $t('feature.dev.title') }}
</a-menu-item>
</a-menu>
</div>
@@ -39,18 +37,18 @@
</template>
<script setup lang="ts">
import { ref } from "vue";
import { useRouter } from "vue-router";
import { ref } from 'vue';
import { useRouter } from 'vue-router';
import {
HeartOutlined,
UserOutlined,
AppstoreOutlined,
SettingOutlined,
BugOutlined,
} from "@ant-design/icons-vue";
import { useStore } from "vuex";
} from '@ant-design/icons-vue';
import { useStore } from 'vuex';
const router = useRouter();
const active = ref(["market"]);
const active = ref(['market']);
const changeMenu = (key: any) => {
router.push(key);
};
@@ -61,11 +59,10 @@ window.rubick.onPluginEnter(({ code }: { code: string }) => {
});
const store = useStore();
const init = () => store.dispatch("init");
const init = () => store.dispatch('init');
init();
</script>
<style lang="less">
<style lang="less" scoped>
* {
margin: 0;
padding: 0;
@@ -74,11 +71,20 @@ init();
.main-container {
display: flex;
align-items: flex-start;
background: #F2EFEF;
background: var(--color-body-bg);
flex-direction: column;
.slider-bar {
width: 100%;
.ant-menu {
background: var(--color-body-bg);
border-color: var(--color-border-light);
:deep(.ant-menu-item) {
&:not(.ant-menu-item-selected) {
color: var(--color-text-primary);
}
}
}
}
}
</style>

View File

@@ -1,5 +1,30 @@
@import '~ant-design-vue/dist/antd.less'; // 引入官方提供的 less 样式入口文件
@import "~ant-design-vue/dist/antd.less"; // 引入官方提供的 less 样式入口文件
@primary-color: #ff4ea4; // 全局主色
@link-color: #ff4ea4; // 链接色
@error-color: #ff4ea4; // 错误色
:root {
--color-text-primary: rgba(0, 0, 0, 0.85);
--color-text-content: #141414;
--color-text-desc: rgba(0, 0, 0, 0.45);
// 背景色
--color-body-bg: #fff;
--color-menu-bg: #f3efef;
--color-list-hover: #e2e2e2;
--color-input-hover: #fff;
// 边框
--color-border-light: #f0f0f0;
}
.dark {
--color-text-primary: #e8e8f0;
--color-text-content: #ccccd8;
--color-text-desc: #8f8fa6;
// 背景色
--color-body-bg: #1c1c28;
--color-menu-bg: #1c1c28;
--color-list-hover: #33333d;
--color-input-hover: #33333d;
// 边框
--color-border-light: #33333d;
}

View File

@@ -0,0 +1,37 @@
.left-menu {
width: 200px;
// height: 100vh;
border-right: 1px solid var(--color-border-light);
.search-container {
padding: 10px;
}
.ant-input-affix-wrapper {
border: none;
background: var(--color-input-hover);
:deep(input) {
background: none;
color: var(--color-text-desc);
}
:deep(.anticon) {
color: var(--color-text-desc);
}
}
:deep(.ant-menu) {
background: var(--color-menu-bg);
height: 100%;
border-right: none;
.ant-menu-item {
color: var(--color-text-content);
&:active {
background: none;
}
}
.ant-menu-item-selected {
background-color: var(--color-list-hover);
color: var(--color-text-primary);
&:after {
display: none;
}
}
}
}

View File

@@ -1,30 +1,62 @@
import axios from "axios";
import axios from 'axios';
let baseURL = 'https://gitcode.net/rubickcenter/rubick-database/-/raw/master';
let access_token = '';
try {
const dbdata = window.rubick.db.get('rubick-localhost-config');
baseURL = dbdata.data.database;
access_token = dbdata.data.access_token;
} catch (e) {
// ignore
}
const instance = axios.create({
baseURL:
baseURL || 'https://gitcode.net/rubickcenter/rubick-database/-/raw/master',
});
export default {
async getTotalPlugins() {
const res = await axios.get(
"https://gitee.com/monkeyWang/rubick-database/raw/master/plugins/total-plugins.json"
);
let targetPath = 'plugins/total-plugins.json';
if (access_token) {
targetPath = `${encodeURIComponent(
targetPath
)}/raw?access_token=${access_token}&ref=master`;
}
const res = await instance.get(targetPath);
return res.data;
},
async getFinderDetail() {
const res = await axios.get(
"https://gitee.com/monkeyWang/rubick-database/raw/master/plugins/finder.json"
);
let targetPath = 'plugins/finder.json';
if (access_token) {
targetPath = `${encodeURIComponent(
targetPath
)}/raw?access_token=${access_token}&ref=master`;
}
const res = await instance.get(targetPath);
return res.data;
},
async getSystemDetail() {
const res = await axios.get(
"https://gitee.com/monkeyWang/rubick-database/raw/master/plugins/system.json"
);
let targetPath = 'plugins/system.json';
if (access_token) {
targetPath = `${encodeURIComponent(
targetPath
)}/raw?access_token=${access_token}&ref=master`;
}
const res = await instance.get(targetPath);
return res.data;
},
async getWorkerDetail() {
const res = await axios.get(
"https://gitee.com/monkeyWang/rubick-database/raw/master/plugins/worker.json"
);
let targetPath = 'plugins/worker.json';
if (access_token) {
targetPath = `${encodeURIComponent(
targetPath
)}/raw?access_token=${access_token}&ref=master`;
}
const res = await instance.get(targetPath);
return res.data;
},
@@ -33,16 +65,34 @@ export default {
return res.data;
},
async getSearchDetail(url: string) {
const res = await axios.get(
"https://gitee.com/monkeyWang/rubick-database/raw/master/plugins/search.json"
);
async getSearchDetail() {
let targetPath = 'plugins/search.json';
if (access_token) {
targetPath = `${encodeURIComponent(
targetPath
)}/raw?access_token=${access_token}&ref=master`;
}
const res = await instance.get(targetPath);
return res.data;
},
async getDevDetail(url: string) {
const res = await axios.get(
"https://gitee.com/monkeyWang/rubick-database/raw/master/plugins/dev.json"
);
async getDevDetail() {
let targetPath = 'plugins/dev.json';
if (access_token) {
targetPath = `${encodeURIComponent(
targetPath
)}/raw?access_token=${access_token}&ref=master`;
}
const res = await instance.get(targetPath);
return res.data;
},
async getImageDetail() {
let targetPath = 'plugins/image.json';
if (access_token) {
targetPath = `${encodeURIComponent(
targetPath
)}/raw?access_token=${access_token}&ref=master`;
}
const res = await instance.get(targetPath);
return res.data;
},
};

View 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;
},
};

View File

@@ -0,0 +1,19 @@
import { createI18n } from 'vue-i18n';
import messages from './langs';
const { remote } = window.require('electron');
const { perf } = remote.getGlobal('OP_CONFIG').get();
console.log(messages);
console.log(perf);
// 2. Create i18n instance with options
const i18n = createI18n({
legacy: false,
locale: perf.common.lang || 'zh-CN', // set locale
fallbackLocale: 'zh-CN', // set fallback locale
messages, // set locale messages
// If you need to specify other options, you can set other options
// ...
});
export default i18n;

View File

@@ -0,0 +1,111 @@
export default {
'en-US': {
feature: {
market: {
title: 'Market',
search: 'Search Plugins',
searchResult: 'Search Results',
explore: 'Explore',
efficiency: 'Efficiency',
searchTool: 'Search Tools',
imageTool: 'Image Tools',
developTool: 'Develop Tools',
systemTool: 'System Tools',
finder: {
recommended: 'Recommended',
lastUpdated: 'Last Updated',
},
install: 'Install',
},
installed: {
title: 'Installed',
tips1: 'There are no plug-ins.',
tips2: 'Go to the plugin market and choose the plugin to install!',
developer: 'Developer',
unknown: 'Unknown',
remove: 'Remove',
functionKey: 'Function Key',
detailInfo: 'Detail Info',
addToPanel: 'Click the + sign to pin the keyword to the super panel',
removeFromPanel:
'Click the - sign to remove the keyword from the super panel',
},
settings: {
title: 'Account And Setting',
account: {
accountInfo: 'Account Info',
tips1: 'rubick',
tips2:
'After the software preferences are set, please restart the software. Please go to the mini program set avatar and nickname.',
themeColor: 'Theme Color',
primaryColor: 'Primary Color',
errorColor: 'Error Color',
warningColor: 'Warning Color',
successColor: 'Success Color',
infoColor: 'Info Color',
personalized: 'Personalized',
greeting: 'Search Box Greeting',
logo: 'Logo',
replace: 'Repalce Logo',
reset: 'Reset Default',
},
basic: {
title: 'Basic',
shortcutKey: 'Shortcut Key',
showOrHiddle: 'Show Or Hiddle',
screenCapture: 'Screen Capture',
common: 'Common',
autoPaste: 'Auto Paste',
autoBoot: 'Auto Boot Up',
spaceExec: 'Space Execution',
on: 'on',
off: 'off',
theme: 'Theme',
darkMode: 'Dark Mode',
language: 'Language',
changeLang: 'Change Language',
cn: '简体中文',
en: 'English',
},
global: {
title: 'Global Shortcut Key',
instructions: 'Instructions and examples',
tips: 'Press the shortcut key, automatically search for the corresponding keyword, when the keyword result is exactly matched, and the result is unique, it will point directly to this function.',
example: 'Example',
example1: 'Shortcut key 「Alt + W」 keyword 「Wechat」',
tips1: 'Press 「Alt + W」 to open the local Wechat app directly',
example2: 'Shortcut key 「Ctrl + Alt + A」 keyword 「screenshot」',
tips2: 'Press 「Ctrl + Alt + A」 to take a screenshot',
shortcutKey: 'Shortcut Key',
funtionKey: 'Funtion Key',
addShortcutKey: 'ADD Global Shortcut Key',
addShortcutKeyTips:
'Press the function keys (Ctrl, Shift, {optionKeyName}) first, and then press other normal keys. Or press the F1-F12 button.',
},
superPanel: {
title: 'Super Panel',
tips: 'Please select the common plug-ins that need to be added to the super panel.',
add: 'Add',
remove: 'Revome',
},
intranet: {
title: 'Intranet Deployment',
tips: "If publishing plug-ins to the public network npm does not meet your company's security requirements, rubick supports private network private sources and private plug-in libraries. If you need private network deployment, you can configure the following rules.",
npmMirror: 'npm mirror',
dbUrl: 'database url',
accessToken: 'access token',
placeholder: 'required for private network gitlab warehouse',
},
},
dev: {
title: 'Developer',
tips: 'The rubick plug-in system relies on npm management. Local debugging needs to first execute npm link in the current directory of the local plug-in.',
pluginName: 'Plugin Name',
install: 'Install',
refreshPlugins: 'Refresh Plugins',
installSuccess: '{pluginName} Install Successed!',
refreshSuccess: '{pluginName} Refresh Successed!',
},
},
},
};

View File

@@ -0,0 +1,9 @@
import en from './en-US';
import cn from './zh-CN';
const langs = {
...en,
...cn,
};
export default langs;

View File

@@ -0,0 +1,109 @@
export default {
'zh-CN': {
feature: {
market: {
title: '插件市场',
search: '搜索插件',
searchResult: '搜索结果',
explore: '探索',
efficiency: '效率',
searchTool: '搜索工具',
imageTool: '图像',
developTool: '开发者',
systemTool: '系统',
finder: {
recommended: '推荐',
lastUpdated: '最近更新',
},
install: '安装',
},
installed: {
title: '已安装',
tips1: '暂无任何插件',
tips2: '去插件市场选择安装合适的插件吧!',
developer: '开发者',
unknown: '未知',
remove: '移除',
functionKey: '功能关键字',
detailInfo: '详情介绍',
addToPanel: '点击+号,固定关键词到超级面板',
removeFromPanel: '点击-号,从超级面板移除关键词',
},
settings: {
title: '账户和设置',
account: {
accountInfo: '账户信息',
tips1: 'rubick 用户',
tips2: '软件偏好设置完成后需重启软件,头像和昵称请前往小程序设置',
themeColor: '主题色设置',
primaryColor: '主色调',
errorColor: '错误色',
warningColor: '警告色',
successColor: '成功色',
infoColor: '提醒色',
personalized: '用户个性化设置',
greeting: '主搜索框欢迎语',
logo: '界面 logo',
replace: '点我替换',
reset: '恢复默认设置',
},
basic: {
title: '基本设置',
shortcutKey: '快捷键',
showOrHiddle: '显示/隐藏快捷键',
screenCapture: '截屏',
common: '通用',
autoPaste: '输入框自动粘贴',
autoBoot: '开机启动',
spaceExec: '空格执行',
on: '开',
off: '关',
theme: '主题',
darkMode: '暗黑模式',
language: '语言',
changeLang: '切换语言',
cn: '简体中文',
en: 'English',
},
global: {
title: '全局快捷键',
instructions: '说明及示例',
tips: '按下快捷键,自动搜索对应关键字,当关键字结果完全匹配,且结果唯一时,会直接指向该功能。',
example: '示例',
example1: '快捷键 「 Alt + W」 关键字 「 微信」',
tips1: '按下Alt + W 直接打开本地微信应用',
example2: '快捷键 「 Ctrl + Alt + A」 关键字 「 截屏」',
tips2: '按下 Ctrl + Alt + A 进行截屏',
shortcutKey: '快捷键',
funtionKey: '功能关键字',
addShortcutKey: '新增全局快捷功能',
addShortcutKeyTips:
'先按功能键Ctrl、Shift、{optionKeyName}),再按其他普通键。或按 F1-F12 单键。',
},
superPanel: {
title: '超级面板设置',
tips: '请选择需要添加到超级面板中的常用插件',
add: '添加',
remove: '移除',
},
intranet: {
title: '内网部署配置',
tips: '把插件发布到公网 npm 如果不符合您的公司安全要求rubick 支持内网私有源和私有插件库,如果您需要内网部署使用,可以自行配置以下规则。',
npmMirror: 'npm 源',
dbUrl: 'database url',
accessToken: 'access token',
placeholder: '内网gitlab仓库必填',
},
},
dev: {
title: '开发者',
tips: 'rubick 插件系统依托于 npm 管理,本地调试需要先在本地插件当前目录执行 npm link',
pluginName: '插件名称',
install: '安装',
refreshPlugins: '刷新插件',
installSuccess: '{pluginName}安装成功!',
refreshSuccess: '{pluginName}刷新成功!',
},
},
},
};

View File

@@ -1,8 +1,18 @@
import { createApp } from "vue";
import Antd from "ant-design-vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";
import "./assets/ant-reset.less";
import { createApp } from 'vue';
import Antd, { ConfigProvider } from 'ant-design-vue';
import App from './App.vue';
import router from './router';
import store from './store';
import './assets/ant-reset.less';
import 'ant-design-vue/dist/antd.variable.min.css';
import registerI18n from './languages/i18n';
createApp(App).use(store).use(Antd).use(router).mount("#app");
const { remote } = window.require('electron');
const { perf } = remote.getGlobal('OP_CONFIG').get();
ConfigProvider.config({
theme: perf.custom || {},
});
createApp(App).use(registerI18n).use(store).use(Antd).use(router).mount('#app');

View File

@@ -1,39 +1,39 @@
import { createRouter, createWebHashHistory, RouteRecordRaw } from "vue-router";
import Market from "../views/market/index.vue";
import Installed from "../views/installed/index.vue";
import Account from "../views/account/index.vue";
import Settings from "../views/settings/index.vue";
import Dev from "../views/dev/index.vue";
import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router';
import Market from '../views/market/index.vue';
import Installed from '../views/installed/index.vue';
import Account from '../views/account/index.vue';
import Settings from '../views/settings/user.vue';
import Dev from '../views/dev/index.vue';
const routes: Array<RouteRecordRaw> = [
{
path: "/market",
name: "market",
path: '/market',
name: 'market',
component: Market,
},
{
path: "/installed",
name: "installed",
path: '/installed',
name: 'installed',
component: Installed,
},
{
path: "/account",
name: "account",
path: '/account',
name: 'account',
component: Account,
},
{
path: "/settings",
name: "settings",
path: '/settings',
name: 'settings',
component: Settings,
},
{
path: "/dev",
name: "dev",
path: '/dev',
name: 'dev',
component: Dev,
},
{
path: "/:catchAll(.*)",
name: "market",
path: '/:catchAll(.*)',
name: 'market',
component: Market,
},
];

View File

@@ -8,5 +8,14 @@ declare module '*.vue' {
declare module 'axios'
interface Window {
rubick: any
rubick: any;
market: any
}
namespace Market {
interface Plugin {
isdownload?: boolean;
name?: string;
isloading: boolean
}
}

View File

@@ -1,7 +1,7 @@
import { createStore } from "vuex";
import request from "@/assets/request";
import { createStore } from 'vuex';
import request from '@/assets/request';
const isDownload = (item: any, targets: any[]) => {
const isDownload = (item: Market.Plugin, targets: any[]) => {
let isDownload = false;
targets.some((plugin) => {
if (plugin.name === item.name) {
@@ -16,6 +16,7 @@ export default createStore({
state: {
totalPlugins: [],
localPlugins: [],
searchValue: '',
},
mutations: {
commonUpdate(state: any, payload) {
@@ -23,57 +24,95 @@ export default createStore({
state[key] = payload[key];
});
},
setSearchValue(state: any, payload) {
state.searchValue = payload;
},
},
actions: {
async init({ commit }) {
const totalPlugins = await request.getTotalPlugins();
const localPlugins = (window as any).market.getLocalPlugins();
const localPlugins = window.market.getLocalPlugins();
totalPlugins.forEach(
(origin: { isdwonload?: any; name?: any; isloading: boolean }) => {
origin.isdwonload = isDownload(origin, localPlugins);
origin.isloading = false;
}
);
commit("commonUpdate", {
totalPlugins.forEach((origin: Market.Plugin) => {
origin.isdownload = isDownload(origin, localPlugins);
origin.isloading = false;
});
// 修复卸载失败,一直转圈的问题。
localPlugins.forEach((origin: Market.Plugin) => {
origin.isloading = false;
});
commit('commonUpdate', {
localPlugins,
totalPlugins,
});
},
startDownload({ commit, state }, name) {
const totalPlugins = JSON.parse(JSON.stringify(state.totalPlugins));
totalPlugins.forEach(
(origin: { isdwonload?: any; name?: any; isloading: boolean }) => {
if (origin.name === name) {
origin.isloading = true;
}
totalPlugins.forEach((origin: Market.Plugin) => {
if (origin.name === name) {
origin.isloading = true;
}
);
commit("commonUpdate", {
});
commit('commonUpdate', {
totalPlugins,
});
},
startUnDownload({ commit, state }, name) {
const localPlugins = window.market.getLocalPlugins();
localPlugins.forEach((origin: Market.Plugin) => {
if (origin.name === name) {
origin.isloading = true;
}
});
commit('commonUpdate', {
localPlugins,
});
},
errorUnDownload({ commit, state }, name) {
const localPlugins = window.market.getLocalPlugins();
// 修复卸载失败,一直转圈的问题。
localPlugins.forEach((origin: Market.Plugin) => {
if (origin.name === name) {
origin.isloading = false;
}
});
commit('commonUpdate', {
localPlugins,
});
},
successDownload({ commit, state }, name) {
const totalPlugins = JSON.parse(JSON.stringify(state.totalPlugins));
totalPlugins.forEach(
(origin: { isdwonload?: any; name?: any; isloading: boolean }) => {
if (origin.name === name) {
origin.isloading = false;
origin.isdwonload = true;
}
totalPlugins.forEach((origin: Market.Plugin) => {
if (origin.name === name) {
origin.isloading = false;
origin.isdownload = true;
}
);
const localPlugins = (window as any).market.getLocalPlugins();
});
const localPlugins = window.market.getLocalPlugins();
commit("commonUpdate", {
commit('commonUpdate', {
totalPlugins,
localPlugins,
});
},
updateLocalPlugin({ commit }) {
const localPlugins = (window as any).market.getLocalPlugins();
commit("commonUpdate", {
async updateLocalPlugin({ commit }) {
const localPlugins = window.market.getLocalPlugins();
const totalPlugins = await request.getTotalPlugins();
totalPlugins.forEach((origin: Market.Plugin) => {
origin.isdownload = isDownload(origin, localPlugins);
origin.isloading = false;
});
commit('commonUpdate', {
localPlugins,
totalPlugins,
});
},
},

View File

@@ -1,21 +1,85 @@
<template>
<div class="account">
<a-result status="404" title="玩命开发中" sub-title="个人中心正在开发中敬请期待...">
<a-result
v-if="!userInfo"
title="请先登录"
sub-title="用户暂未登录无法体验更多设置"
>
<template #extra>
<a-button @click="showModal" type="primary">
使用微信小程序登录
</a-button>
</template>
</a-result>
<a-modal :footer="null" v-model:visible="visible">
<a-result
title="请使用微信扫码登录!"
sub-title="使用微信扫描上面的 rubick 小程序二维码进行授权登录"
>
<template #icon>
<img width="200" :src="imgCode" />
</template>
</a-result>
</a-modal>
</div>
</template>
<script>
export default {
<script setup>
import { nanoid } from 'nanoid';
import { ref, watch } from 'vue';
import { message } from 'ant-design-vue';
import service from '../../assets/service';
const userInfo = ref(window.rubick.dbStorage.getItem('rubick-user-info'));
const imgCode = ref('');
const scene = nanoid();
const visible = ref(false);
const showModal = () => {
visible.value = true;
if (!imgCode.value && !userInfo.value) {
service.getScanCode({ scene }).then((res) => {
imgCode.value = `data:image/png;base64,${res.dataUrl}`;
});
}
};
let timer = null;
watch([visible], () => {
if (visible.value) {
timer = setInterval(() => {
service.checkLoginStatus({ scene }).then((res) => {
console.log(res);
if (res.openId) {
window.rubick.dbStorage.setItem('rubick-user-info', res);
userInfo.value = res;
message.success('登录成功!');
visible.value = false;
clearInterval(timer);
timer = null;
}
});
}, 2000);
} else {
clearInterval(timer);
timer = null;
}
});
</script>
<style lang="less">
<style lang="less" scoped>
.account {
box-sizing: border-box;
width: 100%;
overflow-x: hidden;
background: #f3efef;
height: calc(~"100vh - 46px");
background: var(--color-body-bg);
height: calc(~'100vh - 46px');
:deep(.ant-result-title) {
color: var(--color-text-primary);
}
:deep(.ant-result-subtitle) {
color: var(--color-text-desc);
}
}
</style>

View File

@@ -1,6 +1,10 @@
<template>
<div class="dev">
<a-alert style="margin-bottom: 40px;" message="rubick 插件系统依托于 npm 管理,本地调试需要先在本地插件当前目录执行 npm link" type="warning" />
<a-alert
style="margin-bottom: 40px"
:message="$t('feature.dev.tips')"
type="warning"
/>
<a-form
ref="formRef"
:model="formState"
@@ -8,21 +12,27 @@
:label-col="labelCol"
:wrapper-col="wrapperCol"
>
<a-form-item label="插件名称" name="name">
<a-form-item :label="$t('feature.dev.pluginName')" name="name">
<a-input v-model:value="formState.name" />
</a-form-item>
<a-form-item :wrapper-col="{ span: 14, offset: 4 }">
<a-button :loading="loading" type="primary" @click="onSubmit">安装</a-button>
<a-button @click="refresh" style="margin-left: 10px;">刷新插件</a-button>
<a-button :loading="loading" type="primary" @click="onSubmit">
{{ $t('feature.dev.install') }}
</a-button>
<a-button @click="refresh" style="margin-left: 10px">
{{ $t('feature.dev.refreshPlugins') }}
</a-button>
</a-form-item>
</a-form>
</div>
</template>
<script setup>
import { reactive, ref } from "vue";
import { message } from "ant-design-vue";
import { reactive, ref } from 'vue';
import { message } from 'ant-design-vue';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
const formRef = ref();
const formState = reactive({
@@ -31,7 +41,7 @@ const formState = reactive({
const rules = {
name: {
required: true,
message: "Please input name",
message: 'Please input name',
},
};
const onSubmit = () => {
@@ -47,7 +57,7 @@ const downloadPlugin = async (pluginName) => {
name: pluginName,
isDev: true,
});
message.success(`${pluginName}安装成功!`);
message.success(t('feature.dev.installSuccess', { pluginName: pluginName }));
loading.value = false;
};
@@ -56,7 +66,9 @@ const refresh = () => {
window.market.refreshPlugin({
name: formState.name,
});
message.success(`${formState.name}刷新成功!`);
message.success(
t('feature.dev.refreshSuccess', { pluginName: formState.name })
);
});
};
@@ -64,13 +76,20 @@ const labelCol = { span: 4 };
const wrapperCol = { span: 14 };
</script>
<style lang="less">
<style lang="less" scoped>
.dev {
box-sizing: border-box;
width: 100%;
overflow-x: hidden;
background: #fff;
height: calc(~"100vh - 46px");
background: var(--color-body-bg);
height: calc(~'100vh - 46px');
padding: 20px;
:deep(label) {
color: var(--color-text-content);
}
:deep(.ant-input) {
background: var(--color-input-hover);
color: var(--color-text-content);
}
}
</style>

View File

@@ -1,7 +1,11 @@
<template>
<div class="installed">
<div v-if="!localPlugins.length">
<a-result status="404" title="暂无任何插件" sub-title="去插件市场选择安装合适的插件吧" />
<a-result
status="404"
:title="$t('feature.installed.tips1')"
:sub-title="$t('feature.installed.tips2')"
/>
</div>
<div class="container" v-else>
<div class="installed-list">
@@ -29,7 +33,9 @@
<a-tag>{{ pluginDetail.version }}</a-tag>
</div>
<div class="desc">
开发者{{ `${pluginDetail.author || "未知"}` }}
{{ $t('feature.installed.developer') }}{{
`${pluginDetail.author || $t('feature.installed.unknown')}`
}}
</div>
<div class="desc">
{{ pluginDetail.description }}
@@ -40,13 +46,15 @@
type="danger"
size="small"
shape="round"
:loading="pluginDetail.isloading"
@click="deletePlugin(pluginDetail)"
>移除</a-button
>
{{ $t('feature.installed.remove') }}
</a-button>
</div>
</div>
<a-tabs default-active-key="1">
<a-tab-pane key="1" tab="功能关键字">
<a-tab-pane key="1" :tab="$t('feature.installed.functionKey')">
<div class="feature-container">
<div
class="desc-item"
@@ -56,51 +64,79 @@
<div>{{ item.explain }}</div>
<a-tag
:key="cmd"
@click="
openPlugin({
cmd,
plugin: pluginDetail,
feature: item,
router: $router,
})
"
v-for="cmd in item.cmds"
:class="{ executable: !cmd.label }"
>
{{ cmd }}
<span
@click="
!cmd.label &&
openPlugin({
code: item.code,
cmd,
})
"
>
{{ cmd.label || cmd }}
</span>
<template v-if="!cmd.label" #icon>
<a-tooltip
v-if="!hasAdded(cmd)"
placement="topLeft"
:title="$t('feature.installed.addToPanel')"
>
<PlusCircleOutlined
@click="addCmdToSuperPanel({ code: item.code, cmd })"
/>
</a-tooltip>
<a-tooltip
v-else
placement="topLeft"
:title="$t('feature.installed.removeFromPanel')"
>
<MinusCircleOutlined
@click="removePluginToSuperPanel(cmd)"
/>
</a-tooltip>
</template>
</a-tag>
</div>
</div>
</a-tab-pane>
<a-tab-pane key="2" tab="详情介绍">
<a-tab-pane key="2" :tab="$t('feature.installed.detailInfo')">
<div class="detail-container" v-html="readme"></div>
</a-tab-pane>
</a-tabs>
</div>
</div>
</div>
</template>
<script setup>
import { useStore } from "vuex";
import { computed, ref } from "vue";
import path from "path";
import MarkdownIt from "markdown-it";
import { useStore } from 'vuex';
import { computed, ref, toRaw } from 'vue';
import path from 'path';
import MarkdownIt from 'markdown-it';
import { PlusCircleOutlined, MinusCircleOutlined } from '@ant-design/icons-vue';
import { message } from 'ant-design-vue';
const { remote } = window.require("electron");
const fs = window.require("fs");
const { ipcRenderer } = window.require('electron');
const { remote } = window.require('electron');
const fs = window.require('fs');
const md = new MarkdownIt();
const appPath = remote.app.getPath("cache");
const baseDir = path.join(appPath, "./rubick-plugins");
const appPath = remote.app.getPath('cache');
const baseDir = path.join(appPath, './rubick-plugins');
const store = useStore();
const localPlugins = computed(() =>
store.state.localPlugins.filter(
(plugin) => plugin.name !== "rubick-system-feature"
(plugin) => plugin.name !== 'rubick-system-feature'
)
);
const updateLocalPlugin = () => store.dispatch("updateLocalPlugin");
const updateLocalPlugin = () => store.dispatch('updateLocalPlugin');
const startUnDownload = (name) => store.dispatch('startUnDownload', name);
const errorUnDownload = (name) => store.dispatch('errorUnDownload', name);
const currentSelect = ref([0]);
@@ -108,34 +144,106 @@ const pluginDetail = computed(() => {
return localPlugins.value[currentSelect.value] || {};
});
const superPanelPlugins = ref(
window.rubick.db.get('super-panel-plugins') || {
data: [],
_id: 'super-panel-plugins',
}
);
const addCmdToSuperPanel = ({ cmd, code }) => {
const plugin = {
...toRaw(pluginDetail.value),
cmd,
ext: {
code,
type: 'text',
payload: null,
},
};
superPanelPlugins.value.data.push(plugin);
window.rubick.db.put(toRaw(superPanelPlugins.value));
};
const removePluginToSuperPanel = (cmd) => {
superPanelPlugins.value.data = toRaw(superPanelPlugins.value).data.filter(
(item) => {
return item.cmd !== cmd;
}
);
console.log(toRaw(superPanelPlugins.value));
window.rubick.db.put(toRaw(superPanelPlugins.value));
};
const hasAdded = (cmd) => {
let added = false;
superPanelPlugins.value.data.some((item) => {
if (item.cmd === cmd) {
added = true;
return true;
}
return false;
});
return added;
};
const openPlugin = ({ cmd, code }) => {
window.rubick.openPlugin(
JSON.parse(
JSON.stringify({
...pluginDetail.value,
cmd,
ext: {
code,
type: 'text',
payload: null,
},
})
)
);
};
const readme = computed(() => {
if (!pluginDetail.value.name) return "";
if (!pluginDetail.value.name) return '';
const readmePath = path.resolve(
baseDir,
"node_modules",
'node_modules',
pluginDetail.value.name,
"readme.md"
'readme.md'
);
if (fs.existsSync(readmePath)) {
const str = fs.readFileSync(readmePath, "utf-8");
const str = fs.readFileSync(readmePath, 'utf-8');
return md.render(str);
}
return "";
return '';
});
const deletePlugin = async (plugin) => {
startUnDownload(plugin.name);
const timer = setTimeout(() => {
errorUnDownload(plugin.name);
message.error('卸载超时,请重试!');
}, 20000);
await window.market.deletePlugin(plugin);
updateLocalPlugin();
clearTimeout(timer);
};
</script>
<style lang="less">
<style lang="less" scoped>
.installed {
box-sizing: border-box;
width: 100%;
overflow: hidden;
background: #f3efef;
height: calc(~"100vh - 46px");
background: var(--color-body-bg);
height: calc(~'100vh - 46px');
:deep(.ant-result-title) {
color: var(--color-text-primary);
}
:deep(.ant-result-subtitle) {
color: var(--color-text-desc);
}
.container {
box-sizing: border-box;
width: 100%;
@@ -144,67 +252,106 @@ const deletePlugin = async (plugin) => {
height: 100%;
display: flex;
}
.installed-list {
width: 40%;
background: #fff;
background: var(--color-body-bg);
height: 100%;
padding: 10px 0;
border-right: 1px solid #eee;
border-right: 1px solid var(--color-border-light);
overflow: auto;
.item {
padding: 10px 20px;
display: flex;
align-items: center;
color: var(--color-text-content);
img {
width: 40px;
height: 40px;
margin-right: 20px;
}
.desc {
color: #999;
color: var(--color-text-desc);
}
&.active {
background: #eee;
background: var(--color-list-hover);
}
}
}
.plugin-detail {
padding: 20px 20px 0 20px;
box-sizing: border-box;
width: 60%;
height: 100%;
background: #fff;
background: var(--color-body-bg);
.plugin-top {
display: flex;
align-items: flex-start;
justify-content: space-between;
.title {
font-size: 20px;
display: flex;
align-items: center;
color: var(--color-text-primary);
.ant-tag {
background: var(--color-input-hover);
border: 1px solid var(--color-border-light);
color: var(--color-text-content);
margin-left: 8px;
}
}
.desc {
font-size: 13px;
color: #999;
color: var(--color-text-desc);
}
}
.ant-tabs {
:deep(.ant-tabs-bar) {
color: var(--color-text-content);
border-bottom: 1px solid var(--color-border-light);
}
}
.detail-container,
.feature-container {
height: 380px;
overflow: auto;
color: var(--color-text-content);
img {
width: 100%;
}
}
.desc-item {
border-bottom: 1px solid #ddd;
border-bottom: 1px solid var(--color-border-light);
padding: 10px 0;
color: var(--color-text-content);
.ant-tag {
margin-top: 6px;
&.executable {
cursor: pointer;
color: var(--ant-info-color);
&:hover {
transform: translateY(-2px);
}
}
}
.desc-title {
display: flex;
align-items: center;
justify-content: space-between;
}
.desc-info {
color: #999;
color: var(--color-text-desc);
}
}
}

View File

@@ -3,18 +3,18 @@
<PluginList
v-if="dev && !!dev.length"
@downloadSuccess="downloadSuccess"
title="开发"
:title="$t('feature.market.developTool')"
:list="dev"
/>
</div>
</template>
<script setup>
import { ref, computed, onBeforeMount } from "vue";
import request from "../../../assets/request/index";
import PluginList from "./plugin-list.vue";
import { ref, computed, onBeforeMount } from 'vue';
import request from '../../../assets/request/index';
import PluginList from './plugin-list.vue';
import { useStore } from "vuex";
import { useStore } from 'vuex';
const store = useStore();
const totalPlugins = computed(() => store.state.totalPlugins);

View File

@@ -11,34 +11,31 @@
<right-circle-outlined />
</div>
</template>
<div :key="index" v-for="(banner, index) in (data.banners || [])">
<div :key="index" v-for="(banner, index) in data.banners || []">
<img @click="jumpTo(banner.link)" width="100%" :src="banner.src" />
</div>
</a-carousel>
<PluginList
v-if="recommend && !!recommend.length"
@downloadSuccess="downloadSuccess"
title="推荐"
:title="$t('feature.market.finder.recommended')"
:list="recommend"
/>
<PluginList
v-if="newList && !!newList.length"
title="最近更新"
:title="$t('feature.market.finder.lastUpdated')"
:list="newList"
/>
</div>
</template>
<script setup>
import {
LeftCircleOutlined,
RightCircleOutlined,
} from "@ant-design/icons-vue";
import { ref, computed, onBeforeMount } from "vue";
import request from "../../../assets/request/index";
import PluginList from "./plugin-list.vue";
import { LeftCircleOutlined, RightCircleOutlined } from '@ant-design/icons-vue';
import { ref, computed, onBeforeMount } from 'vue';
import request from '../../../assets/request/index';
import PluginList from './plugin-list.vue';
import { useStore } from "vuex";
import { useStore } from 'vuex';
const store = useStore();
const totalPlugins = computed(() => store.state.totalPlugins);
@@ -75,7 +72,6 @@ const newList = computed(() => {
return searchInfo;
});
});
</script>
<style lang="less">

View File

@@ -1,13 +1,49 @@
<template>
<div class="system">
<PluginList
v-if="system && !!system.length"
@downloadSuccess="downloadSuccess"
:title="$t('feature.market.imageTool')"
:list="system"
/>
</div>
</template>
<script>
export default {
name: "image"
};
<script setup>
import { ref, computed, onBeforeMount } from 'vue';
import request from '../../../assets/request/index';
import PluginList from './plugin-list.vue';
import { useStore } from 'vuex';
const store = useStore();
const totalPlugins = computed(() => store.state.totalPlugins);
const data = ref([]);
onBeforeMount(async () => {
data.value = await request.getImageDetail();
});
const system = computed(() => {
const defaultData = data.value || [];
if (!defaultData.length) return [];
return defaultData.map((plugin) => {
let searchInfo = null;
totalPlugins.value.forEach((t) => {
if (t.name === plugin) {
searchInfo = t;
}
});
return searchInfo;
});
});
</script>
<style scoped>
<style lang="less">
.system {
width: 100%;
height: 100vh;
overflow-x: hidden;
box-sizing: border-box;
}
</style>

View File

@@ -2,13 +2,20 @@
<div class="panel-item">
<h3 class="title">{{ title }}</h3>
<div class="list-item">
<a-list :grid="{ gutter: 16, column: 2 }" :data-source="list">
<a-list
:grid="{ gutter: 16, column: 2 }"
:data-source="list.filter((item) => !!item)"
>
<template #renderItem="{ item, index }">
<a-list-item @click="showDetail(item)">
<a-list-item v-if="item" @click="showDetail(item)">
<template #actions>
<a-button style="color: #ff4ea4;" type="text" :loading="item.isloading">
<a-button
class="download-plugin-btn"
type="text"
:loading="item.isloading"
>
<CloudDownloadOutlined
v-show="!item.isloading && !item.isdwonload"
v-show="!item.isloading && !item.isdownload"
@click.stop="downloadPlugin(item, index)"
style="font-size: 20px; cursor: pointer"
/>
@@ -16,7 +23,7 @@
</template>
<a-list-item-meta>
<template #description>
<span class="ellipse">{{ item.description }}</span>
<span class="ellipse desc">{{ item.description }}</span>
</template>
<template #title>
<span class="ellipse">{{ item.pluginName }}</span>
@@ -38,18 +45,15 @@
:get-container="false"
class="plugin-info"
:style="{ position: 'absolute' }"
@close="visible=false"
@close="visible = false"
>
<template #title>
<div class="plugin-title-info">
<div class="back-icon" @click="visible=false">
<div class="back-icon" @click="visible = false">
<ArrowLeftOutlined />
</div>
<div class="info">
<img
:src="detail.logo"
class="plugin-icon"
/>
<img :src="detail.logo" class="plugin-icon" />
<div class="plugin-desc">
<div class="title">
{{ detail.pluginName }}
@@ -57,11 +61,19 @@
<div class="desc">
{{ detail.description }}
</div>
<a-button shape="round" type="primary">
<a-button
v-if="!detail.isdownload"
@click.stop="downloadPlugin(detail)"
shape="round"
type="primary"
:loading="detail.isloading"
>
<template #icon>
<CloudDownloadOutlined />
<CloudDownloadOutlined
v-show="!detail.isloading && !detail.isdownload"
/>
</template>
获取
{{ $t('feature.market.install') }}
</a-button>
</div>
</div>
@@ -75,18 +87,20 @@
import {
CloudDownloadOutlined,
ArrowLeftOutlined,
} from "@ant-design/icons-vue";
} from '@ant-design/icons-vue';
import { defineProps, ref } from "vue";
import { useStore } from "vuex";
import { message } from "ant-design-vue";
import MarkdownIt from "markdown-it";
import request from "../../../assets/request/index";
import { defineProps, ref } from 'vue';
import { useStore } from 'vuex';
import { message } from 'ant-design-vue';
import MarkdownIt from 'markdown-it';
import request from '../../../assets/request/index';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
const store = useStore();
const startDownload = (name) => store.dispatch("startDownload", name);
const successDownload = (name) => store.dispatch("successDownload", name);
const startDownload = (name) => store.dispatch('startDownload', name);
const successDownload = (name) => store.dispatch('successDownload', name);
defineProps({
list: {
@@ -99,19 +113,19 @@ defineProps({
const downloadPlugin = async (plugin) => {
startDownload(plugin.name);
await window.market.downloadPlugin(plugin);
message.success(`${plugin.name}安装成功!`);
message.success(t('feature.dev.installSuccess', { pluginName: plugin.name }));
successDownload(plugin.name);
};
const visible = ref(false);
const detail = ref({});
const markdown = new MarkdownIt();
const content = ref("");
const content = ref('');
const showDetail = async (item) => {
visible.value = true;
detail.value = item;
let mdContent = "暂无内容";
let mdContent = '暂无内容';
if (item.homePage) {
mdContent = await request.getPluginDetail(item.homePage);
}
@@ -125,8 +139,12 @@ const showDetail = async (item) => {
}
.panel-item {
margin: 20px 0;
.download-plugin-btn {
color: var(--ant-primary-color);
}
.title {
margin-bottom: 30px;
color: var(--color-text-primary);
}
.ellipse {
display: inline-block;
@@ -134,13 +152,17 @@ const showDetail = async (item) => {
overflow: hidden;
text-overflow: ellipsis;
width: 100%;
color: var(--color-text-content);
&.desc {
color: var(--color-text-desc);
}
}
&:after{
content: " ";
&:after {
content: ' ';
display: block;
width: 100%;
height: 1px;
border-bottom: 1px solid #eee;
border-bottom: 1px solid var(--color-border-light);
transform: scaleY(0.5);
}
.ant-list-item {
@@ -156,6 +178,21 @@ const showDetail = async (item) => {
.ant-drawer-content-wrapper {
box-shadow: none !important;
.ant-drawer-content {
background: var(--color-body-bg);
}
.ant-drawer-header {
background: var(--color-body-bg);
border-bottom: 1px solid var(--color-border-light);
}
}
}
.dark {
.plugin-title-info {
.back-icon {
filter: invert(1) brightness(200%);
}
}
}
@@ -182,6 +219,7 @@ const showDetail = async (item) => {
.title {
font-size: 18px;
font-weight: bold;
color: var(--color-text-primary);
}
.desc {
@@ -189,11 +227,15 @@ const showDetail = async (item) => {
font-weight: normal;
margin-top: 5px;
margin-bottom: 20px;
color: var(--color-text-desc);
}
}
}
}
.home-page-container {
* {
color: var(--color-text-content);
}
img {
width: 100%;
}

View File

@@ -0,0 +1,45 @@
<template>
<div class="result">
<PluginList
v-if="result && !!result.length"
@downloadSuccess="downloadSuccess"
:title="$t('feature.market.searchResult')"
:list="result"
/>
</div>
</template>
<script setup>
import { computed } from 'vue';
import PluginList from './plugin-list.vue';
import { useStore } from 'vuex';
const store = useStore();
const totalPlugins = computed(() => store.state.totalPlugins);
const searchValue = computed(() => store.state.searchValue);
const result = computed(() => {
if (searchValue.value.trim().length > 0) {
const pattern = new RegExp(searchValue.value);
return totalPlugins.value.filter((plugin) => {
if (plugin.pluginName.match(pattern)) {
return true;
} else {
return false;
}
});
} else {
return totalPlugins.value;
}
});
</script>
<style lang="less">
.result {
width: 100%;
height: 100vh;
overflow-x: hidden;
box-sizing: border-box;
}
</style>

View File

@@ -3,18 +3,18 @@
<PluginList
v-if="system && !!system.length"
@downloadSuccess="downloadSuccess"
title="系统插件"
:title="$t('feature.market.systemTool')"
:list="system"
/>
</div>
</template>
<script setup>
import { ref, computed, onBeforeMount } from "vue";
import request from "../../../assets/request/index";
import PluginList from "./plugin-list.vue";
import { ref, computed, onBeforeMount } from 'vue';
import request from '../../../assets/request/index';
import PluginList from './plugin-list.vue';
import { useStore } from "vuex";
import { useStore } from 'vuex';
const store = useStore();
const totalPlugins = computed(() => store.state.totalPlugins);

View File

@@ -3,18 +3,18 @@
<PluginList
v-if="tools && !!tools.length"
@downloadSuccess="downloadSuccess"
title="搜索工具"
:title="$t('feature.market.searchTool')"
:list="tools"
/>
</div>
</template>
<script setup>
import { ref, computed, onBeforeMount } from "vue";
import request from "../../../assets/request/index";
import PluginList from "./plugin-list.vue";
import { ref, computed, onBeforeMount } from 'vue';
import request from '../../../assets/request/index';
import PluginList from './plugin-list.vue';
import { useStore } from "vuex";
import { useStore } from 'vuex';
const store = useStore();
const totalPlugins = computed(() => store.state.totalPlugins);

View File

@@ -3,18 +3,18 @@
<PluginList
v-if="system && !!system.length"
@downloadSuccess="downloadSuccess"
title="生产效率"
:title="$t('feature.market.efficiency')"
:list="system"
/>
</div>
</template>
<script setup>
import { ref, computed, onBeforeMount } from "vue";
import request from "../../../assets/request/index";
import PluginList from "./plugin-list.vue";
import { ref, computed, onBeforeMount } from 'vue';
import request from '../../../assets/request/index';
import PluginList from './plugin-list.vue';
import { useStore } from "vuex";
import { useStore } from 'vuex';
const store = useStore();
const totalPlugins = computed(() => store.state.totalPlugins);

View File

@@ -4,8 +4,9 @@
<div class="search-container">
<a-input-search
v-model:value="searchValue"
placeholder="搜索插件"
:placeholder="$t('feature.market.search')"
style="width: 100%"
class="search"
@search="onSearch"
/>
</div>
@@ -15,37 +16,37 @@
<template #icon>
<StarOutlined />
</template>
探索
{{ $t('feature.market.explore') }}
</a-menu-item>
<a-menu-item key="worker">
<template #icon>
<SendOutlined style="transform: rotate(-45deg)" />
</template>
效率
{{ $t('feature.market.efficiency') }}
</a-menu-item>
<a-menu-item key="tools">
<template #icon>
<SearchOutlined />
</template>
搜索工具
{{ $t('feature.market.searchTool') }}
</a-menu-item>
<a-menu-item key="image">
<template #icon>
<FileImageOutlined />
</template>
图像
{{ $t('feature.market.imageTool') }}
</a-menu-item>
<a-menu-item key="dev">
<template #icon>
<CodeOutlined />
</template>
开发
{{ $t('feature.market.developTool') }}
</a-menu-item>
<a-menu-item key="system">
<template #icon>
<DatabaseOutlined />
</template>
系统
{{ $t('feature.market.systemTool') }}
</a-menu-item>
</a-menu>
</div>
@@ -63,26 +64,30 @@ import {
FileImageOutlined,
DatabaseOutlined,
CodeOutlined,
} from "@ant-design/icons-vue";
import { reactive, toRefs, computed } from "vue";
import { useStore } from "vuex";
import Finder from "./components/finder.vue";
import System from "./components/system.vue";
import Worker from "./components/worker.vue";
import Tools from "./components/tools.vue";
import Dev from "./components/devlopment.vue";
} from '@ant-design/icons-vue';
import { reactive, toRefs, computed } from 'vue';
import { useStore } from 'vuex';
import Finder from './components/finder.vue';
import System from './components/system.vue';
import Worker from './components/worker.vue';
import Tools from './components/tools.vue';
import Dev from './components/devlopment.vue';
import Image from './components/image.vue';
import Result from './components/result.vue';
const Components = {
finder: Finder,
system: System,
worker: Worker,
image: Image,
tools: Tools,
dev: Dev,
result: Result,
};
const state = reactive({
searchValue: "",
current: ["finder"],
searchValue: '',
current: ['finder'],
});
const store = useStore();
@@ -90,39 +95,34 @@ const store = useStore();
const totalPlugins = computed(() => store.state.totalPlugins);
const { searchValue, current } = toRefs(state);
const onSearch = (searchValue: string) => {
state.current = ['result'];
store.commit('setSearchValue', searchValue);
};
</script>
<style lang="less">
<style lang="less" scoped>
@import '~@/assets/common.less';
.market {
display: flex;
box-sizing: border-box;
align-items: flex-start;
width: 100%;
overflow: hidden;
background: #F3EFEF;
height: calc(~"100vh - 46px");
.left-menu {
width: 200px;
height: 100vh;
.search-container {
padding: 10px;
}
.ant-input-affix-wrapper {
border: none;
}
.ant-menu {
background: #F3EFEF;
.ant-menu-item-selected {
background-color: #E2E2E2;
color: #141414;
&:after {
display: none;
}
}
background: var(--color-menu-bg);
height: calc(~'100vh - 46px');
.search {
:deep(.ant-btn),
:deep(.ant-input),
:deep(.ant-input-group-addon) {
color: var(--ant-primary-color) !important;
background: var(--color-input-hover);
border-color: var(--color-border-light);
}
}
.container {
background: #fff;
background: var(--color-body-bg);
width: calc(~'100% - 200px');
height: 100%;
box-sizing: border-box;

View File

@@ -2,104 +2,170 @@
<div class="settings">
<div class="left-menu">
<a-menu v-model:selectedKeys="currentSelect" mode="inline">
<a-menu-item key="userInfo">
<template #icon>
<UserOutlined />
</template>
{{ $t('feature.settings.account.accountInfo') }}
</a-menu-item>
<a-menu-item key="normal">
<template #icon>
<ToolOutlined />
</template>
基本设置
{{ $t('feature.settings.basic.title') }}
</a-menu-item>
<a-menu-item key="global">
<template #icon>
<LaptopOutlined />
</template>
全局快捷键
{{ $t('feature.settings.global.title') }}
</a-menu-item>
<!-- <a-menu-item key="superpanel">-->
<!-- <template #icon>-->
<!-- <FileAddOutlined />-->
<!-- </template>-->
<!-- {{ $t('feature.settings.superPanel.title') }}-->
<!-- </a-menu-item>-->
<a-menu-item key="localhost">
<template #icon>
<DatabaseOutlined />
</template>
{{ $t('feature.settings.intranet.title') }}
</a-menu-item>
</a-menu>
</div>
<div class="settings-detail">
<UserInfo v-if="currentSelect[0] === 'userInfo'" />
<div v-if="currentSelect[0] === 'normal'">
<div class="setting-item">
<div class="title">
快捷键(需要使用 option/ctrl/shift/command 键修饰)
{{ $t('feature.settings.basic.shortcutKey') }}
</div>
<div class="settings-item-li">
<div class="label">显示/隐藏快捷键</div>
<div
class="value"
tabIndex="-1"
@keyup="(e) => changeShortCut(e, 'showAndHidden')"
>
{{ shortCut.showAndHidden }}
<div class="label">
{{ $t('feature.settings.basic.showOrHiddle') }}
</div>
<a-tooltip placement="top" trigger="click">
<template #title>
<span>{{ tipText }}</span>
<template v-if="isWindows">
<br />
<span
style="cursor: pointer; text-decoration: underline"
@click="resetDefault('Alt')"
>
Alt+Space
</span>
<span
style="
cursor: pointer;
margin-left: 8px;
text-decoration: underline;
"
@click="resetDefault('Ctrl')"
>
Ctrl+Space
</span>
</template>
</template>
<div
class="value"
tabIndex="-1"
@keyup="(e) => changeShortCut(e, 'showAndHidden')"
>
{{ shortCut.showAndHidden }}
</div>
</a-tooltip>
</div>
<div class="settings-item-li">
<div class="label">
{{ $t('feature.settings.basic.screenCapture') }}
</div>
<a-tooltip placement="top" trigger="click">
<template #title>
<span>{{ tipText }}</span>
</template>
<div
class="value"
tabIndex="-1"
@keyup="(e) => changeShortCut(e, 'capture')"
>
{{ shortCut.capture }}
</div>
</a-tooltip>
</div>
<!-- <div class="settings-item-li">-->
<!-- <div class="label">插件分离快捷键</div>-->
<!-- <div-->
<!-- class="value"-->
<!-- tabIndex="-1"-->
<!-- @keyup="(e) => changeShortCut(e, 'separate')"-->
<!-- >-->
<!-- {{ shortCut.separate }}-->
<!-- </div>-->
<!-- </div>-->
<!-- <div class="settings-item-li">-->
<!-- <div class="label">返回主界面</div>-->
<!-- <div-->
<!-- class="value"-->
<!-- tabIndex="-1"-->
<!-- @keyup="(e) => changeShortCut(e, 'quit')"-->
<!-- >-->
<!-- {{ shortCut.quit }}-->
<!-- </div>-->
<!-- </div>-->
</div>
<div class="setting-item">
<div class="title">通用</div>
<div class="title">{{ $t('feature.settings.basic.common') }}</div>
<div class="settings-item-li">
<div class="label">输入框自动粘贴</div>
<div class="label">
{{ $t('feature.settings.basic.autoPaste') }}
</div>
<a-switch
v-model:checked="common.autoPast"
checked-children=""
un-checked-children=""
:checked-children="$t('feature.settings.basic.on')"
:un-checked-children="$t('feature.settings.basic.off')"
></a-switch>
</div>
<div class="settings-item-li">
<div class="label">开机启动</div>
<div class="label">{{ $t('feature.settings.basic.autoBoot') }}</div>
<a-switch
v-model:checked="common.start"
checked-children=""
un-checked-children=""
:checked-children="$t('feature.settings.basic.on')"
:un-checked-children="$t('feature.settings.basic.off')"
></a-switch>
</div>
<div class="settings-item-li">
<div class="label">空格执行</div>
<div class="label">
{{ $t('feature.settings.basic.spaceExec') }}
</div>
<a-switch
v-model:checked="common.space"
checked-children=""
un-checked-children=""
:checked-children="$t('feature.settings.basic.on')"
:un-checked-children="$t('feature.settings.basic.off')"
></a-switch>
</div>
</div>
<!-- <div class="setting-item">-->
<!-- <div class="title">本地搜索启动</div>-->
<!-- <div class="settings-item-li">-->
<!-- <div class="label">搜索启动应用&文件</div>-->
<!-- <a-switch-->
<!-- v-model:checked="local.search"-->
<!-- checked-children="开"-->
<!-- un-checked-children="关"-->
<!-- ></a-switch>-->
<!-- </div>-->
<!-- </div>-->
<div class="setting-item">
<div class="title">{{ $t('feature.settings.basic.theme') }}</div>
<div class="settings-item-li">
<div class="label">{{ $t('feature.settings.basic.darkMode') }}</div>
<a-switch
v-model:checked="common.darkMode"
:checked-children="$t('feature.settings.basic.on')"
:un-checked-children="$t('feature.settings.basic.off')"
></a-switch>
</div>
</div>
<div class="setting-item">
<div class="title">{{ $t('feature.settings.basic.language') }}</div>
<div class="settings-item-li">
<div class="label">
{{ $t('feature.settings.basic.changeLang') }}
</div>
<a-select
v-model:value="state.common.lang"
label-in-value
style="width: 240px"
:options="options"
@change="changeLanguage"
></a-select>
</div>
</div>
</div>
<div v-if="currentSelect[0] === 'global'">
<a-collapse>
<a-collapse-panel key="1" header="说明及示例">
<a-collapse-panel
key="1"
:header="$t('feature.settings.global.instructions')"
>
<div>
按下快捷键自动搜索对应关键字当关键字结果完全匹配且结果唯一时会直接指向该功能
{{ $t('feature.settings.global.tips') }}
</div>
<h3 style="margin-top: 10px;">示例</h3>
<a-divider style="margin: 5px 0;" />
<h3 style="margin-top: 10px">
{{ $t('feature.settings.global.example') }}
</h3>
<a-divider style="margin: 5px 0" />
<a-list item-layout="horizontal" :data-source="examples">
<template #renderItem="{ item }">
<a-list-item>
@@ -115,58 +181,78 @@
</a-collapse>
<div class="feature-container">
<div class="keywords item">
<div>快捷键</div>
<a-tooltip placement="top" trigger="click">
<template #title>
<span>先按功能键CtrlShiftAltOptionCommand再按其他普通键或按
F1-F12 单键
</span>
</template>
<div
:key="index"
v-for="(item, index) in global"
class="value"
tabIndex="2"
@keyup="(e) => changeGlobalKey(e, index)"
>
{{ item.key }}
</div>
</a-tooltip>
<div>{{ $t('feature.settings.global.shortcutKey') }}</div>
<template :key="index" v-for="(item, index) in global">
<a-tooltip placement="top" trigger="click">
<template #title>
<span>{{ tipText }}</span>
</template>
<div
class="value"
tabIndex="2"
@keyup="(e) => changeGlobalKey(e, index)"
>
{{ item.key }}
<MinusCircleOutlined
@click.stop="deleteGlobalKey(e, index)"
/>
</div>
</a-tooltip>
</template>
</div>
<div class="short-cut item">
<div>功能关键字</div>
<a-input
:key="index"
:value="item.value"
v-for="(item, index) in global"
class="value"
:disabled="!item.key"
@change="(e) => changeGlobalValue(index, e.target.value)"
/>
<div>{{ $t('feature.settings.global.funtionKey') }}</div>
<template v-for="(item, index) in global" :key="index">
<a-input
:value="item.value"
class="value"
allowClear
:disabled="!item.key"
@change="(e) => changeGlobalValue(index, e.target.value)"
/>
</template>
</div>
</div>
<div @click="addConfig" class="add-global">+ 新增全局快捷功能</div>
<div @click="addConfig" class="add-global">
<PlusCircleOutlined />
{{ $t('feature.settings.global.addShortcutKey') }}
</div>
</div>
<SuperPanel v-if="currentSelect[0] === 'superpanel'" />
<Localhost v-if="currentSelect[0] === 'localhost'" />
</div>
</div>
</template>
<script setup>
import { ToolOutlined, LaptopOutlined } from "@ant-design/icons-vue";
import debounce from "lodash.debounce";
import { ref, reactive, watch, toRefs, toRaw } from "vue";
import keycodes from "./keycode";
import {
ToolOutlined,
LaptopOutlined,
DatabaseOutlined,
MinusCircleOutlined,
PlusCircleOutlined,
FileAddOutlined,
UserOutlined,
} from '@ant-design/icons-vue';
import debounce from 'lodash.debounce';
import { ref, reactive, watch, toRefs, computed, onMounted, toRaw } from 'vue';
import keycodes from './keycode';
import Localhost from './localhost.vue';
import SuperPanel from './super-panel.vue';
import UserInfo from './user-info';
import { useI18n } from 'vue-i18n';
const { locale, t } = useI18n();
const { remote, ipcRenderer } = window.require("electron");
const { remote, ipcRenderer } = window.require('electron');
const examples = [
{
title: "快捷键 「 Alt + W」 关键字 「 微信」",
desc: "按下Alt + W 直接打开本地微信应用",
title: t('feature.settings.global.example1'),
desc: t('feature.settings.global.tips1'),
},
{
title: "快捷键 「 Alt + Q」 关键字 「 取色」",
desc: "按下Alt + Q 直接打开屏幕取色功能",
title: t('feature.settings.global.example2'),
desc: t('feature.settings.global.tips2'),
},
];
@@ -175,135 +261,209 @@ const state = reactive({
common: {},
local: {},
global: [],
custom: {},
});
const currentSelect = ref(["normal"]);
const isWindows = window?.rubick?.isWindows();
const tipText = computed(() => {
const optionKeyName = isWindows ? 'Alt' : 'Option、Command';
return t('feature.settings.global.addShortcutKeyTips', {
optionKeyName: optionKeyName,
});
});
const {perf, global: defaultGlobal} = remote.getGlobal("OP_CONFIG").get();
const currentSelect = ref(['userInfo']);
const { perf, global: defaultGlobal } = remote.getGlobal('OP_CONFIG').get();
state.shortCut = perf.shortCut;
state.custom = perf.custom;
state.common = perf.common;
state.local = perf.local;
state.global = defaultGlobal;
const setConfig = debounce(() => {
remote.getGlobal("OP_CONFIG").set(JSON.parse(JSON.stringify({
perf: {
shortCut: state.shortCut,
common: state.common,
local: state.local,
},
global: state.global,
})));
ipcRenderer.send("re-register");
}, 2000);
remote.getGlobal('OP_CONFIG').set(
JSON.parse(
JSON.stringify({
perf: {
shortCut: state.shortCut,
common: state.common,
local: state.local,
custom: state.custom,
},
global: state.global,
})
)
);
ipcRenderer.send('re-register');
}, 500);
watch(state, setConfig);
const changeShortCut = (e, key) => {
if (e.altKey && e.keyCode !== 18) {
const compose = `Option+${keycodes[e.keyCode].toUpperCase()}`;
state.shortCut[key] = compose;
}
let compose = '';
// 添加是否包含功能键的判断
let incluFuncKeys = false;
if (e.ctrlKey && e.keyCode !== 17) {
const compose = `Ctrl+${keycodes[e.keyCode].toUpperCase()}`;
state.perf.shortCut[key] = compose;
compose += '+Ctrl';
incluFuncKeys = true;
}
if (e.shiftKey && e.keyCode !== 16) {
const compose = `Shift+${keycodes[e.keyCode].toUpperCase()}`;
state.perf.shortCut[key] = compose;
compose += '+Shift';
incluFuncKeys = true;
}
if (e.altKey && e.keyCode !== 18) {
compose += '+Option';
incluFuncKeys = true;
}
if (e.metaKey && e.keyCode !== 93) {
const compose = `Command+${keycodes[e.keyCode].toUpperCase()}`;
state.perf.shortCut[key] = compose;
compose += '+Command';
incluFuncKeys = true;
}
compose += '+' + keycodes[e.keyCode].toUpperCase();
compose = compose.substring(1);
if (
incluFuncKeys &&
e.keyCode !== 16 &&
e.keyCode !== 17 &&
e.keyCode !== 18 &&
e.keyCode !== 93
) {
state.shortCut[key] = compose;
} else {
// 不做处理
}
};
const changeGlobalKey = (e, index) => {
let compose;
if (e.altKey && e.keyCode !== 18) {
compose = `Alt+${keycodes[e.keyCode].toUpperCase()}`;
}
let compose = '';
// 添加是否包含功能键的判断
let incluFuncKeys = false;
if (e.ctrlKey && e.keyCode !== 17) {
compose = `Ctrl+${keycodes[e.keyCode].toUpperCase()}`;
compose += '+Ctrl';
incluFuncKeys = true;
}
if (e.shiftKey && e.keyCode !== 16) {
compose = `Shift+${keycodes[e.keyCode].toUpperCase()}`;
compose += '+Shift';
incluFuncKeys = true;
}
if (e.altKey && e.keyCode !== 18) {
compose += '+Option';
incluFuncKeys = true;
}
if (e.metaKey && e.keyCode !== 93) {
compose = `Command+${keycodes[e.keyCode].toUpperCase()}`;
compose += '+Command';
incluFuncKeys = true;
}
if (compose) {
compose += '+' + keycodes[e.keyCode].toUpperCase();
compose = compose.substring(1);
if (
incluFuncKeys &&
e.keyCode !== 16 &&
e.keyCode !== 17 &&
e.keyCode !== 18 &&
e.keyCode !== 93
) {
state.global[index].key = compose;
} else {
// 不做处理
}
// f1 - f12
if (e.keyCode >= 112 && e.keyCode <= 123) {
if (!incluFuncKeys && e.keyCode >= 112 && e.keyCode <= 123) {
compose = keycodes[e.keyCode].toUpperCase();
}
if (compose) {
state.global[index].key = compose;
}
};
const resetDefault = (key) => {
switch (key) {
case 'Alt':
state.shortCut['showAndHidden'] = 'Option+SPACE';
// copyValue.value = "Option+SPACE";
break;
case 'Ctrl':
state.shortCut['showAndHidden'] = 'Ctrl+SPACE';
// copyValue.value = "Ctrl+SPACE";
break;
default:
break;
}
setConfig();
};
const changeGlobalValue = (index, value) => {
state.global[index].value = value;
}
};
const deleteGlobalKey = (e, index) => {
state.global.splice(index, 1);
// delete state.global[index];
};
const addConfig = () => {
state.global.push({
key: "",
value: "",
key: '',
value: '',
});
};
const {shortCut, common, local, global} = toRefs(state);
const { shortCut, common, local, global } = toRefs(state);
const options = ref([
{
value: 'zh-CN',
label: t('feature.settings.basic.cn'),
},
{
value: 'en-US',
label: t('feature.settings.basic.en'),
},
]);
const changeLanguage = (value) => {
state.common.lang = value.key;
locale.value = value.key;
};
</script>
<style lang="less">
@import '~@/assets/common.less';
.settings {
box-sizing: border-box;
width: 100%;
overflow-x: hidden;
background: #f3efef;
height: calc(~"100vh - 46px");
background: var(--color-body-bg);
height: calc(~'100vh - 46px');
display: flex;
.left-menu {
width: 200px;
height: 100%;
.search-container {
padding: 10px;
}
.ant-input-affix-wrapper {
border: none;
}
.ant-menu {
background: #F3EFEF;
.ant-menu-item-selected {
background-color: #E2E2E2;
color: #141414;
&:after {
display: none;
}
}
}
.ant-menu {
background: var(--color-body-bg) !important;
color: var(--color-text-content) !important;
}
.settings-detail {
padding: 20px;
box-sizing: border-box;
flex: 1;
overflow: auto;
height: 100%;
background: #fff;
background: var(--color-body-bg);
.setting-item {
margin-bottom: 20px;
.ant-form-item {
margin-bottom: 0;
}
.title {
color: #6c9fe2;
color: var(--ant-primary-color);
font-size: 15px;
margin-bottom: 10px;
}
.settings-item-li {
padding-left: 20px;
display: flex;
@@ -311,49 +471,123 @@ const {shortCut, common, local, global} = toRefs(state);
align-items: center;
justify-content: space-between;
margin-bottom: 10px;
.label {
color: #646464;
color: var(--color-text-content);
}
.value {
width: 300px;
cursor: pointer;
text-align: center;
border: 1px solid #ddd;
color: #6c9fe2;
border: 1px solid var(--color-border-light);
color: var(--ant-primary-color);
font-size: 14px;
height: 24px;
font-weight: lighter;
background: var(--color-input-hover);
.ant-input {
text-align: center;
color: var(--ant-primary-color);
font-size: 14px;
font-weight: lighter;
background: var(--color-input-hover);
}
}
.ant-switch {
&:not(.ant-switch-checked) {
background: var(--color-list-hover);
}
}
}
}
}
.feature-container {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 10px;
font-size: 14px;
.item {
flex: 1;
color: var(--color-text-content);
}
.short-cut {
margin-left: 20px;
}
.value {
cursor: pointer;
text-align: center;
border: 1px solid #ddd;
color: #6c9fe2;
border: 1px solid var(--color-border-light);
color: var(--ant-primary-color);
font-size: 14px;
height: 24px;
font-weight: lighter;
margin-top: 10px;
position: relative;
background: var(--color-input-hover);
.ant-input {
color: var(--ant-primary-color);
font-weight: lighter;
background: none;
}
.anticon {
color: var(--color-text-desc);
}
&.ant-input-affix-wrapper {
display: flex;
}
&:hover {
.anticon {
display: block;
color: var(--color-text-content);
}
}
.anticon {
position: absolute;
display: none;
right: 4px;
top: 50%;
transform: translateY(-50%);
}
}
}
.add-global {
color: #6c9fe2;
color: var(--ant-primary-color);
margin-top: 20px;
width: 100%;
text-align: center;
cursor: pointer;
}
.ant-collapse {
background: var(--color-input-hover);
.ant-collapse-content {
background: var(--color-input-hover);
color: var(--color-text-content);
}
h3,
.ant-collapse-header,
.ant-list-item-meta-title {
color: var(--color-text-primary);
}
.ant-list-item-meta-description {
color: var(--color-text-desc);
}
}
}
</style>

View File

@@ -0,0 +1,116 @@
<template>
<a-alert
:message="$t('feature.settings.intranet.tips')"
type="warning"
style="margin-bottom: 20px"
/>
<a-form
name="custom-validation"
ref="formRef"
:model="formState"
:rules="rules"
v-bind="layout"
>
<a-form-item
has-feedback
:label="$t('feature.settings.intranet.npmMirror')"
name="register"
>
<a-input
placeholder="https://registry.npm.taobao.org"
v-model:value="formState.register"
/>
</a-form-item>
<a-form-item
has-feedback
:label="$t('feature.settings.intranet.dbUrl')"
name="database"
>
<a-input
placeholder="https://gitcode.net/rubickcenter/rubick-database/-/raw/master"
v-model:value="formState.database"
/>
</a-form-item>
<a-form-item
has-feedback
:label="$t('feature.settings.intranet.accessToken')"
name="access_token"
>
<a-input
:placeholder="$t('feature.settings.intranet.placeholder')"
v-model:value="formState.access_token"
/>
</a-form-item>
<a-form-item :wrapper-col="{ span: 18, offset: 6 }">
<a-button @click="submit" type="primary">确定</a-button>
<a-button style="margin-left: 10px" @click="resetForm">恢复默认</a-button>
</a-form-item>
</a-form>
</template>
<script lang="ts" setup>
import { ref, toRaw } from 'vue';
import { message } from 'ant-design-vue';
let _rev: any;
let defaultConfig = {
register: 'https://registry.npm.taobao.org',
database: 'https://gitcode.net/rubickcenter/rubick-database/-/raw/master',
access_token: '',
};
try {
const dbdata = window.rubick.db.get('rubick-localhost-config');
defaultConfig = dbdata.data;
_rev = dbdata._rev;
} catch (e) {
// ignore
}
const formState = ref(JSON.parse(JSON.stringify(defaultConfig)));
const rules = {
register: [{ required: true, trigger: 'change' }],
database: [{ required: true, trigger: 'change' }],
};
const layout = {
labelCol: { span: 6 },
wrapperCol: { span: 18 },
};
const resetForm = () => {
formState.value = {
register: 'https://registry.npmmirror.com',
database: 'https://gitcode.net/rubickcenter/rubick-database/-/raw/master',
access_token: '',
};
};
const submit = () => {
const changeData: any = {
_id: 'rubick-localhost-config',
data: toRaw(formState.value),
};
if (_rev) {
changeData._rev = _rev;
}
window.rubick.db.put(changeData);
message.success('设置成功!重启插件市场后生效!');
};
</script>
<style lang="less" scoped>
.ant-form {
:deep(.ant-form-item) {
label {
color: var(--color-text-content);
}
}
}
:deep(.ant-input) {
background: var(--color-input-hover);
color: var(--color-text-content);
}
</style>

View File

@@ -0,0 +1,99 @@
<template>
<p>{{ $t('feature.settings.superPanel.tips') }}</p>
<div class="super-list-item panel-item">
<a-list
:grid="{ gutter: 16, column: 2 }"
:data-source="localPlugins.filter((item) => !!item)"
>
<template #renderItem="{ item }">
<a-list-item v-if="item">
<template #actions>
<a-button
v-if="!hasAdded(item)"
@click="addPluginToSuperPanel(item)"
style="color: #7ec699"
type="text"
>
{{ $t('feature.settings.superPanel.add') }}
</a-button>
<a-button
v-else
@click="removePluginToSuperPanel(item)"
style="color: #ff4ea4"
type="text"
>
{{ $t('feature.settings.superPanel.remove') }}
</a-button>
</template>
<a-list-item-meta>
<template #description>
<span class="ellipse">{{ item.description }}</span>
</template>
<template #title>
<span class="ellipse">{{ item.pluginName }}</span>
</template>
<template #avatar>
<a-avatar :src="item.logo" />
</template>
</a-list-item-meta>
</a-list-item>
</template>
</a-list>
</div>
</template>
<script setup>
import { useStore } from 'vuex';
import { computed, ref, toRaw } from 'vue';
const store = useStore();
const localPlugins = computed(() =>
store.state.localPlugins.filter(
(plugin) =>
plugin.name !== 'rubick-system-feature' &&
plugin.name !== 'rubick-system-super-panel'
)
);
const hasAdded = (plugin) => {
let added = false;
superPanelPlugins.value.data.some((item) => {
if (item.name === plugin.name) {
added = true;
return true;
}
return false;
});
return added;
};
const superPanelPlugins = ref(
window.rubick.db.get('super-panel-db') || {
data: [],
_id: 'super-panel-db',
}
);
const addPluginToSuperPanel = (plugin) => {
superPanelPlugins.value.data.push(toRaw(plugin));
window.rubick.db.put(toRaw(superPanelPlugins.value));
};
const removePluginToSuperPanel = (plugin) => {
superPanelPlugins.value.data = toRaw(superPanelPlugins.value).data.filter(
(item) => {
return item.name !== plugin.name;
}
);
window.rubick.db.put(toRaw(superPanelPlugins.value));
};
</script>
<style lang="less" scoped>
p {
color: var(--color-text-primary);
}
.super-list-item.panel-item {
&:after {
display: none;
}
}
</style>

View File

@@ -0,0 +1,228 @@
<template>
<div class="user-info">
<!-- <div class="info-container">-->
<!-- <a-result-->
<!-- class="user-info-result"-->
<!-- :title="userInfo.name || $t('feature.settings.account.tips1')"-->
<!-- :sub-title="$t('feature.settings.account.tips2')"-->
<!-- >-->
<!-- <template #icon>-->
<!-- <a-avatar :size="64" v-if="!userInfo.avatar">-->
<!-- <template #icon><UserOutlined /></template>-->
<!-- </a-avatar>-->
<!-- <a-avatar :src="userInfo.avatar" :size="64" v-else />-->
<!-- </template>-->
<!-- </a-result>-->
<!-- </div>-->
<div class="settings-container">
<div class="setting-item">
<div class="title">
{{ $t('feature.settings.account.themeColor') }}
</div>
<div class="settings-item-li">
<div class="label">
{{ $t('feature.settings.account.primaryColor') }}
</div>
<a-input v-model:value="custom.primaryColor" class="value">
<template #prefix>
<div
:style="{
background: custom.primaryColor,
width: '10px',
height: '10px',
}"
></div>
</template>
</a-input>
</div>
<div class="settings-item-li">
<div class="label">
{{ $t('feature.settings.account.errorColor') }}
</div>
<a-input v-model:value="custom.errorColor" class="value">
<template #prefix>
<div
:style="{
background: custom.errorColor,
width: '10px',
height: '10px',
}"
></div>
</template>
</a-input>
</div>
<div class="settings-item-li">
<div class="label">
{{ $t('feature.settings.account.warningColor') }}
</div>
<a-input v-model:value="custom.warningColor" class="value">
<template #prefix>
<div
:style="{
background: custom.warningColor,
width: '10px',
height: '10px',
}"
></div>
</template>
</a-input>
</div>
<div class="settings-item-li">
<div class="label">
{{ $t('feature.settings.account.successColor') }}
</div>
<a-input v-model:value="custom.successColor" class="value">
<template #prefix>
<div
:style="{
background: custom.successColor,
width: '10px',
height: '10px',
}"
></div>
</template>
</a-input>
</div>
<div class="settings-item-li">
<div class="label">
{{ $t('feature.settings.account.infoColor') }}
</div>
<a-input v-model:value="custom.infoColor" class="value">
<template #prefix>
<div
:style="{
background: custom.infoColor,
width: '10px',
height: '10px',
}"
></div>
</template>
</a-input>
</div>
</div>
<div class="setting-item">
<div class="title">
{{ $t('feature.settings.account.personalized') }}
</div>
<div class="settings-item-li">
<div class="label">
{{ $t('feature.settings.account.greeting') }}
</div>
<a-input v-model:value="custom.placeholder" class="value"></a-input>
</div>
<div class="settings-item-li">
<div class="label">
{{ $t('feature.settings.account.logo') }}
</div>
<div class="img-container">
<img class="custom-img" :src="custom.logo" />
<a-button @click="changeLogo" size="small" type="link">
{{ $t('feature.settings.account.replace') }}
</a-button>
</div>
</div>
</div>
<div class="footer-btn">
<a-button @click="reset" type="danger">
{{ $t('feature.settings.account.reset') }}
</a-button>
</div>
</div>
</div>
</template>
<script setup>
import { reactive, ref, toRefs, watch } from 'vue';
import { Modal } from 'ant-design-vue';
import { UserOutlined } from '@ant-design/icons-vue';
import debounce from 'lodash.debounce';
import service from '../../assets/service';
const { remote, ipcRenderer } = window.require('electron');
const state = reactive({
custom: {},
});
const { perf } = remote.getGlobal('OP_CONFIG').get();
state.custom = perf.custom || {};
const userInfo = ref(window.rubick.dbStorage.getItem('rubick-user-info'));
service.getUserInfo({ openId: userInfo.value.openId }).then((res) => {
userInfo.value = res;
});
const setConfig = debounce(() => {
remote.getGlobal('OP_CONFIG').set(
JSON.parse(
JSON.stringify({
perf: {
...perf,
custom: state.custom,
},
})
)
);
ipcRenderer.send('re-register');
}, 500);
watch(state, setConfig);
const { custom } = toRefs(state);
const changeLogo = () => {
const [logoPath] = window.rubick.showOpenDialog({
title: '请选择 logo 路径',
filters: [{ name: 'images', extensions: ['png'] }],
properties: ['openFile'],
});
state.custom.logo = `file://${logoPath}`;
};
const reset = () => {
Modal.warning({
title: '确定恢复默认设置吗?',
content: '回复后之前的设置将会被清空',
onOk() {
const defaultcustom = remote.getGlobal('OP_CONFIG').getDefaultConfig()
.perf.custom;
state.custom = JSON.parse(JSON.stringify(defaultcustom));
},
});
};
</script>
<style lang="less">
.settings-container {
margin-top: 18px;
}
.user-info-result {
padding: 0;
&.ant-result {
padding: 24px;
}
.icon {
font-size: 48px;
}
.ant-result-icon {
margin-bottom: 12px;
}
.ant-result-title {
font-size: 18px;
}
}
.img-container {
width: 300px;
}
.custom-img {
width: 60px;
height: 60px;
}
.footer-btn {
text-align: right;
border-top: 1px dashed #ddd;
padding-top: 12px;
}
</style>

View File

@@ -0,0 +1,88 @@
<template>
<div class="account">
<!-- todo 暂时先去掉登录等小程序做好了再加回来吧 -->
<!-- <a-result-->
<!-- v-if="!userInfo"-->
<!-- title="请先登录"-->
<!-- sub-title="登录后可开启用户个性化设置"-->
<!-- >-->
<!-- <template #extra>-->
<!-- <a-button @click="showModal" type="primary">-->
<!-- 使用微信小程序登录-->
<!-- </a-button>-->
<!-- </template>-->
<!-- </a-result>-->
<Index />
<a-modal :footer="null" v-model:visible="visible">
<a-result
title="请使用微信扫码登录!"
sub-title="使用微信扫描上面的 rubick 小程序二维码进行授权登录"
>
<template #icon>
<img width="200" :src="imgCode" />
</template>
</a-result>
</a-modal>
</div>
</template>
<script setup>
import { nanoid } from 'nanoid';
import { ref, watch } from 'vue';
import { message } from 'ant-design-vue';
import Index from './index';
import service from '../../assets/service';
const userInfo = ref(window.rubick.dbStorage.getItem('rubick-user-info'));
const imgCode = ref('');
const scene = nanoid();
const visible = ref(false);
const showModal = () => {
visible.value = true;
if (!imgCode.value && !userInfo.value) {
service.getScanCode({ scene }).then((res) => {
imgCode.value = `data:image/png;base64,${res.dataUrl}`;
});
}
};
let timer = null;
watch([visible], () => {
if (visible.value) {
timer = setInterval(() => {
service.checkLoginStatus({ scene }).then((res) => {
console.log(res);
if (res.openId) {
window.rubick.dbStorage.setItem('rubick-user-info', res);
userInfo.value = res;
message.success('登录成功!');
visible.value = false;
clearInterval(timer);
timer = null;
}
});
}, 2000);
} else {
clearInterval(timer);
timer = null;
}
});
</script>
<style lang="less" scoped>
.account {
box-sizing: border-box;
width: 100%;
overflow-x: hidden;
background: var(--color-body-bg);
height: calc(~'100vh - 46px');
:deep(.ant-result-title) {
color: var(--color-text-primary);
}
:deep(.ant-result-subtitle) {
color: var(--color-text-desc);
}
}
</style>

View File

@@ -1,5 +1,6 @@
{
"compilerOptions": {
"allowJs": true,
"target": "esnext",
"module": "esnext",
"strict": true,

9607
feature/yarn.lock Normal file

File diff suppressed because it is too large Load Diff

23
guide/.gitignore vendored Normal file
View File

@@ -0,0 +1,23 @@
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

24
guide/README.md Normal file
View File

@@ -0,0 +1,24 @@
# guide
## Project setup
```
yarn install
```
### Compiles and hot-reloads for development
```
yarn serve
```
### Compiles and minifies for production
```
yarn build
```
### Lints and fixes files
```
yarn lint
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).

5
guide/babel.config.js Normal file
View File

@@ -0,0 +1,5 @@
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
]
}

19
guide/jsconfig.json Normal file
View File

@@ -0,0 +1,19 @@
{
"compilerOptions": {
"target": "es5",
"module": "esnext",
"baseUrl": "./",
"moduleResolution": "node",
"paths": {
"@/*": [
"src/*"
]
},
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
}
}

43
guide/package.json Normal file
View File

@@ -0,0 +1,43 @@
{
"name": "guide",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve --port 8083",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"core-js": "^3.8.3",
"vue": "^3.2.13"
},
"devDependencies": {
"@babel/core": "^7.12.16",
"@babel/eslint-parser": "^7.12.16",
"@vue/cli-plugin-babel": "~5.0.0",
"@vue/cli-plugin-eslint": "~5.0.0",
"@vue/cli-service": "~5.0.0",
"eslint": "^7.32.0",
"eslint-plugin-vue": "^8.0.3"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/vue3-essential",
"eslint:recommended"
],
"parserOptions": {
"parser": "@babel/eslint-parser"
},
"rules": {}
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead",
"not ie 11"
]
}

BIN
guide/public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

17
guide/public/index.html Normal file
View File

@@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title>rubick 桌面端开源工具箱</title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>

166
guide/src/App.vue Normal file
View File

@@ -0,0 +1,166 @@
<template>
<div class="guide-container">
<div class="step0" v-show="step === 0">
<div class="title">您好我叫 Rubick</div>
<div class="desc">快捷键 <span class="down-line">Alt + R</span> 可以快速打开我</div>
<div class="img-container">
<img class="img" src="./assets/img.png" />
<div class="info">
<svg class="top-icon" focusable="false" aria-hidden="true" viewBox="0 0 24 24" data-testid="NorthIcon"><path d="m5 9 1.41 1.41L11 5.83V22h2V5.83l4.59 4.59L19 9l-7-7-7 7z"></path></svg>
点击 logo 进入插件市场
</div>
</div>
</div>
<div class="step0 step1" v-show="step === 1">
<div class="title">选择需要的插件安装</div>
<div class="desc">基于 <span class="down-line">npm</span> 的插件包管理像小程序一样用完即走</div>
<div class="img-container">
<img class="img" src="./assets/img_1.png" />
</div>
</div>
<div class="step0" v-show="step === 2">
<div class="title"><span class="down-line">关键字</span>搜索应用和插件</div>
<div class="desc">搜索框内输入关键字可以搜索安装的应用和插件</div>
<div class="img-container">
<img class="img" src="./assets/img_2.png" />
</div>
</div>
<div class="step0 step1" v-show="step === 3">
<div class="title">完全开源免费支持内网部署</div>
<div class="desc">进入插件市场的 <span class="down-line">账户与设置</span> 菜单进行内网部署设置</div>
<div class="img-container">
<img class="img" src="./assets/img_3.png" />
</div>
</div>
<div class="footer">
<div></div>
<div class="step">
<span class="step-num">{{ step + 1 }} / 4</span>
<div class="button" @click="netStep">{{ step + 1 === 4 ? '完成' : '下一步' }}</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue';
const step = ref(0);
const { ipcRenderer } = window.require('electron');
const netStep = () => {
if (step.value >= 3) {
return ipcRenderer.send('guide:service', { type: 'close' });
}
step.value = step.value + 1;
}
</script>
<style lang="less">
@text-color: #574777; // 全局主色
@primary-color: #ff4ea4; // 全局主色
* {
margin: 0;
padding: 0;
}
.guide-container {
.step0 {
padding: 28px;
padding-top: 36px;
box-sizing: border-box;
display: flex;
flex-direction: column;
width: 100vw;
height: 100vh;
}
.title {
font-size: 28px;
font-weight: 600;
color: @text-color;
}
.down-line {
line-height: 24px;
color: @primary-color;
}
.desc {
padding-top: 10px;
box-sizing: border-box;
font-size: 24px;
}
.img-container {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.img {
width: 680px;
}
.info {
padding-top: 42px;
margin-right: 178px;
box-sizing: border-box;
width: 100%;
text-align: right;
position: relative;
color: @text-color;
.top-icon {
position: absolute;
right: 0;
top: 0;
user-select: none;
width: 1em;
height: 1em;
display: inline-block;
fill: currentcolor;
flex-shrink: 0;
transition: fill 200ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;
font-size: 1.5rem;
}
}
}
.footer {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
padding: 20px;
box-sizing: border-box;
.step {
display: flex;
align-items: center;
}
.step-num {
margin-right: 20px;
}
.button {
width: 100px;
height: 40px;
line-height: 40px;
background: @primary-color;
color: #fff;
display: flex;
aligin-items: center;
justify-content: center;
border-radius: 4px;
}
}
.step4 {
.img {
width: 300px;
}
}
.step1 {
.img {
width: 550px;
}
}
</style>

BIN
guide/src/assets/bg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

BIN
guide/src/assets/img.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
guide/src/assets/img_1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

BIN
guide/src/assets/img_2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

BIN
guide/src/assets/img_3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

BIN
guide/src/assets/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

4
guide/src/main.js Normal file
View File

@@ -0,0 +1,4 @@
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')

16
guide/vue.config.js Normal file
View File

@@ -0,0 +1,16 @@
const path = require('path');
module.exports = {
css: {
// 配置css模块
loaderOptions: {
// 向预处理器 Loader 传递配置选项
less: {
// 配置less其他样式解析用法一致
javascriptEnabled: true, // 设置为true
},
},
},
outputDir: path.join(__dirname, '../public/guide'),
publicPath: process.env.NODE_ENV === 'production' ? '' : '/',
};

6168
guide/yarn.lock Normal file

File diff suppressed because it is too large Load Diff

20388
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,7 @@
{
"name": "rubick",
"version": "2.0.1-beta.10",
"version": "2.4.4",
"author": "muwoo <2424880409@qq.com>",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
@@ -14,17 +15,22 @@
"postuninstall": "electron-builder install-app-deps"
},
"main": "background.js",
"optionalDependencies": {
"electron-clipboard-ex": "^1.3.3"
},
"dependencies": {
"@better-scroll/core": "^2.4.2",
"ant-design-vue": "^2.2.8",
"ant-design-vue": "3.2.14",
"axios": "^1.3.4",
"core-js": "^3.6.5",
"cross-spawn": "^7.0.3",
"electron-updater": "^4.6.5",
"extract-file-icon": "^0.3.2",
"fix-path": "^3.0.0",
"get-mac-apps": "^1.0.2",
"got": "^11.8.3",
"libnpmsearch": "^3.1.2",
"lodash.throttle": "^4.1.1",
"node-key-sender": "^1.0.11",
"pouchdb": "^7.2.2",
"vue": "^3.0.0",
"vue-router": "^4.0.0-0",
@@ -45,18 +51,21 @@
"@vue/compiler-sfc": "^3.0.0",
"@vue/eslint-config-prettier": "^6.0.0",
"@vue/eslint-config-typescript": "^7.0.0",
"babel-plugin-import": "^1.13.3",
"electron": "^13.0.0",
"electron-builder": "22.13.1",
"electron-devtools-installer": "^3.1.0",
"eslint": "^6.7.2",
"eslint-plugin-prettier": "^3.3.1",
"eslint-plugin-vue": "^7.0.0",
"less": "^3.0.4",
"less-loader": "^5.0.0",
"prettier": "^2.2.1",
"prettier": "^2.8.4",
"typescript": "~4.1.5",
"vue-cli-plugin-electron-builder": "~2.1.1",
"worker-plugin": "^5.0.1",
"electron-builder": "22.13.1"
"worker-plugin": "^5.0.1"
},
"__npminstall_done": false
"resolutions": {
"vue-cli-plugin-electron-builder/electron-builder": "^23.0.3"
}
}

Some files were not shown because too many files have changed in this diff Show More