Merge pull request #230 from rubickCenter/feat/v3.0.0

Feat/v3.0.0
This commit is contained in:
木偶 2023-09-16 11:35:18 +08:00 committed by GitHub
commit 9a3ca8403b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 669 additions and 166 deletions

View File

@ -1,7 +1,7 @@
{ {
"name": "rubick-system-feature", "name": "rubick-system-feature",
"pluginName": "rubick 系统菜单", "pluginName": "系统菜单",
"description": "rubick 系统菜单", "description": "系统菜单",
"main": "index.html", "main": "index.html",
"logo": "https://pic1.zhimg.com/80/v2-c09780808301668a82e6646cb42f0806_720w.png", "logo": "https://pic1.zhimg.com/80/v2-c09780808301668a82e6646cb42f0806_720w.png",
"version": "0.0.0", "version": "0.0.0",
@ -10,19 +10,19 @@
"features": [ "features": [
{ {
"code": "market", "code": "market",
"explain": "rubick 插件市场", "explain": "插件市场",
"cmds":[ "cmds":[
"插件市场" "插件市场"
] ]
},{ },{
"code": "installed", "code": "installed",
"explain": "rubick 已安装插件", "explain": "已安装插件",
"cmds":[ "cmds":[
"已安装插件" "已安装插件"
] ]
},{ },{
"code": "settings", "code": "settings",
"explain": "rubick 偏好设置", "explain": "偏好设置",
"cmds":[ "cmds":[
"偏好设置" "偏好设置"
] ]

View File

@ -1,4 +1,21 @@
const remote = require('@electron/remote'); 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 = { window.market = {
getLocalPlugins() { getLocalPlugins() {
@ -13,4 +30,10 @@ window.market = {
refreshPlugin(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

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

View File

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

View File

@ -14,6 +14,12 @@
</template> </template>
{{ $t('feature.settings.basic.title') }} {{ $t('feature.settings.basic.title') }}
</a-menu-item> </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"> <a-menu-item key="global">
<template #icon> <template #icon>
<LaptopOutlined /> <LaptopOutlined />
@ -220,6 +226,7 @@
</div> </div>
<SuperPanel v-if="currentSelect[0] === 'superpanel'" /> <SuperPanel v-if="currentSelect[0] === 'superpanel'" />
<Localhost v-if="currentSelect[0] === 'localhost'" /> <Localhost v-if="currentSelect[0] === 'localhost'" />
<LocalStart v-if="currentSelect[0] === 'localstart'" />
</div> </div>
</div> </div>
</template> </template>
@ -232,6 +239,7 @@ import {
MinusCircleOutlined, MinusCircleOutlined,
PlusCircleOutlined, PlusCircleOutlined,
UserOutlined, UserOutlined,
FolderOpenOutlined,
} from '@ant-design/icons-vue'; } from '@ant-design/icons-vue';
import debounce from 'lodash.debounce'; import debounce from 'lodash.debounce';
import { ref, reactive, watch, toRefs, computed } from 'vue'; import { ref, reactive, watch, toRefs, computed } from 'vue';
@ -239,6 +247,7 @@ import keycodes from './keycode';
import Localhost from './localhost.vue'; import Localhost from './localhost.vue';
import SuperPanel from './super-panel.vue'; import SuperPanel from './super-panel.vue';
import UserInfo from './user-info'; import UserInfo from './user-info';
import LocalStart from './local-start';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import localConfig from '@/confOp'; import localConfig from '@/confOp';

View File

@ -0,0 +1,111 @@
<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 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

@ -1,6 +1,6 @@
{ {
"name": "rubick", "name": "rubick",
"version": "3.0.1", "version": "3.1.0",
"author": "muwoo <2424880409@qq.com>", "author": "muwoo <2424880409@qq.com>",
"private": true, "private": true,
"scripts": { "scripts": {
@ -32,7 +32,9 @@
"got": "^11.8.3", "got": "^11.8.3",
"lodash.throttle": "^4.1.1", "lodash.throttle": "^4.1.1",
"node-key-sender": "^1.0.11", "node-key-sender": "^1.0.11",
"pinyin-match": "^1.2.4",
"pouchdb": "^7.2.2", "pouchdb": "^7.2.2",
"simple-plist": "0.2.1",
"vue": "^3.0.0", "vue": "^3.0.0",
"vue-router": "^4.0.0-0", "vue-router": "^4.0.0-0",
"vuex": "^4.0.0-0", "vuex": "^4.0.0-0",

View File

@ -1,7 +1,7 @@
{ {
"name": "rubick-system-feature", "name": "rubick-system-feature",
"pluginName": "rubick 系统菜单", "pluginName": "系统菜单",
"description": "rubick 系统菜单", "description": "系统菜单",
"main": "index.html", "main": "index.html",
"logo": "https://pic1.zhimg.com/80/v2-c09780808301668a82e6646cb42f0806_720w.png", "logo": "https://pic1.zhimg.com/80/v2-c09780808301668a82e6646cb42f0806_720w.png",
"version": "0.0.0", "version": "0.0.0",
@ -10,19 +10,19 @@
"features": [ "features": [
{ {
"code": "market", "code": "market",
"explain": "rubick 插件市场", "explain": "插件市场",
"cmds":[ "cmds":[
"插件市场" "插件市场"
] ]
},{ },{
"code": "installed", "code": "installed",
"explain": "rubick 已安装插件", "explain": "已安装插件",
"cmds":[ "cmds":[
"已安装插件" "已安装插件"
] ]
},{ },{
"code": "settings", "code": "settings",
"explain": "rubick 偏好设置", "explain": "偏好设置",
"cmds":[ "cmds":[
"偏好设置" "偏好设置"
] ]

View File

@ -1,4 +1,21 @@
const remote = require('@electron/remote'); 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 = { window.market = {
getLocalPlugins() { getLocalPlugins() {
@ -13,4 +30,10 @@ window.market = {
refreshPlugin(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,12 +1,14 @@
const WINDOW_MAX_HEIGHT = 600; const WINDOW_MAX_HEIGHT = 600;
const WINDOW_MIN_HEIGHT = 60; const WINDOW_MIN_HEIGHT = 60;
const PRE_ITEM_HEIGHT = 60; const PRE_ITEM_HEIGHT = 60;
const HISTORY_HEIGHT = 80;
export default (searchList: Array<any>): number => { export default (searchList: Array<any>, historyList): number => {
if (!searchList) return WINDOW_MAX_HEIGHT; const defaultHeight = historyList.length ? HISTORY_HEIGHT : 0;
if (!searchList.length) return WINDOW_MIN_HEIGHT; if (!searchList) return WINDOW_MAX_HEIGHT + defaultHeight;
return searchList.length * PRE_ITEM_HEIGHT + WINDOW_MIN_HEIGHT + 5 > if (!searchList.length) return WINDOW_MIN_HEIGHT + defaultHeight;
return searchList.length * PRE_ITEM_HEIGHT + WINDOW_MIN_HEIGHT >
WINDOW_MAX_HEIGHT WINDOW_MAX_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]/; const isZhRegex = /[\u4e00-\u9fa5]/;
async function getAppIcon( async function getAppIcon(appPath: string, nativeImage: any, name: string) {
appPath: string,
nativeImage: {
createThumbnailFromPath: (
iconPath: string,
size: { width: number; height: number }
) => { toDataURL: () => string };
},
name: string
) {
try { try {
const iconpath = path.join(icondir, `${name}.png`); const iconpath = path.join(icondir, `${name}.png`);
const iconnone = path.join(icondir, `${name}.none`); const iconnone = path.join(icondir, `${name}.none`);
@ -33,52 +24,40 @@ async function getAppIcon(
const existsnone = fs.existsSync(iconnone); const existsnone = fs.existsSync(iconnone);
if (exists) return true; if (exists) return true;
if (existsnone) return false; if (existsnone) return false;
const appName: string = appPath.split('/').pop() || ''; // const appName: string = appPath.split('/').pop() || '';
const extname: string = path.extname(appName); // const extname: string = path.extname(appName);
const appSubStr: string = appName.split(extname)[0]; // const appSubStr: string = appName.split(extname)[0];
const path1 = path.join(appPath, `/Contents/Resources/App.icns`); // const path1 = path.join(appPath, `/Contents/Resources/App.icns`);
const path2 = path.join(appPath, `/Contents/Resources/AppIcon.icns`); // const path2 = path.join(appPath, `/Contents/Resources/AppIcon.icns`);
const path3 = path.join(appPath, `/Contents/Resources/${appSubStr}.icns`); // const path3 = path.join(appPath, `/Contents/Resources/${appSubStr}.icns`);
const path4 = path.join( // const path4 = path.join(
appPath, // appPath,
`/Contents/Resources/${appSubStr.replace(' ', '')}.icns` // `/Contents/Resources/${appSubStr.replace(' ', '')}.icns`
); // );
let iconPath: string = path1; // let iconPath: string = path1;
if (fs.existsSync(path1)) { // if (fs.existsSync(path1)) {
iconPath = path1; // iconPath = path1;
} else if (fs.existsSync(path2)) { // } else if (fs.existsSync(path2)) {
iconPath = path2; // iconPath = path2;
} else if (fs.existsSync(path3)) { // } else if (fs.existsSync(path3)) {
iconPath = path3; // iconPath = path3;
} else if (fs.existsSync(path4)) { // } else if (fs.existsSync(path4)) {
iconPath = path4; // iconPath = path4;
} else { // } else {
// 性能最低的方式 // // 性能最低的方式
const resourceList = fs.readdirSync( // const resourceList = fs.readdirSync(
path.join(appPath, `/Contents/Resources`) // path.join(appPath, `/Contents/Resources`)
); // );
const iconName = resourceList.filter( // const iconName = resourceList.filter(
(file) => path.extname(file) === '.icns' // (file) => path.extname(file) === '.icns'
)[0]; // )[0];
if (!iconName) { // if (!iconName) {
fs.writeFileSync(iconnone, ''); // fs.writeFileSync(iconnone, '');
return false; // return false;
} // }
iconPath = path.join(appPath, `/Contents/Resources/${iconName}`); // iconPath = path.join(appPath, `/Contents/Resources/${iconName}`);
} // }
const img = await nativeImage.createThumbnailFromPath(iconPath, { await getMacApps.app2png(appPath, iconpath);
width: 64,
height: 64,
});
const base64Data = img.toDataURL().replace(/^data:.+;base64,/, '"');
const result = Buffer.from(base64Data, 'base64');
fs.writeFile(iconpath, result, 'base64', () => {
// todo
});
return true; return true;
} catch (e) { } catch (e) {
return false; return false;
@ -120,12 +99,12 @@ export default async (nativeImage: any) => {
}; };
if (app._name && isZhRegex.test(app._name)) { if (app._name && isZhRegex.test(app._name)) {
const [, pinyinArr] = translate(app._name); // const [, pinyinArr] = translate(app._name);
const firstLatter = pinyinArr.map((py) => py[0]); // const firstLatter = pinyinArr.map((py) => py[0]);
// 拼音 // // 拼音
fileOptions.keyWords.push(pinyinArr.join('')); // fileOptions.keyWords.push(pinyinArr.join(''));
// 缩写 // // 缩写
fileOptions.keyWords.push(firstLatter.join('')); // fileOptions.keyWords.push(firstLatter.join(''));
// 中文 // 中文
fileOptions.keyWords.push(app._name); 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 { export default {
getApps: () => { getApps: () => {
@ -7,4 +8,5 @@ export default {
isInstalled: (appName) => { isInstalled: (appName) => {
return new Promise((resolve, reject) => getApps(resolve, reject, 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')); keyWords.push(path.basename(appDetail.target, '.exe'));
if (isZhRegex.test(appName)) { if (isZhRegex.test(appName)) {
const [, pinyinArr] = translate(appName); // const [, pinyinArr] = translate(appName);
const zh_firstLatter = pinyinArr.map((py) => py[0]); // const zh_firstLatter = pinyinArr.map((py) => py[0]);
// 拼音 // // 拼音
keyWords.push(pinyinArr.join('')); // keyWords.push(pinyinArr.join(''));
// 缩写 // 缩写
keyWords.push(zh_firstLatter.join('')); // keyWords.push(zh_firstLatter.join(''));
} else { } else {
const firstLatter = appName const firstLatter = appName
.split(' ') .split(' ')

View File

@ -9,8 +9,6 @@ import {
screen, screen,
shell, shell,
} from 'electron'; } from 'electron';
import { runner, detach } from '../browsers';
import DBInstance from './db';
import fs from 'fs'; import fs from 'fs';
import { screenCapture } from '@/core'; import { screenCapture } from '@/core';
import plist from 'plist'; import plist from 'plist';
@ -20,6 +18,10 @@ import { DECODE_KEY } from '@/common/constans/main';
import getCopyFiles from '@/common/utils/getCopyFiles'; import getCopyFiles from '@/common/utils/getCopyFiles';
import mainInstance from '../index'; import mainInstance from '../index';
import { runner, detach } from '../browsers';
import DBInstance from './db';
import getWinPosition from './getWinPosition';
const runnerInstance = runner(); const runnerInstance = runner();
const detachInstance = detach(); const detachInstance = detach();
@ -65,6 +67,7 @@ class API extends DBInstance {
const originWindow = this.getCurrentWindow(window, e); const originWindow = this.getCurrentWindow(window, e);
if (!originWindow) return; if (!originWindow) return;
originWindow.setBounds({ x: x - mouseX, y: y - mouseY, width, height }); originWindow.setBounds({ x: x - mouseX, y: y - mouseY, width, height });
getWinPosition.setPosition(x - mouseX, y - mouseY);
} }
public loadPlugin({ data: plugin }, window) { public loadPlugin({ data: plugin }, window) {
@ -319,6 +322,22 @@ class API extends DBInstance {
ks.sendKeys(keys); 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(); export default new API();

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

@ -10,6 +10,7 @@ import {
} from 'electron'; } from 'electron';
import screenCapture from '@/core/screen-capture'; import screenCapture from '@/core/screen-capture';
import localConfig from '@/main/common/initLocalConfig'; import localConfig from '@/main/common/initLocalConfig';
import winPosition from './getWinPosition';
const registerHotKey = (mainWindow: BrowserWindow): void => { const registerHotKey = (mainWindow: BrowserWindow): void => {
// 设置开机启动 // 设置开机启动
@ -56,20 +57,7 @@ const registerHotKey = (mainWindow: BrowserWindow): void => {
globalShortcut.register(config.perf.shortCut.showAndHidden, () => { globalShortcut.register(config.perf.shortCut.showAndHidden, () => {
const currentShow = mainWindow.isVisible() && mainWindow.isFocused(); const currentShow = mainWindow.isVisible() && mainWindow.isFocused();
if (currentShow) return mainWindow.hide(); if (currentShow) return mainWindow.hide();
const { x: wx, y: wy } = winPosition.getPosition();
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
)
);
mainWindow.setAlwaysOnTop(false); mainWindow.setAlwaysOnTop(false);
mainWindow.setVisibleOnAllWorkspaces(true, { visibleOnFullScreen: true }); mainWindow.setVisibleOnAllWorkspaces(true, { visibleOnFullScreen: true });
mainWindow.focus(); mainWindow.focus();

View File

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

View File

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

View File

@ -1,14 +1,24 @@
<template> <template>
<div <div
v-show=" v-show="!currentPlugin.name"
!!options.length &&
(searchValue || !!clipboardFile.length) &&
!currentPlugin.name
"
class="options" class="options"
ref="scrollDom" 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 }"> <template #renderItem="{ item, index }">
<a-list-item <a-list-item
@click="() => item.click()" @click="() => item.click()"
@ -16,7 +26,7 @@
> >
<a-list-item-meta :description="renderDesc(item.desc)"> <a-list-item-meta :description="renderDesc(item.desc)">
<template #title> <template #title>
<span v-html="renderTitle(item.name)"></span> <span v-html="renderTitle(item.name, item.match)"></span>
</template> </template>
<template #avatar> <template #avatar>
<a-avatar style="border-radius: 0" :src="item.icon" /> <a-avatar style="border-radius: 0" :src="item.icon" />
@ -52,18 +62,15 @@ const props = defineProps({
default: 0, default: 0,
}, },
currentPlugin: {}, currentPlugin: {},
pluginHistory: (() => [])(),
clipboardFile: (() => [])(), clipboardFile: (() => [])(),
}); });
const renderTitle = (title) => { const renderTitle = (title, match) => {
if (typeof title !== 'string') return; if (typeof title !== 'string') return;
if (!props.searchValue) return title; if (!props.searchValue || !match) return title;
const result = title.toLowerCase().split(props.searchValue.toLowerCase()); const result = title.substring(match[0], match[1] + 1);
if (result && result.length > 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>`;
return `<div>${result[0]}<span style='color: var(--ant-error-color)'>${props.searchValue}</span>${result[1]}</div>`;
} else {
return `<div>${result[0]}</div>`;
}
}; };
const renderDesc = (desc) => { const renderDesc = (desc) => {
@ -91,15 +98,45 @@ const sort = (options) => {
</script> </script>
<style lang="less"> <style lang="less">
.ellpise {
overflow:hidden;
text-overflow:ellipsis;
display:-webkit-box;
-webkit-line-clamp:1;
-webkit-box-orient:vertical;
}
.options { .options {
position: absolute; position: absolute;
top: 62px; top: 60px;
left: 0; left: 0;
width: 100%; width: 100%;
z-index: 99; z-index: 99;
max-height: calc(~'100vh - 64px'); max-height: calc(~'100vh - 60px');
overflow: auto; overflow: auto;
background: var(--color-body-bg); 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 { .op-item {
padding: 0 10px; padding: 0 10px;
height: 60px; height: 60px;

View File

@ -19,6 +19,7 @@
class="main-input" class="main-input"
@input="e => changeValue(e)" @input="e => changeValue(e)"
@keydown.down="e => keydownEvent(e, 'down')" @keydown.down="e => keydownEvent(e, 'down')"
@keydown.tab="e => keydownEvent(e, 'down')"
@keydown.up="e => keydownEvent(e, 'up')" @keydown.up="e => keydownEvent(e, 'up')"
@keydown="e => checkNeedInit(e)" @keydown="e => checkNeedInit(e)"
:value="searchValue" :value="searchValue"
@ -71,6 +72,7 @@ const props: any = defineProps({
type: String, type: String,
default: '', default: '',
}, },
pluginHistory: (() => [])(),
currentPlugin: {}, currentPlugin: {},
pluginLoading: Boolean, pluginLoading: Boolean,
clipboardFile: (() => [])(), clipboardFile: (() => [])(),
@ -107,7 +109,7 @@ const keydownEvent = (e, key: string) => {
modifiers, modifiers,
}, },
}); });
const runPluginDisable = e.target.value === '' || props.currentPlugin.name; const runPluginDisable = ((e.target.value === '' && !props.pluginHistory.length) || props.currentPlugin.name) ;
switch (key) { switch (key) {
case 'up': case 'up':
emit('changeCurrent', -1); emit('changeCurrent', -1);

View File

@ -7,6 +7,8 @@ import {
Avatar, Avatar,
Tag, Tag,
ConfigProvider, ConfigProvider,
Row,
Col,
} from 'ant-design-vue'; } from 'ant-design-vue';
import App from './App.vue'; import App from './App.vue';
import localConfig from './confOp'; import localConfig from './confOp';
@ -26,4 +28,6 @@ createApp(App)
.use(Input) .use(Input)
.use(Avatar) .use(Avatar)
.use(Tag) .use(Tag)
.use(Row)
.use(Col)
.mount('#app'); .mount('#app');

View File

@ -56,7 +56,7 @@ export default ({ currentPlugin, optionsRef, openPlugin, setOptionsRef }) => {
regImg.test(ext) && regImg.test(ext) &&
fileList.length === 1 fileList.length === 1
) { ) {
options.push({ const option = {
name: cmd.label, name: cmd.label,
value: 'plugin', value: 'plugin',
icon: plugin.logo, icon: plugin.logo,
@ -75,17 +75,19 @@ export default ({ currentPlugin, optionsRef, openPlugin, setOptionsRef }) => {
.toDataURL(), .toDataURL(),
}, },
openPlugin, openPlugin,
option,
}); });
clearClipboardFile(); clearClipboardFile();
}, },
}); };
options.push(option);
} }
// 如果是文件,且符合文件正则类型 // 如果是文件,且符合文件正则类型
if ( if (
fileList.length > 1 || fileList.length > 1 ||
(cmd.type === 'file' && new RegExp(cmd.match).test(ext)) (cmd.type === 'file' && new RegExp(cmd.match).test(ext))
) { ) {
options.push({ const option = {
name: cmd, name: cmd,
value: 'plugin', value: 'plugin',
icon: plugin.logo, icon: plugin.logo,
@ -96,6 +98,7 @@ export default ({ currentPlugin, optionsRef, openPlugin, setOptionsRef }) => {
plugin, plugin,
fe, fe,
cmd, cmd,
option,
ext: { ext: {
code: fe.code, code: fe.code,
type: cmd.type || 'text', type: cmd.type || 'text',
@ -105,7 +108,8 @@ export default ({ currentPlugin, optionsRef, openPlugin, setOptionsRef }) => {
}); });
clearClipboardFile(); clearClipboardFile();
}, },
}); };
options.push(option);
} }
}); });
}); });
@ -155,7 +159,7 @@ export default ({ currentPlugin, optionsRef, openPlugin, setOptionsRef }) => {
feature.forEach((fe) => { feature.forEach((fe) => {
fe.cmds.forEach((cmd) => { fe.cmds.forEach((cmd) => {
if (cmd.type === 'img') { if (cmd.type === 'img') {
options.push({ const option = {
name: cmd.label, name: cmd.label,
value: 'plugin', value: 'plugin',
icon: plugin.logo, icon: plugin.logo,
@ -172,10 +176,12 @@ export default ({ currentPlugin, optionsRef, openPlugin, setOptionsRef }) => {
payload: dataUrl, payload: dataUrl,
}, },
openPlugin, openPlugin,
option,
}); });
clearClipboardFile(); clearClipboardFile();
}, },
}); };
options.push(option);
} }
}); });
}); });

View File

@ -9,6 +9,7 @@ import { execSync } from 'child_process';
import searchManager from './search'; import searchManager from './search';
import optionsManager from './options'; import optionsManager from './options';
import { PLUGIN_INSTALL_DIR as baseDir } from '@/common/constans/renderer'; import { PLUGIN_INSTALL_DIR as baseDir } from '@/common/constans/renderer';
import { message } from 'ant-design-vue';
const createPluginManager = (): any => { const createPluginManager = (): any => {
const pluginInstance = new PluginHandler({ const pluginInstance = new PluginHandler({
@ -21,12 +22,35 @@ const createPluginManager = (): any => {
localPlugins: [], localPlugins: [],
currentPlugin: {}, currentPlugin: {},
pluginLoading: false, pluginLoading: false,
pluginHistory: [],
}); });
const appList = ref([]); const appList: any = ref([]);
const initPlugins = async () => { const initPlugins = async () => {
appList.value = await appSearch(nativeImage); 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) => { const loadPlugin = async (plugin) => {
@ -43,7 +67,7 @@ const createPluginManager = (): any => {
state.pluginLoading = false; state.pluginLoading = false;
}; };
const openPlugin = async (plugin) => { const openPlugin = async (plugin, option) => {
if (plugin.pluginType === 'ui' || plugin.pluginType === 'system') { if (plugin.pluginType === 'ui' || plugin.pluginType === 'system') {
if (state.currentPlugin && state.currentPlugin.name === plugin.name) { if (state.currentPlugin && state.currentPlugin.name === plugin.name) {
return; return;
@ -64,8 +88,29 @@ const createPluginManager = (): any => {
}); });
} }
if (plugin.pluginType === 'app') { 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 } = const { searchValue, onSearch, setSearchValue, placeholder } =

View File

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

View File

@ -3,7 +3,14 @@ import path from 'path';
import { toRaw } from 'vue'; import { toRaw } from 'vue';
import commonConst from '@/common/utils/commonConst'; 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 pluginPath = path.resolve(baseDir, 'node_modules', plugin.name);
const pluginDist = { const pluginDist = {
...toRaw(plugin), ...toRaw(plugin),
@ -24,5 +31,5 @@ export default function pluginClickEvent({ plugin, fe, cmd, ext, openPlugin }) {
? 'http://localhost:8081/#/' ? 'http://localhost:8081/#/'
: `file://${__static}/feature/index.html`; : `file://${__static}/feature/index.html`;
} }
openPlugin(pluginDist); openPlugin(pluginDist, option);
} }

View File

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

View File

@ -2728,6 +2728,11 @@ balanced-match@^1.0.0:
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== 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: base64-js@^1.0.2, base64-js@^1.3.1, base64-js@^1.5.1:
version "1.5.1" version "1.5.1"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
@ -2768,6 +2773,11 @@ bfj@^6.1.1:
hoopy "^0.1.4" hoopy "^0.1.4"
tryer "^1.0.1" 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: big.js@^3.1.3:
version "3.2.0" version "3.2.0"
resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e" resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e"
@ -2871,6 +2881,20 @@ boxen@^5.0.0:
widest-line "^3.1.0" widest-line "^3.1.0"
wrap-ansi "^7.0.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: brace-expansion@^1.1.7:
version "1.1.11" version "1.1.11"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
@ -8684,6 +8708,11 @@ pinkie@^2.0.0:
resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
integrity sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg== 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: pkg-dir@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-1.0.0.tgz#7a4b508a8d5bb2d629d447056ff4e9c9314cf3d4" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-1.0.0.tgz#7a4b508a8d5bb2d629d447056ff4e9c9314cf3d4"
@ -8705,6 +8734,15 @@ pkg-dir@^4.1.0:
dependencies: dependencies:
find-up "^4.0.0" 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: plist@^3.0.1, plist@^3.0.4:
version "3.0.6" version "3.0.6"
resolved "https://registry.yarnpkg.com/plist/-/plist-3.0.6.tgz#7cfb68a856a7834bca6dbfe3218eb9c7740145d3" resolved "https://registry.yarnpkg.com/plist/-/plist-3.0.6.tgz#7cfb68a856a7834bca6dbfe3218eb9c7740145d3"
@ -10038,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" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== 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: simple-swizzle@^0.2.2:
version "0.2.2" version "0.2.2"
resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a"
@ -10349,6 +10396,11 @@ stream-browserify@^2.0.1:
inherits "~2.0.1" inherits "~2.0.1"
readable-stream "^2.0.2" 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: stream-each@^1.1.0:
version "1.2.3" version "1.2.3"
resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae" resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae"
@ -11762,11 +11814,21 @@ xdg-basedir@^4.0.0:
resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13" resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13"
integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q== 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: xmlbuilder@>=11.0.1, xmlbuilder@^15.1.1:
version "15.1.1" version "15.1.1"
resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-15.1.1.tgz#9dcdce49eea66d8d10b42cae94a79c3c8d0c2ec5" resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-15.1.1.tgz#9dcdce49eea66d8d10b42cae94a79c3c8d0c2ec5"
integrity sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg== 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: xtend@^4.0.0, xtend@^4.0.2, xtend@~4.0.0, xtend@~4.0.1:
version "4.0.2" version "4.0.2"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"