mirror of
https://github.com/rubickCenter/rubick
synced 2025-10-26 22:51:25 +08:00
Compare commits
39 Commits
v2.0.1-bet
...
v2.0.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1e4757f70d | ||
|
|
6adf25dbee | ||
|
|
7fbb12d04b | ||
|
|
ded16b9580 | ||
|
|
d379c58082 | ||
|
|
8a536374ea | ||
|
|
bcfc968c9d | ||
|
|
4bf3f3a602 | ||
|
|
497de040cf | ||
|
|
a22a78fa0a | ||
|
|
d2894c66ba | ||
|
|
ff7473deb2 | ||
|
|
842a44a6d1 | ||
|
|
751c73b3a6 | ||
|
|
240175c571 | ||
|
|
8107d74537 | ||
|
|
861950145f | ||
|
|
7b320c9dd1 | ||
|
|
6640d66fac | ||
|
|
357846d2e6 | ||
|
|
3b3ddf224c | ||
|
|
4439d0548f | ||
|
|
21163b2277 | ||
|
|
480aaf2970 | ||
|
|
06596d87ae | ||
|
|
1008e86fbb | ||
|
|
62ec316337 | ||
|
|
735a450260 | ||
|
|
417ab071df | ||
|
|
1e73ab5ee6 | ||
|
|
e5ff219685 | ||
|
|
2beac06e7c | ||
|
|
6b96df3da5 | ||
|
|
8521262344 | ||
|
|
4cf00f9270 | ||
|
|
bdae8c280b | ||
|
|
04e674d1cd | ||
|
|
371565744e | ||
|
|
58aabb9f1e |
2
.github/FUNDING.yml
vendored
2
.github/FUNDING.yml
vendored
@@ -1,4 +1,4 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: #muwoo
|
||||
custom: ['https://muwoo.github.io/blogs'] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
||||
custom: ['https://rubickcenter.github.io/rubick/run/#%E8%B5%9E%E5%8A%A9'] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
||||
|
||||
3
.github/workflows/main.yml
vendored
3
.github/workflows/main.yml
vendored
@@ -23,7 +23,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-latest, windows-2019]
|
||||
os: [macos-latest, windows-2019, ubuntu-latest]
|
||||
|
||||
# create steps
|
||||
steps:
|
||||
@@ -47,6 +47,7 @@ jobs:
|
||||
run: |
|
||||
yarn
|
||||
yarn global add xvfb-maybe
|
||||
yarn global add @vue/cli
|
||||
|
||||
- name: Build & release app
|
||||
run: |
|
||||
|
||||
@@ -32,6 +32,8 @@ Based on electron open source toolbox, free integration of rich plug-ins, to cre
|
||||
## Installation package
|
||||
* [Rubick Mac OS](https://github.com/rubickCenter/rubick/releases)
|
||||
* [Rubick Windows](https://github.com/rubickCenter/rubick/releases)
|
||||
* [Rubick Linux](https://github.com/rubickCenter/rubick/releases)
|
||||
|
||||
|
||||
## Feature list
|
||||
- [x] Plug-in management based on npm package mode, installing plugins is as easy as installing npm packages.
|
||||
@@ -41,6 +43,8 @@ Based on electron open source toolbox, free integration of rich plug-ins, to cre
|
||||
- [x] Support searching for locally installed apps or preferences
|
||||
- [x] Support MacOS
|
||||
- [x] Support Windows
|
||||
- [x] Support Linux
|
||||
|
||||
|
||||
|
||||
## Docs
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
module.exports = {
|
||||
presets: ["@vue/cli-plugin-babel/preset"],
|
||||
plugins: [
|
||||
[
|
||||
"import",
|
||||
{ libraryName: "ant-design-vue", libraryDirectory: "es", style: "css" },
|
||||
], // `style: true` 会加载 less 文件
|
||||
],
|
||||
};
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#### 示例
|
||||
|
||||
```js
|
||||
rubcik.onPluginReady(({ code, type, payload }) => {
|
||||
rubick.onPluginReady(({ code, type, payload }) => {
|
||||
console.log('插件装配完成,已准备好')
|
||||
})
|
||||
/*
|
||||
|
||||
@@ -50,6 +50,27 @@ macos 选择 `pkg` 文件,windows 选择 `exe` 文件。
|
||||
|
||||

|
||||
|
||||
### 内网部署
|
||||
::: tip
|
||||
如果把插件发布到公网 `npm` 如果不符合您的公司安全要求,`rubick` 支持内网私有源和私有插件库,如果您需要内网部署使用,可以自行配置以下规则。
|
||||
:::
|
||||
`rubick` 依赖 `npm` 仓库做插件管理,依赖 `gitee` 做插件数据存储,所以如果要进行内网部署,主要需要替换这2个设置。详细设置:
|
||||
`插件市场 -> 设置 -> 内网部署设置`
|
||||
|
||||

|
||||
|
||||
#### 1. 替换 npm 源
|
||||
插件发布到私有 `npm` 源即可。
|
||||
|
||||
#### 2. 替换 `gitee` 源为内网 `gitlab`: database url
|
||||
|
||||
* clone 下载 rubick 插件库:[https://gitee.com/monkeyWang/rubick-database](https://gitee.com/monkeyWang/rubick-database)
|
||||
* 提交仓库到私有 `gitlab` 库。
|
||||
|
||||
替换格式:`https://gitlab.xxx.com/api/v4/projects/{projectId}/repository/files/` 。因为接口为 `gitlab openAPI`,所以需要填写仓库 `access_token`
|
||||
|
||||
|
||||
### 更多功能
|
||||
如果您还需要更多功能,欢迎来这里给我们提建议:[issues](https://github.com/rubickCenter/rubick/issues) 。
|
||||
有价值的想法我们会加入到后期的开发当中。同时也欢迎一起加入共建。
|
||||
|
||||
|
||||
@@ -1,30 +1,53 @@
|
||||
import axios from "axios";
|
||||
|
||||
let baseURL = "https://gitee.com/monkeyWang/rubick-database/raw/master";
|
||||
let access_token = "";
|
||||
|
||||
try {
|
||||
const dbdata = window.rubick.db.get("rubick-localhost-config");
|
||||
baseURL = dbdata.data.database;
|
||||
access_token = dbdata.data.access_token;
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
const instance = axios.create({
|
||||
baseURL: baseURL || "https://gitee.com/monkeyWang/rubick-database/raw/master",
|
||||
});
|
||||
|
||||
export default {
|
||||
async getTotalPlugins() {
|
||||
const res = await axios.get(
|
||||
"https://gitee.com/monkeyWang/rubick-database/raw/master/plugins/total-plugins.json"
|
||||
);
|
||||
let targetPath = "plugins/total-plugins.json";
|
||||
if (access_token) {
|
||||
targetPath = `${encodeURIComponent(targetPath)}/raw?access_token=${access_token}&ref=master`
|
||||
}
|
||||
const res = await instance.get(targetPath);
|
||||
return res.data;
|
||||
},
|
||||
|
||||
async getFinderDetail() {
|
||||
const res = await axios.get(
|
||||
"https://gitee.com/monkeyWang/rubick-database/raw/master/plugins/finder.json"
|
||||
);
|
||||
let targetPath = "plugins/finder.json";
|
||||
if (access_token) {
|
||||
targetPath = `${encodeURIComponent(targetPath)}/raw?access_token=${access_token}&ref=master`
|
||||
}
|
||||
const res = await instance.get(targetPath);
|
||||
return res.data;
|
||||
},
|
||||
|
||||
async getSystemDetail() {
|
||||
const res = await axios.get(
|
||||
"https://gitee.com/monkeyWang/rubick-database/raw/master/plugins/system.json"
|
||||
);
|
||||
let targetPath = "plugins/system.json";
|
||||
if (access_token) {
|
||||
targetPath = `${encodeURIComponent(targetPath)}/raw?access_token=${access_token}&ref=master`
|
||||
}
|
||||
const res = await instance.get(targetPath);
|
||||
return res.data;
|
||||
},
|
||||
async getWorkerDetail() {
|
||||
const res = await axios.get(
|
||||
"https://gitee.com/monkeyWang/rubick-database/raw/master/plugins/worker.json"
|
||||
);
|
||||
let targetPath = "plugins/worker.json";
|
||||
if (access_token) {
|
||||
targetPath = `${encodeURIComponent(targetPath)}/raw?access_token=${access_token}&ref=master`
|
||||
}
|
||||
const res = await instance.get(targetPath);
|
||||
return res.data;
|
||||
},
|
||||
|
||||
@@ -33,16 +56,20 @@ export default {
|
||||
return res.data;
|
||||
},
|
||||
|
||||
async getSearchDetail(url: string) {
|
||||
const res = await axios.get(
|
||||
"https://gitee.com/monkeyWang/rubick-database/raw/master/plugins/search.json"
|
||||
);
|
||||
async getSearchDetail() {
|
||||
let targetPath = "plugins/search.json";
|
||||
if (access_token) {
|
||||
targetPath = `${encodeURIComponent(targetPath)}/raw?access_token=${access_token}&ref=master`
|
||||
}
|
||||
const res = await instance.get(targetPath);
|
||||
return res.data;
|
||||
},
|
||||
async getDevDetail(url: string) {
|
||||
const res = await axios.get(
|
||||
"https://gitee.com/monkeyWang/rubick-database/raw/master/plugins/dev.json"
|
||||
);
|
||||
async getDevDetail() {
|
||||
let targetPath = "plugins/dev.json";
|
||||
if (access_token) {
|
||||
targetPath = `${encodeURIComponent(targetPath)}/raw?access_token=${access_token}&ref=master`
|
||||
}
|
||||
const res = await instance.get(targetPath);
|
||||
return res.data;
|
||||
},
|
||||
};
|
||||
|
||||
@@ -53,6 +53,21 @@ export default createStore({
|
||||
totalPlugins,
|
||||
});
|
||||
},
|
||||
|
||||
startUnDownload({ commit, state }, name) {
|
||||
const localPlugins = (window as any).market.getLocalPlugins();
|
||||
localPlugins.forEach(
|
||||
(origin: { isdwonload?: any; name?: any; isloading: boolean }) => {
|
||||
if (origin.name === name) {
|
||||
origin.isloading = true;
|
||||
}
|
||||
}
|
||||
);
|
||||
commit("commonUpdate", {
|
||||
localPlugins,
|
||||
});
|
||||
},
|
||||
|
||||
successDownload({ commit, state }, name) {
|
||||
const totalPlugins = JSON.parse(JSON.stringify(state.totalPlugins));
|
||||
totalPlugins.forEach(
|
||||
@@ -70,10 +85,20 @@ export default createStore({
|
||||
localPlugins,
|
||||
});
|
||||
},
|
||||
updateLocalPlugin({ commit }) {
|
||||
async updateLocalPlugin({ commit }) {
|
||||
const localPlugins = (window as any).market.getLocalPlugins();
|
||||
const totalPlugins = await request.getTotalPlugins();
|
||||
|
||||
totalPlugins.forEach(
|
||||
(origin: { isdwonload?: any; name?: any; isloading: boolean }) => {
|
||||
origin.isdwonload = isDownload(origin, localPlugins);
|
||||
origin.isloading = false;
|
||||
}
|
||||
);
|
||||
|
||||
commit("commonUpdate", {
|
||||
localPlugins,
|
||||
totalPlugins,
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
@@ -40,8 +40,11 @@
|
||||
type="danger"
|
||||
size="small"
|
||||
shape="round"
|
||||
:loading="pluginDetail.isloading"
|
||||
@click="deletePlugin(pluginDetail)"
|
||||
>移除</a-button
|
||||
>
|
||||
移除
|
||||
</a-button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
@@ -56,17 +59,11 @@
|
||||
<div>{{ item.explain }}</div>
|
||||
<a-tag
|
||||
:key="cmd"
|
||||
@click="
|
||||
openPlugin({
|
||||
cmd,
|
||||
plugin: pluginDetail,
|
||||
feature: item,
|
||||
router: $router,
|
||||
})
|
||||
"
|
||||
v-for="cmd in item.cmds"
|
||||
@close="removeFeature(cmd)"
|
||||
:color="!cmd.label && '#87d068'"
|
||||
>
|
||||
{{ cmd }}
|
||||
{{ cmd.label || cmd }}
|
||||
</a-tag>
|
||||
</div>
|
||||
</div>
|
||||
@@ -101,6 +98,7 @@ const localPlugins = computed(() =>
|
||||
)
|
||||
);
|
||||
const updateLocalPlugin = () => store.dispatch("updateLocalPlugin");
|
||||
const startUnDownload = (name) => store.dispatch("startUnDownload", name);
|
||||
|
||||
const currentSelect = ref([0]);
|
||||
|
||||
@@ -124,6 +122,7 @@ const readme = computed(() => {
|
||||
});
|
||||
|
||||
const deletePlugin = async (plugin) => {
|
||||
startUnDownload(plugin.name);
|
||||
await window.market.deletePlugin(plugin);
|
||||
updateLocalPlugin();
|
||||
};
|
||||
@@ -150,6 +149,7 @@ const deletePlugin = async (plugin) => {
|
||||
height: 100%;
|
||||
padding: 10px 0;
|
||||
border-right: 1px solid #eee;
|
||||
overflow: auto;
|
||||
.item {
|
||||
padding: 10px 20px;
|
||||
display: flex;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<div class="list-item">
|
||||
<a-list :grid="{ gutter: 16, column: 2 }" :data-source="list">
|
||||
<template #renderItem="{ item, index }">
|
||||
<a-list-item @click="showDetail(item)">
|
||||
<a-list-item v-if="item" @click="showDetail(item)">
|
||||
<template #actions>
|
||||
<a-button style="color: #ff4ea4;" type="text" :loading="item.isloading">
|
||||
<CloudDownloadOutlined
|
||||
@@ -57,9 +57,9 @@
|
||||
<div class="desc">
|
||||
{{ detail.description }}
|
||||
</div>
|
||||
<a-button shape="round" type="primary">
|
||||
<a-button v-if="!detail.isdwonload" @click.stop="downloadPlugin(detail)" shape="round" type="primary" :loading="detail.isloading">
|
||||
<template #icon>
|
||||
<CloudDownloadOutlined />
|
||||
<CloudDownloadOutlined v-show="!detail.isloading && !detail.isdwonload" />
|
||||
</template>
|
||||
获取
|
||||
</a-button>
|
||||
|
||||
@@ -14,6 +14,12 @@
|
||||
</template>
|
||||
全局快捷键
|
||||
</a-menu-item>
|
||||
<a-menu-item key="localhost">
|
||||
<template #icon>
|
||||
<DatabaseOutlined />
|
||||
</template>
|
||||
内网部署配置
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</div>
|
||||
<div class="settings-detail">
|
||||
@@ -32,26 +38,6 @@
|
||||
{{ shortCut.showAndHidden }}
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="settings-item-li">-->
|
||||
<!-- <div class="label">插件分离快捷键</div>-->
|
||||
<!-- <div-->
|
||||
<!-- class="value"-->
|
||||
<!-- tabIndex="-1"-->
|
||||
<!-- @keyup="(e) => changeShortCut(e, 'separate')"-->
|
||||
<!-- >-->
|
||||
<!-- {{ shortCut.separate }}-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="settings-item-li">-->
|
||||
<!-- <div class="label">返回主界面</div>-->
|
||||
<!-- <div-->
|
||||
<!-- class="value"-->
|
||||
<!-- tabIndex="-1"-->
|
||||
<!-- @keyup="(e) => changeShortCut(e, 'quit')"-->
|
||||
<!-- >-->
|
||||
<!-- {{ shortCut.quit }}-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div class="title">通用</div>
|
||||
@@ -80,17 +66,6 @@
|
||||
></a-switch>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="setting-item">-->
|
||||
<!-- <div class="title">本地搜索启动</div>-->
|
||||
<!-- <div class="settings-item-li">-->
|
||||
<!-- <div class="label">搜索启动应用&文件</div>-->
|
||||
<!-- <a-switch-->
|
||||
<!-- v-model:checked="local.search"-->
|
||||
<!-- checked-children="开"-->
|
||||
<!-- un-checked-children="关"-->
|
||||
<!-- ></a-switch>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
</div>
|
||||
<div v-if="currentSelect[0] === 'global'">
|
||||
<a-collapse>
|
||||
@@ -147,15 +122,17 @@
|
||||
</div>
|
||||
<div @click="addConfig" class="add-global">+ 新增全局快捷功能</div>
|
||||
</div>
|
||||
<Localhost v-if="currentSelect[0] === 'localhost'" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ToolOutlined, LaptopOutlined } from "@ant-design/icons-vue";
|
||||
import { ToolOutlined, LaptopOutlined, DatabaseOutlined } from "@ant-design/icons-vue";
|
||||
import debounce from "lodash.debounce";
|
||||
import { ref, reactive, watch, toRefs, toRaw } from "vue";
|
||||
import keycodes from "./keycode";
|
||||
import Localhost from "./localhost.vue";
|
||||
|
||||
const { remote, ipcRenderer } = window.require("electron");
|
||||
|
||||
|
||||
90
feature/src/views/settings/localhost.vue
Normal file
90
feature/src/views/settings/localhost.vue
Normal file
@@ -0,0 +1,90 @@
|
||||
<template>
|
||||
<a-alert
|
||||
message="把插件发布到公网 npm 如果不符合您的公司安全要求,rubick 支持内网私有源和私有插件库,如果您需要内网部署使用,可以自行配置以下规则。"
|
||||
type="warning"
|
||||
style="margin-bottom: 20px"
|
||||
/>
|
||||
<a-form
|
||||
name="custom-validation"
|
||||
ref="formRef"
|
||||
:model="formState"
|
||||
:rules="rules"
|
||||
v-bind="layout"
|
||||
>
|
||||
<a-form-item has-feedback label="npm 源" name="register">
|
||||
<a-input
|
||||
placeholder="https://registry.npm.taobao.org"
|
||||
v-model:value="formState.register"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item has-feedback label="database url" name="database">
|
||||
<a-input
|
||||
placeholder="https://gitee.com/monkeyWang/rubick-database/raw/master"
|
||||
v-model:value="formState.database"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item has-feedback label="access_token" name="access_token">
|
||||
<a-input
|
||||
placeholder="内网gitlab仓库必填"
|
||||
v-model:value="formState.access_token"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item :wrapper-col="{ span: 18, offset: 6 }">
|
||||
<a-button @click="submit" type="primary">确定</a-button>
|
||||
<a-button style="margin-left: 10px" @click="resetForm">恢复默认</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, toRaw } from "vue";
|
||||
import { message } from "ant-design-vue";
|
||||
|
||||
let _rev: any;
|
||||
|
||||
let defaultConfig = {
|
||||
register: "https://registry.npm.taobao.org",
|
||||
database: "https://gitee.com/monkeyWang/rubick-database/raw/master",
|
||||
access_token: "",
|
||||
};
|
||||
|
||||
try {
|
||||
const dbdata = window.rubick.db.get("rubick-localhost-config");
|
||||
defaultConfig = dbdata.data;
|
||||
_rev = dbdata._rev;
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
const formState = ref(JSON.parse(JSON.stringify(defaultConfig)));
|
||||
|
||||
const rules = {
|
||||
register: [{ required: true, trigger: "change" }],
|
||||
database: [{ required: true, trigger: "change" }],
|
||||
};
|
||||
const layout = {
|
||||
labelCol: { span: 6 },
|
||||
wrapperCol: { span: 18 },
|
||||
};
|
||||
|
||||
const resetForm = () => {
|
||||
formState.value = {
|
||||
register: "https://registry.npm.taobao.org",
|
||||
database: "https://gitee.com/monkeyWang/rubick-database/raw/master",
|
||||
access_token: "",
|
||||
};
|
||||
};
|
||||
|
||||
const submit = () => {
|
||||
const changeData: any = {
|
||||
_id: "rubick-localhost-config",
|
||||
data: toRaw(formState.value),
|
||||
};
|
||||
|
||||
if (_rev) {
|
||||
changeData._rev = _rev;
|
||||
}
|
||||
|
||||
window.rubick.db.put(changeData);
|
||||
message.success("设置成功!重启插件市场后生效!");
|
||||
};
|
||||
</script>
|
||||
12
package.json
12
package.json
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"name": "rubick",
|
||||
"version": "2.0.1-beta.11",
|
||||
"version": "2.0.2",
|
||||
"author": "muwoo <2424880409@qq.com>",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve",
|
||||
@@ -14,6 +15,9 @@
|
||||
"postuninstall": "electron-builder install-app-deps"
|
||||
},
|
||||
"main": "background.js",
|
||||
"optionalDependencies": {
|
||||
"electron-clipboard-ex": "^1.3.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@better-scroll/core": "^2.4.2",
|
||||
"ant-design-vue": "^2.2.8",
|
||||
@@ -23,7 +27,6 @@
|
||||
"fix-path": "^3.0.0",
|
||||
"get-mac-apps": "^1.0.2",
|
||||
"got": "^11.8.3",
|
||||
"libnpmsearch": "^3.1.2",
|
||||
"lodash.throttle": "^4.1.1",
|
||||
"pouchdb": "^7.2.2",
|
||||
"vue": "^3.0.0",
|
||||
@@ -45,7 +48,9 @@
|
||||
"@vue/compiler-sfc": "^3.0.0",
|
||||
"@vue/eslint-config-prettier": "^6.0.0",
|
||||
"@vue/eslint-config-typescript": "^7.0.0",
|
||||
"babel-plugin-import": "^1.13.3",
|
||||
"electron": "^13.0.0",
|
||||
"electron-builder": "22.13.1",
|
||||
"electron-devtools-installer": "^3.1.0",
|
||||
"eslint": "^6.7.2",
|
||||
"eslint-plugin-prettier": "^3.3.1",
|
||||
@@ -55,8 +60,7 @@
|
||||
"prettier": "^2.2.1",
|
||||
"typescript": "~4.1.5",
|
||||
"vue-cli-plugin-electron-builder": "~2.1.1",
|
||||
"worker-plugin": "^5.0.1",
|
||||
"electron-builder": "22.13.1"
|
||||
"worker-plugin": "^5.0.1"
|
||||
},
|
||||
"__npminstall_done": false
|
||||
}
|
||||
|
||||
2
public/feature/css/app.efef6e76.css
Normal file
2
public/feature/css/app.efef6e76.css
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
<!DOCTYPE html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="favicon.ico"><title>feature</title><link href="css/app.f8214d90.css" rel="preload" as="style"><link href="js/app.bad50f73.js" rel="preload" as="script"><link href="js/chunk-vendors.e8fd66a6.js" rel="preload" as="script"><link href="css/app.f8214d90.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but feature doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script src="js/chunk-vendors.e8fd66a6.js"></script><script src="js/app.bad50f73.js"></script></body></html>
|
||||
<!DOCTYPE html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="favicon.ico"><title>feature</title><link href="css/app.efef6e76.css" rel="preload" as="style"><link href="js/app.b6f0fed9.js" rel="preload" as="script"><link href="js/chunk-vendors.335eb4e0.js" rel="preload" as="script"><link href="css/app.efef6e76.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but feature doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script src="js/chunk-vendors.335eb4e0.js"></script><script src="js/app.b6f0fed9.js"></script></body></html>
|
||||
2
public/feature/js/app.b6f0fed9.js
Normal file
2
public/feature/js/app.b6f0fed9.js
Normal file
File diff suppressed because one or more lines are too long
1
public/feature/js/app.b6f0fed9.js.map
Normal file
1
public/feature/js/app.b6f0fed9.js.map
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
public/feature/js/chunk-vendors.335eb4e0.js.map
Normal file
1
public/feature/js/chunk-vendors.335eb4e0.js.map
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
BIN
public/logo.png
Normal file
BIN
public/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
@@ -137,4 +137,12 @@ window.rubick = {
|
||||
},
|
||||
|
||||
getLocalId: () => ipcSendSync("getLocalId"),
|
||||
|
||||
removePlugin() {
|
||||
ipcSend("removePlugin");
|
||||
},
|
||||
|
||||
shellShowItemInFolder: path => {
|
||||
ipcSend("shellShowItemInFolder", { path });
|
||||
},
|
||||
};
|
||||
|
||||
@@ -17,8 +17,9 @@ export default function getCopyFiles(): Array<any> | null {
|
||||
return null;
|
||||
}
|
||||
} else if (commonConst.windows()) {
|
||||
const filePath = clipboard.readBuffer('FileNameW').toString('ucs2').replace(RegExp(String.fromCharCode(0), 'g'), '');
|
||||
fileInfo = [filePath];
|
||||
/* eslint-disable */
|
||||
const clipboardEx = require("electron-clipboard-ex");
|
||||
fileInfo = clipboardEx.readFilePaths();
|
||||
// todo
|
||||
} else {
|
||||
if (!commonConst.linux()) return null;
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
import path from "path";
|
||||
import fs from "fs";
|
||||
|
||||
export default (): string => {
|
||||
let localDataFile: any = process.env.HOME;
|
||||
if (!localDataFile) {
|
||||
localDataFile = process.env.LOCALAPPDATA;
|
||||
}
|
||||
return localDataFile;
|
||||
const rubickPath = path.join(localDataFile, "rubick")
|
||||
if (!fs.existsSync(rubickPath)) {
|
||||
fs.mkdirSync(rubickPath);
|
||||
}
|
||||
return rubickPath;
|
||||
};
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import path from "path";
|
||||
import fs from "fs";
|
||||
import getLocalDataFile from "./getLocalDataFile";
|
||||
import commonConst from "./commonConst";
|
||||
import defaultConfigForAnyPlatform from "../constans/defaultConfig";
|
||||
|
||||
const configPath = path.join(getLocalDataFile(), "./rubick-config.json");
|
||||
@@ -10,34 +9,34 @@ global.OP_CONFIG = {
|
||||
config: null,
|
||||
get() {
|
||||
try {
|
||||
if (!global.config) {
|
||||
global.config = JSON.parse(
|
||||
if (!global.OP_CONFIG.config) {
|
||||
global.OP_CONFIG.config = JSON.parse(
|
||||
fs.readFileSync(configPath, "utf8") ||
|
||||
JSON.stringify(defaultConfigForAnyPlatform)
|
||||
);
|
||||
}
|
||||
// 重置
|
||||
if (
|
||||
!global.config.version ||
|
||||
global.config.version < defaultConfigForAnyPlatform.version
|
||||
!global.OP_CONFIG.config.version ||
|
||||
global.OP_CONFIG.config.version < defaultConfigForAnyPlatform.version
|
||||
) {
|
||||
global.config = defaultConfigForAnyPlatform;
|
||||
global.OP_CONFIG.config = defaultConfigForAnyPlatform;
|
||||
fs.writeFileSync(
|
||||
configPath,
|
||||
JSON.stringify(defaultConfigForAnyPlatform)
|
||||
);
|
||||
}
|
||||
return global.config;
|
||||
return global.OP_CONFIG.config;
|
||||
} catch (e) {
|
||||
global.config = defaultConfigForAnyPlatform;
|
||||
return global.config;
|
||||
global.OP_CONFIG.config = defaultConfigForAnyPlatform;
|
||||
return global.OP_CONFIG.config;
|
||||
}
|
||||
},
|
||||
set(value) {
|
||||
global.config = {
|
||||
...global.config,
|
||||
global.OP_CONFIG.config = {
|
||||
...global.OP_CONFIG.config,
|
||||
...value,
|
||||
};
|
||||
fs.writeFileSync(configPath, JSON.stringify(global.config));
|
||||
fs.writeFileSync(configPath, JSON.stringify(global.OP_CONFIG.config));
|
||||
},
|
||||
};
|
||||
|
||||
@@ -3,12 +3,27 @@ import fs from "fs";
|
||||
import getLocalDataFile from "./getLocalDataFile";
|
||||
import { PluginHandler } from "@/core";
|
||||
import { PLUGIN_INSTALL_DIR as baseDir } from "@/common/constans/main";
|
||||
import { API } from "@/main/common/api";
|
||||
|
||||
const configPath = path.join(getLocalDataFile(), "./rubick-local-plugin.json");
|
||||
|
||||
const pluginInstance = new PluginHandler({
|
||||
baseDir,
|
||||
});
|
||||
let registry;
|
||||
let pluginInstance;
|
||||
(async () => {
|
||||
try {
|
||||
registry = (await API.dbGet({ data: { id: "rubick-localhost-config" } })).data.register;
|
||||
console.log(registry);
|
||||
pluginInstance = new PluginHandler({
|
||||
baseDir,
|
||||
registry,
|
||||
});
|
||||
} catch (e) {
|
||||
pluginInstance = new PluginHandler({
|
||||
baseDir,
|
||||
registry,
|
||||
});
|
||||
}
|
||||
})();
|
||||
|
||||
global.LOCAL_PLUGINS = {
|
||||
PLUGINS: [],
|
||||
|
||||
@@ -1,3 +1,217 @@
|
||||
import path from "path";
|
||||
import originfs from "original-fs";
|
||||
|
||||
const app_paths = [
|
||||
"/usr/share/applications",
|
||||
"/var/lib/snapd/desktop/applications",
|
||||
`${window.process.env.HOME}/.local/share/applications`,
|
||||
];
|
||||
const emptyIcon = "";
|
||||
|
||||
function dirAppRead(dir, target) {
|
||||
let files: Array<string> | null = null;
|
||||
try {
|
||||
if (!originfs.existsSync(dir)) return;
|
||||
files = originfs.readdirSync(dir);
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
if (files.length !== 0) {
|
||||
for (const file of files) {
|
||||
const app = path.join(dir, file);
|
||||
path.extname(app) === ".desktop" && target.push(app);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function convertEntryFile2Feature(appPath) {
|
||||
let appInfo: any = null;
|
||||
try {
|
||||
appInfo = originfs.readFileSync(appPath, "utf8");
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
if (!appInfo.includes("[Desktop Entry]")) {
|
||||
return null;
|
||||
}
|
||||
appInfo = appInfo
|
||||
.substr(appInfo.indexOf("[Desktop Entry]"))
|
||||
.replace("[Desktop Entry]", "")
|
||||
.trim();
|
||||
|
||||
/**
|
||||
* appInfo eg:
|
||||
* Version=1.0
|
||||
* Name=FireFox
|
||||
* Name[ar]=***
|
||||
* Name[ast]=***
|
||||
* [Desktop Action new-private-window]
|
||||
* Name=***
|
||||
*/
|
||||
const splitIndex = appInfo.indexOf("\n[");
|
||||
|
||||
if (splitIndex > 0) {
|
||||
appInfo = appInfo.substr(0, splitIndex).trim();
|
||||
}
|
||||
|
||||
const targetAppInfo: any = {};
|
||||
appInfo.match(/^[\w\-[\]]+ ?=.*$/gm).forEach((e) => {
|
||||
const index = e.indexOf("=");
|
||||
targetAppInfo[e.substr(0, index).trim()] = e.substr(index + 1).trim();
|
||||
});
|
||||
|
||||
/**
|
||||
* targetAppInfo = {
|
||||
* Type: "Application",
|
||||
* Version: "1.0",
|
||||
* Exec: "xxxx",
|
||||
* }
|
||||
*/
|
||||
|
||||
if (targetAppInfo.Type !== "Application") {
|
||||
return null;
|
||||
}
|
||||
if (!targetAppInfo.Exec) {
|
||||
return null;
|
||||
}
|
||||
if (
|
||||
targetAppInfo.NoDisplay === "true" &&
|
||||
!targetAppInfo.Exec.startsWith("gnome-control-center")
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
let os = String(window.process.env.DESKTOP_SESSION).toLowerCase();
|
||||
if (os === "ubuntu") {
|
||||
os = "gnome";
|
||||
if (
|
||||
targetAppInfo.OnlyShowIn &&
|
||||
!targetAppInfo.OnlyShowIn.toLowerCase().includes(os)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (
|
||||
targetAppInfo.NotShowIn &&
|
||||
targetAppInfo.NotShowIn.toLowerCase().includes(os)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
let icon = targetAppInfo.Icon;
|
||||
if (!icon) return null;
|
||||
if (icon.startsWith("/")) {
|
||||
if (!originfs.existsSync(icon)) return null;
|
||||
} else if (
|
||||
appPath.startsWith("/usr/share/applications") ||
|
||||
appPath.startsWith("/var/lib/snapd/desktop/applications")
|
||||
) {
|
||||
icon = getIcon(icon);
|
||||
} else {
|
||||
if (
|
||||
!appPath.startsWith(
|
||||
(window as any).process.env.HOME + "/.local/share/applications"
|
||||
)
|
||||
)
|
||||
return null;
|
||||
appPath = path.join(
|
||||
(window as any).process.env.HOME,
|
||||
".local/share/icons",
|
||||
appPath + ".png"
|
||||
);
|
||||
originfs.existsSync(appPath) || (appPath = emptyIcon);
|
||||
}
|
||||
let desc = "";
|
||||
const LANG = (window as any).process.env.LANG.split(".")[0];
|
||||
if (`Comment[${LANG}]` in targetAppInfo) {
|
||||
desc = targetAppInfo[`Comment[${LANG}]`];
|
||||
} else if (targetAppInfo.Comment) {
|
||||
desc = targetAppInfo.Comment;
|
||||
} else {
|
||||
desc = appPath;
|
||||
}
|
||||
|
||||
let execPath = targetAppInfo.Exec.replace(/ %[A-Za-z]/g, "")
|
||||
.replace(/"/g, "")
|
||||
.trim();
|
||||
targetAppInfo.Terminal === "true" &&
|
||||
(execPath = "gnome-terminal -x " + execPath);
|
||||
|
||||
const info = {
|
||||
value: "plugin",
|
||||
pluginType: "app",
|
||||
desc,
|
||||
icon: "file://" + icon,
|
||||
keyWords: [targetAppInfo.Name],
|
||||
action: execPath,
|
||||
};
|
||||
|
||||
if ("X-Ubuntu-Gettext-Domain" in targetAppInfo) {
|
||||
const cmd = targetAppInfo["X-Ubuntu-Gettext-Domain"];
|
||||
cmd && cmd !== targetAppInfo.Name && info.keyWords.push(cmd);
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
function getIcon(filePath) {
|
||||
const themes = [
|
||||
"ubuntu-mono-dark",
|
||||
"ubuntu-mono-light",
|
||||
"Yaru",
|
||||
"hicolor",
|
||||
"Adwaita",
|
||||
"Humanity",
|
||||
];
|
||||
|
||||
const sizes = ["48x48", "48", "scalable", "256x256", "512x512", "256", "512"];
|
||||
const types = [
|
||||
"apps",
|
||||
"categories",
|
||||
"devices",
|
||||
"mimetypes",
|
||||
"legacy",
|
||||
"actions",
|
||||
"places",
|
||||
"status",
|
||||
"mimes",
|
||||
];
|
||||
const exts = [".png", ".svg"];
|
||||
for (const theme of themes) {
|
||||
for (const size of sizes) {
|
||||
for (const type of types) {
|
||||
for (const ext of exts) {
|
||||
let iconPath = path.join(
|
||||
"/usr/share/icons",
|
||||
theme,
|
||||
size,
|
||||
type,
|
||||
filePath + ext
|
||||
);
|
||||
if (originfs.existsSync(iconPath)) return iconPath;
|
||||
iconPath = path.join(
|
||||
"/usr/share/icons",
|
||||
theme,
|
||||
type,
|
||||
size,
|
||||
filePath + ext
|
||||
);
|
||||
if (originfs.existsSync(iconPath)) return iconPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return originfs.existsSync(path.join("/usr/share/pixmaps", filePath + ".png"))
|
||||
? path.join("/usr/share/pixmaps", filePath + ".png")
|
||||
: emptyIcon;
|
||||
}
|
||||
|
||||
export default () => {
|
||||
// todo linux search
|
||||
const apps: any = [];
|
||||
const fileList = [];
|
||||
app_paths.forEach((dir) => {
|
||||
dirAppRead(dir, fileList);
|
||||
});
|
||||
|
||||
fileList.forEach((e) => {
|
||||
apps.push(convertEntryFile2Feature(e));
|
||||
});
|
||||
return apps.filter((app) => !!app);
|
||||
};
|
||||
|
||||
@@ -6,8 +6,14 @@ import { shell } from "electron";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const fileIcon = require("extract-file-icon");
|
||||
|
||||
const filePath = path.resolve("C:\\ProgramData\\Microsoft\\Windows\\Start Menu\\Programs");
|
||||
|
||||
|
||||
const appData = path.join(os.homedir(), "./AppData/Roaming");
|
||||
|
||||
const startMenu = path.join(appData, "Microsoft\\Windows\\Start Menu\\Programs");
|
||||
|
||||
const fileLists: any = [];
|
||||
const isZhRegex = /[\u4e00-\u9fa5]/;
|
||||
|
||||
@@ -58,7 +64,10 @@ function fileDisplay(filePath) {
|
||||
} catch(e) {
|
||||
//
|
||||
}
|
||||
if (!appDetail.target || appDetail.target.toLowerCase().indexOf("unin") >= 0) return;
|
||||
if (!appDetail.target || appDetail.target.toLowerCase().indexOf("unin") >= 0 || appDetail.args) return;
|
||||
|
||||
// C:/program/cmd.exe => cmd
|
||||
keyWords.push(path.basename(appDetail.target, ".exe"));
|
||||
|
||||
if (isZhRegex.test(appName)) {
|
||||
const py = translate(appName);
|
||||
@@ -101,5 +110,6 @@ function fileDisplay(filePath) {
|
||||
|
||||
export default () => {
|
||||
fileDisplay(filePath);
|
||||
fileDisplay(startMenu);
|
||||
return fileLists;
|
||||
};
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import appSearch from "@/core/app-search";
|
||||
import PluginHandler from "@/core/plugin-handler";
|
||||
import LocalDb from "@/core/db";
|
||||
|
||||
export {
|
||||
appSearch,
|
||||
PluginHandler,
|
||||
LocalDb,
|
||||
};
|
||||
|
||||
@@ -3,12 +3,12 @@ import {
|
||||
AdapterInfo,
|
||||
} from "@/core/plugin-handler/types";
|
||||
import fs from "fs-extra";
|
||||
import search, { Result } from "libnpmsearch";
|
||||
import path from "path";
|
||||
import got from "got";
|
||||
import fixPath from "fix-path";
|
||||
|
||||
import spawn from "cross-spawn";
|
||||
import { ipcRenderer } from "electron";
|
||||
|
||||
fixPath();
|
||||
|
||||
@@ -37,7 +37,19 @@ class AdapterHandler {
|
||||
);
|
||||
}
|
||||
this.baseDir = options.baseDir;
|
||||
this.registry = options.registry || "https://registry.npm.taobao.org";
|
||||
|
||||
let register = options.registry || "https://registry.npm.taobao.org";
|
||||
|
||||
try {
|
||||
const dbdata = ipcRenderer.sendSync("msg-trigger", {
|
||||
type: "dbGet",
|
||||
data: { id: "rubick-localhost-config" },
|
||||
});
|
||||
register = dbdata.data.register;
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
this.registry = register || "https://registry.npm.taobao.org";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -77,30 +89,6 @@ class AdapterHandler {
|
||||
await this.execCommand(installCmd, adapters);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 npm 搜索插件
|
||||
* 传入 streamFunc 可以流式处理
|
||||
* @param {string} adapter 插件名称
|
||||
* @param {(data: Result) => void} [streamFunc] 流式处理钩子
|
||||
* @memberof AdapterHandler
|
||||
*/
|
||||
async search(adapter: string, streamFunc?: (data: Result) => void) {
|
||||
return await new Promise<Result[]>((resolve, reject) => {
|
||||
const result: Result[] = [];
|
||||
const stream = search.stream(adapter);
|
||||
stream.on("data", (data: Result) => {
|
||||
result.push(data);
|
||||
if (streamFunc !== undefined) streamFunc(data);
|
||||
});
|
||||
stream.on("end", () => {
|
||||
resolve(result);
|
||||
});
|
||||
stream.on("error", (e: any) => {
|
||||
reject(e);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新指定插件
|
||||
* @param {...string[]} adapters 插件名称
|
||||
|
||||
@@ -34,7 +34,6 @@ export default () => {
|
||||
// Load the index.html when not in development
|
||||
win.loadURL("app://./index.html");
|
||||
}
|
||||
|
||||
protocol.interceptFileProtocol("image", (req, callback) => {
|
||||
const url = req.url.substr(8);
|
||||
callback(decodeURI(url));
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
Notification,
|
||||
nativeImage,
|
||||
clipboard,
|
||||
shell,
|
||||
} from "electron";
|
||||
import { runner, detach } from "../browsers";
|
||||
import fs from "fs";
|
||||
@@ -19,7 +20,7 @@ const dbInstance = new LocalDb(app.getPath("userData"));
|
||||
|
||||
dbInstance.init();
|
||||
|
||||
const API: any = {
|
||||
export const API: any = {
|
||||
currentPlugin: null,
|
||||
DBKEY: "RUBICK_DB_DEFAULT",
|
||||
getCurrentWindow: (window, e) => {
|
||||
@@ -155,7 +156,7 @@ const API: any = {
|
||||
return dbInstance.bulkDocs(API.DBKEY, data.docs);
|
||||
},
|
||||
dbAllDocs({ data }) {
|
||||
return dbInstance.bulkDocs(API.DBKEY, data.key);
|
||||
return dbInstance.allDocs(API.DBKEY, data.key);
|
||||
},
|
||||
getFeatures() {
|
||||
return API.currentPlugin.features;
|
||||
@@ -185,9 +186,12 @@ const API: any = {
|
||||
removeFeature({ data }, window) {
|
||||
API.currentPlugin = {
|
||||
...API.currentPlugin,
|
||||
features: API.currentPlugin.features.filter(
|
||||
(feature) => feature.code !== data.code
|
||||
),
|
||||
features: API.currentPlugin.features.filter((feature) => {
|
||||
if (data.code.type) {
|
||||
return feature.code.type !== data.code.type;
|
||||
}
|
||||
return feature.code !== data.code;
|
||||
}),
|
||||
};
|
||||
window.webContents.executeJavaScript(
|
||||
`window.updatePlugin(${JSON.stringify({
|
||||
@@ -236,13 +240,21 @@ const API: any = {
|
||||
detachInputChange({ data }) {
|
||||
API.sendSubInputChangeEvent({ data });
|
||||
},
|
||||
|
||||
getLocalId() {
|
||||
return encodeURIComponent(app.getPath("home"));
|
||||
},
|
||||
|
||||
shellShowItemInFolder({ data }) {
|
||||
shell.showItemInFolder(data.path);
|
||||
return true;
|
||||
},
|
||||
};
|
||||
|
||||
export default (mainWindow: BrowserWindow) => {
|
||||
// 响应 preload.js 事件
|
||||
ipcMain.on("msg-trigger", async (event, arg) => {
|
||||
const window = arg.winId ? BrowserWindow.fromId(arg.winId) : mainWindow;
|
||||
|
||||
const data = await API[arg.type](arg, window, event);
|
||||
event.returnValue = data;
|
||||
// event.sender.send(`msg-back-${arg.type}`, data);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div v-if="commonConst.windows()" class="drag-bar"></div>
|
||||
<div :class="!commonConst.windows() && 'drag'" id="components-layout">
|
||||
<div v-if="commonConst.windows() || commonConst.linux()" class="drag-bar"></div>
|
||||
<div :class="!commonConst.windows() && !commonConst.linux() && 'drag'" id="components-layout">
|
||||
<div class="rubick-select">
|
||||
<Search
|
||||
:currentPlugin="currentPlugin"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div v-show="!!options.length && (searchValue || !!clipboardFile.length) && !currentPlugin.name" class="options" ref="scrollDom">
|
||||
<a-list item-layout="horizontal" :dataSource="options">
|
||||
<a-list item-layout="horizontal" :dataSource="sort(options)">
|
||||
<template #renderItem="{ item, index }">
|
||||
<a-list-item
|
||||
@click="() => item.click()"
|
||||
@@ -66,6 +66,20 @@ const renderDesc = (desc) => {
|
||||
}
|
||||
return desc;
|
||||
};
|
||||
|
||||
const sort = (options) => {
|
||||
for (let i = 0; i < options.length; i++) {
|
||||
for (let j = i + 1; j < options.length; j++) {
|
||||
if (options[j].zIndex > options[i].zIndex) {
|
||||
let temp = options[i];
|
||||
options[i] = options[j];
|
||||
options[j] = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
return options;
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
<div class="select-tag" v-show="currentPlugin.cmd">{{ currentPlugin.cmd }}</div>
|
||||
<div :class="clipboardFile[0].name ? 'clipboard-tag' : 'clipboard-img'" v-if="!!clipboardFile.length">
|
||||
<img :src="getIcon()" />
|
||||
{{ clipboardFile[0].name }}
|
||||
<div class="ellipse">{{ clipboardFile[0].name }}</div>
|
||||
<a-tag color="#aaa" v-if="clipboardFile.length > 1">{{ clipboardFile.length }}</a-tag>
|
||||
</div>
|
||||
<a-input
|
||||
id="search"
|
||||
@@ -177,7 +178,7 @@ const changeHideOnBlur = () => {
|
||||
const getIcon = () => {
|
||||
if (props.clipboardFile[0].dataUrl) return props.clipboardFile[0].dataUrl;
|
||||
return props.clipboardFile[0].isFile ? require("../assets/file.png") : require("../assets/folder.png")
|
||||
}
|
||||
};
|
||||
|
||||
const newWindow = () => {
|
||||
ipcRenderer.send("msg-trigger", {
|
||||
@@ -197,6 +198,12 @@ const newWindow = () => {
|
||||
left: 0;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
.ellipse {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
max-width: 200px;
|
||||
}
|
||||
.select-tag {
|
||||
white-space: pre;
|
||||
user-select: none;
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
import { createApp } from "vue";
|
||||
import Antd from "ant-design-vue";
|
||||
import { Button, List, Spin, Input, Avatar, Tag } from "ant-design-vue";
|
||||
import App from "./App.vue";
|
||||
import "ant-design-vue/dist/antd.css";
|
||||
|
||||
createApp(App).use(Antd).mount("#app");
|
||||
createApp(App)
|
||||
.use(Button)
|
||||
.use(List)
|
||||
.use(Spin)
|
||||
.use(Input)
|
||||
.use(Avatar)
|
||||
.use(Tag)
|
||||
.mount("#app");
|
||||
|
||||
@@ -120,8 +120,8 @@ export default ({
|
||||
clearClipboardFile();
|
||||
window.setSubInputValue({ value: contentText });
|
||||
}
|
||||
clipboard.clear();
|
||||
}
|
||||
clipboard.clear();
|
||||
};
|
||||
|
||||
const clearClipboardFile = () => {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { reactive, toRefs, ref } from "vue";
|
||||
import { nativeImage, remote, ipcRenderer } from "electron";
|
||||
import { appSearch, PluginHandler } from "@/core";
|
||||
import appSearch from "@/core/app-search";
|
||||
import { PluginHandler } from "@/core";
|
||||
import path from "path";
|
||||
import commonConst from "@/common/utils/commonConst";
|
||||
import { execSync } from "child_process";
|
||||
@@ -28,7 +29,7 @@ const createPluginManager = (): any => {
|
||||
};
|
||||
|
||||
const openPlugin = (plugin) => {
|
||||
if (plugin.pluginType === "ui") {
|
||||
if (plugin.pluginType === "ui" || plugin.pluginType === "system") {
|
||||
if (state.currentPlugin && state.currentPlugin.name === plugin.name) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ const optionsManager = ({
|
||||
icon: plugin.logo,
|
||||
desc: fe.explain,
|
||||
type: plugin.pluginType,
|
||||
zIndex: cmd.label ? 0 : 1, // 排序权重
|
||||
click: () => {
|
||||
pluginClickEvent({
|
||||
plugin,
|
||||
@@ -61,10 +62,10 @@ const optionsManager = ({
|
||||
cmd,
|
||||
ext: cmd.type
|
||||
? {
|
||||
code: fe.code,
|
||||
type: cmd.type || "text",
|
||||
payload: searchValue.value,
|
||||
}
|
||||
code: fe.code,
|
||||
type: cmd.type || "text",
|
||||
payload: searchValue.value,
|
||||
}
|
||||
: null,
|
||||
openPlugin,
|
||||
});
|
||||
@@ -101,14 +102,17 @@ const optionsManager = ({
|
||||
}
|
||||
})
|
||||
.map((plugin) => {
|
||||
plugin.click = () => {
|
||||
openPlugin(plugin);
|
||||
return {
|
||||
...plugin,
|
||||
zIndex: 1,
|
||||
click: () => {
|
||||
openPlugin(plugin);
|
||||
},
|
||||
};
|
||||
return plugin;
|
||||
}),
|
||||
];
|
||||
return options;
|
||||
}
|
||||
};
|
||||
|
||||
watch(searchValue, () => search(searchValue.value));
|
||||
// search Input operation
|
||||
@@ -126,7 +130,12 @@ const optionsManager = ({
|
||||
optionsRef.value = options;
|
||||
};
|
||||
|
||||
const { searchFocus, clipboardFile, clearClipboardFile, readClipboardContent } = useFocus({
|
||||
const {
|
||||
searchFocus,
|
||||
clipboardFile,
|
||||
clearClipboardFile,
|
||||
readClipboardContent,
|
||||
} = useFocus({
|
||||
currentPlugin,
|
||||
optionsRef,
|
||||
openPlugin,
|
||||
|
||||
@@ -15,6 +15,7 @@ module.exports = {
|
||||
entry: "src/renderer/main.ts",
|
||||
},
|
||||
},
|
||||
productionSourceMap: false,
|
||||
pluginOptions: {
|
||||
electronBuilder: {
|
||||
nodeIntegration: true,
|
||||
@@ -50,7 +51,10 @@ module.exports = {
|
||||
},
|
||||
mac: {
|
||||
icon: "public/icons/icon.icns",
|
||||
target: "pkg",
|
||||
target: [
|
||||
"dmg",
|
||||
"pkg"
|
||||
],
|
||||
extendInfo: {
|
||||
LSUIElement: 1,
|
||||
},
|
||||
@@ -66,6 +70,7 @@ module.exports = {
|
||||
linux: {
|
||||
icon: "public/icons/",
|
||||
publish: ["github"],
|
||||
target: "deb",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user