mirror of
https://github.com/rubickCenter/rubick
synced 2025-06-29 17:22:44 +08:00
♻️ search 框输入交互优化
This commit is contained in:
parent
951f21f5fa
commit
8a35e60e48
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "rubick2",
|
"name": "rubick",
|
||||||
"version": "0.1.0",
|
"version": "2.0.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"serve": "vue-cli-service serve",
|
"serve": "vue-cli-service serve",
|
||||||
|
BIN
public/icon.ico
Normal file
BIN
public/icon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.2 KiB |
BIN
public/icon@2x.png
Normal file
BIN
public/icon@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.8 KiB |
BIN
public/icon@3x.png
Normal file
BIN
public/icon@3x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.2 KiB |
@ -32,9 +32,9 @@ window.rubick = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// 窗口交互
|
// 窗口交互
|
||||||
// hideMainWindow() {
|
hideMainWindow() {
|
||||||
// ipcSendSync("hideMainWindow");
|
ipcSendSync("hideMainWindow");
|
||||||
// },
|
},
|
||||||
showMainWindow() {
|
showMainWindow() {
|
||||||
ipcSendSync("showMainWindow");
|
ipcSendSync("showMainWindow");
|
||||||
},
|
},
|
||||||
|
60
src/common/utils/localConfig.ts
Normal file
60
src/common/utils/localConfig.ts
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
import path from "path";
|
||||||
|
import fs from "fs";
|
||||||
|
import getLocalDataFile from "./getLocalDataFile";
|
||||||
|
import { app } from "electron";
|
||||||
|
|
||||||
|
const configPath = path.join(getLocalDataFile(), "./rubick-config.json");
|
||||||
|
|
||||||
|
const defaultConfigForAnyPlatform = {
|
||||||
|
version: 1,
|
||||||
|
perf: {
|
||||||
|
shortCut: {
|
||||||
|
showAndHidden: "Option+R",
|
||||||
|
separate: "Ctrl+D",
|
||||||
|
quit: "Shift+Escape",
|
||||||
|
},
|
||||||
|
common: {
|
||||||
|
start: true,
|
||||||
|
space: true,
|
||||||
|
// 是否失焦隐藏。默认在dev环境不隐藏,在打包后隐藏。
|
||||||
|
hideOnBlur: app.isPackaged,
|
||||||
|
},
|
||||||
|
local: {
|
||||||
|
search: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
global: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
global.OP_CONFIG = {
|
||||||
|
config: null,
|
||||||
|
get() {
|
||||||
|
try {
|
||||||
|
if (!global.config) {
|
||||||
|
global.config = JSON.parse(
|
||||||
|
fs.readFileSync(configPath, "utf8") ||
|
||||||
|
JSON.stringify(defaultConfigForAnyPlatform)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// 重置
|
||||||
|
if (
|
||||||
|
!global.config.version ||
|
||||||
|
global.config.version < defaultConfigForAnyPlatform.version
|
||||||
|
) {
|
||||||
|
global.config = defaultConfigForAnyPlatform;
|
||||||
|
fs.writeFileSync(
|
||||||
|
configPath,
|
||||||
|
JSON.stringify(defaultConfigForAnyPlatform)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return global.config;
|
||||||
|
} catch (e) {
|
||||||
|
global.config = defaultConfigForAnyPlatform;
|
||||||
|
return global.config;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
set(key, value) {
|
||||||
|
global.config[key] = value;
|
||||||
|
fs.writeFileSync(configPath, JSON.stringify(global.config));
|
||||||
|
},
|
||||||
|
};
|
@ -34,15 +34,17 @@ global.LOCAL_PLUGINS = {
|
|||||||
},
|
},
|
||||||
addPlugin(plugin) {
|
addPlugin(plugin) {
|
||||||
let has = false;
|
let has = false;
|
||||||
global.LOCAL_PLUGINS.PLUGINS.some((p) => {
|
const currentPlugins = global.LOCAL_PLUGINS.getLocalPlugins();
|
||||||
|
currentPlugins.some((p) => {
|
||||||
has = p.name === plugin.name;
|
has = p.name === plugin.name;
|
||||||
return has;
|
return has;
|
||||||
});
|
});
|
||||||
if (!has) {
|
if (!has) {
|
||||||
global.LOCAL_PLUGINS.PLUGINS.unshift(plugin);
|
currentPlugins.unshift(plugin);
|
||||||
|
global.LOCAL_PLUGINS.PLUGINS = currentPlugins;
|
||||||
fs.writeFileSync(
|
fs.writeFileSync(
|
||||||
configPath,
|
configPath,
|
||||||
JSON.stringify(global.LOCAL_PLUGINS.PLUGINS)
|
JSON.stringify(currentPlugins)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -49,6 +49,7 @@ export default () => {
|
|||||||
window.removeBrowserView(view);
|
window.removeBrowserView(view);
|
||||||
window.setSize(800, 60);
|
window.setSize(800, 60);
|
||||||
executeHooks("PluginOut", null);
|
executeHooks("PluginOut", null);
|
||||||
|
window.webContents.executeJavaScript(`window.initRubick()`);
|
||||||
view = undefined;
|
view = undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
45
src/main/common/registerHotKey.ts
Normal file
45
src/main/common/registerHotKey.ts
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import { globalShortcut, BrowserWindow, screen } from "electron";
|
||||||
|
|
||||||
|
export default (mainWindow: BrowserWindow): void => {
|
||||||
|
const config = global.OP_CONFIG.get();
|
||||||
|
globalShortcut.unregisterAll();
|
||||||
|
// 注册偏好快捷键
|
||||||
|
globalShortcut.register(config.perf.shortCut.showAndHidden, () => {
|
||||||
|
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(true);
|
||||||
|
mainWindow.setVisibleOnAllWorkspaces(true, { visibleOnFullScreen: true });
|
||||||
|
mainWindow.focus();
|
||||||
|
mainWindow.setVisibleOnAllWorkspaces(false, { visibleOnFullScreen: true });
|
||||||
|
mainWindow.setPosition(wx, wy);
|
||||||
|
mainWindow.show();
|
||||||
|
});
|
||||||
|
|
||||||
|
globalShortcut.register(config.perf.shortCut.separate, () => {
|
||||||
|
// todo
|
||||||
|
});
|
||||||
|
|
||||||
|
globalShortcut.register(config.perf.shortCut.quit, () => {
|
||||||
|
// mainWindow.webContents.send('init-rubick');
|
||||||
|
// mainWindow.show();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 注册自定义全局快捷键
|
||||||
|
config.global.forEach((sc) => {
|
||||||
|
if (!sc.key || !sc.value) return;
|
||||||
|
globalShortcut.register(sc.key, () => {
|
||||||
|
mainWindow.webContents.send("global-short-key", sc.value);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
75
src/main/common/tray.ts
Normal file
75
src/main/common/tray.ts
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
import { dialog, Menu, Tray, app, shell, BrowserWindow } from "electron";
|
||||||
|
import path from "path";
|
||||||
|
import pkg from "../../../package.json";
|
||||||
|
import os from "os";
|
||||||
|
import commonConst from "@/common/utils/commonConst";
|
||||||
|
|
||||||
|
function createTray(window: BrowserWindow): Promise<Tray> {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
let icon;
|
||||||
|
if (commonConst.macOS()) {
|
||||||
|
icon = "./icon@3x.png";
|
||||||
|
} else if (commonConst.windows()) {
|
||||||
|
icon = parseInt(os.release()) < 10 ? "./icon@2x.png" : "./icon.ico";
|
||||||
|
} else {
|
||||||
|
icon = "icon@2x.png";
|
||||||
|
}
|
||||||
|
const appIcon = new Tray(path.join(__static, icon));
|
||||||
|
const contextMenu = Menu.buildFromTemplate([
|
||||||
|
{
|
||||||
|
label: "帮助文档",
|
||||||
|
click: () => {
|
||||||
|
process.nextTick(() => {
|
||||||
|
shell.openExternal("https://github.com/clouDr-f2e/rubick");
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "意见反馈",
|
||||||
|
click: () => {
|
||||||
|
process.nextTick(() => {
|
||||||
|
shell.openExternal("https://github.com/clouDr-f2e/rubick/issues");
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ type: "separator" },
|
||||||
|
{
|
||||||
|
label: "显示窗口",
|
||||||
|
accelerator: "Alt+R",
|
||||||
|
click() {
|
||||||
|
window.show();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
role: "quit",
|
||||||
|
label: "退出",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "重启",
|
||||||
|
click() {
|
||||||
|
app.relaunch();
|
||||||
|
app.quit();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ type: "separator" },
|
||||||
|
{
|
||||||
|
label: "关于",
|
||||||
|
click() {
|
||||||
|
dialog.showMessageBox({
|
||||||
|
title: "拉比克",
|
||||||
|
message: "极简、插件化的现代桌面软件",
|
||||||
|
detail: `Version: ${pkg.version}\nAuthor: muwoo`,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
appIcon.on("click", () => {
|
||||||
|
appIcon.popUpContextMenu(contextMenu);
|
||||||
|
});
|
||||||
|
appIcon.setContextMenu(contextMenu);
|
||||||
|
|
||||||
|
resolve(appIcon);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export default createTray;
|
@ -5,7 +5,11 @@ import commonConst from "../common/utils/commonConst";
|
|||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import API from "./common/api";
|
import API from "./common/api";
|
||||||
|
import createTray from "./common/tray";
|
||||||
|
import registerHotKey from "./common/registerHotKey";
|
||||||
|
|
||||||
import "../common/utils/localPlugin";
|
import "../common/utils/localPlugin";
|
||||||
|
import "../common/utils/localConfig";
|
||||||
|
|
||||||
class App {
|
class App {
|
||||||
private windowCreator: { init: () => void; getWindow: () => BrowserWindow };
|
private windowCreator: { init: () => void; getWindow: () => BrowserWindow };
|
||||||
@ -48,8 +52,8 @@ class App {
|
|||||||
this.createWindow();
|
this.createWindow();
|
||||||
API(this.windowCreator.getWindow());
|
API(this.windowCreator.getWindow());
|
||||||
// this.init()
|
// this.init()
|
||||||
// createTray(this.windowCreator.getWindow())
|
createTray(this.windowCreator.getWindow());
|
||||||
// autoUpdate()
|
registerHotKey(this.windowCreator.getWindow());
|
||||||
};
|
};
|
||||||
if (!app.isReady()) {
|
if (!app.isReady()) {
|
||||||
app.on("ready", readyFunction);
|
app.on("ready", readyFunction);
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
@changeSelect="changeSelect"
|
@changeSelect="changeSelect"
|
||||||
:searchValue="searchValue"
|
:searchValue="searchValue"
|
||||||
:placeholder="placeholder"
|
:placeholder="placeholder"
|
||||||
|
@choosePlugin="choosePlugin"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Result
|
<Result
|
||||||
@ -56,6 +57,7 @@ getPluginInfo({
|
|||||||
|
|
||||||
watch([searchValue], () => {
|
watch([searchValue], () => {
|
||||||
currentSelect.value = 0;
|
currentSelect.value = 0;
|
||||||
|
if (currentPlugin.value.name) return;
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
ipcRenderer.sendSync("msg-trigger", {
|
ipcRenderer.sendSync("msg-trigger", {
|
||||||
type: "setExpendHeight",
|
type: "setExpendHeight",
|
||||||
@ -81,6 +83,12 @@ const openMenu = () => {
|
|||||||
cmd: "插件市场",
|
cmd: "插件市场",
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const choosePlugin = () => {
|
||||||
|
const currentChoose = options.value[currentSelect.value];
|
||||||
|
console.log(currentChoose);
|
||||||
|
currentChoose.click();
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
|
@ -7,13 +7,22 @@
|
|||||||
@input="(e) => changeValue(e)"
|
@input="(e) => changeValue(e)"
|
||||||
@keydown.down="() => emit('changeCurrent', 1)"
|
@keydown.down="() => emit('changeCurrent', 1)"
|
||||||
@keydown.up="() => emit('changeCurrent', -1)"
|
@keydown.up="() => emit('changeCurrent', -1)"
|
||||||
@keydown="checkNeedInit"
|
@keydown="e => checkNeedInit(e)"
|
||||||
:value="searchValue"
|
:value="searchValue"
|
||||||
:placeholder="placeholder || 'Hi, Rubick2'"
|
:placeholder="placeholder || 'Hi, Rubick2'"
|
||||||
|
@keypress.enter="
|
||||||
|
(e) => targetSearch({ value: e.target.value, type: 'enter' })
|
||||||
|
"
|
||||||
|
@keypress.space="
|
||||||
|
(e) => targetSearch({ value: e.target.value, type: 'space' })
|
||||||
|
"
|
||||||
>
|
>
|
||||||
<template #suffix>
|
<template #suffix>
|
||||||
<div @click="() => emit('openMenu')" class="suffix-tool" >
|
<div @click="() => emit('openMenu')" class="suffix-tool" >
|
||||||
<div class="rubick-logo">
|
<div v-if="currentPlugin && currentPlugin.logo" style="position: relative">
|
||||||
|
<img class="icon-tool" :src="currentPlugin.logo" />
|
||||||
|
</div>
|
||||||
|
<div v-else class="rubick-logo">
|
||||||
<img src="../assets/logo.png" />
|
<img src="../assets/logo.png" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -42,14 +51,31 @@ const changeValue = (e) => {
|
|||||||
emit("onSearch", e);
|
emit("onSearch", e);
|
||||||
};
|
};
|
||||||
|
|
||||||
const emit = defineEmits(["onSearch", "changeCurrent", "openMenu", "changeSelect"]);
|
const emit = defineEmits([
|
||||||
|
"onSearch",
|
||||||
|
"changeCurrent",
|
||||||
|
"openMenu",
|
||||||
|
"changeSelect",
|
||||||
|
"choosePlugin",
|
||||||
|
]);
|
||||||
|
|
||||||
const checkNeedInit = (e) => {
|
const checkNeedInit = (e) => {
|
||||||
if (props.searchValue === "" && e.keyCode === 8) {
|
if (e.target.value === "" && e.keyCode === 8) {
|
||||||
closeTag();
|
closeTag();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const targetSearch = ({ value, type }) => {
|
||||||
|
if (props.currentPlugin.name) {
|
||||||
|
return ipcRenderer.sendSync("msg-trigger", {
|
||||||
|
type: "sendSubInputChangeEvent",
|
||||||
|
data: { text: value },
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
emit("choosePlugin");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const closeTag = () => {
|
const closeTag = () => {
|
||||||
emit("changeSelect", {});
|
emit("changeSelect", {});
|
||||||
ipcRenderer.send("msg-trigger", {
|
ipcRenderer.send("msg-trigger", {
|
||||||
@ -95,7 +121,7 @@ const closeTag = () => {
|
|||||||
border: none !important;
|
border: none !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.rubick-logo {
|
.rubick-logo, .icon-tool {
|
||||||
width: 40px;
|
width: 40px;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
background: #574778;
|
background: #574778;
|
||||||
@ -107,6 +133,9 @@ const closeTag = () => {
|
|||||||
width: 32px;
|
width: 32px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.icon-tool {
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
.ant-input:focus {
|
.ant-input:focus {
|
||||||
border: none;
|
border: none;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
|
@ -3,6 +3,7 @@ import { nativeImage, remote, ipcRenderer } from "electron";
|
|||||||
import { appSearch, PluginHandler } from "@/core";
|
import { appSearch, 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 searchManager from "./search";
|
import searchManager from "./search";
|
||||||
import optionsManager from "./options";
|
import optionsManager from "./options";
|
||||||
|
|
||||||
@ -43,12 +44,11 @@ const createPluginManager = (): any => {
|
|||||||
})
|
})
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
// @ts-ignore
|
|
||||||
// document.getElementById("search").value = "";
|
|
||||||
// state.searchValue = "";
|
|
||||||
setSearchValue("");
|
setSearchValue("");
|
||||||
}
|
}
|
||||||
|
if (plugin.pluginType === "app") {
|
||||||
|
execSync(plugin.action);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const { searchValue, onSearch, setSearchValue, placeholder } = searchManager();
|
const { searchValue, onSearch, setSearchValue, placeholder } = searchManager();
|
||||||
@ -57,6 +57,7 @@ const createPluginManager = (): any => {
|
|||||||
baseDir,
|
baseDir,
|
||||||
appList,
|
appList,
|
||||||
openPlugin,
|
openPlugin,
|
||||||
|
currentPlugin: toRefs(state).currentPlugin,
|
||||||
});
|
});
|
||||||
// plugin operation
|
// plugin operation
|
||||||
const getPluginInfo = async ({ pluginName, pluginPath }) => {
|
const getPluginInfo = async ({ pluginName, pluginPath }) => {
|
||||||
@ -85,6 +86,12 @@ const createPluginManager = (): any => {
|
|||||||
remote.getGlobal("LOCAL_PLUGINS").updatePlugin(currentPlugin);
|
remote.getGlobal("LOCAL_PLUGINS").updatePlugin(currentPlugin);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
window.initRubick = () => {
|
||||||
|
state.currentPlugin = {};
|
||||||
|
setSearchValue("");
|
||||||
|
window.setSubInput({ placeholder: "" });
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...toRefs(state),
|
...toRefs(state),
|
||||||
initPlugins,
|
initPlugins,
|
||||||
|
@ -12,12 +12,13 @@ function searchKeyValues(lists, value) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const optionsManager = ({ searchValue, baseDir, appList, openPlugin }) => {
|
const optionsManager = ({ searchValue, baseDir, appList, openPlugin, currentPlugin }) => {
|
||||||
const optionsRef = ref([]);
|
const optionsRef = ref([]);
|
||||||
|
|
||||||
watch(searchValue, () => search(searchValue.value));
|
watch(searchValue, () => search(searchValue.value));
|
||||||
// search Input operation
|
// search Input operation
|
||||||
const search = throttle((value) => {
|
const search = throttle((value) => {
|
||||||
|
if (currentPlugin.value.name) return;
|
||||||
if (!value) return;
|
if (!value) return;
|
||||||
const localPlugins = remote.getGlobal("LOCAL_PLUGINS").getLocalPlugins();
|
const localPlugins = remote.getGlobal("LOCAL_PLUGINS").getLocalPlugins();
|
||||||
let options: any = [];
|
let options: any = [];
|
||||||
|
@ -11,10 +11,6 @@ const searchManager = () => {
|
|||||||
const onSearch = (e) => {
|
const onSearch = (e) => {
|
||||||
const value = e.target.value;
|
const value = e.target.value;
|
||||||
state.searchValue = value;
|
state.searchValue = value;
|
||||||
ipcRenderer.sendSync("msg-trigger", {
|
|
||||||
type: "sendSubInputChangeEvent",
|
|
||||||
data: value,
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const setSearchValue = (value: string) => {
|
const setSearchValue = (value: string) => {
|
||||||
|
1
src/renderer/shims-vue.d.ts
vendored
1
src/renderer/shims-vue.d.ts
vendored
@ -18,4 +18,5 @@ interface Window {
|
|||||||
setSubInputValue: ({ value }: { value: string }) => void;
|
setSubInputValue: ({ value }: { value: string }) => void;
|
||||||
removeSubInput: () => void;
|
removeSubInput: () => void;
|
||||||
updatePlugin: (plugin: any) => void;
|
updatePlugin: (plugin: any) => void;
|
||||||
|
initRubick: () => void;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user