🚨 增加 prettier

This commit is contained in:
muwoo 2023-03-16 14:45:53 +08:00
parent 4f58bfdc4f
commit dc74251bd0
19 changed files with 403 additions and 203 deletions

View File

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

19
.prettierrc Normal file
View File

@ -0,0 +1,19 @@
{
"tabWidth": 2,
"useTabs": false,
"semi": true,
"singleQuote": true,
"jsxSingleQuote": true,
"trailingComma": "es5",
"bracketSpacing": true,
"jsxBracketSameLine": false,
"arrowParens": "always",
"printWidth": 80,
"embeddedLanguageFormatting": "auto",
"htmlWhitespaceSensitivity": "ignore",
"preserve": "preserve",
"insertPragma": false,
"quoteProps": "as-needed",
"requirePragma": false,
"endOfLine": "auto"
}

View File

@ -15,7 +15,7 @@
@click="currentSelect = [index]" @click="currentSelect = [index]"
v-for="(plugin, index) in localPlugins" v-for="(plugin, index) in localPlugins"
> >
<img :src="plugin.logo" /> <img :src="plugin.logo"/>
<div class="info"> <div class="info">
<div class="title"> <div class="title">
{{ plugin.pluginName }} {{ plugin.pluginName }}
@ -63,18 +63,25 @@
<a-tag <a-tag
:key="cmd" :key="cmd"
v-for="cmd in item.cmds" v-for="cmd in item.cmds"
@close="removeFeature(cmd)"
@click="
!cmd.label &&
openPlugin({
code: item.code,
cmd
})
"
:class="{ executable: !cmd.label }" :class="{ executable: !cmd.label }"
:color="!cmd.label && '#87d068'" :color="!cmd.label && '#87d068'"
> >
{{ cmd.label || cmd }} <span @click="!cmd.label &&
openPlugin({
code: item.code,
cmd
})"
>
{{ cmd.label || cmd }}
</span>
<template v-if="!cmd.label" #icon>
<a-tooltip v-if="!hasAdded(cmd)" placement="topLeft" title="点击+号,固定关键词到超级面板">
<PlusCircleOutlined @click="addCmdToSuperPanel({code: item.code, cmd})" />
</a-tooltip>
<a-tooltip v-else placement="topLeft" title="点击-号,从超级面板移除关键词">
<MinusCircleOutlined @click="removePluginToSuperPanel(cmd)" />
</a-tooltip>
</template>
</a-tag> </a-tag>
</div> </div>
</div> </div>
@ -89,13 +96,15 @@
</template> </template>
<script setup> <script setup>
import { useStore } from "vuex"; import {useStore} from "vuex";
import { computed, ref } from "vue"; import {computed, ref, toRaw} from "vue";
import path from "path"; import path from "path";
import MarkdownIt from "markdown-it"; import MarkdownIt from "markdown-it";
const { ipcRenderer } = window.require("electron"); import {PlusCircleOutlined, MinusCircleOutlined} from "@ant-design/icons-vue";
const { remote } = window.require("electron"); const {ipcRenderer} = window.require("electron");
const {remote} = window.require("electron");
const fs = window.require("fs"); const fs = window.require("fs");
const md = new MarkdownIt(); const md = new MarkdownIt();
@ -117,8 +126,46 @@ const pluginDetail = computed(() => {
return localPlugins.value[currentSelect.value] || {}; return localPlugins.value[currentSelect.value] || {};
}); });
const openPlugin = ({ cmd, code }) => { const superPanelPlugins = ref(window.rubick.db.get("super-panel-plugins") || {
console.log(pluginDetail.value); data: [],
_id: "super-panel-plugins",
});
console.log(toRaw(superPanelPlugins.value.data))
const addCmdToSuperPanel = ({cmd, code}) => {
const plugin = {
...toRaw(pluginDetail.value),
cmd,
ext: {
code,
type: "text",
payload: null,
},
};
superPanelPlugins.value.data.push(plugin);
window.rubick.db.put(toRaw(superPanelPlugins.value));
};
const removePluginToSuperPanel = (cmd) => {
superPanelPlugins.value.data = toRaw(superPanelPlugins.value).data.filter((item) => {
return item.cmd !== cmd;
});
console.log(toRaw(superPanelPlugins.value) )
window.rubick.db.put(toRaw(superPanelPlugins.value));
};
const hasAdded = (cmd) => {
let added = false;
superPanelPlugins.value.data.some((item) => {
if (item.cmd === cmd) {
added = true;
return true;
}
return false;
});
return added;
};
const openPlugin = ({cmd, code}) => {
window.rubick.openPlugin( window.rubick.openPlugin(
JSON.parse( JSON.parse(
JSON.stringify({ JSON.stringify({
@ -163,6 +210,7 @@ const deletePlugin = async plugin => {
overflow: hidden; overflow: hidden;
background: #f3efef; background: #f3efef;
height: calc(~"100vh - 46px"); height: calc(~"100vh - 46px");
.container { .container {
box-sizing: border-box; box-sizing: border-box;
width: 100%; width: 100%;
@ -171,6 +219,7 @@ const deletePlugin = async plugin => {
height: 100%; height: 100%;
display: flex; display: flex;
} }
.installed-list { .installed-list {
width: 40%; width: 40%;
background: #fff; background: #fff;
@ -178,68 +227,84 @@ const deletePlugin = async plugin => {
padding: 10px 0; padding: 10px 0;
border-right: 1px solid #eee; border-right: 1px solid #eee;
overflow: auto; overflow: auto;
.item { .item {
padding: 10px 20px; padding: 10px 20px;
display: flex; display: flex;
align-items: center; align-items: center;
img { img {
width: 40px; width: 40px;
height: 40px; height: 40px;
margin-right: 20px; margin-right: 20px;
} }
.desc { .desc {
color: #999; color: #999;
} }
&.active { &.active {
background: #eee; background: #eee;
} }
} }
} }
.plugin-detail { .plugin-detail {
padding: 20px 20px 0 20px; padding: 20px 20px 0 20px;
box-sizing: border-box; box-sizing: border-box;
width: 60%; width: 60%;
height: 100%; height: 100%;
background: #fff; background: #fff;
.plugin-top { .plugin-top {
display: flex; display: flex;
align-items: flex-start; align-items: flex-start;
justify-content: space-between; justify-content: space-between;
.title { .title {
font-size: 20px; font-size: 20px;
display: flex; display: flex;
align-items: center; align-items: center;
} }
.desc { .desc {
font-size: 13px; font-size: 13px;
color: #999; color: #999;
} }
} }
.detail-container, .detail-container,
.feature-container { .feature-container {
height: 380px; height: 380px;
overflow: auto; overflow: auto;
img { img {
width: 100%; width: 100%;
} }
} }
.desc-item { .desc-item {
border-bottom: 1px solid #ddd; border-bottom: 1px solid #ddd;
padding: 10px 0; padding: 10px 0;
.ant-tag { .ant-tag {
margin-top: 6px; margin-top: 6px;
&.executable { &.executable {
cursor: pointer; cursor: pointer;
&:hover { &:hover {
transform: translateY(-2px); transform: translateY(-2px);
} }
} }
} }
.desc-title { .desc-title {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
} }
.desc-info { .desc-info {
color: #999; color: #999;
} }

View File

@ -14,6 +14,12 @@
</template> </template>
全局快捷键 全局快捷键
</a-menu-item> </a-menu-item>
<a-menu-item key="superpanel">
<template #icon>
<FileAddOutlined />
</template>
超级面板设置
</a-menu-item>
<a-menu-item key="localhost"> <a-menu-item key="localhost">
<template #icon> <template #icon>
<DatabaseOutlined /> <DatabaseOutlined />
@ -131,6 +137,7 @@
</div> </div>
</div> </div>
<Localhost v-if="currentSelect[0] === 'localhost'" /> <Localhost v-if="currentSelect[0] === 'localhost'" />
<SuperPanel v-if="currentSelect[0] === 'superpanel'" />
</div> </div>
</div> </div>
</template> </template>
@ -141,12 +148,14 @@ import {
LaptopOutlined, LaptopOutlined,
DatabaseOutlined, DatabaseOutlined,
MinusCircleOutlined, MinusCircleOutlined,
PlusCircleOutlined PlusCircleOutlined,
FileAddOutlined,
} 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, toRaw } from "vue"; import { ref, reactive, watch, toRefs, computed, toRaw } from "vue";
import keycodes from "./keycode"; import keycodes from "./keycode";
import Localhost from "./localhost.vue"; import Localhost from "./localhost.vue";
import SuperPanel from "./super-panel.vue";
const { remote, ipcRenderer } = window.require("electron"); const { remote, ipcRenderer } = window.require("electron");

View File

@ -0,0 +1,77 @@
<template>
请选择需要添加到超级面板中的常用插件
<div class="super-list-item panel-item">
<a-list :grid="{ gutter: 16, column: 2 }" :data-source="localPlugins.filter(item => !!item)">
<template #renderItem="{ item }">
<a-list-item v-if="item">
<template #actions>
<a-button v-if="!hasAdded(item)" @click="addPluginToSuperPanel(item)" style="color: #7ec699" type="text">
添加
</a-button>
<a-button v-else @click="removePluginToSuperPanel(item)" style="color: #ff4ea4;" type="text">
移除
</a-button>
</template>
<a-list-item-meta>
<template #description>
<span class="ellipse">{{ item.description }}</span>
</template>
<template #title>
<span class="ellipse">{{ item.pluginName }}</span>
</template>
<template #avatar>
<a-avatar :src="item.logo"/>
</template>
</a-list-item-meta>
</a-list-item>
</template>
</a-list>
</div>
</template>
<script setup>
import {useStore} from "vuex";
import {computed, ref, toRaw} from "vue";
const store = useStore();
const localPlugins = computed(() =>
store.state.localPlugins.filter(
plugin => plugin.name !== "rubick-system-feature" && plugin.name !== "rubick-system-super-panel"
)
);
const hasAdded = (plugin) => {
let added = false;
superPanelPlugins.value.data.some((item) => {
if (item.name === plugin.name) {
added = true;
return true;
}
return false;
});
return added;
};
const superPanelPlugins = ref(window.rubick.db.get("super-panel-db") || {
data: [],
_id: "super-panel-db",
});
const addPluginToSuperPanel = (plugin) => {
superPanelPlugins.value.data.push(toRaw(plugin));
window.rubick.db.put(toRaw(superPanelPlugins.value));
};
const removePluginToSuperPanel = (plugin) => {
superPanelPlugins.value.data = toRaw(superPanelPlugins.value).data.filter((item) => {
return item.name !== plugin.name;
});
window.rubick.db.put(toRaw(superPanelPlugins.value));
};
</script>
<style lang="less">
.super-list-item.panel-item {
&:after {
display: none;
}
}
</style>

View File

@ -1,6 +1,6 @@
{ {
"name": "rubick", "name": "rubick",
"version": "2.0.7", "version": "2.0.8",
"author": "muwoo <2424880409@qq.com>", "author": "muwoo <2424880409@qq.com>",
"private": true, "private": true,
"scripts": { "scripts": {
@ -57,7 +57,7 @@
"eslint-plugin-vue": "^7.0.0", "eslint-plugin-vue": "^7.0.0",
"less": "^3.0.4", "less": "^3.0.4",
"less-loader": "^5.0.0", "less-loader": "^5.0.0",
"prettier": "^2.2.1", "prettier": "^2.8.4",
"typescript": "~4.1.5", "typescript": "~4.1.5",
"vue-cli-plugin-electron-builder": "~2.1.1", "vue-cli-plugin-electron-builder": "~2.1.1",
"worker-plugin": "^5.0.1" "worker-plugin": "^5.0.1"

View File

@ -38,6 +38,12 @@ export default () => {
const createView = (plugin, window: BrowserWindow) => { const createView = (plugin, window: BrowserWindow) => {
let pluginIndexPath = plugin.tplPath || plugin.indexPath; let pluginIndexPath = plugin.tplPath || plugin.indexPath;
// 再尝试去找
if (plugin.name === "rubick-system-feature" && !pluginIndexPath) {
pluginIndexPath = commonConst.dev()
? "http://localhost:8081/#/"
: `file://${__static}/feature/index.html`;
}
if (!pluginIndexPath) { if (!pluginIndexPath) {
const pluginPath = path.resolve(baseDir, "node_modules", plugin.name); const pluginPath = path.resolve(baseDir, "node_modules", plugin.name);
pluginIndexPath = `file://${path.join(pluginPath, "./", plugin.main)}`; pluginIndexPath = `file://${path.join(pluginPath, "./", plugin.main)}`;

View File

@ -38,7 +38,6 @@ class App {
this.onQuit(); this.onQuit();
} }
} }
beforeReady() { beforeReady() {
// 系统托盘 // 系统托盘
if (commonConst.macOS()) { if (commonConst.macOS()) {
@ -55,7 +54,6 @@ class App {
createWindow() { createWindow() {
this.windowCreator.init(); this.windowCreator.init();
} }
onReady() { onReady() {
const readyFunction = () => { const readyFunction = () => {
this.createWindow(); this.createWindow();

View File

@ -35,14 +35,14 @@
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang='ts'>
import { watch, ref, nextTick, toRaw } from "vue"; import { watch, ref, nextTick, toRaw } from 'vue';
import { ipcRenderer, remote } from "electron"; import { ipcRenderer, remote } from 'electron';
import Result from "./components/result.vue"; import Result from './components/result.vue';
import Search from "./components/search.vue"; 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 commonConst from "@/common/utils/commonConst"; import commonConst from '@/common/utils/commonConst';
const { const {
initPlugins, initPlugins,
@ -59,30 +59,30 @@ const {
clipboardFile, clipboardFile,
setSearchValue, setSearchValue,
clearClipboardFile, clearClipboardFile,
readClipboardContent readClipboardContent,
} = createPluginManager(); } = createPluginManager();
initPlugins(); initPlugins();
const currentSelect = ref(0); const currentSelect = ref(0);
const menuPluginInfo = ref({}); const menuPluginInfo: any = ref({});
getPluginInfo({ getPluginInfo({
pluginName: "feature", pluginName: 'feature',
// eslint-disable-next-line no-undef // eslint-disable-next-line no-undef
pluginPath: `${__static}/feature/package.json` pluginPath: `${__static}/feature/package.json`,
}).then(res => { }).then(res => {
menuPluginInfo.value = res; menuPluginInfo.value = res;
remote.getGlobal("LOCAL_PLUGINS").addPlugin(res); remote.getGlobal('LOCAL_PLUGINS').addPlugin(res);
}); });
watch([options], () => { watch([options], () => {
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),
}); });
}); });
}); });
@ -101,12 +101,12 @@ const openMenu = (ext) => {
openPlugin({ openPlugin({
...toRaw(menuPluginInfo.value), ...toRaw(menuPluginInfo.value),
feature: menuPluginInfo.value.features[0], feature: menuPluginInfo.value.features[0],
cmd: "插件市场", cmd: '插件市场',
ext ext,
}); });
}; };
window.rubick.openMenu = openMenu window.rubick.openMenu = openMenu;
const choosePlugin = () => { const choosePlugin = () => {
const currentChoose = options.value[currentSelect.value]; const currentChoose = options.value[currentSelect.value];
@ -114,11 +114,11 @@ const choosePlugin = () => {
}; };
const clearSearchValue = () => { const clearSearchValue = () => {
setSearchValue(""); setSearchValue('');
}; };
</script> </script>
<style lang="less"> <style lang='less'>
.drag-bar { .drag-bar {
-webkit-app-region: drag; -webkit-app-region: drag;
width: 100%; width: 100%;
@ -128,6 +128,7 @@ const clearSearchValue = () => {
top: 0; top: 0;
left: 0; left: 0;
} }
#components-layout { #components-layout {
height: 100vh; height: 100vh;
overflow: hidden; overflow: hidden;
@ -135,6 +136,7 @@ const clearSearchValue = () => {
width: 0; width: 0;
} }
} }
.drag { .drag {
-webkit-app-region: drag; -webkit-app-region: drag;
} }

View File

@ -28,9 +28,10 @@
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang='ts' setup>
import BScroll from "@better-scroll/core"; import BScroll from '@better-scroll/core';
import { defineProps, onMounted, ref } from "vue"; import { defineProps, onMounted, ref } from 'vue';
const scrollDom = ref(null); const scrollDom = ref(null);
onMounted(() => { onMounted(() => {
@ -40,7 +41,7 @@ onMounted(() => {
const props = defineProps({ const props = defineProps({
searchValue: { searchValue: {
type: [String, Number], type: [String, Number],
default: "", default: '',
}, },
options: { options: {
type: Array, type: Array,
@ -55,11 +56,11 @@ const props = defineProps({
}); });
const renderTitle = (title) => { const renderTitle = (title) => {
if (typeof title !== "string") return; if (typeof title !== 'string') return;
if (!props.searchValue) return title; if (!props.searchValue) return title;
const result = title.toLowerCase().split(props.searchValue.toLowerCase()); const result = title.toLowerCase().split(props.searchValue.toLowerCase());
if (result && result.length > 1) { if (result && result.length > 1) {
return `<div>${result[0]}<span style="color: red">${props.searchValue}</span>${result[1]}</div>`; return `<div>${result[0]}<span style='color: red'>${props.searchValue}</span>${result[1]}</div>`;
} else { } else {
return `<div>${result[0]}</div>`; return `<div>${result[0]}</div>`;
} }

View File

@ -51,10 +51,11 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { defineProps, defineEmits, ref, computed } from "vue"; import { defineProps, defineEmits, ref } from 'vue';
import { ipcRenderer, remote } from "electron"; import { ipcRenderer, remote } from 'electron';
import { LoadingOutlined, MoreOutlined } from "@ant-design/icons-vue"; import { LoadingOutlined, MoreOutlined } from '@ant-design/icons-vue';
const opConfig = remote.getGlobal("OP_CONFIG");
const opConfig = remote.getGlobal('OP_CONFIG');
const { Menu } = remote; const { Menu } = remote;
const config = ref(opConfig.get()); const config = ref(opConfig.get());
@ -62,63 +63,63 @@ const config = ref(opConfig.get());
const props: any = defineProps({ const props: any = defineProps({
searchValue: { searchValue: {
type: [String, Number], type: [String, Number],
default: "" default: '',
}, },
placeholder: { placeholder: {
type: String, type: String,
default: "" default: '',
}, },
currentPlugin: {}, currentPlugin: {},
pluginLoading: Boolean, pluginLoading: Boolean,
clipboardFile: (() => [])() clipboardFile: (() => [])(),
}); });
const changeValue = e => { const changeValue = e => {
if (props.currentPlugin.name === "rubick-system-feature") return; if (props.currentPlugin.name === 'rubick-system-feature') return;
targetSearch({ value: e.target.value }); targetSearch({ value: e.target.value });
emit("onSearch", e); emit('onSearch', e);
}; };
const emit = defineEmits([ const emit = defineEmits([
"onSearch", 'onSearch',
"changeCurrent", 'changeCurrent',
"openMenu", 'openMenu',
"changeSelect", 'changeSelect',
"choosePlugin", 'choosePlugin',
"focus", 'focus',
"clearSearchValue", 'clearSearchValue',
"readClipboardContent" 'readClipboardContent',
]); ]);
const keydownEvent = (e, key: string) => { const keydownEvent = (e, key: string) => {
const { ctrlKey, shiftKey, altKey, metaKey } = e; const { ctrlKey, shiftKey, altKey, metaKey } = e;
const modifiers: Array<string> = []; const modifiers: Array<string> = [];
ctrlKey && modifiers.push("control"); ctrlKey && modifiers.push('control');
shiftKey && modifiers.push("shift"); shiftKey && modifiers.push('shift');
altKey && modifiers.push("alt"); altKey && modifiers.push('alt');
metaKey && modifiers.push("meta"); metaKey && modifiers.push('meta');
ipcRenderer.send("msg-trigger", { ipcRenderer.send('msg-trigger', {
type: "sendPluginSomeKeyDownEvent", type: 'sendPluginSomeKeyDownEvent',
data: { data: {
keyCode: e.code, keyCode: e.code,
modifiers modifiers,
} },
}); });
const runPluginDisable = e.target.value === "" || props.currentPlugin.name; const runPluginDisable = e.target.value === '' || props.currentPlugin.name;
switch (key) { switch (key) {
case "up": case 'up':
emit("changeCurrent", -1); emit('changeCurrent', -1);
break; break;
case "down": case 'down':
emit("changeCurrent", 1); emit('changeCurrent', 1);
break; break;
case "enter": case 'enter':
if (runPluginDisable) return; if (runPluginDisable) return;
emit("choosePlugin"); emit('choosePlugin');
break; break;
case "space": case 'space':
if (runPluginDisable || !opConfig.get().perf.common.space) return; if (runPluginDisable || !opConfig.get().perf.common.space) return;
emit("choosePlugin"); emit('choosePlugin');
break; break;
default: default:
break; break;
@ -128,63 +129,63 @@ const keydownEvent = (e, key: string) => {
const checkNeedInit = e => { const checkNeedInit = e => {
const { ctrlKey, metaKey } = e; const { ctrlKey, metaKey } = e;
if (e.target.value === "" && e.keyCode === 8) { if (e.target.value === '' && e.keyCode === 8) {
closeTag(); closeTag();
} }
// //
if ((ctrlKey || metaKey) && e.key === "v") { if ((ctrlKey || metaKey) && e.key === 'v') {
emit("readClipboardContent"); emit('readClipboardContent');
} }
}; };
const targetSearch = ({ value }) => { const targetSearch = ({ value }) => {
if (props.currentPlugin.name) { if (props.currentPlugin.name) {
return ipcRenderer.sendSync("msg-trigger", { return ipcRenderer.sendSync('msg-trigger', {
type: "sendSubInputChangeEvent", type: 'sendSubInputChangeEvent',
data: { text: value } data: { text: value },
}); });
} }
}; };
const closeTag = () => { const closeTag = () => {
emit("changeSelect", {}); emit('changeSelect', {});
emit("clearClipbord"); emit('clearClipbord');
ipcRenderer.send("msg-trigger", { ipcRenderer.send('msg-trigger', {
type: "removePlugin" type: 'removePlugin',
}); });
}; };
const showSeparate = () => { const showSeparate = () => {
let pluginMenu: any = [ let pluginMenu: any = [
{ {
label: config.value.perf.common.hideOnBlur ? "钉住" : "自动隐藏", label: config.value.perf.common.hideOnBlur ? '钉住' : '自动隐藏',
click: changeHideOnBlur click: changeHideOnBlur,
} },
]; ];
if (props.currentPlugin && props.currentPlugin.logo) { if (props.currentPlugin && props.currentPlugin.logo) {
pluginMenu = pluginMenu.concat([ pluginMenu = pluginMenu.concat([
{ {
label: "开发者工具", label: '开发者工具',
click: () => { click: () => {
ipcRenderer.send("msg-trigger", { type: "openPluginDevTools" }); ipcRenderer.send('msg-trigger', { type: 'openPluginDevTools' });
// todo // todo
} },
}, },
{ {
label: "当前插件信息", label: '当前插件信息',
submenu: [ submenu: [
{ {
label: "简介" label: '简介',
}, },
{ {
label: "功能" label: '功能',
} },
] ],
}, },
{ {
label: "分离窗口", label: '分离窗口',
click: newWindow click: newWindow,
} },
]); ]);
} }
let menu = Menu.buildFromTemplate(pluginMenu); let menu = Menu.buildFromTemplate(pluginMenu);
@ -201,13 +202,13 @@ const changeHideOnBlur = () => {
const getIcon = () => { const getIcon = () => {
if (props.clipboardFile[0].dataUrl) return props.clipboardFile[0].dataUrl; if (props.clipboardFile[0].dataUrl) return props.clipboardFile[0].dataUrl;
return props.clipboardFile[0].isFile return props.clipboardFile[0].isFile
? require("../assets/file.png") ? require('../assets/file.png')
: require("../assets/folder.png"); : require('../assets/folder.png');
}; };
const newWindow = () => { const newWindow = () => {
ipcRenderer.send("msg-trigger", { ipcRenderer.send('msg-trigger', {
type: "detachPlugin" type: 'detachPlugin',
}); });
// todo // todo
}; };
@ -218,7 +219,7 @@ window.rubick.hooks.onShow = () => {
}; };
window.rubick.hooks.onHide = () => { window.rubick.hooks.onHide = () => {
emit("clearSearchValue"); emit('clearSearchValue');
}; };
</script> </script>
@ -238,6 +239,7 @@ window.rubick.hooks.onHide = () => {
white-space: nowrap; white-space: nowrap;
max-width: 200px; max-width: 200px;
} }
.select-tag { .select-tag {
white-space: pre; white-space: pre;
user-select: none; user-select: none;
@ -252,6 +254,7 @@ window.rubick.hooks.onHide = () => {
margin-right: 1px; margin-right: 1px;
padding: 0 10px; padding: 0 10px;
} }
.main-input { .main-input {
height: 60px !important; height: 60px !important;
box-sizing: border-box; box-sizing: border-box;
@ -259,6 +262,7 @@ window.rubick.hooks.onHide = () => {
border: none; border: none;
outline: none; outline: none;
box-shadow: none !important; box-shadow: none !important;
.ant-select-selection, .ant-select-selection,
.ant-input, .ant-input,
.ant-select-selection__rendered { .ant-select-selection__rendered {
@ -267,6 +271,7 @@ window.rubick.hooks.onHide = () => {
border: none !important; border: none !important;
} }
} }
.rubick-logo, .rubick-logo,
.icon-tool { .icon-tool {
width: 40px; width: 40px;

View File

@ -1,6 +1,6 @@
import { createApp } from "vue"; import { createApp } from 'vue';
import { Button, List, Spin, Input, Avatar, Tag } from "ant-design-vue"; import { Button, List, Spin, Input, Avatar, Tag } from 'ant-design-vue';
import App from "./App.vue"; import App from './App.vue';
createApp(App) createApp(App)
.use(Button) .use(Button)
@ -9,4 +9,4 @@ createApp(App)
.use(Input) .use(Input)
.use(Avatar) .use(Avatar)
.use(Tag) .use(Tag)
.mount("#app"); .mount('#app');

View File

@ -1,13 +1,13 @@
import getCopyFiles from "@/common/utils/getCopyFiles"; import getCopyFiles from '@/common/utils/getCopyFiles';
import { clipboard, nativeImage, remote, ipcRenderer } from "electron"; import { clipboard, nativeImage, remote, ipcRenderer } from 'electron';
import path from "path"; import path from 'path';
import pluginClickEvent from "./pluginClickEvent"; import pluginClickEvent from './pluginClickEvent';
import { ref } from "vue"; import { ref } from 'vue';
export default ({ currentPlugin, optionsRef, openPlugin, setOptionsRef }) => { export default ({ currentPlugin, optionsRef, openPlugin, setOptionsRef }) => {
const clipboardFile: any = ref([]); const clipboardFile: any = ref([]);
const searchFocus = () => { const searchFocus = () => {
const config = remote.getGlobal("OP_CONFIG").get(); const config = remote.getGlobal('OP_CONFIG').get();
// 未开启自动粘贴 // 未开启自动粘贴
if (!config.perf.common.autoPast) return; if (!config.perf.common.autoPast) return;
@ -15,18 +15,18 @@ export default ({ currentPlugin, optionsRef, openPlugin, setOptionsRef }) => {
const fileList = getCopyFiles(); const fileList = getCopyFiles();
// 拷贝的是文件 // 拷贝的是文件
if (fileList) { if (fileList) {
window.setSubInputValue({ value: "" }); window.setSubInputValue({ value: '' });
clipboardFile.value = fileList; clipboardFile.value = fileList;
const localPlugins = remote.getGlobal("LOCAL_PLUGINS").getLocalPlugins(); const localPlugins = remote.getGlobal('LOCAL_PLUGINS').getLocalPlugins();
const options: any = [ const options: any = [
{ {
name: "复制路径", name: '复制路径',
value: "plugin", value: 'plugin',
icon: require("../assets/link.png"), icon: require('../assets/link.png'),
desc: "复制路径到剪切板", desc: '复制路径到剪切板',
click: () => { click: () => {
clipboard.writeText(fileList.map((file) => file.path).join(",")); clipboard.writeText(fileList.map((file) => file.path).join(','));
ipcRenderer.send("msg-trigger", { type: "hideMainWindow" }); ipcRenderer.send('msg-trigger', { type: 'hideMainWindow' });
}, },
}, },
]; ];
@ -50,13 +50,13 @@ export default ({ currentPlugin, optionsRef, openPlugin, setOptionsRef }) => {
fe.cmds.forEach((cmd) => { fe.cmds.forEach((cmd) => {
const regImg = /\.(png|jpg|gif|jpeg|webp)$/; const regImg = /\.(png|jpg|gif|jpeg|webp)$/;
if ( if (
cmd.type === "img" && cmd.type === 'img' &&
regImg.test(ext) && regImg.test(ext) &&
fileList.length === 1 fileList.length === 1
) { ) {
options.push({ options.push({
name: cmd.label, name: cmd.label,
value: "plugin", value: 'plugin',
icon: plugin.logo, icon: plugin.logo,
desc: fe.explain, desc: fe.explain,
type: plugin.pluginType, type: plugin.pluginType,
@ -67,7 +67,7 @@ export default ({ currentPlugin, optionsRef, openPlugin, setOptionsRef }) => {
cmd, cmd,
ext: { ext: {
code: fe.code, code: fe.code,
type: cmd.type || "text", type: cmd.type || 'text',
payload: nativeImage payload: nativeImage
.createFromPath(fileList[0].path) .createFromPath(fileList[0].path)
.toDataURL(), .toDataURL(),
@ -81,11 +81,11 @@ export default ({ currentPlugin, optionsRef, openPlugin, setOptionsRef }) => {
// 如果是文件,且符合文件正则类型 // 如果是文件,且符合文件正则类型
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({ options.push({
name: cmd, name: cmd,
value: "plugin", value: 'plugin',
icon: plugin.logo, icon: plugin.logo,
desc: fe.explain, desc: fe.explain,
type: plugin.pluginType, type: plugin.pluginType,
@ -96,7 +96,7 @@ export default ({ currentPlugin, optionsRef, openPlugin, setOptionsRef }) => {
cmd, cmd,
ext: { ext: {
code: fe.code, code: fe.code,
type: cmd.type || "text", type: cmd.type || 'text',
payload: fileList, payload: fileList,
}, },
openPlugin, openPlugin,
@ -115,7 +115,7 @@ export default ({ currentPlugin, optionsRef, openPlugin, setOptionsRef }) => {
} }
const clipboardType = clipboard.availableFormats(); const clipboardType = clipboard.availableFormats();
if (!clipboardType.length) return; if (!clipboardType.length) return;
if ("text/plain" === clipboardType[0]) { if ('text/plain' === clipboardType[0]) {
const contentText = clipboard.readText(); const contentText = clipboard.readText();
if (contentText.trim()) { if (contentText.trim()) {
clearClipboardFile(); clearClipboardFile();
@ -134,7 +134,7 @@ export default ({ currentPlugin, optionsRef, openPlugin, setOptionsRef }) => {
// read image // read image
const img = clipboard.readImage(); const img = clipboard.readImage();
const dataUrl = img.toDataURL(); const dataUrl = img.toDataURL();
if (!dataUrl.replace("data:image/png;base64,", "")) return; if (!dataUrl.replace('data:image/png;base64,', '')) return;
clipboardFile.value = [ clipboardFile.value = [
{ {
isFile: true, isFile: true,
@ -143,7 +143,7 @@ export default ({ currentPlugin, optionsRef, openPlugin, setOptionsRef }) => {
dataUrl, dataUrl,
}, },
]; ];
const localPlugins = remote.getGlobal("LOCAL_PLUGINS").getLocalPlugins(); const localPlugins = remote.getGlobal('LOCAL_PLUGINS').getLocalPlugins();
const options: any = []; const options: any = [];
// 再正则插件 // 再正则插件
localPlugins.forEach((plugin) => { localPlugins.forEach((plugin) => {
@ -152,10 +152,10 @@ export default ({ currentPlugin, optionsRef, openPlugin, setOptionsRef }) => {
if (!feature) return; if (!feature) return;
feature.forEach((fe) => { feature.forEach((fe) => {
fe.cmds.forEach((cmd) => { fe.cmds.forEach((cmd) => {
if (cmd.type === "img") { if (cmd.type === 'img') {
options.push({ options.push({
name: cmd.label, name: cmd.label,
value: "plugin", value: 'plugin',
icon: plugin.logo, icon: plugin.logo,
desc: fe.explain, desc: fe.explain,
type: plugin.pluginType, type: plugin.pluginType,
@ -166,7 +166,7 @@ export default ({ currentPlugin, optionsRef, openPlugin, setOptionsRef }) => {
cmd, cmd,
ext: { ext: {
code: fe.code, code: fe.code,
type: cmd.type || "text", type: cmd.type || 'text',
payload: dataUrl, payload: dataUrl,
}, },
openPlugin, openPlugin,

View File

@ -1,13 +1,13 @@
import { reactive, toRefs, ref } from "vue"; import { reactive, toRefs, ref } from 'vue';
import { nativeImage, remote, ipcRenderer } from "electron"; import { nativeImage, remote, ipcRenderer } from 'electron';
import appSearch from "@/core/app-search"; import appSearch from '@/core/app-search';
import { PluginHandler } from "@/core"; import { PluginHandler } from '@/core';
import path from "path"; import path from 'path';
import commonConst from "@/common/utils/commonConst"; import commonConst from '@/common/utils/commonConst';
import { execSync } from "child_process"; 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';
const createPluginManager = (): any => { const createPluginManager = (): any => {
const pluginInstance = new PluginHandler({ const pluginInstance = new PluginHandler({
@ -34,27 +34,27 @@ const createPluginManager = (): any => {
}; };
const openPlugin = (plugin) => { const openPlugin = (plugin) => {
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;
} }
loadPlugin(plugin); loadPlugin(plugin);
ipcRenderer.sendSync("msg-trigger", { ipcRenderer.sendSync('msg-trigger', {
type: "openPlugin", type: 'openPlugin',
data: JSON.parse( data: JSON.parse(
JSON.stringify({ JSON.stringify({
...plugin, ...plugin,
ext: plugin.ext || { ext: plugin.ext || {
code: plugin.feature.code, code: plugin.feature.code,
type: plugin.cmd.type || "text", type: plugin.cmd.type || 'text',
payload: null, payload: null,
}, },
}) })
), ),
}); });
setSearchValue(""); setSearchValue('');
} }
if (plugin.pluginType === "app") { if (plugin.pluginType === 'app') {
execSync(plugin.action); execSync(plugin.action);
} }
}; };
@ -83,8 +83,8 @@ const createPluginManager = (): any => {
...pluginInfo, ...pluginInfo,
icon: pluginInfo.logo, icon: pluginInfo.logo,
indexPath: commonConst.dev() indexPath: commonConst.dev()
? "http://localhost:8081/#/" ? 'http://localhost:8081/#/'
: `file://${path.join(pluginPath, "../", pluginInfo.main)}`, : `file://${path.join(pluginPath, '../', pluginInfo.main)}`,
}; };
}; };
@ -104,18 +104,18 @@ const createPluginManager = (): any => {
window.updatePlugin = ({ currentPlugin }: any) => { window.updatePlugin = ({ currentPlugin }: any) => {
state.currentPlugin = currentPlugin; state.currentPlugin = currentPlugin;
remote.getGlobal("LOCAL_PLUGINS").updatePlugin(currentPlugin); remote.getGlobal('LOCAL_PLUGINS').updatePlugin(currentPlugin);
}; };
window.setCurrentPlugin = ({ currentPlugin }) => { window.setCurrentPlugin = ({ currentPlugin }) => {
state.currentPlugin = currentPlugin; state.currentPlugin = currentPlugin;
setSearchValue(""); setSearchValue('');
}; };
window.initRubick = () => { window.initRubick = () => {
state.currentPlugin = {}; state.currentPlugin = {};
setSearchValue(""); setSearchValue('');
window.setSubInput({ placeholder: "" }); window.setSubInput({ placeholder: '' });
}; };
window.pluginLoaded = () => { window.pluginLoaded = () => {

View File

@ -1,21 +1,21 @@
import { ref, watch } from "vue"; import { ref, watch } from 'vue';
import throttle from "lodash.throttle"; import throttle from 'lodash.throttle';
import { remote, ipcRenderer } from "electron"; import { remote, ipcRenderer } from 'electron';
import pluginClickEvent from "./pluginClickEvent"; import pluginClickEvent from './pluginClickEvent';
import useFocus from "./clipboardWatch"; import useFocus from './clipboardWatch';
function formatReg(regStr) { function formatReg(regStr) {
const flags = regStr.replace(/.*\/([gimy]*)$/, "$1"); const flags = regStr.replace(/.*\/([gimy]*)$/, '$1');
const pattern = flags.replace(new RegExp("^/(.*?)/" + flags + "$"), "$1"); const pattern = flags.replace(new RegExp('^/(.*?)/' + flags + '$'), '$1');
return new RegExp(pattern, flags); return new RegExp(pattern, flags);
} }
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 item.toLowerCase().indexOf(value.toLowerCase()) >= 0;
} }
if (item.type === "regex" && !strict) { if (item.type === 'regex' && !strict) {
return formatReg(item.match).test(value); return formatReg(item.match).test(value);
} }
return false; return false;
@ -31,13 +31,13 @@ const optionsManager = ({
const optionsRef = ref([]); const optionsRef = ref([]);
// 全局快捷键 // 全局快捷键
ipcRenderer.on("global-short-key", (e, msg) => { ipcRenderer.on('global-short-key', (e, msg) => {
const options = getOptionsFromSearchValue(msg, true); const options = getOptionsFromSearchValue(msg, true);
options[0].click(); options[0].click();
}); });
const getOptionsFromSearchValue = (value, strict = false) => { const getOptionsFromSearchValue = (value, strict = false) => {
const localPlugins = remote.getGlobal("LOCAL_PLUGINS").getLocalPlugins(); const localPlugins = remote.getGlobal('LOCAL_PLUGINS').getLocalPlugins();
let options: any = []; let options: any = [];
// todo 先搜索 plugin // todo 先搜索 plugin
localPlugins.forEach((plugin) => { localPlugins.forEach((plugin) => {
@ -50,7 +50,7 @@ const optionsManager = ({
...options, ...options,
...cmds.map((cmd) => ({ ...cmds.map((cmd) => ({
name: cmd.label || cmd, name: cmd.label || cmd,
value: "plugin", value: 'plugin',
icon: plugin.logo, icon: plugin.logo,
desc: fe.explain, desc: fe.explain,
type: plugin.pluginType, type: plugin.pluginType,
@ -63,7 +63,7 @@ const optionsManager = ({
ext: cmd.type ext: cmd.type
? { ? {
code: fe.code, code: fe.code,
type: cmd.type || "text", type: cmd.type || 'text',
payload: searchValue.value, payload: searchValue.value,
} }
: null, : null,

View File

@ -1,13 +1,13 @@
import { PLUGIN_INSTALL_DIR as baseDir } from "@/common/constans/renderer"; import { PLUGIN_INSTALL_DIR as baseDir } from '@/common/constans/renderer';
import path from "path"; 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 }) {
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),
indexPath: `file://${path.join(pluginPath, "./", plugin.main || "")}`, indexPath: `file://${path.join(pluginPath, './', plugin.main || '')}`,
cmd: cmd.label || cmd, cmd: cmd.label || cmd,
feature: fe, feature: fe,
ext, ext,
@ -15,13 +15,13 @@ export default function pluginClickEvent({ plugin, fe, cmd, ext, openPlugin }) {
// 模板文件 // 模板文件
if (!plugin.main) { if (!plugin.main) {
pluginDist.tplPath = commonConst.dev() pluginDist.tplPath = commonConst.dev()
? "http://localhost:8082/#/" ? 'http://localhost:8082/#/'
: `file://${__static}/tpl/index.html`; : `file://${__static}/tpl/index.html`;
} }
// 插件市场 // 插件市场
if (plugin.name === "rubick-system-feature") { if (plugin.name === 'rubick-system-feature') {
pluginDist.indexPath = commonConst.dev() pluginDist.indexPath = commonConst.dev()
? "http://localhost:8081/#/" ? 'http://localhost:8081/#/'
: `file://${__static}/feature/index.html`; : `file://${__static}/feature/index.html`;
} }
openPlugin(pluginDist); openPlugin(pluginDist);

View File

@ -1,10 +1,9 @@
import { reactive, toRefs } from "vue"; import { reactive, toRefs } from 'vue';
import { ipcRenderer, remote } from "electron";
const searchManager = () => { const searchManager = () => {
const state = reactive({ const state = reactive({
searchValue: "", searchValue: '',
placeholder: "", placeholder: '',
}); });
// search Input operation // search Input operation
@ -21,7 +20,7 @@ const searchManager = () => {
state.placeholder = placeholder; state.placeholder = placeholder;
}; };
window.removeSubInput = () => { window.removeSubInput = () => {
state.placeholder = ""; state.placeholder = '';
}; };
window.setSubInputValue = ({ value }: { value: string }) => { window.setSubInputValue = ({ value }: { value: string }) => {
state.searchValue = value; state.searchValue = value;

View File

@ -1,17 +1,17 @@
/* eslint-disable */ /* eslint-disable */
declare module "*.vue" { declare module '*.vue' {
import type { DefineComponent } from "vue"; import type { DefineComponent } from 'vue';
const component: DefineComponent<{}, {}, any>; const component: DefineComponent<{}, {}, any>;
export default component; export default component;
} }
declare module "main" { declare module 'main' {
export function main(): any; export function main(): any;
} }
declare const __static: string; declare const __static: string;
declare module "lodash.throttle"; declare module 'lodash.throttle';
interface Window { interface Window {
rubick: any; rubick: any;

View File

@ -4615,6 +4615,14 @@ electron-builder@^22.2.0:
update-notifier "^5.1.0" update-notifier "^5.1.0"
yargs "^17.0.1" yargs "^17.0.1"
electron-clipboard-ex@^1.3.3:
version "1.3.3"
resolved "https://registry.yarnpkg.com/electron-clipboard-ex/-/electron-clipboard-ex-1.3.3.tgz#d035716ba7fcadf6e1cd91507f1a127f11cbbc63"
integrity sha512-bny+IQhbLd7ur4NMKJ6P9+WRG2KTF6yGrbKem2N/zIdK64Yk3hCqVEiuyON6b2aOeEUDGkvS8LCkk4Q2IimehA==
dependencies:
node-addon-api "^4.0.0"
node-gyp-build "^4.2.3"
electron-devtools-installer@^3.1.0: electron-devtools-installer@^3.1.0:
version "3.2.0" version "3.2.0"
resolved "https://registry.yarnpkg.com/electron-devtools-installer/-/electron-devtools-installer-3.2.0.tgz#acc48d24eb7033fe5af284a19667e73b78d406d0" resolved "https://registry.yarnpkg.com/electron-devtools-installer/-/electron-devtools-installer-3.2.0.tgz#acc48d24eb7033fe5af284a19667e73b78d406d0"
@ -9008,11 +9016,16 @@ prettier-linter-helpers@^1.0.0:
dependencies: dependencies:
fast-diff "^1.1.2" fast-diff "^1.1.2"
"prettier@^1.18.2 || ^2.0.0", prettier@^2.2.1: "prettier@^1.18.2 || ^2.0.0":
version "2.7.1" version "2.7.1"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.7.1.tgz#e235806850d057f97bb08368a4f7d899f7760c64" resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.7.1.tgz#e235806850d057f97bb08368a4f7d899f7760c64"
integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g== integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==
prettier@^2.8.4:
version "2.8.4"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.4.tgz#34dd2595629bfbb79d344ac4a91ff948694463c3"
integrity sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==
pretty-error@^2.0.2: pretty-error@^2.0.2:
version "2.1.2" version "2.1.2"
resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-2.1.2.tgz#be89f82d81b1c86ec8fdfbc385045882727f93b6" resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-2.1.2.tgz#be89f82d81b1c86ec8fdfbc385045882727f93b6"