Compare commits

...

23 Commits

Author SHA1 Message Date
木偶
8fe916020b Merge pull request #232 from rubickCenter/feat/v3.0.0
🐛 修复 windows 本地启动呼起问题
2023-09-18 10:37:16 +08:00
muwoo
d442fae447 🐛 修复 windows 本地启动呼起问题 2023-09-18 10:35:51 +08:00
木偶
9a3ca8403b Merge pull request #230 from rubickCenter/feat/v3.0.0
Feat/v3.0.0
2023-09-16 11:35:18 +08:00
muwoo
96f53e3b40 优化拼音搜索 #174,#67,#114,#61,#16 2023-09-16 11:34:34 +08:00
muwoo
b06df01527 🔖 release v3.1.0 2023-09-16 10:27:34 +08:00
muwoo
c7eb266002 支持窗口记忆#216;支持本地启动;支持搜索历史记录 2023-09-16 10:16:22 +08:00
木偶
9b303aa5c7 Merge pull request #225 from cc01cc/docs-url-fix-01
修复 404 链接 /rubick/blob/master/static/preload.js#L49
2023-09-16 09:52:34 +08:00
木偶
aa059b2596 Merge pull request #226 from cc01cc/docs-fix-url-02
更新 contributing 链接
2023-09-16 09:52:00 +08:00
muwoo
c21c08c370 支持本地启动,修改mac 下获取 APP icon 的方式 2023-09-15 16:17:52 +08:00
cc01cc
b3c5d30bfb fix-url 2023-09-13 21:59:09 +08:00
cc01cc
2255cb783f 修复 404 链接 2023-09-13 21:43:26 +08:00
木偶
ecb6b6bc29 Merge pull request #222 from rubickCenter/feat/v3.0.0
🐛 修复 #221 & 性能优化,支持插件窗口池
2023-09-13 14:31:28 +08:00
muwoo
61b4e37fe0 🐛 修复 #221 & 性能优化,支持插件窗口池 2023-09-13 14:29:06 +08:00
木偶
25dd314042 Merge pull request #218 from rubickCenter/feat/v3.0.0
Feat/v3.0.0
2023-09-01 18:00:22 +08:00
muwoo
6dffd1a793 🐛 修复部分问题 2023-09-01 17:56:16 +08:00
muwoo
f4f91e1639 ♻️ 修改系统设置存储方式 2023-08-22 17:41:51 +08:00
muwoo
d2d94c13b7 ⬆️ 升级 electron 到 26 2023-08-22 13:52:47 +08:00
muwoo
6e5a08b9d8 merge master 2023-08-22 10:09:52 +08:00
木偶
5080f23ef9 Update README.zh-CN.md 2023-08-21 11:19:18 +08:00
木偶
d96fbd99ec Update README.md 2023-08-21 11:18:53 +08:00
王伟
bd871a1320 fix: 修复账户问题&替换windows截图工具 2023-08-19 11:20:13 +08:00
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
74 changed files with 1248 additions and 576 deletions

View File

@@ -54,6 +54,8 @@ Based on electron open source toolbox, free integration of rich plug-ins, to cre
## Docs
[Rubick website](https://rubick.vip)
[Rubick Docs](https://rubickCenter.github.io/rubick/)
@@ -86,7 +88,7 @@ If you need more features, please come here to give us suggestions[issues](ht
We will add valuable ideas to the later development. At the same time, welcome to join and build together。
## 贡献
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>
This project exists thanks to all the people who contribute. [[Contribute](https://github.com/rubickCenter/rubick/graphs/contributors)]. <a href="https://github.com/rubickCenter/rubick/graphs/contributors"><img src="https://opencollective.com/rubick/contributors.svg?width=890&button=false" /></a>
## 反馈
对本项目有兴趣或者想要交流学习的同学可以扫码加下面的微信,备注 rubick帮助我们更好的成长

View File

@@ -54,6 +54,8 @@
## 使用文档
[Rubick 官网](https://rubick.vip)
[Rubick Docs](https://rubickCenter.github.io/rubick/)
@@ -86,7 +88,7 @@
有价值的想法我们会加入到后期的开发当中。同时也欢迎一起加入共建。
## 贡献
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>
This project exists thanks to all the people who contribute. [[Contribute](https://github.com/rubickCenter/rubick/graphs/contributors)]. <a href="https://github.com/rubickCenter/rubick/graphs/contributors"><img src="https://opencollective.com/rubick/contributors.svg?width=890&button=false" /></a>
## 反馈
对本项目有兴趣或者想要交流学习的同学可以扫码加下面的微信,备注 rubick帮助我们更好的成长

View File

@@ -80,7 +80,7 @@ window.showNotification = function () {
rubick.showNotification('HI, rubick')
}
```
rubick 更多支持 API 能力参考:[rubick 全局API](https://github.com/rubickCenter/rubick/blob/master/static/preload.js#L49)
rubick 更多支持 API 能力参考:[rubick 全局API](https://github.com/rubickCenter/rubick/blob/master/public/preload.js)
### 测试写好的插件
由于 `rubick` 插件是基于 `npm` 的管理方式,所以开发者调试插件,也是基于 `npm` 的软连接的方式进行调试。

View File

@@ -1,28 +1,28 @@
{
"name": "rubick-system-feature",
"pluginName": "rubick 系统菜单",
"description": "rubick 系统菜单",
"pluginName": "系统菜单",
"description": "系统菜单",
"main": "index.html",
"logo": "https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/acb761082f4a4b46847e7cd8b180f63c~tplv-k3u1fbpfcp-watermark.image",
"logo": "https://pic1.zhimg.com/80/v2-c09780808301668a82e6646cb42f0806_720w.png",
"version": "0.0.0",
"preload":"preload.js",
"pluginType": "ui",
"features": [
{
"code": "market",
"explain": "rubick 插件市场",
"explain": "插件市场",
"cmds":[
"插件市场"
]
},{
"code": "installed",
"explain": "rubick 已安装插件",
"explain": "已安装插件",
"cmds":[
"已安装插件"
]
},{
"code": "settings",
"explain": "rubick 偏好设置",
"explain": "偏好设置",
"cmds":[
"偏好设置"
]

View File

@@ -1,16 +1,39 @@
const {remote} = require("electron");
const remote = require('@electron/remote');
const { ipcRenderer } = require('electron');
const ipcSendSync = (type, data) => {
const returnValue = ipcRenderer.sendSync('msg-trigger', {
type,
data,
});
if (returnValue instanceof Error) throw returnValue;
return returnValue;
};
const ipcSend = (type, data) => {
ipcRenderer.send('msg-trigger', {
type,
data,
});
};
window.market = {
getLocalPlugins() {
return remote.getGlobal("LOCAL_PLUGINS").getLocalPlugins();
return remote.getGlobal('LOCAL_PLUGINS').getLocalPlugins();
},
downloadPlugin(plugin) {
return remote.getGlobal("LOCAL_PLUGINS").downloadPlugin(plugin);
return remote.getGlobal('LOCAL_PLUGINS').downloadPlugin(plugin);
},
deletePlugin(plugin) {
return remote.getGlobal("LOCAL_PLUGINS").deletePlugin(plugin);
return remote.getGlobal('LOCAL_PLUGINS').deletePlugin(plugin);
},
refreshPlugin(plugin) {
return remote.getGlobal("LOCAL_PLUGINS").refreshPlugin(plugin);
return remote.getGlobal('LOCAL_PLUGINS').refreshPlugin(plugin);
},
addLocalStartPlugin(plugin) {
ipcSend('addLocalStartPlugin', { plugin });
},
removeLocalStartPlugin(plugin) {
ipcSend('removeLocalStartPlugin', { plugin });
},
};

View File

@@ -69,6 +69,7 @@ init();
}
.main-container {
-webkit-app-region: no-drag;
display: flex;
align-items: flex-start;
background: var(--color-body-bg);

22
feature/src/confOp.ts Normal file
View File

@@ -0,0 +1,22 @@
const LOCAL_CONFIG_KEY = 'rubick-local-config';
const localConfig = {
getConfig(): Promise<any> {
const data: any = window.rubick.db.get(LOCAL_CONFIG_KEY) || {};
return data.data;
},
setConfig(data: any) {
const localConfig: any = window.rubick.db.get(LOCAL_CONFIG_KEY) || {};
window.rubick.db.put({
_id: LOCAL_CONFIG_KEY,
_rev: localConfig._rev,
data: {
...localConfig.data,
...data,
},
});
},
};
export default localConfig;

View File

@@ -1,10 +1,7 @@
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);
import localConfig from '@/confOp';
const { perf }: any = localConfig.getConfig();
// 2. Create i18n instance with options
const i18n = createI18n({

View File

@@ -96,6 +96,9 @@ export default {
accessToken: 'access token',
placeholder: 'required for private network gitlab warehouse',
},
localstart: {
title: 'Local Start',
},
},
dev: {
title: 'Developer',

View File

@@ -94,6 +94,9 @@ export default {
accessToken: 'access token',
placeholder: '内网gitlab仓库必填',
},
localstart: {
title: '本地启动',
},
},
dev: {
title: '开发者',

View File

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

View File

@@ -94,7 +94,7 @@
:title="$t('feature.installed.removeFromPanel')"
>
<MinusCircleOutlined
@click="removePluginToSuperPanel(cmd)"
@click="removePluginToSuperPanel({ cmd })"
/>
</a-tooltip>
</template>
@@ -121,11 +121,11 @@ import { message } from 'ant-design-vue';
const { ipcRenderer } = window.require('electron');
const { remote } = window.require('electron');
const remote = window.require('@electron/remote');
const fs = window.require('fs');
const md = new MarkdownIt();
const appPath = remote.app.getPath('cache');
const appPath = remote.app.getPath('userData');
const baseDir = path.join(appPath, './rubick-plugins');
const store = useStore();
@@ -145,9 +145,9 @@ const pluginDetail = computed(() => {
});
const superPanelPlugins = ref(
window.rubick.db.get('super-panel-plugins') || {
window.rubick.db.get('super-panel-user-plugins') || {
data: [],
_id: 'super-panel-plugins',
_id: 'super-panel-user-plugins',
}
);
@@ -165,13 +165,13 @@ const addCmdToSuperPanel = ({ cmd, code }) => {
window.rubick.db.put(toRaw(superPanelPlugins.value));
};
const removePluginToSuperPanel = (cmd) => {
const removePluginToSuperPanel = ({ cmd, name }) => {
superPanelPlugins.value.data = toRaw(superPanelPlugins.value).data.filter(
(item) => {
if (name) return item.name !== name;
return item.cmd !== cmd;
}
);
console.log(toRaw(superPanelPlugins.value));
window.rubick.db.put(toRaw(superPanelPlugins.value));
};
@@ -209,7 +209,7 @@ const readme = computed(() => {
baseDir,
'node_modules',
pluginDetail.value.name,
'readme.md'
'README.md'
);
if (fs.existsSync(readmePath)) {
const str = fs.readFileSync(readmePath, 'utf-8');
@@ -225,9 +225,12 @@ const deletePlugin = async (plugin) => {
message.error('卸载超时,请重试!');
}, 20000);
await window.market.deletePlugin(plugin);
removePluginToSuperPanel({ name: plugin.name });
updateLocalPlugin();
clearTimeout(timer);
};
</script>
<style lang="less" scoped>

View File

@@ -14,18 +14,24 @@
</template>
{{ $t('feature.settings.basic.title') }}
</a-menu-item>
<a-menu-item key="localstart">
<template #icon>
<FolderOpenOutlined />
</template>
{{ $t('feature.settings.localstart.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="superpanel">-->
<!-- <template #icon>-->
<!-- <FileAddOutlined />-->
<!-- </template>-->
<!-- {{ $t('feature.settings.superPanel.title') }}-->
<!-- </a-menu-item>-->
<a-menu-item key="localhost">
<template #icon>
<DatabaseOutlined />
@@ -220,6 +226,7 @@
</div>
<SuperPanel v-if="currentSelect[0] === 'superpanel'" />
<Localhost v-if="currentSelect[0] === 'localhost'" />
<LocalStart v-if="currentSelect[0] === 'localstart'" />
</div>
</div>
</template>
@@ -231,19 +238,22 @@ import {
DatabaseOutlined,
MinusCircleOutlined,
PlusCircleOutlined,
FileAddOutlined,
UserOutlined,
FolderOpenOutlined,
} from '@ant-design/icons-vue';
import debounce from 'lodash.debounce';
import { ref, reactive, watch, toRefs, computed, onMounted, toRaw } from 'vue';
import { ref, reactive, watch, toRefs, computed } from 'vue';
import keycodes from './keycode';
import Localhost from './localhost.vue';
import SuperPanel from './super-panel.vue';
import UserInfo from './user-info';
import LocalStart from './local-start';
import { useI18n } from 'vue-i18n';
import localConfig from '@/confOp';
const { locale, t } = useI18n();
const { remote, ipcRenderer } = window.require('electron');
const { ipcRenderer } = window.require('electron');
const examples = [
{
@@ -274,7 +284,7 @@ const tipText = computed(() => {
const currentSelect = ref(['userInfo']);
const { perf, global: defaultGlobal } = remote.getGlobal('OP_CONFIG').get();
const { perf, global: defaultGlobal } = localConfig.getConfig();
state.shortCut = perf.shortCut;
state.custom = perf.custom;
@@ -283,7 +293,7 @@ state.local = perf.local;
state.global = defaultGlobal;
const setConfig = debounce(() => {
remote.getGlobal('OP_CONFIG').set(
localConfig.setConfig(
JSON.parse(
JSON.stringify({
perf: {

View File

@@ -0,0 +1,112 @@
<template>
<div class="file-container" @drop.prevent="dropFile" @dragenter="checkDrop" @dragover="checkDrop">
<a-alert message="可拖放文件夹到这里加入启动" type="info" show-icon />
<a-list item-layout="horizontal" :data-source="localStartList">
<template #renderItem="{ item }">
<a-list-item>
<template #actions>
<a key="list-loadmore-edit" @click="() => remove(item)">移除</a>
</template>
<a-list-item-meta :description="item.desc">
<template #title>
<div>
<span :class="item.del ? 'del-title' : ''">{{item.name}}</span>
<span v-if="item.del" class="has-del">文件不存在</span>
</div>
</template>
<template #avatar>
<a-avatar shape="square" :src="item.icon" />
</template>
</a-list-item-meta>
</a-list-item>
</template>
</a-list>
</div>
</template>
<script setup>
import { ref } from 'vue';
const fs = window.require('fs');
const process = window.require('process');
const dbId = 'rubick-local-start-app';
const localStartList = ref(window.rubick.dbStorage.getItem(dbId) || []);
const checkFileExists = () => {
localStartList.value = localStartList.value.map((plugin) => {
if (!fs.existsSync(plugin.desc)) {
return {
...plugin,
del: true,
};
}
return plugin;
});
};
checkFileExists();
const dropFile = (e) => {
const files = Array.from(e.dataTransfer.files).map((file) => {
const action =
process.platform === 'win32'
? `start "dummyclient" "${file.path}"`
: `open ${file.path.replace(/ /g, '\\ ')}`;
const plugin = {
icon: window.rubick.getFileIcon(file.path),
value: 'plugin',
desc: file.path,
pluginType: 'app',
name: file.name,
action,
keyWords: [file.name],
names: [file.name],
};
window.market.addLocalStartPlugin(plugin);
return plugin;
});
localStartList.value = [
...localStartList.value,
...files,
];
window.rubick.dbStorage.setItem(
dbId,
JSON.parse(JSON.stringify(localStartList.value))
);
};
const remove = (item) => {
localStartList.value = localStartList.value.filter(
(app) => app.desc !== item.desc
);
window.rubick.dbStorage.setItem(
dbId,
JSON.parse(JSON.stringify(localStartList.value))
);
window.market.removeLocalStartPlugin(JSON.parse(JSON.stringify(item)));
};
const checkDrop = (e) => {
e.preventDefault();
};
</script>
<style lang="less">
.file-container {
box-sizing: border-box;
width: 100%;
overflow-x: hidden;
background: var(--color-body-bg);
height: calc(~'100vh - 106px');
.del-title {
text-decoration-line: line-through;
text-decoration-color: var(--ant-error-color);
}
.has-del {
color: var(--ant-error-color);
font-size: 12px;
margin-left: 6px;
}
}
</style>

View File

@@ -80,7 +80,7 @@ const layout = {
const resetForm = () => {
formState.value = {
register: 'https://registry.npm.taobao.org',
register: 'https://registry.npmmirror.com',
database: 'https://gitcode.net/rubickcenter/rubick-database/-/raw/master',
access_token: '',
};

View File

@@ -1,19 +1,19 @@
<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="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">
@@ -122,41 +122,40 @@
</div>
</div>
</div>
<div class="footer-btn">
<a-button @click="reset" type="danger">
{{ $t('feature.settings.account.reset') }}
</a-button>
</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 localConfig from '@/confOp';
import service from '../../assets/service';
const { remote, ipcRenderer } = window.require('electron');
const { ipcRenderer } = window.require('electron');
const state = reactive({
custom: {},
});
const { perf } = remote.getGlobal('OP_CONFIG').get();
const { perf } = localConfig.getConfig();
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;
});
// service.getUserInfo({ openId: userInfo.value.openId }).then((res) => {
// userInfo.value = res;
// });
const setConfig = debounce(() => {
remote.getGlobal('OP_CONFIG').set(
localConfig.setConfig(
JSON.parse(
JSON.stringify({
perf: {
@@ -181,17 +180,17 @@ const changeLogo = () => {
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));
},
});
};
// 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">

View File

@@ -1,17 +1,18 @@
<template>
<div class="account">
<a-result
v-if="!userInfo"
title="请先登录"
sub-title="登录后可开启用户个性化设置"
>
<template #extra>
<a-button @click="showModal" type="primary">
使用微信小程序登录
</a-button>
</template>
</a-result>
<Index v-else />
<!-- 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="请使用微信扫码登录!"

View File

@@ -3,7 +3,7 @@
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve --port 8083",
"serve": "vue-cli-service serve --port 8084",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},

View File

@@ -1,6 +1,6 @@
{
"name": "rubick",
"version": "2.4.2",
"version": "3.1.1",
"author": "muwoo <2424880409@qq.com>",
"private": true,
"scripts": {
@@ -20,6 +20,7 @@
},
"dependencies": {
"@better-scroll/core": "^2.4.2",
"@electron/remote": "^2.0.10",
"ant-design-vue": "3.2.14",
"axios": "^1.3.4",
"core-js": "^3.6.5",
@@ -31,7 +32,9 @@
"got": "^11.8.3",
"lodash.throttle": "^4.1.1",
"node-key-sender": "^1.0.11",
"pinyin-match": "^1.2.4",
"pouchdb": "^7.2.2",
"simple-plist": "0.2.1",
"vue": "^3.0.0",
"vue-router": "^4.0.0-0",
"vuex": "^4.0.0-0",
@@ -52,7 +55,7 @@
"@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": "26.0.0",
"electron-builder": "22.13.1",
"electron-devtools-installer": "^3.1.0",
"eslint": "^6.7.2",

Binary file not shown.

Binary file not shown.

BIN
public/ScreenCapture.exe Normal file

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
<!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"><link rel="icon" href="favicon.ico"><title>feature</title><link href="css/app.518884da.css" rel="preload" as="style"><link href="css/chunk-vendors.7f9dcb72.css" rel="preload" as="style"><link href="js/app.e81c0c2f.js" rel="preload" as="script"><link href="js/chunk-vendors.cc39b888.js" rel="preload" as="script"><link href="css/chunk-vendors.7f9dcb72.css" rel="stylesheet"><link href="css/app.518884da.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but feature doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script src="js/chunk-vendors.cc39b888.js"></script><script src="js/app.e81c0c2f.js"></script></body></html>
<!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"><link rel="icon" href="favicon.ico"><title>feature</title><link href="css/app.4e3502cb.css" rel="preload" as="style"><link href="css/chunk-vendors.7f9dcb72.css" rel="preload" as="style"><link href="js/app.5fe607e9.js" rel="preload" as="script"><link href="js/chunk-vendors.73a23bae.js" rel="preload" as="script"><link href="css/chunk-vendors.7f9dcb72.css" rel="stylesheet"><link href="css/app.4e3502cb.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but feature doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script src="js/chunk-vendors.73a23bae.js"></script><script src="js/app.5fe607e9.js"></script></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,28 +1,28 @@
{
"name": "rubick-system-feature",
"pluginName": "rubick 系统菜单",
"description": "rubick 系统菜单",
"pluginName": "系统菜单",
"description": "系统菜单",
"main": "index.html",
"logo": "https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/acb761082f4a4b46847e7cd8b180f63c~tplv-k3u1fbpfcp-watermark.image",
"logo": "https://pic1.zhimg.com/80/v2-c09780808301668a82e6646cb42f0806_720w.png",
"version": "0.0.0",
"preload":"preload.js",
"pluginType": "ui",
"features": [
{
"code": "market",
"explain": "rubick 插件市场",
"explain": "插件市场",
"cmds":[
"插件市场"
]
},{
"code": "installed",
"explain": "rubick 已安装插件",
"explain": "已安装插件",
"cmds":[
"已安装插件"
]
},{
"code": "settings",
"explain": "rubick 偏好设置",
"explain": "偏好设置",
"cmds":[
"偏好设置"
]

View File

@@ -1,16 +1,39 @@
const {remote} = require("electron");
const remote = require('@electron/remote');
const { ipcRenderer } = require('electron');
const ipcSendSync = (type, data) => {
const returnValue = ipcRenderer.sendSync('msg-trigger', {
type,
data,
});
if (returnValue instanceof Error) throw returnValue;
return returnValue;
};
const ipcSend = (type, data) => {
ipcRenderer.send('msg-trigger', {
type,
data,
});
};
window.market = {
getLocalPlugins() {
return remote.getGlobal("LOCAL_PLUGINS").getLocalPlugins();
return remote.getGlobal('LOCAL_PLUGINS').getLocalPlugins();
},
downloadPlugin(plugin) {
return remote.getGlobal("LOCAL_PLUGINS").downloadPlugin(plugin);
return remote.getGlobal('LOCAL_PLUGINS').downloadPlugin(plugin);
},
deletePlugin(plugin) {
return remote.getGlobal("LOCAL_PLUGINS").deletePlugin(plugin);
return remote.getGlobal('LOCAL_PLUGINS').deletePlugin(plugin);
},
refreshPlugin(plugin) {
return remote.getGlobal("LOCAL_PLUGINS").refreshPlugin(plugin);
return remote.getGlobal('LOCAL_PLUGINS').refreshPlugin(plugin);
},
addLocalStartPlugin(plugin) {
ipcSend('addLocalStartPlugin', { plugin });
},
removeLocalStartPlugin(plugin) {
ipcSend('removeLocalStartPlugin', { plugin });
},
};

View File

@@ -1,5 +1,5 @@
export default {
version: 12,
version: 0,
perf: {
custom: {
primaryColor: '#ff4ea4',

View File

@@ -1,89 +1,86 @@
import { app } from "electron";
import path from "path";
import { app } from 'electron';
import path from 'path';
const appPath = app.getPath("cache");
const appPath = app.getPath('userData');
console.log(appPath);
const PLUGIN_INSTALL_DIR = path.join(appPath, "./rubick-plugins");
const PLUGIN_INSTALL_DIR = path.join(appPath, './rubick-plugins');
const DECODE_KEY = {
Backspace: "Backspace",
Tab: "Tab",
Enter: "Enter",
MediaPlayPause: "MediaPlayPause",
Escape: "Escape",
Space: "Space",
PageUp: "PageUp",
PageDown: "PageDown",
End: "End",
Home: "Home",
ArrowLeft: "Left",
ArrowUp: "Up",
ArrowRight: "Right",
ArrowDown: "Down",
PrintScreen: "PrintScreen",
Insert: "Insert",
Delete: "Delete",
Digit0: "0",
Digit1: "1",
Digit2: "2",
Digit3: "3",
Digit4: "4",
Digit5: "5",
Digit6: "6",
Digit7: "7",
Digit8: "8",
Digit9: "9",
KeyA: "A",
KeyB: "B",
KeyC: "C",
KeyD: "D",
KeyE: "E",
KeyF: "F",
KeyG: "G",
KeyH: "H",
KeyI: "I",
KeyJ: "J",
KeyK: "K",
KeyL: "L",
KeyM: "M",
KeyN: "N",
KeyO: "O",
KeyP: "P",
KeyQ: "Q",
KeyR: "R",
KeyS: "S",
KeyT: "T",
KeyU: "U",
KeyV: "V",
KeyW: "W",
KeyX: "X",
KeyY: "Y",
KeyZ: "Z",
F1: "F1",
F2: "F2",
F3: "F3",
F4: "F4",
F5: "F5",
F6: "F6",
F7: "F7",
F8: "F8",
F9: "F9",
F10: "F10",
F11: "F11",
F12: "F12",
Semicolon: ";",
Equal: "=",
Comma: ",",
Minus: "-",
Period: ".",
Slash: "/",
Backquote: "`",
BracketLeft: "[",
Backslash: "\\",
BracketRight: "]",
Backspace: 'Backspace',
Tab: 'Tab',
Enter: 'Enter',
MediaPlayPause: 'MediaPlayPause',
Escape: 'Escape',
Space: 'Space',
PageUp: 'PageUp',
PageDown: 'PageDown',
End: 'End',
Home: 'Home',
ArrowLeft: 'Left',
ArrowUp: 'Up',
ArrowRight: 'Right',
ArrowDown: 'Down',
PrintScreen: 'PrintScreen',
Insert: 'Insert',
Delete: 'Delete',
Digit0: '0',
Digit1: '1',
Digit2: '2',
Digit3: '3',
Digit4: '4',
Digit5: '5',
Digit6: '6',
Digit7: '7',
Digit8: '8',
Digit9: '9',
KeyA: 'A',
KeyB: 'B',
KeyC: 'C',
KeyD: 'D',
KeyE: 'E',
KeyF: 'F',
KeyG: 'G',
KeyH: 'H',
KeyI: 'I',
KeyJ: 'J',
KeyK: 'K',
KeyL: 'L',
KeyM: 'M',
KeyN: 'N',
KeyO: 'O',
KeyP: 'P',
KeyQ: 'Q',
KeyR: 'R',
KeyS: 'S',
KeyT: 'T',
KeyU: 'U',
KeyV: 'V',
KeyW: 'W',
KeyX: 'X',
KeyY: 'Y',
KeyZ: 'Z',
F1: 'F1',
F2: 'F2',
F3: 'F3',
F4: 'F4',
F5: 'F5',
F6: 'F6',
F7: 'F7',
F8: 'F8',
F9: 'F9',
F10: 'F10',
F11: 'F11',
F12: 'F12',
Semicolon: ';',
Equal: '=',
Comma: ',',
Minus: '-',
Period: '.',
Slash: '/',
Backquote: '`',
BracketLeft: '[',
Backslash: '\\',
BracketRight: ']',
Quote: "'",
};

View File

@@ -1,8 +1,8 @@
import { remote } from "electron";
import path from "path";
import { app } from '@electron/remote';
import path from 'path';
const appPath = remote.app.getPath("cache");
const appPath = app.getPath('userData');
const PLUGIN_INSTALL_DIR = path.join(appPath, "./rubick-plugins");
const PLUGIN_INSTALL_DIR = path.join(appPath, './rubick-plugins');
export { PLUGIN_INSTALL_DIR };

View File

@@ -1,17 +1,17 @@
export default {
linux(): boolean {
return process.platform === "linux";
return process.platform === 'linux';
},
macOS(): boolean {
return process.platform === "darwin";
return process.platform === 'darwin';
},
windows(): boolean {
return process.platform === "win32";
return process.platform === 'win32';
},
production(): boolean {
return process.env.NODE_ENV !== "development";
return process.env.NODE_ENV !== 'development';
},
dev(): boolean {
return process.env.NODE_ENV === "development";
return process.env.NODE_ENV === 'development';
},
};

View File

@@ -1,5 +1,4 @@
import { ipcRenderer } from 'electron';
import commonConst from './commonConst';
const useDrag = () => {
let animationId: number;
@@ -10,7 +9,7 @@ const useDrag = () => {
let draggable = true;
const onMouseDown = (e) => {
if (commonConst.macOS()) return;
// if (commonConst.macOS()) return;
draggable = true;
mouseX = e.clientX;
mouseY = e.clientY;

View File

@@ -1,33 +1,33 @@
import commonConst from "./commonConst";
import { clipboard, remote } from "electron";
import plist from "plist";
import fs from "fs";
import path from "path";
import ofs from "original-fs";
import commonConst from './commonConst';
import { clipboard } from 'electron';
import plist from 'plist';
import fs from 'fs';
import path from 'path';
import ofs from 'original-fs';
export default function getCopyFiles(): Array<any> | null {
let fileInfo;
if (commonConst.macOS()) {
if (!clipboard.has("NSFilenamesPboardType")) return null;
const result = clipboard.read("NSFilenamesPboardType");
if (!clipboard.has('NSFilenamesPboardType')) return null;
const result = clipboard.read('NSFilenamesPboardType');
if (!result) return null;
try {
fileInfo = plist.parse(result);
} catch (e) {
return null;
}
} else if (process.platform === "win32") {
} else if (process.platform === 'win32') {
/* eslint-disable */
const clipboardEx = require("electron-clipboard-ex");
const clipboardEx = require('electron-clipboard-ex');
fileInfo = clipboardEx.readFilePaths();
// todo
} else {
if (!commonConst.linux()) return null;
if (!clipboard.has("text/uri-list")) return null;
const result = clipboard.read("text/uri-list").match(/^file:\/\/\/.*/gm);
if (!clipboard.has('text/uri-list')) return null;
const result = clipboard.read('text/uri-list').match(/^file:\/\/\/.*/gm);
if (!result || !result.length) return null;
fileInfo = result.map((e) =>
decodeURIComponent(e).replace(/^file:\/\//, "")
decodeURIComponent(e).replace(/^file:\/\//, '')
);
}
if (!Array.isArray(fileInfo)) return null;

View File

@@ -1,12 +1,12 @@
import path from "path";
import fs from "fs";
import path from 'path';
import fs from 'fs';
export default (): string => {
let localDataFile: any = process.env.HOME;
if (!localDataFile) {
localDataFile = process.env.LOCALAPPDATA;
}
const rubickPath = path.join(localDataFile, "rubick");
const rubickPath = path.join(localDataFile, 'rubick');
if (!fs.existsSync(rubickPath)) {
fs.mkdirSync(rubickPath);
}

View File

@@ -1,12 +1,14 @@
const WINDOW_MAX_HEIGHT = 600;
const WINDOW_MIN_HEIGHT = 60;
const PRE_ITEM_HEIGHT = 60;
const HISTORY_HEIGHT = 80;
export default (searchList: Array<any>): number => {
if (!searchList) return WINDOW_MAX_HEIGHT;
if (!searchList.length) return WINDOW_MIN_HEIGHT;
return searchList.length * PRE_ITEM_HEIGHT + WINDOW_MIN_HEIGHT + 5 >
export default (searchList: Array<any>, historyList): number => {
const defaultHeight = historyList.length ? HISTORY_HEIGHT : 0;
if (!searchList) return WINDOW_MAX_HEIGHT + defaultHeight;
if (!searchList.length) return WINDOW_MIN_HEIGHT + defaultHeight;
return searchList.length * PRE_ITEM_HEIGHT + WINDOW_MIN_HEIGHT >
WINDOW_MAX_HEIGHT
? WINDOW_MAX_HEIGHT
: searchList.length * PRE_ITEM_HEIGHT + WINDOW_MIN_HEIGHT + 5;
: searchList.length * PRE_ITEM_HEIGHT + WINDOW_MIN_HEIGHT;
};

View File

@@ -16,16 +16,7 @@ if (!exists) {
const isZhRegex = /[\u4e00-\u9fa5]/;
async function getAppIcon(
appPath: string,
nativeImage: {
createThumbnailFromPath: (
iconPath: string,
size: { width: number; height: number }
) => { toDataURL: () => string };
},
name: string
) {
async function getAppIcon(appPath: string, nativeImage: any, name: string) {
try {
const iconpath = path.join(icondir, `${name}.png`);
const iconnone = path.join(icondir, `${name}.none`);
@@ -33,52 +24,40 @@ async function getAppIcon(
const existsnone = fs.existsSync(iconnone);
if (exists) return true;
if (existsnone) return false;
const appName: string = appPath.split('/').pop() || '';
const extname: string = path.extname(appName);
const appSubStr: string = appName.split(extname)[0];
const path1 = path.join(appPath, `/Contents/Resources/App.icns`);
const path2 = path.join(appPath, `/Contents/Resources/AppIcon.icns`);
const path3 = path.join(appPath, `/Contents/Resources/${appSubStr}.icns`);
const path4 = path.join(
appPath,
`/Contents/Resources/${appSubStr.replace(' ', '')}.icns`
);
let iconPath: string = path1;
if (fs.existsSync(path1)) {
iconPath = path1;
} else if (fs.existsSync(path2)) {
iconPath = path2;
} else if (fs.existsSync(path3)) {
iconPath = path3;
} else if (fs.existsSync(path4)) {
iconPath = path4;
} else {
// 性能最低的方式
const resourceList = fs.readdirSync(
path.join(appPath, `/Contents/Resources`)
);
const iconName = resourceList.filter(
(file) => path.extname(file) === '.icns'
)[0];
if (!iconName) {
fs.writeFileSync(iconnone, '');
return false;
}
iconPath = path.join(appPath, `/Contents/Resources/${iconName}`);
}
const img = await nativeImage.createThumbnailFromPath(iconPath, {
width: 64,
height: 64,
});
const base64Data = img.toDataURL().replace(/^data:.+;base64,/, '"');
const result = Buffer.from(base64Data, 'base64');
fs.writeFile(iconpath, result, 'base64', () => {
// todo
});
// const appName: string = appPath.split('/').pop() || '';
// const extname: string = path.extname(appName);
// const appSubStr: string = appName.split(extname)[0];
// const path1 = path.join(appPath, `/Contents/Resources/App.icns`);
// const path2 = path.join(appPath, `/Contents/Resources/AppIcon.icns`);
// const path3 = path.join(appPath, `/Contents/Resources/${appSubStr}.icns`);
// const path4 = path.join(
// appPath,
// `/Contents/Resources/${appSubStr.replace(' ', '')}.icns`
// );
// let iconPath: string = path1;
// if (fs.existsSync(path1)) {
// iconPath = path1;
// } else if (fs.existsSync(path2)) {
// iconPath = path2;
// } else if (fs.existsSync(path3)) {
// iconPath = path3;
// } else if (fs.existsSync(path4)) {
// iconPath = path4;
// } else {
// // 性能最低的方式
// const resourceList = fs.readdirSync(
// path.join(appPath, `/Contents/Resources`)
// );
// const iconName = resourceList.filter(
// (file) => path.extname(file) === '.icns'
// )[0];
// if (!iconName) {
// fs.writeFileSync(iconnone, '');
// return false;
// }
// iconPath = path.join(appPath, `/Contents/Resources/${iconName}`);
// }
await getMacApps.app2png(appPath, iconpath);
return true;
} catch (e) {
return false;
@@ -120,12 +99,12 @@ export default async (nativeImage: any) => {
};
if (app._name && isZhRegex.test(app._name)) {
const [, pinyinArr] = translate(app._name);
const firstLatter = pinyinArr.map((py) => py[0]);
// 拼音
fileOptions.keyWords.push(pinyinArr.join(''));
// 缩写
fileOptions.keyWords.push(firstLatter.join(''));
// const [, pinyinArr] = translate(app._name);
// const firstLatter = pinyinArr.map((py) => py[0]);
// // 拼音
// fileOptions.keyWords.push(pinyinArr.join(''));
// // 缩写
// fileOptions.keyWords.push(firstLatter.join(''));
// 中文
fileOptions.keyWords.push(app._name);
}

View File

@@ -0,0 +1,109 @@
import path from 'path';
import fs from 'fs';
import { exec } from 'child_process';
// eslint-disable-next-line @typescript-eslint/no-var-requires
const plist = require('simple-plist');
const getIconFile = (appFileInput) => {
return new Promise((resolve, reject) => {
const plistPath = path.join(appFileInput, 'Contents', 'Info.plist');
plist.readFile(plistPath, (err, data) => {
if (err || !data.CFBundleIconFile) {
return resolve(
'/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/GenericApplicationIcon.icns'
);
}
const iconFile = path.join(
appFileInput,
'Contents',
'Resources',
data.CFBundleIconFile
);
const iconFiles = [iconFile, iconFile + '.icns', iconFile + '.tiff'];
const existedIcon = iconFiles.find((iconFile) => {
return fs.existsSync(iconFile);
});
resolve(
existedIcon ||
'/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/GenericApplicationIcon.icns'
);
});
});
};
// const sortIcons = (icons) => {
// const aWins = -1;
// const bWins = 1;
// const catWins = 0;
// return icons.sort((a, b) => {
// const aSize = parseInt(a.match(/(\d+)x\1/)[1], 10);
// const bSize = parseInt(b.match(/(\d+)x\1/)[1], 10);
// if (aSize === bSize) {
// if (a.indexOf('@2x') > -1) return aWins;
// if (b.indexOf('@2x') > -1) return bWins;
// return catWins;
// }
// if (aSize > bSize) return aWins;
// if (aSize < bSize) return bWins;
// return catWins;
// });
// };
// const icnsToPng = (iconFile, pngFileOutput) => {
// const outputDir = pngFileOutput.split('.')[0] + '.iconset'
// return new Promise((resolve, reject) => {
// exec(`iconutil --convert iconset '${iconFile}' --output '${outputDir}'`, (error) => {
// if (error) return reject(error)
// fs.readdir(outputDir, (error, files) => {
// if (error) {
// return resolve(tiffToPng(iconFile, pngFileOutput))
// }
// const realIcons = files.map((file) => {
// return path.join(outputDir, file)
// })
// const biggestIcon = sortIcons(realIcons).find(Boolean)
// fs.rename(biggestIcon, pngFileOutput, (error) => {
// error ? reject(error) : resolve(realIcons.filter((file) => {
// return file !== biggestIcon
// }))
// })
// })
// })
// }).then((files) => {
// // Cleanup temp icons
// return Promise.all(files.map((file) => {
// return new Promise((resolve, reject) => {
// fs.unlink(file, (error) => {
// error ? reject(error) : resolve()
// })
// })
// }))
// }).then(() => {
// // Cleanup temp directory
// return new Promise((resolve, reject) => {
// fs.rmdir(outputDir, (error) => {
// error ? reject(error) : resolve()
// })
// })
// })
// }
const tiffToPng = (iconFile, pngFileOutput) => {
return new Promise((resolve, reject) => {
exec(
`sips -s format png '${iconFile}' --out '${pngFileOutput}' --resampleHeightWidth 64 64`,
(error) => {
error ? reject(error) : resolve(null);
}
);
});
};
const app2png = (appFileInput, pngFileOutput) => {
return getIconFile(appFileInput).then((iconFile) => {
return tiffToPng(iconFile, pngFileOutput);
});
};
export default app2png;

View File

@@ -1,4 +1,5 @@
import getApps from "./getApps";
import getApps from './getApps';
import app2png from './app2png';
export default {
getApps: () => {
@@ -7,4 +8,5 @@ export default {
isInstalled: (appName) => {
return new Promise((resolve, reject) => getApps(resolve, reject, appName));
},
app2png,
};

View File

@@ -78,12 +78,12 @@ function fileDisplay(filePath) {
keyWords.push(path.basename(appDetail.target, '.exe'));
if (isZhRegex.test(appName)) {
const [, pinyinArr] = translate(appName);
const zh_firstLatter = pinyinArr.map((py) => py[0]);
// 拼音
keyWords.push(pinyinArr.join(''));
// const [, pinyinArr] = translate(appName);
// const zh_firstLatter = pinyinArr.map((py) => py[0]);
// // 拼音
// keyWords.push(pinyinArr.join(''));
// 缩写
keyWords.push(zh_firstLatter.join(''));
// keyWords.push(zh_firstLatter.join(''));
} else {
const firstLatter = appName
.split(' ')

View File

@@ -52,7 +52,7 @@ class AdapterHandler {
} catch (e) {
// ignore
}
this.registry = register || 'https://registry.npm.taobao.org';
this.registry = register || 'https://registry.npmmirror.com/';
}
async upgrade(name: string): Promise<void> {
@@ -150,27 +150,21 @@ class AdapterHandler {
}
return adapters;
}
private cleanCache() {
spawn('npm', ['cache', 'clean', '-f'], {
cwd: this.baseDir,
});
}
/**
* 运行包管理器
* @memberof AdapterHandler
*/
private async execCommand(cmd: string, modules: string[]): Promise<string> {
this.cleanCache();
return new Promise((resolve: any, reject: any) => {
let args: string[] = [cmd]
const args: string[] = [cmd]
.concat(
cmd !== 'uninstall' ? modules.map((m) => `${m}@latest`) : modules
)
.concat('--color=always')
.concat('--save');
if (cmd !== 'uninstall')
args = args.concat(`--registry=${this.registry}`);
.concat('--save')
.concat(`--registry=${this.registry}`);
const npm = spawn('npm', args, {
cwd: this.baseDir,
});

View File

@@ -5,7 +5,7 @@ import path from 'path';
// 截图方法windows
export const screenWindow = (cb) => {
const url = path.resolve(__static, 'PrintScr.exe');
const url = path.resolve(__static, 'ScreenCapture.exe');
const screen_window = execFile(url);
screen_window.on('exit', (code) => {
if (code) {

View File

@@ -1,4 +1,5 @@
import { BrowserWindow, ipcMain, nativeTheme } from 'electron';
import localConfig from '../common/initLocalConfig';
import path from 'path';
export default () => {
let win: any;
@@ -9,6 +10,8 @@ export default () => {
event.returnValue = data;
});
createWindow(pluginInfo, viewInfo, view);
// eslint-disable-next-line @typescript-eslint/no-var-requires
require('@electron/remote/main').enable(win.webContents);
};
const createWindow = async (pluginInfo, viewInfo, view) => {
@@ -28,7 +31,6 @@ export default () => {
y: viewInfo.y,
webPreferences: {
webSecurity: false,
enableRemoteModule: true,
backgroundThrottling: false,
contextIsolation: false,
webviewTag: true,
@@ -49,8 +51,9 @@ export default () => {
win = undefined;
});
win.once('ready-to-show', () => {
const darkMode = global.OP_CONFIG.get().perf.common.darkMode;
win.once('ready-to-show', async () => {
const config = await localConfig.getConfig();
const darkMode = config.perf.common.darkMode;
darkMode &&
win.webContents.executeJavaScript(
`document.body.classList.add("dark");window.rubick.theme="dark"`

View File

@@ -43,7 +43,6 @@ export default () => {
height: 600,
webPreferences: {
webSecurity: false,
enableRemoteModule: true,
backgroundThrottling: false,
contextIsolation: false,
webviewTag: true,
@@ -53,7 +52,7 @@ export default () => {
});
if (process.env.WEBPACK_DEV_SERVER_URL) {
// Load the url of the dev server if in development mode
win.loadURL('http://localhost:8083');
win.loadURL('http://localhost:8084');
} else {
win.loadURL(`file://${path.join(__static, './guide/index.html')}`);
}

View File

@@ -1,12 +1,18 @@
import { app, BrowserWindow, protocol, nativeTheme } from 'electron';
import path from 'path';
import { createProtocol } from 'vue-cli-plugin-electron-builder/lib';
import versonHandler from '../common/versionHandler';
// import versonHandler from '../common/versionHandler';
import localConfig from '@/main/common/initLocalConfig';
// eslint-disable-next-line @typescript-eslint/no-var-requires
require('@electron/remote/main').initialize();
export default () => {
let win: any;
const init = () => {
createWindow();
// eslint-disable-next-line @typescript-eslint/no-var-requires
require('@electron/remote/main').enable(win.webContents);
};
const createWindow = async () => {
@@ -22,7 +28,6 @@ export default () => {
backgroundColor: nativeTheme.shouldUseDarkColors ? '#1c1c28' : '#fff',
webPreferences: {
webSecurity: false,
enableRemoteModule: true,
backgroundThrottling: false,
contextIsolation: false,
webviewTag: true,
@@ -50,7 +55,7 @@ export default () => {
win.webContents.executeJavaScript(
`window.rubick && window.rubick.hooks && typeof window.rubick.hooks.onShow === "function" && window.rubick.hooks.onShow()`
);
versonHandler.checkUpdate();
// versonHandler.checkUpdate();
// win.webContents.openDevTools();
});
@@ -61,8 +66,8 @@ export default () => {
});
// 判断失焦是否隐藏
win.on('blur', () => {
const config = { ...global.OP_CONFIG.get() };
win.on('blur', async () => {
const config = await localConfig.getConfig();
if (config.perf.common.hideOnBlur) {
win.hide();
}

View File

@@ -2,6 +2,7 @@ import { BrowserView, BrowserWindow, session } from 'electron';
import path from 'path';
import commonConst from '../../common/utils/commonConst';
import { PLUGIN_INSTALL_DIR as baseDir } from '@/common/constans/main';
import localConfig from '@/main/common/initLocalConfig';
const getRelativePath = (indexPath) => {
return commonConst.windows()
@@ -27,12 +28,62 @@ const getPreloadPath = (plugin, pluginIndexPath) => {
return path.resolve(getRelativePath(pluginIndexPath), `../`, preload);
};
const viewPoolManager = () => {
const viewPool: any = {
views: [],
};
const maxLen = 4;
return {
getView(pluginName) {
return viewPool.views.find((view) => view.pluginName === pluginName);
},
addView(pluginName, view) {
if (this.getView(pluginName)) return;
if (viewPool.views.length > maxLen) {
viewPool.views.shift();
}
viewPool.views.push({
pluginName,
view,
});
},
};
};
export default () => {
let view;
const viewInstance = viewPoolManager();
const viewReadyFn = async (window, { pluginSetting, ext }) => {
if (!view) return;
const height = pluginSetting && pluginSetting.height;
window.setSize(800, height || 660);
view.setBounds({ x: 0, y: 60, width: 800, height: height || 600 });
view.setAutoResize({ width: true });
executeHooks('PluginEnter', ext);
executeHooks('PluginReady', ext);
const config = await localConfig.getConfig();
const darkMode = config.perf.common.darkMode;
darkMode &&
view.webContents.executeJavaScript(
`document.body.classList.add("dark");window.rubick.theme="dark"`
);
window.webContents.executeJavaScript(`window.pluginLoaded()`);
};
const init = (plugin, window: BrowserWindow) => {
if (view === null || view === undefined) {
createView(plugin, window);
if (viewInstance.getView(plugin.name) && !commonConst.dev()) {
view = viewInstance.getView(plugin.name).view;
window.setBrowserView(view);
view.inited = true;
viewReadyFn(window, plugin);
} else {
createView(plugin, window);
viewInstance.addView(plugin.name, view);
}
// eslint-disable-next-line @typescript-eslint/no-var-requires
require('@electron/remote/main').enable(view.webContents);
}
};
@@ -65,7 +116,6 @@ export default () => {
view = new BrowserView({
webPreferences: {
enableRemoteModule: true,
webSecurity: false,
nodeIntegration: true,
contextIsolation: false,
@@ -73,25 +123,16 @@ export default () => {
webviewTag: true,
preload,
session: ses,
defaultFontSize: 14,
defaultFontFamily: {
standard: 'system-ui',
serif: 'system-ui',
},
},
});
window.setBrowserView(view);
view.webContents.loadURL(pluginIndexPath);
view.webContents.once('dom-ready', () => {
if (!view) return;
const height = pluginSetting && pluginSetting.height;
window.setSize(800, height || 660);
view.setBounds({ x: 0, y: 60, width: 800, height: height || 600 });
view.setAutoResize({ width: true });
executeHooks('PluginEnter', plugin.ext);
executeHooks('PluginReady', plugin.ext);
darkMode = global.OP_CONFIG.get().perf.common.darkMode;
darkMode &&
view.webContents.executeJavaScript(
`document.body.classList.add("dark");window.rubick.theme="dark"`
);
window.webContents.executeJavaScript(`window.pluginLoaded()`);
});
view.webContents.once('dom-ready', () => viewReadyFn(window, plugin));
// 修复请求跨域问题
view.webContents.session.webRequest.onBeforeSendHeaders(
(details, callback) => {

View File

@@ -9,9 +9,8 @@ import {
screen,
shell,
} from 'electron';
import { runner, detach } from '../browsers';
import fs from 'fs';
import { LocalDb, screenCapture } from '@/core';
import { screenCapture } from '@/core';
import plist from 'plist';
import ks from 'node-key-sender';
@@ -19,16 +18,15 @@ import { DECODE_KEY } from '@/common/constans/main';
import getCopyFiles from '@/common/utils/getCopyFiles';
import mainInstance from '../index';
import { runner, detach } from '../browsers';
import DBInstance from './db';
import getWinPosition from './getWinPosition';
const runnerInstance = runner();
const detachInstance = detach();
const dbInstance = new LocalDb(app.getPath('userData'));
dbInstance.init();
class API {
class API extends DBInstance {
public currentPlugin: null | any = null;
private DBKEY = 'RUBICK_DB_DEFAULT';
init(mainWindow: BrowserWindow) {
// 响应 preload.js 事件
ipcMain.on('msg-trigger', async (event, arg) => {
@@ -37,6 +35,10 @@ class API {
event.returnValue = data;
// event.sender.send(`msg-back-${arg.type}`, data);
});
// 按 ESC 退出插件
mainWindow.webContents.on('before-input-event', (event, input) =>
this.__EscapeKeyDown(event, input, mainWindow)
);
}
public getCurrentWindow = (window, e) => {
@@ -65,6 +67,7 @@ class API {
const originWindow = this.getCurrentWindow(window, e);
if (!originWindow) return;
originWindow.setBounds({ x: x - mouseX, y: y - mouseY, width, height });
getWinPosition.setPosition(x - mouseX, y - mouseY);
}
public loadPlugin({ data: plugin }, window) {
@@ -85,15 +88,12 @@ class API {
})})`
);
window.show();
// 按 ESC 退出插件
window.webContents.on('before-input-event', (event, input) =>
this.__EscapeKeyDown(event, input, window)
);
runnerInstance
.getView()
.webContents.on('before-input-event', (event, input) =>
const view = runnerInstance.getView();
if (!view.inited) {
view.webContents.on('before-input-event', (event, input) =>
this.__EscapeKeyDown(event, input, window)
);
}
}
public removePlugin(e, window) {
@@ -196,26 +196,6 @@ class API {
return false;
}
public dbPut({ data }) {
return dbInstance.put(this.DBKEY, data.data);
}
public dbGet({ data }) {
return dbInstance.get(this.DBKEY, data.id);
}
public dbRemove({ data }) {
return dbInstance.remove(this.DBKEY, data.doc);
}
public dbBulkDocs({ data }) {
return dbInstance.bulkDocs(this.DBKEY, data.docs);
}
public dbAllDocs({ data }) {
return dbInstance.allDocs(this.DBKEY, data.key);
}
public getFeatures() {
return this.currentPlugin.features;
}
@@ -342,6 +322,22 @@ class API {
ks.sendKeys(keys);
}
}
public addLocalStartPlugin({ data: { plugin } }, window) {
window.webContents.executeJavaScript(
`window.addLocalStartPlugin(${JSON.stringify({
plugin,
})})`
);
}
public removeLocalStartPlugin({ data: { plugin } }, window) {
window.webContents.executeJavaScript(
`window.removeLocalStartPlugin(${JSON.stringify({
plugin,
})})`
);
}
}
export default new API();

28
src/main/common/db.ts Normal file
View File

@@ -0,0 +1,28 @@
import { LocalDb } from '@/core';
import { app } from 'electron';
const dbInstance = new LocalDb(app.getPath('userData'));
dbInstance.init();
export default class DBInstance {
private DBKEY = 'RUBICK_DB_DEFAULT';
public dbPut({ data }) {
return dbInstance.put(this.DBKEY, data.data);
}
public dbGet({ data }) {
return dbInstance.get(this.DBKEY, data.id);
}
public dbRemove({ data }) {
return dbInstance.remove(this.DBKEY, data.doc);
}
public dbBulkDocs({ data }) {
return dbInstance.bulkDocs(this.DBKEY, data.docs);
}
public dbAllDocs({ data }) {
return dbInstance.allDocs(this.DBKEY, data.key);
}
}

View File

@@ -0,0 +1,34 @@
import { screen } from 'electron';
const winPosition = {
x: 0,
y: 0,
id: -1,
getPosition(): { x: number; y: number } {
const { x, y } = screen.getCursorScreenPoint();
const currentDisplay = screen.getDisplayNearestPoint({ x, y });
if (winPosition.id !== currentDisplay.id) {
winPosition.id = currentDisplay.id;
winPosition.x = parseInt(
String(
currentDisplay.workArea.x + currentDisplay.workArea.width / 2 - 400
)
);
winPosition.y = parseInt(
String(
currentDisplay.workArea.y + currentDisplay.workArea.height / 2 - 200
)
);
}
return {
x: winPosition.x,
y: winPosition.y,
};
},
setPosition(x: number, y: number): void {
winPosition.x = x;
winPosition.y = y;
},
};
export default winPosition;

View File

@@ -0,0 +1,51 @@
import defaultConfig from '@/common/constans/defaultConfig';
import DBInstance from './db';
const LOCAL_CONFIG_KEY = 'rubick-local-config';
const db = new DBInstance();
const localConfig = {
async init(): Promise<any> {
const localConfig = await db.dbGet({ data: { id: LOCAL_CONFIG_KEY } });
if (
!localConfig ||
!localConfig.data ||
localConfig.data.version !== defaultConfig.version
) {
const data: any = {
_id: LOCAL_CONFIG_KEY,
data: defaultConfig,
};
if (localConfig && localConfig.data) {
data._rev = localConfig.data._rev;
}
await db.dbPut({
data: { data },
});
}
},
async getConfig(): Promise<any> {
const data: any =
(await db.dbGet({ data: { id: LOCAL_CONFIG_KEY } })) || {};
return data.data;
},
async setConfig(data) {
const localConfig: any =
(await db.dbGet({ data: { id: LOCAL_CONFIG_KEY } })) || {};
await db.dbPut({
data: {
data: {
_id: LOCAL_CONFIG_KEY,
_rev: localConfig._rev,
data: {
...localConfig.data,
...data,
},
},
},
});
},
};
export default localConfig;

View File

@@ -9,19 +9,21 @@ import {
Notification,
} from 'electron';
import screenCapture from '@/core/screen-capture';
import localConfig from '@/main/common/initLocalConfig';
import winPosition from './getWinPosition';
const registerHotKey = (mainWindow: BrowserWindow): void => {
// 设置开机启动
const setAutoLogin = () => {
const config = global.OP_CONFIG.get();
const setAutoLogin = async () => {
const config = await localConfig.getConfig();
app.setLoginItemSettings({
openAtLogin: config.perf.common.start,
openAsHidden: true,
});
};
// 设置暗黑模式
const setDarkMode = () => {
const config = global.OP_CONFIG.get();
const setDarkMode = async () => {
const config = await localConfig.getConfig();
const isDark = config.perf.common.darkMode;
if (isDark) {
nativeTheme.themeSource = 'dark';
@@ -46,29 +48,16 @@ const registerHotKey = (mainWindow: BrowserWindow): void => {
}
};
const init = () => {
setAutoLogin();
setDarkMode();
const config = global.OP_CONFIG.get();
const init = async () => {
await setAutoLogin();
await setDarkMode();
const config = await localConfig.getConfig();
globalShortcut.unregisterAll();
// 注册偏好快捷键
globalShortcut.register(config.perf.shortCut.showAndHidden, () => {
const currentShow = mainWindow.isVisible() && mainWindow.isFocused();
if (currentShow) return mainWindow.hide();
const { x, y } = screen.getCursorScreenPoint();
const currentDisplay = screen.getDisplayNearestPoint({ x, y });
const wx = parseInt(
String(
currentDisplay.workArea.x + currentDisplay.workArea.width / 2 - 400
)
);
const wy = parseInt(
String(
currentDisplay.workArea.y + currentDisplay.workArea.height / 2 - 200
)
);
const { x: wx, y: wy } = winPosition.getPosition();
mainWindow.setAlwaysOnTop(false);
mainWindow.setVisibleOnAllWorkspaces(true, { visibleOnFullScreen: true });
mainWindow.focus();

View File

@@ -2,7 +2,6 @@ import { dialog, Menu, Tray, app, shell, BrowserWindow } from 'electron';
import path from 'path';
import pkg from '../../../package.json';
import os from 'os';
import API from '../common/api';
import commonConst from '@/common/utils/commonConst';
import { guide } from '../browsers';
@@ -21,11 +20,6 @@ function createTray(window: BrowserWindow): Promise<Tray> {
}
const appIcon = new Tray(path.join(__static, icon));
const getShowAndHiddenHotKey = (): string => {
const config = global.OP_CONFIG.get();
return config.perf.shortCut.showAndHidden;
};
const openSettings = () => {
window.webContents.executeJavaScript(
`window.rubick && window.rubick.openMenu && window.rubick.openMenu({ code: "settings" })`
@@ -59,8 +53,7 @@ function createTray(window: BrowserWindow): Promise<Tray> {
},
{ type: 'separator' },
{
label: '显示窗口',
accelerator: getShowAndHiddenHotKey(),
label: '显示',
click() {
window.show();
},

View File

@@ -1,10 +1,7 @@
import { dialog } from 'electron';
import { autoUpdater } from 'electron-updater';
import pkg from '../../../package.json';
import API from './api';
import commonConst from '@/common/utils/commonConst';
import { main } from '../browsers';
import { app } from 'electron';
class VersionHandler {
private lastestVersion: string;

View File

@@ -12,9 +12,9 @@ import commonConst from '../common/utils/commonConst';
import API from './common/api';
import createTray from './common/tray';
import registerHotKey from './common/registerHotKey';
import localConfig from './common/initLocalConfig';
import '../common/utils/localPlugin';
import '../common/utils/localConfig';
import registerySystemPlugin from './common/registerySystemPlugin';
@@ -55,12 +55,13 @@ class App {
this.windowCreator.init();
}
onReady() {
const readyFunction = () => {
const config = global.OP_CONFIG.get();
const readyFunction = async () => {
await localConfig.init();
const config = await localConfig.getConfig();
if (!config.perf.common.guide) {
guide().init();
config.perf.common.guide = true;
global.OP_CONFIG.set(config);
localConfig.setConfig(config);
}
this.createWindow();
const mainWindow = this.windowCreator.getWindow();

View File

@@ -1,7 +1,6 @@
<template>
<div
id="components-layout"
:class="commonConst.macOS() && 'drag'"
@mousedown="onMouseDown"
>
<Search
@@ -13,6 +12,7 @@
:searchValue="searchValue"
:placeholder="placeholder"
:pluginLoading="pluginLoading"
:pluginHistory="pluginHistory"
:clipboardFile="clipboardFile || []"
@choosePlugin="choosePlugin"
@focus="searchFocus"
@@ -21,6 +21,7 @@
@readClipboardContent="readClipboardContent"
/>
<Result
:pluginHistory="pluginHistory"
:currentPlugin="currentPlugin"
:searchValue="searchValue"
:currentSelect="currentSelect"
@@ -32,15 +33,15 @@
<script setup lang="ts">
import { watch, ref, nextTick, toRaw } from 'vue';
import { ipcRenderer, remote } from 'electron';
import { ipcRenderer } from 'electron';
import Result from './components/result.vue';
import Search from './components/search.vue';
import getWindowHeight from '../common/utils/getWindowHeight';
import createPluginManager from './plugins-manager';
import useDrag from '../common/utils/dragWindow';
import commonConst from '@/common/utils/commonConst';
const { onMouseDown } = useDrag();
const remote = window.require('@electron/remote');
const {
initPlugins,
@@ -58,6 +59,7 @@ const {
setSearchValue,
clearClipboardFile,
readClipboardContent,
pluginHistory,
} = createPluginManager();
initPlugins();
@@ -74,24 +76,37 @@ getPluginInfo({
remote.getGlobal('LOCAL_PLUGINS').addPlugin(res);
});
watch([options], () => {
watch([options, pluginHistory], () => {
currentSelect.value = 0;
if (currentPlugin.value.name) return;
nextTick(() => {
ipcRenderer.sendSync('msg-trigger', {
type: 'setExpendHeight',
data: getWindowHeight(options.value),
data: getWindowHeight(options.value, pluginHistory.value),
});
});
});
const changeIndex = (index) => {
if (!options.value.length) return;
if (!options.value.length) {
if (!pluginHistory.value.length) return;
if (
currentSelect.value + index > pluginHistory.value.length - 1 ||
currentSelect.value + index < 0
) {
currentSelect.value = 0;
return;
}
currentSelect.value = currentSelect.value + index;
return;
}
if (
currentSelect.value + index > options.value.length - 1 ||
currentSelect.value + index < 0
)
) {
currentSelect.value = 0;
return;
}
currentSelect.value = currentSelect.value + index;
};
@@ -101,14 +116,20 @@ const openMenu = (ext) => {
feature: menuPluginInfo.value.features[0],
cmd: '插件市场',
ext,
click: () => openMenu(ext),
});
};
window.rubick.openMenu = openMenu;
const choosePlugin = () => {
const currentChoose = options.value[currentSelect.value];
currentChoose.click();
if (options.value.length) {
const currentChoose = options.value[currentSelect.value];
currentChoose.click();
} else {
const currentChoose = pluginHistory.value[currentSelect.value];
currentChoose.click();
}
};
const clearSearchValue = () => {

View File

@@ -5,7 +5,7 @@
// 背景色
--color-body-bg: #fff;
--color-menu-bg: #f3efef;
--color-list-hover: #e2e2e2;
--color-list-hover: #ebeee8;
--color-input-hover: #fff;
// 边框
--color-border-light: #f0f0f0;

View File

@@ -1,14 +1,24 @@
<template>
<div
v-show="
!!options.length &&
(searchValue || !!clipboardFile.length) &&
!currentPlugin.name
"
v-show="!currentPlugin.name"
class="options"
ref="scrollDom"
>
<a-list item-layout="horizontal" :dataSource="sort(options)">
<div class="history-plugins" v-if="!options.length || !(searchValue || !!clipboardFile.length)">
<a-row>
<a-col
@click="() => item.click()"
:class="currentSelect === index ? 'active history-item' : 'history-item'"
:span="3"
v-for="(item, index) in pluginHistory"
:key="index"
>
<a-avatar style="border-radius: 0" :src="item.icon" />
<div class="name ellpise">{{item.pluginName || item._name || item.name}}</div>
</a-col>
</a-row>
</div>
<a-list v-else item-layout="horizontal" :dataSource="sort(options)">
<template #renderItem="{ item, index }">
<a-list-item
@click="() => item.click()"
@@ -16,7 +26,7 @@
>
<a-list-item-meta :description="renderDesc(item.desc)">
<template #title>
<span v-html="renderTitle(item.name)"></span>
<span v-html="renderTitle(item.name, item.match)"></span>
</template>
<template #avatar>
<a-avatar style="border-radius: 0" :src="item.icon" />
@@ -52,18 +62,15 @@ const props = defineProps({
default: 0,
},
currentPlugin: {},
pluginHistory: (() => [])(),
clipboardFile: (() => [])(),
});
const renderTitle = (title) => {
const renderTitle = (title, match) => {
if (typeof title !== 'string') return;
if (!props.searchValue) return title;
const result = title.toLowerCase().split(props.searchValue.toLowerCase());
if (result && result.length > 1) {
return `<div>${result[0]}<span style='color: var(--ant-error-color)'>${props.searchValue}</span>${result[1]}</div>`;
} else {
return `<div>${result[0]}</div>`;
}
if (!props.searchValue || !match) return title;
const result = title.substring(match[0], match[1] + 1);
return `<div>${title.substring(0, match[0])}<span style='color: var(--ant-error-color)'>${result}</span>${title.substring(match[1]+1, title.length)}</div>`;
};
const renderDesc = (desc) => {
@@ -91,15 +98,45 @@ const sort = (options) => {
</script>
<style lang="less">
.ellpise {
overflow:hidden;
text-overflow:ellipsis;
display:-webkit-box;
-webkit-line-clamp:1;
-webkit-box-orient:vertical;
}
.options {
position: absolute;
top: 62px;
top: 60px;
left: 0;
width: 100%;
z-index: 99;
max-height: calc(~'100vh - 64px');
max-height: calc(~'100vh - 60px');
overflow: auto;
background: var(--color-body-bg);
.history-plugins {
width: 100%;
border-top: 1px dashed #ddd;
box-sizing: border-box;
.history-item {
box-sizing: border-box;
height: 79px;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
border-right: 1px dashed #ddd;
&.active {
background: var(--color-list-hover);
}
}
.name {
margin-top: 4px;
width: 100%;
text-align: center;
}
}
.op-item {
padding: 0 10px;
height: 60px;

View File

@@ -19,6 +19,7 @@
class="main-input"
@input="e => changeValue(e)"
@keydown.down="e => keydownEvent(e, 'down')"
@keydown.tab="e => keydownEvent(e, 'down')"
@keydown.up="e => keydownEvent(e, 'up')"
@keydown="e => checkNeedInit(e)"
:value="searchValue"
@@ -53,13 +54,14 @@
<script setup lang="ts">
import { defineProps, defineEmits, ref } from 'vue';
import { ipcRenderer, remote } from 'electron';
import { ipcRenderer } from 'electron';
import { LoadingOutlined, MoreOutlined } from '@ant-design/icons-vue';
const opConfig = remote.getGlobal('OP_CONFIG');
const remote = window.require('@electron/remote');
import localConfig from '../confOp';
const { Menu } = remote;
const config = ref(opConfig.get());
const config: any = ref(localConfig.getConfig());
const props: any = defineProps({
searchValue: {
@@ -70,6 +72,7 @@ const props: any = defineProps({
type: String,
default: '',
},
pluginHistory: (() => [])(),
currentPlugin: {},
pluginLoading: Boolean,
clipboardFile: (() => [])(),
@@ -106,7 +109,7 @@ const keydownEvent = (e, key: string) => {
modifiers,
},
});
const runPluginDisable = e.target.value === '' || props.currentPlugin.name;
const runPluginDisable = ((e.target.value === '' && !props.pluginHistory.length) || props.currentPlugin.name) ;
switch (key) {
case 'up':
emit('changeCurrent', -1);
@@ -119,7 +122,7 @@ const keydownEvent = (e, key: string) => {
emit('choosePlugin');
break;
case 'space':
if (runPluginDisable || !opConfig.get().perf.common.space) return;
if (runPluginDisable || !config.value.perf.common.space) return;
emit('choosePlugin');
break;
default:
@@ -216,14 +219,14 @@ const showSeparate = () => {
const changeLang = (lang) => {
let cfg = { ...config.value };
cfg.perf.common.lang = lang;
opConfig.set(cfg);
localConfig.setConfig(JSON.parse(JSON.stringify(cfg)));
config.value = cfg;
};
const changeHideOnBlur = () => {
let cfg = { ...config.value };
cfg.perf.common.hideOnBlur = !cfg.perf.common.hideOnBlur;
opConfig.set(cfg);
localConfig.setConfig(JSON.parse(JSON.stringify(cfg)));
config.value = cfg;
};
@@ -261,6 +264,9 @@ window.rubick.hooks.onHide = () => {
left: 0;
width: 100%;
align-items: center;
height: 60px;
display: flex;
align-items: center;
.ellipse {
overflow: hidden;
text-overflow: ellipsis;
@@ -284,7 +290,7 @@ window.rubick.hooks.onHide = () => {
}
.main-input {
height: 60px !important;
height: 40px !important;
box-sizing: border-box;
flex: 1;
border: none;

22
src/renderer/confOp.ts Normal file
View File

@@ -0,0 +1,22 @@
const LOCAL_CONFIG_KEY = 'rubick-local-config';
const localConfig = {
getConfig(): Promise<any> {
const data: any = window.rubick.db.get(LOCAL_CONFIG_KEY) || {};
return data.data;
},
setConfig(data) {
const localConfig: any = window.rubick.db.get(LOCAL_CONFIG_KEY) || {};
window.rubick.db.put({
_id: LOCAL_CONFIG_KEY,
_rev: localConfig._rev,
data: {
...localConfig.data,
...data,
},
});
},
};
export default localConfig;

View File

@@ -7,17 +7,18 @@ import {
Avatar,
Tag,
ConfigProvider,
Row,
Col,
} from 'ant-design-vue';
import App from './App.vue';
import localConfig from './confOp';
import 'ant-design-vue/dist/antd.variable.min.css';
const { remote } = window.require('electron');
const { perf } = remote.getGlobal('OP_CONFIG').get();
const config: any = localConfig.getConfig();
ConfigProvider.config({
theme: perf.custom || {},
theme: config.perf.custom || {},
});
createApp(App)
@@ -27,4 +28,6 @@ createApp(App)
.use(Input)
.use(Avatar)
.use(Tag)
.use(Row)
.use(Col)
.mount('#app');

View File

@@ -1,13 +1,15 @@
import getCopyFiles from '@/common/utils/getCopyFiles';
import { clipboard, nativeImage, remote, ipcRenderer } from 'electron';
import { clipboard, nativeImage, ipcRenderer } from 'electron';
import { getGlobal } from '@electron/remote';
import path from 'path';
import pluginClickEvent from './pluginClickEvent';
import localConfig from '../confOp';
import { ref } from 'vue';
export default ({ currentPlugin, optionsRef, openPlugin, setOptionsRef }) => {
const clipboardFile: any = ref([]);
const searchFocus = () => {
const config = remote.getGlobal('OP_CONFIG').get();
const config: any = localConfig.getConfig();
// 未开启自动粘贴
if (!config.perf.common.autoPast) return;
@@ -17,7 +19,7 @@ export default ({ currentPlugin, optionsRef, openPlugin, setOptionsRef }) => {
if (fileList) {
window.setSubInputValue({ value: '' });
clipboardFile.value = fileList;
const localPlugins = remote.getGlobal('LOCAL_PLUGINS').getLocalPlugins();
const localPlugins = getGlobal('LOCAL_PLUGINS').getLocalPlugins();
const options: any = [
{
name: '复制路径',
@@ -54,7 +56,7 @@ export default ({ currentPlugin, optionsRef, openPlugin, setOptionsRef }) => {
regImg.test(ext) &&
fileList.length === 1
) {
options.push({
const option = {
name: cmd.label,
value: 'plugin',
icon: plugin.logo,
@@ -73,17 +75,19 @@ export default ({ currentPlugin, optionsRef, openPlugin, setOptionsRef }) => {
.toDataURL(),
},
openPlugin,
option,
});
clearClipboardFile();
},
});
};
options.push(option);
}
// 如果是文件,且符合文件正则类型
if (
fileList.length > 1 ||
(cmd.type === 'file' && new RegExp(cmd.match).test(ext))
) {
options.push({
const option = {
name: cmd,
value: 'plugin',
icon: plugin.logo,
@@ -94,6 +98,7 @@ export default ({ currentPlugin, optionsRef, openPlugin, setOptionsRef }) => {
plugin,
fe,
cmd,
option,
ext: {
code: fe.code,
type: cmd.type || 'text',
@@ -103,7 +108,8 @@ export default ({ currentPlugin, optionsRef, openPlugin, setOptionsRef }) => {
});
clearClipboardFile();
},
});
};
options.push(option);
}
});
});
@@ -143,7 +149,7 @@ export default ({ currentPlugin, optionsRef, openPlugin, setOptionsRef }) => {
dataUrl,
},
];
const localPlugins = remote.getGlobal('LOCAL_PLUGINS').getLocalPlugins();
const localPlugins = getGlobal('LOCAL_PLUGINS').getLocalPlugins();
const options: any = [];
// 再正则插件
localPlugins.forEach((plugin) => {
@@ -153,7 +159,7 @@ export default ({ currentPlugin, optionsRef, openPlugin, setOptionsRef }) => {
feature.forEach((fe) => {
fe.cmds.forEach((cmd) => {
if (cmd.type === 'img') {
options.push({
const option = {
name: cmd.label,
value: 'plugin',
icon: plugin.logo,
@@ -170,10 +176,12 @@ export default ({ currentPlugin, optionsRef, openPlugin, setOptionsRef }) => {
payload: dataUrl,
},
openPlugin,
option,
});
clearClipboardFile();
},
});
};
options.push(option);
}
});
});

View File

@@ -1,5 +1,6 @@
import { reactive, toRefs, ref } from 'vue';
import { nativeImage, remote, ipcRenderer } from 'electron';
import { nativeImage, ipcRenderer } from 'electron';
import { getGlobal } from '@electron/remote';
import appSearch from '@/core/app-search';
import { PluginHandler } from '@/core';
import path from 'path';
@@ -8,6 +9,7 @@ import { execSync } from 'child_process';
import searchManager from './search';
import optionsManager from './options';
import { PLUGIN_INSTALL_DIR as baseDir } from '@/common/constans/renderer';
import { message } from 'ant-design-vue';
const createPluginManager = (): any => {
const pluginInstance = new PluginHandler({
@@ -20,12 +22,35 @@ const createPluginManager = (): any => {
localPlugins: [],
currentPlugin: {},
pluginLoading: false,
pluginHistory: [],
});
const appList = ref([]);
const appList: any = ref([]);
const initPlugins = async () => {
appList.value = await appSearch(nativeImage);
initLocalStartPlugin();
};
const initLocalStartPlugin = () => {
const result = ipcRenderer.sendSync('msg-trigger', {
type: 'dbGet',
data: {
id: 'rubick-local-start-app',
},
});
if (result && result.value) {
appList.value = [...appList.value, ...result.value];
}
};
window.removeLocalStartPlugin = ({ plugin }) => {
appList.value = appList.value.filter((app) => app.desc !== plugin.desc);
};
window.addLocalStartPlugin = ({ plugin }) => {
window.removeLocalStartPlugin({ plugin });
appList.value.push(plugin);
};
const loadPlugin = async (plugin) => {
@@ -42,7 +67,7 @@ const createPluginManager = (): any => {
state.pluginLoading = false;
};
const openPlugin = async (plugin) => {
const openPlugin = async (plugin, option) => {
if (plugin.pluginType === 'ui' || plugin.pluginType === 'system') {
if (state.currentPlugin && state.currentPlugin.name === plugin.name) {
return;
@@ -63,8 +88,29 @@ const createPluginManager = (): any => {
});
}
if (plugin.pluginType === 'app') {
execSync(plugin.action);
try {
execSync(plugin.action);
} catch (e) {
message.error('启动应用出错,请确保启动应用存在!');
}
}
window.initRubick();
changePluginHistory({
...plugin,
...option,
});
};
const changePluginHistory = (plugin) => {
if (state.pluginHistory.length >= 8) {
state.pluginHistory.pop();
}
state.pluginHistory.forEach((p, index) => {
if (p.name === plugin.name) {
state.pluginHistory.splice(index, 1);
}
});
state.pluginHistory.unshift(plugin);
};
const { searchValue, onSearch, setSearchValue, placeholder } =
@@ -112,7 +158,7 @@ const createPluginManager = (): any => {
window.updatePlugin = ({ currentPlugin }: any) => {
state.currentPlugin = currentPlugin;
remote.getGlobal('LOCAL_PLUGINS').updatePlugin(currentPlugin);
getGlobal('LOCAL_PLUGINS').updatePlugin(currentPlugin);
};
window.setCurrentPlugin = ({ currentPlugin }) => {

View File

@@ -1,6 +1,8 @@
import { ref, watch } from 'vue';
import throttle from 'lodash.throttle';
import { remote, ipcRenderer } from 'electron';
import { ipcRenderer } from 'electron';
import { getGlobal } from '@electron/remote';
import PinyinMatch from 'pinyin-match';
import pluginClickEvent from './pluginClickEvent';
import useFocus from './clipboardWatch';
@@ -13,12 +15,12 @@ function formatReg(regStr) {
function searchKeyValues(lists, value, strict = false) {
return lists.filter((item) => {
if (typeof item === 'string') {
return item.toLowerCase().indexOf(value.toLowerCase()) >= 0;
return !!PinyinMatch.match(item, value);
}
if (item.type === 'regex' && !strict) {
return formatReg(item.match).test(value);
}
if (item.type === 'over') {
if (item.type === 'over' && !strict) {
return true;
}
return false;
@@ -40,7 +42,7 @@ const optionsManager = ({
});
const getOptionsFromSearchValue = (value, strict = false) => {
const localPlugins = remote.getGlobal('LOCAL_PLUGINS').getLocalPlugins();
const localPlugins = getGlobal('LOCAL_PLUGINS').getLocalPlugins();
let options: any = [];
// todo 先搜索 plugin
localPlugins.forEach((plugin) => {
@@ -51,29 +53,34 @@ const optionsManager = ({
const cmds = searchKeyValues(fe.cmds, value, strict);
options = [
...options,
...cmds.map((cmd) => ({
name: cmd.label || cmd,
value: 'plugin',
icon: plugin.logo,
desc: fe.explain,
type: plugin.pluginType,
zIndex: cmd.label ? 0 : 1, // 排序权重
click: () => {
pluginClickEvent({
plugin,
fe,
cmd,
ext: cmd.type
? {
code: fe.code,
type: cmd.type || 'text',
payload: searchValue.value,
}
: null,
openPlugin,
});
},
})),
...cmds.map((cmd) => {
const option = {
name: cmd.label || cmd,
value: 'plugin',
icon: plugin.logo,
desc: fe.explain,
type: plugin.pluginType,
match: PinyinMatch.match(cmd.label || cmd, value),
zIndex: cmd.label ? 0 : 1, // 排序权重
click: () => {
pluginClickEvent({
plugin,
fe,
cmd,
ext: cmd.type
? {
code: fe.code,
type: cmd.type || 'text',
payload: searchValue.value,
}
: null,
openPlugin,
option,
});
},
};
return option;
}),
];
});
});
@@ -88,13 +95,16 @@ const optionsManager = ({
descMap.set(plugin, true);
let has = false;
plugin.keyWords.some((keyWord) => {
const match = PinyinMatch.match(keyWord, value);
if (
keyWord
.toLocaleUpperCase()
.indexOf(value.toLocaleUpperCase()) >= 0
// keyWord
// .toLocaleUpperCase()
// .indexOf(value.toLocaleUpperCase()) >= 0 ||
match
) {
has = keyWord;
plugin.name = keyWord;
plugin.match = match;
return true;
}
return false;
@@ -105,13 +115,14 @@ const optionsManager = ({
}
})
.map((plugin) => {
return {
const option = {
...plugin,
zIndex: 1,
click: () => {
openPlugin(plugin);
openPlugin(plugin, option);
},
};
return option;
}),
];
return options;

View File

@@ -3,7 +3,14 @@ import path from 'path';
import { toRaw } from 'vue';
import commonConst from '@/common/utils/commonConst';
export default function pluginClickEvent({ plugin, fe, cmd, ext, openPlugin }) {
export default function pluginClickEvent({
plugin,
fe,
cmd,
ext,
openPlugin,
option,
}) {
const pluginPath = path.resolve(baseDir, 'node_modules', plugin.name);
const pluginDist = {
...toRaw(plugin),
@@ -15,7 +22,7 @@ export default function pluginClickEvent({ plugin, fe, cmd, ext, openPlugin }) {
// 模板文件
if (!plugin.main) {
pluginDist.tplPath = commonConst.dev()
? 'http://localhost:8082/#/'
? 'http://localhost:8083/#/'
: `file://${__static}/tpl/index.html`;
}
// 插件市场
@@ -24,5 +31,5 @@ export default function pluginClickEvent({ plugin, fe, cmd, ext, openPlugin }) {
? 'http://localhost:8081/#/'
: `file://${__static}/feature/index.html`;
}
openPlugin(pluginDist);
openPlugin(pluginDist, option);
}

View File

@@ -21,6 +21,8 @@ interface Window {
loadPlugin: (plugin: any) => void;
updatePlugin: (plugin: any) => void;
initRubick: () => void;
addLocalStartPlugin: (plugin: any) => void;
removeLocalStartPlugin: (plugin: any) => void;
setCurrentPlugin: (plugin: any) => void;
pluginLoaded: () => void;
getMainInputInfo: () => any;

View File

@@ -24,7 +24,12 @@ module.exports = {
nodeIntegration: true,
mainProcessFile: 'src/main/index.ts',
mainProcessWatch: ['src/main'],
externals: ['pouchdb', 'extract-file-icon', 'electron-screenshots'],
externals: [
'pouchdb',
'extract-file-icon',
'electron-screenshots',
'@electron/remote',
],
// Use this to change the entry point of your app's render process. default src/[main|index].[js|ts]
builderOptions: {
productName: 'rubick2',

189
yarn.lock
View File

@@ -998,21 +998,25 @@
ajv "^6.12.0"
ajv-keywords "^3.4.1"
"@electron/get@^1.0.1":
version "1.14.1"
resolved "https://registry.yarnpkg.com/@electron/get/-/get-1.14.1.tgz#16ba75f02dffb74c23965e72d617adc721d27f40"
integrity sha512-BrZYyL/6m0ZXz/lDxy/nlVhQz+WF+iPS6qXolEU8atw7h6v1aYkjwJZ63m+bJMBTxDE66X+r2tPS4a/8C82sZw==
"@electron/get@^2.0.0":
version "2.0.2"
resolved "https://registry.yarnpkg.com/@electron/get/-/get-2.0.2.tgz#ae2a967b22075e9c25aaf00d5941cd79c21efd7e"
integrity sha512-eFZVFoRXb3GFGd7Ak7W4+6jBl9wBtiZ4AaYOse97ej6mKj5tkyO0dUnUChs1IhJZtx1BENo4/p4WUTXpi6vT+g==
dependencies:
debug "^4.1.1"
env-paths "^2.2.0"
fs-extra "^8.1.0"
got "^9.6.0"
got "^11.8.5"
progress "^2.0.3"
semver "^6.2.0"
sumchecker "^3.0.1"
optionalDependencies:
global-agent "^3.0.0"
global-tunnel-ng "^2.7.1"
"@electron/remote@^2.0.10":
version "2.0.10"
resolved "https://registry.yarnpkg.com/@electron/remote/-/remote-2.0.10.tgz#133e2f607b1861ac249bd78b5abd1e961feed713"
integrity sha512-3SFKKaQXcyWgwmibud+UqJl/XlHOgLcI3fwtB9pNelPSJAcTxocOJrF6FaxBIQaj1+R05Di6xuAswZpXAW7xhA==
"@electron/universal@1.0.5":
version "1.0.5"
@@ -1391,10 +1395,10 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.6.4.tgz#fd26723a8a3f8f46729812a7f9b4fc2d1608ed39"
integrity sha512-I4BD3L+6AWiUobfxZ49DlU43gtI+FTHSv9pE2Zekg6KjMpre4ByusaljW3vYSLJrvQ1ck1hUaeVu8HVlY3vzHg==
"@types/node@^14.6.2":
version "14.18.23"
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.18.23.tgz#70f5f20b0b1b38f696848c1d3647bb95694e615e"
integrity sha512-MhbCWN18R4GhO8ewQWAFK4TGQdBpXWByukz7cWyJmXhvRuCIaM/oWytGPqVmDzgEnnaIc9ss6HbU5mUi+vyZPA==
"@types/node@^18.11.18":
version "18.17.6"
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.17.6.tgz#0296e9a30b22d2a8fcaa48d3c45afe51474ca55b"
integrity sha512-fGmT/P7z7ecA6bv/ia5DlaWCH4YeZvAQMNpUhrJjtAhOhZfoxS1VLUgU2pdk63efSjQaOJWdXMuAJsws+8I6dg==
"@types/normalize-package-data@^2.4.0":
version "2.4.1"
@@ -1525,6 +1529,13 @@
dependencies:
"@types/yargs-parser" "*"
"@types/yauzl@^2.9.1":
version "2.10.0"
resolved "https://registry.yarnpkg.com/@types/yauzl/-/yauzl-2.10.0.tgz#b3248295276cf8c6f153ebe6a9aba0c988cb2599"
integrity sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==
dependencies:
"@types/node" "*"
"@typescript-eslint/eslint-plugin@^4.18.0":
version "4.33.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.33.0.tgz#c24dc7c8069c7706bc40d99f6fa87edcb2005276"
@@ -2717,6 +2728,11 @@ balanced-match@^1.0.0:
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
base64-js@1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.1.2.tgz#d6400cac1c4c660976d90d07a04351d89395f5e8"
integrity sha512-AIxxJSNK6fMJTnRuY14y/+86h+R4Ybztcchea+Al8aPIPFa6LvDSV90VN5EH81DVXQmh6YjIqpLyG/ljQDoqeQ==
base64-js@^1.0.2, base64-js@^1.3.1, base64-js@^1.5.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
@@ -2757,6 +2773,11 @@ bfj@^6.1.1:
hoopy "^0.1.4"
tryer "^1.0.1"
big-integer@^1.6.7:
version "1.6.51"
resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.51.tgz#0df92a5d9880560d3ff2d5fd20245c889d130686"
integrity sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==
big.js@^3.1.3:
version "3.2.0"
resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e"
@@ -2860,6 +2881,20 @@ boxen@^5.0.0:
widest-line "^3.1.0"
wrap-ansi "^7.0.0"
bplist-creator@0.0.7:
version "0.0.7"
resolved "https://registry.yarnpkg.com/bplist-creator/-/bplist-creator-0.0.7.tgz#37df1536092824b87c42f957b01344117372ae45"
integrity sha512-xp/tcaV3T5PCiaY04mXga7o/TE+t95gqeLmADeBI1CvZtdWTbgBt3uLpvh4UWtenKeBhCV6oVxGk38yZr2uYEA==
dependencies:
stream-buffers "~2.2.0"
bplist-parser@0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/bplist-parser/-/bplist-parser-0.1.1.tgz#d60d5dcc20cba6dc7e1f299b35d3e1f95dafbae6"
integrity sha512-2AEM0FXy8ZxVLBuqX0hqt1gDwcnz2zygEkQ6zaD5Wko/sB9paUNwlpawrFtKeHUAQUOzjVy9AO4oeonqIHKA9Q==
dependencies:
big-integer "^1.6.7"
brace-expansion@^1.1.7:
version "1.1.11"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
@@ -3720,7 +3755,7 @@ concat-map@0.0.1:
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
concat-stream@^1.5.0, concat-stream@^1.6.2:
concat-stream@^1.5.0:
version "1.6.2"
resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34"
integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==
@@ -3730,14 +3765,6 @@ concat-stream@^1.5.0, concat-stream@^1.6.2:
readable-stream "^2.2.2"
typedarray "^0.0.6"
config-chain@^1.1.11:
version "1.1.13"
resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.13.tgz#fad0795aa6a6cdaff9ed1b68e9dff94372c232f4"
integrity sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==
dependencies:
ini "^1.3.4"
proto-list "~1.2.1"
configstore@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/configstore/-/configstore-5.0.1.tgz#d365021b5df4b98cdd187d6a3b0e3f6a7cc5ed96"
@@ -4170,7 +4197,7 @@ dayjs@^1.10.5:
resolved "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.9.tgz#9ca491933fadd0a60a2c19f6c237c03517d71d1a"
integrity sha512-QvzAURSbQ0pKdIye2txOzNaHmxtUBXerpY0FJsFXUMKbIZeFm5ht1LS/jFsrncjnmtv8HsG0W2g6c0zUjZWmpA==
debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9:
debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8:
version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
@@ -4765,14 +4792,14 @@ electron-updater@^4.6.5:
lodash.isequal "^4.5.0"
semver "^7.3.5"
electron@^13.0.0:
version "13.6.9"
resolved "https://registry.yarnpkg.com/electron/-/electron-13.6.9.tgz#7bd83cc1662ceaaa09dcd132a7b507cec888b028"
integrity sha512-Es/sBy85NIuqsO9MW41PUCpwIkeinlTQ7g0ainfnmRAM2rmog3GBxVCaoV5dzEjwTF7TKG1Yr/E7Z3qHmlfWAg==
electron@26.0.0:
version "26.0.0"
resolved "https://registry.yarnpkg.com/electron/-/electron-26.0.0.tgz#f054aad7db99379aba11237622e9742bbe800dea"
integrity sha512-x57bdCaDvgnlc41VOm/UWihJCCiI3OxJKiBgB/e5F7Zd6avo+61mO6IzQS7Bu/k/a1KPjou25EUORR6UPKznBQ==
dependencies:
"@electron/get" "^1.0.1"
"@types/node" "^14.6.2"
extract-zip "^1.0.3"
"@electron/get" "^2.0.0"
"@types/node" "^18.11.18"
extract-zip "^2.0.1"
elliptic@^6.5.3:
version "6.5.4"
@@ -4807,7 +4834,7 @@ emojis-list@^3.0.0:
resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78"
integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==
encodeurl@^1.0.2, encodeurl@~1.0.2:
encodeurl@~1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==
@@ -5330,15 +5357,16 @@ extract-file-icon@^0.3.2:
dependencies:
node-addon-api "1.7.1"
extract-zip@^1.0.3:
version "1.7.0"
resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.7.0.tgz#556cc3ae9df7f452c493a0cfb51cc30277940927"
integrity sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA==
extract-zip@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-2.0.1.tgz#663dca56fe46df890d5f131ef4a06d22bb8ba13a"
integrity sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==
dependencies:
concat-stream "^1.6.2"
debug "^2.6.9"
mkdirp "^0.5.4"
debug "^4.1.1"
get-stream "^5.1.0"
yauzl "^2.10.0"
optionalDependencies:
"@types/yauzl" "^2.9.1"
extsprintf@1.3.0:
version "1.3.0"
@@ -5913,16 +5941,6 @@ global-dirs@^3.0.0:
dependencies:
ini "2.0.0"
global-tunnel-ng@^2.7.1:
version "2.7.1"
resolved "https://registry.yarnpkg.com/global-tunnel-ng/-/global-tunnel-ng-2.7.1.tgz#d03b5102dfde3a69914f5ee7d86761ca35d57d8f"
integrity sha512-4s+DyciWBV0eK148wqXxcmVAbFVPqtc3sEtUE/GTQfuU80rySLcMhUmHKSHI7/LDj8q0gDYI1lIhRRB7ieRAqg==
dependencies:
encodeurl "^1.0.2"
lodash "^4.17.10"
npm-conf "^1.1.3"
tunnel "^0.0.6"
globals@^11.1.0:
version "11.12.0"
resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
@@ -6008,6 +6026,23 @@ got@^11.8.3:
p-cancelable "^2.0.0"
responselike "^2.0.0"
got@^11.8.5:
version "11.8.6"
resolved "https://registry.yarnpkg.com/got/-/got-11.8.6.tgz#276e827ead8772eddbcfc97170590b841823233a"
integrity sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==
dependencies:
"@sindresorhus/is" "^4.0.0"
"@szmarczak/http-timer" "^4.0.5"
"@types/cacheable-request" "^6.0.1"
"@types/responselike" "^1.0.0"
cacheable-lookup "^5.0.3"
cacheable-request "^7.0.2"
decompress-response "^6.0.0"
http2-wrapper "^1.0.0-beta.5.2"
lowercase-keys "^2.0.0"
p-cancelable "^2.0.0"
responselike "^2.0.0"
got@^9.6.0:
version "9.6.0"
resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85"
@@ -6559,7 +6594,7 @@ ini@2.0.0:
resolved "https://registry.yarnpkg.com/ini/-/ini-2.0.0.tgz#e5fd556ecdd5726be978fa1001862eacb0a94bc5"
integrity sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==
ini@^1.3.4, ini@~1.3.0:
ini@~1.3.0:
version "1.3.8"
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c"
integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==
@@ -7524,7 +7559,7 @@ lodash.uniq@^4.5.0:
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
integrity sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==
lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.3:
lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.3:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
@@ -7898,7 +7933,7 @@ mixin-deep@^1.2.0:
for-in "^1.0.2"
is-extendable "^1.0.1"
mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@^0.5.4, mkdirp@^0.5.6, mkdirp@~0.5.1:
mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@^0.5.6, mkdirp@~0.5.1:
version "0.5.6"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6"
integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==
@@ -8072,7 +8107,7 @@ node-gyp-build@~4.1.0:
node-key-sender@^1.0.11:
version "1.0.11"
resolved "https://registry.npmmirror.com/node-key-sender/-/node-key-sender-1.0.11.tgz#93210f07163607d8daf2874f1a29567d0acdb94c"
resolved "https://registry.yarnpkg.com/node-key-sender/-/node-key-sender-1.0.11.tgz#93210f07163607d8daf2874f1a29567d0acdb94c"
integrity sha512-vv2IXd8QdZBFYXaIy02uy2rK6EKj+tOTEuoTxJKS9l8zw8Cz6DeLffR8ompj7N2A3h6XK7aiy+YAcTaeOqwp2Q==
node-libs-browser@^2.2.1:
@@ -8166,14 +8201,6 @@ normalize-url@^6.0.1:
resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a"
integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==
npm-conf@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/npm-conf/-/npm-conf-1.1.3.tgz#256cc47bd0e218c259c4e9550bf413bc2192aff9"
integrity sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw==
dependencies:
config-chain "^1.1.11"
pify "^3.0.0"
npm-run-path@^2.0.0:
version "2.0.2"
resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
@@ -8681,6 +8708,11 @@ pinkie@^2.0.0:
resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
integrity sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==
pinyin-match@^1.2.4:
version "1.2.4"
resolved "https://registry.yarnpkg.com/pinyin-match/-/pinyin-match-1.2.4.tgz#94381bb6501cfd3c24f923fe36c81710d8c49bcc"
integrity sha512-HpUiaSxcG3rrpKAMZXq/rMHbEp7wvfu9B64lHJBy+63xAr/hVdBC8xqkWWPnNyjSb19ihdh8FnXo+9m6jAr9Mg==
pkg-dir@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-1.0.0.tgz#7a4b508a8d5bb2d629d447056ff4e9c9314cf3d4"
@@ -8702,6 +8734,15 @@ pkg-dir@^4.1.0:
dependencies:
find-up "^4.0.0"
plist@2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/plist/-/plist-2.0.1.tgz#0a32ca9481b1c364e92e18dc55c876de9d01da8b"
integrity sha512-pLZ1xkqqdO0puqm8g9kHzGb9oPkW32RPprDsNtjyVJ1cAWdglIgq+k+kO3sFAm5fEGIW04B4oa27JsfzncnHkA==
dependencies:
base64-js "1.1.2"
xmlbuilder "8.2.2"
xmldom "0.1.x"
plist@^3.0.1, plist@^3.0.4:
version "3.0.6"
resolved "https://registry.yarnpkg.com/plist/-/plist-3.0.6.tgz#7cfb68a856a7834bca6dbfe3218eb9c7740145d3"
@@ -9158,11 +9199,6 @@ promise-inflight@^1.0.1:
resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3"
integrity sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==
proto-list@~1.2.1:
version "1.2.4"
resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849"
integrity sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==
proxy-addr@~2.0.7:
version "2.0.7"
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025"
@@ -10040,6 +10076,15 @@ signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3:
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
simple-plist@0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/simple-plist/-/simple-plist-0.2.1.tgz#71766db352326928cf3a807242ba762322636723"
integrity sha512-1xgqR0IwahCZDfwUp36DmxKX0dwoh/KtnxbY8D5cs19BF5889ZlRSViTAknEWO39ND573T2NBBHqP7Qf6spPPQ==
dependencies:
bplist-creator "0.0.7"
bplist-parser "0.1.1"
plist "2.0.1"
simple-swizzle@^0.2.2:
version "0.2.2"
resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a"
@@ -10351,6 +10396,11 @@ stream-browserify@^2.0.1:
inherits "~2.0.1"
readable-stream "^2.0.2"
stream-buffers@~2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/stream-buffers/-/stream-buffers-2.2.0.tgz#91d5f5130d1cef96dcfa7f726945188741d09ee4"
integrity sha512-uyQK/mx5QjHun80FLJTfaWE7JtwfRMKBLkMne6udYOmvH0CawotVa7TfgYHzAnpphn4+TweIx1QKMnRIbipmUg==
stream-each@^1.1.0:
version "1.2.3"
resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae"
@@ -10926,11 +10976,6 @@ tunnel-agent@^0.6.0:
dependencies:
safe-buffer "^5.0.1"
tunnel@^0.0.6:
version "0.0.6"
resolved "https://registry.yarnpkg.com/tunnel/-/tunnel-0.0.6.tgz#72f1314b34a5b192db012324df2cc587ca47f92c"
integrity sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==
tweetnacl@^0.14.3, tweetnacl@~0.14.0:
version "0.14.5"
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
@@ -11769,11 +11814,21 @@ xdg-basedir@^4.0.0:
resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13"
integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==
xmlbuilder@8.2.2:
version "8.2.2"
resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-8.2.2.tgz#69248673410b4ba42e1a6136551d2922335aa773"
integrity sha512-eKRAFz04jghooy8muekqzo8uCSVNeyRedbuJrp0fovbLIi7wlsYtdUn3vBAAPq2Y3/0xMz2WMEUQ8yhVVO9Stw==
xmlbuilder@>=11.0.1, xmlbuilder@^15.1.1:
version "15.1.1"
resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-15.1.1.tgz#9dcdce49eea66d8d10b42cae94a79c3c8d0c2ec5"
integrity sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==
xmldom@0.1.x:
version "0.1.31"
resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.31.tgz#b76c9a1bd9f0a9737e5a72dc37231cf38375e2ff"
integrity sha512-yS2uJflVQs6n+CyjHoaBmVSqIDevTAWrzMmjG1Gc7h1qQ7uVozNhEPJAwZXWyGQ/Gafo3fCwrcaokezLPupVyQ==
xtend@^4.0.0, xtend@^4.0.2, xtend@~4.0.0, xtend@~4.0.1:
version "4.0.2"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"