mirror of
https://github.com/rubickCenter/rubick
synced 2025-06-30 01:32:45 +08:00
ref: 优化 取色和截屏
This commit is contained in:
parent
de6e33c126
commit
d824f503e6
@ -25,7 +25,17 @@ let mainConfig = {
|
|||||||
{
|
{
|
||||||
test: /\.node$/,
|
test: /\.node$/,
|
||||||
use: 'node-loader'
|
use: 'node-loader'
|
||||||
}
|
},
|
||||||
|
{
|
||||||
|
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
|
||||||
|
use: {
|
||||||
|
loader: 'url-loader',
|
||||||
|
query: {
|
||||||
|
limit: 10000,
|
||||||
|
name: 'imgs/[name]--[folder].[ext]'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
node: {
|
node: {
|
||||||
|
659
package-lock.json
generated
659
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -21,7 +21,7 @@
|
|||||||
"asar": false,
|
"asar": false,
|
||||||
"productName": "rubick2",
|
"productName": "rubick2",
|
||||||
"appId": "com.example.yourapp2",
|
"appId": "com.example.yourapp2",
|
||||||
"compression":"maximum",
|
"compression": "maximum",
|
||||||
"directories": {
|
"directories": {
|
||||||
"output": "build"
|
"output": "build"
|
||||||
},
|
},
|
||||||
|
@ -1,103 +0,0 @@
|
|||||||
const { BrowserWindow, ipcMain, globalShortcut } = require("electron");
|
|
||||||
const os = require('os')
|
|
||||||
const path = require('path')
|
|
||||||
|
|
||||||
module.exports = () => {
|
|
||||||
let captureWins = []
|
|
||||||
|
|
||||||
let init = () => {
|
|
||||||
if (captureWins.length) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
createWindow();
|
|
||||||
};
|
|
||||||
|
|
||||||
let createWindow = () => {
|
|
||||||
const { screen } = require('electron');
|
|
||||||
let displays = screen.getAllDisplays();
|
|
||||||
captureWins = displays.map((display) => {
|
|
||||||
let captureWin = new BrowserWindow({
|
|
||||||
// window 使用 fullscreen, mac 设置为 undefined, 不可为 false
|
|
||||||
fullscreen: os.platform() === 'win32' || undefined,
|
|
||||||
width: display.bounds.width,
|
|
||||||
height: display.bounds.height,
|
|
||||||
x: display.bounds.x,
|
|
||||||
y: display.bounds.y,
|
|
||||||
transparent: true,
|
|
||||||
frame: false,
|
|
||||||
movable: false,
|
|
||||||
resizable: false,
|
|
||||||
enableLargerThanScreen: true,
|
|
||||||
hasShadow: false,
|
|
||||||
show: false,
|
|
||||||
title: 'capture',
|
|
||||||
webPreferences: {
|
|
||||||
enableRemoteModule: true,
|
|
||||||
nodeIntegration: true,
|
|
||||||
webSecurity: false,
|
|
||||||
devTools: false,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
captureWin.setAlwaysOnTop(true, 'screen-saver')
|
|
||||||
captureWin.setFullScreenable(false)
|
|
||||||
|
|
||||||
captureWin.loadFile(`${__static}/plugins/capture/index.html`);
|
|
||||||
|
|
||||||
let { x, y } = screen.getCursorScreenPoint()
|
|
||||||
if (x >= display.bounds.x && x <= display.bounds.x + display.bounds.width && y >= display.bounds.y && y <= display.bounds.y + display.bounds.height) {
|
|
||||||
captureWin.focus()
|
|
||||||
} else {
|
|
||||||
captureWin.blur()
|
|
||||||
}
|
|
||||||
|
|
||||||
captureWin.on("closed", () => {
|
|
||||||
captureWin = undefined;
|
|
||||||
});
|
|
||||||
|
|
||||||
captureWin.once('ready-to-show', () => captureWin.show());
|
|
||||||
return captureWin
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
let getWindow = () => captureWins;
|
|
||||||
|
|
||||||
const close = () => {
|
|
||||||
const wins = BrowserWindow.getAllWindows();
|
|
||||||
wins.forEach((win) => {
|
|
||||||
if (win.title === 'capture') win.close();
|
|
||||||
captureWins = [];
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
ipcMain.on('capture-screen', (e, { type = 'start', screenId, winId, x, y } = {}) => {
|
|
||||||
if (type === 'start') {
|
|
||||||
init()
|
|
||||||
} else if (type === 'complete') {
|
|
||||||
if (captureWins) {
|
|
||||||
captureWins.forEach(win => win.close())
|
|
||||||
captureWins = []
|
|
||||||
}
|
|
||||||
// nothing
|
|
||||||
} else if (type === 'select') {
|
|
||||||
captureWins.forEach(win => win.webContents.send('capture-screen', { type: 'select', screenId }))
|
|
||||||
} else if (type === 'getAllDisplays') {
|
|
||||||
const { screen } = require('electron');
|
|
||||||
let displays = screen.getAllDisplays();
|
|
||||||
const currentScreen = displays.filter(d => d.bounds.x === x && d.bounds.y === y)[0];
|
|
||||||
e.sender.send('getAllDisplays', {
|
|
||||||
screen: {
|
|
||||||
scaleFactor: currentScreen.scaleFactor,
|
|
||||||
id: currentScreen.id,
|
|
||||||
bounds: currentScreen.bounds,
|
|
||||||
},
|
|
||||||
winId,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
init: init,
|
|
||||||
getWindow: getWindow,
|
|
||||||
close,
|
|
||||||
};
|
|
||||||
};
|
|
@ -1,7 +1,6 @@
|
|||||||
module.exports = () => ({
|
module.exports = () => ({
|
||||||
picker: require("./picker")(),
|
picker: require("./picker")(),
|
||||||
separator: require("./separate")(),
|
separator: require("./separate")(),
|
||||||
capture: require("./capture")(),
|
|
||||||
superPanel: require("./superPanel")(),
|
superPanel: require("./superPanel")(),
|
||||||
main: require("./main")(),
|
main: require("./main")(),
|
||||||
});
|
});
|
||||||
|
@ -13,14 +13,13 @@ module.exports = () => {
|
|||||||
win = new BrowserWindow({
|
win = new BrowserWindow({
|
||||||
frame: false,
|
frame: false,
|
||||||
autoHideMenuBar: true,
|
autoHideMenuBar: true,
|
||||||
width: 100,
|
width: 108,
|
||||||
height: 100,
|
height: 108,
|
||||||
transparent: true,
|
transparent: true,
|
||||||
alwaysOnTop: true,
|
alwaysOnTop: true,
|
||||||
resizable: false,
|
resizable: false,
|
||||||
focusable: true,
|
focusable: true,
|
||||||
hasShadow: false,
|
hasShadow: false,
|
||||||
// icon: nativeImage.createFromPath(`${dirname}/build/icon.png`),
|
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
nodeIntegration: true,
|
nodeIntegration: true,
|
||||||
devTools: false,
|
devTools: false,
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
const {stringify} = require('query-string');
|
const { BrowserWindow } = require("electron");
|
||||||
const { BrowserWindow, nativeImage } = require("electron");
|
|
||||||
|
|
||||||
module.exports = () => {
|
module.exports = () => {
|
||||||
let win;
|
let win;
|
||||||
@ -10,7 +9,7 @@ module.exports = () => {
|
|||||||
|
|
||||||
let createWindow = (opts) => {
|
let createWindow = (opts) => {
|
||||||
const winURL = process.env.NODE_ENV === 'development'
|
const winURL = process.env.NODE_ENV === 'development'
|
||||||
? `http://localhost:9080/#/plugin?${stringify(opts)}`
|
? `http://localhost:9080/#/plugin`
|
||||||
: `${__dirname}/index.html`
|
: `${__dirname}/index.html`
|
||||||
win = new BrowserWindow({
|
win = new BrowserWindow({
|
||||||
height: 600,
|
height: 600,
|
||||||
@ -27,11 +26,14 @@ module.exports = () => {
|
|||||||
nodeIntegration: true // 在网页中集成Node
|
nodeIntegration: true // 在网页中集成Node
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
process.env.NODE_ENV === 'development' ? win.loadURL(winURL) : win.loadFile(winURL, {
|
process.env.NODE_ENV === 'development' ? win.loadURL(winURL) : win.loadFile(winURL, {
|
||||||
hash: `#/plugin?${stringify(opts)}`,
|
hash: `#/plugin`,
|
||||||
});
|
});
|
||||||
win.once('ready-to-show', () => win.show());
|
|
||||||
|
win.webContents.executeJavaScript(`window.setPluginInfo(${opts})`).then(() => {
|
||||||
|
win.show()
|
||||||
|
});
|
||||||
|
|
||||||
win.on("closed", () => {
|
win.on("closed", () => {
|
||||||
win = undefined;
|
win = undefined;
|
||||||
});
|
});
|
||||||
|
@ -1,12 +1,8 @@
|
|||||||
import {app, BrowserWindow, dialog} from 'electron';
|
import {app, BrowserWindow, dialog} from 'electron';
|
||||||
import {getlocalDataFile, saveData, getData} from './utils';
|
|
||||||
import path from "path";
|
|
||||||
|
|
||||||
const puppeteer = require("puppeteer-core");
|
const puppeteer = require("puppeteer-core");
|
||||||
const pie = require("puppeteer-in-electron")
|
const pie = require("puppeteer-in-electron")
|
||||||
|
|
||||||
const appPath = path.join(getlocalDataFile());
|
|
||||||
const dbPath = path.join(appPath, './db.json');
|
|
||||||
|
|
||||||
let browser
|
let browser
|
||||||
pie.initialize(app).then(res => {
|
pie.initialize(app).then(res => {
|
||||||
@ -34,93 +30,6 @@ export default {
|
|||||||
setExpendHeight({height}, mainWindow) {
|
setExpendHeight({height}, mainWindow) {
|
||||||
mainWindow.setSize(800, height || 60);
|
mainWindow.setSize(800, height || 60);
|
||||||
},
|
},
|
||||||
db: {
|
|
||||||
put({data}) {
|
|
||||||
data._rev = '';
|
|
||||||
let dbData = getData(dbPath) || [];
|
|
||||||
let target = [];
|
|
||||||
dbData.some((d, i) => {
|
|
||||||
if (d._id === data._id) {
|
|
||||||
target = [d, i]
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
// 更新
|
|
||||||
if (target[0]) {
|
|
||||||
dbData[target[1]] = data;
|
|
||||||
} else {
|
|
||||||
dbData.push(data);
|
|
||||||
}
|
|
||||||
saveData(dbPath, dbData);
|
|
||||||
return {
|
|
||||||
id: data._id,
|
|
||||||
ok: true,
|
|
||||||
rev: '',
|
|
||||||
}
|
|
||||||
},
|
|
||||||
get({key}) {
|
|
||||||
const dbData = getData(dbPath) || [];
|
|
||||||
|
|
||||||
return dbData.find(d => d._id === key) || {};
|
|
||||||
},
|
|
||||||
remove({key}) {
|
|
||||||
key = typeof key === 'object' ? key._id : key;
|
|
||||||
let dbData = getData(dbPath);
|
|
||||||
let find = false;
|
|
||||||
dbData.some((d, i) => {
|
|
||||||
if (d._id === key) {
|
|
||||||
dbData.splice(i, 1);
|
|
||||||
find = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
if (find) {
|
|
||||||
saveData(dbPath, dbData);
|
|
||||||
return {
|
|
||||||
id: key,
|
|
||||||
ok: true,
|
|
||||||
rev: '',
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
id: key,
|
|
||||||
ok: false,
|
|
||||||
rev: '',
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
bulkDocs({docs}) {
|
|
||||||
const dbData = getData(dbPath);
|
|
||||||
dbData.forEach((d, i) => {
|
|
||||||
const result = docs.find(data => data._id === d._id);
|
|
||||||
if (result) {
|
|
||||||
dbData[i] = result;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
saveData(dbPath, dbData);
|
|
||||||
return docs.map(d => ({
|
|
||||||
id: d._id,
|
|
||||||
success: true,
|
|
||||||
rev: '',
|
|
||||||
}))
|
|
||||||
},
|
|
||||||
allDocs({key}) {
|
|
||||||
const dbData = getData(dbPath);
|
|
||||||
if (!key) {
|
|
||||||
return dbData;
|
|
||||||
}
|
|
||||||
if (typeof key === 'string') {
|
|
||||||
return dbData.filter(d => d._id.indexOf(key) >= 0);
|
|
||||||
}
|
|
||||||
if (Array.isArray(key)) {
|
|
||||||
return dbData.filter(d => key.indexOf(d._id) >= 0);
|
|
||||||
}
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
ubrowser: {
|
ubrowser: {
|
||||||
goto: async ({winId}) => {
|
goto: async ({winId}) => {
|
||||||
|
@ -1,117 +1,13 @@
|
|||||||
import {
|
import {app} from 'electron';
|
||||||
globalShortcut,
|
|
||||||
ipcMain,
|
|
||||||
BrowserWindow,
|
|
||||||
clipboard,
|
|
||||||
Notification,
|
|
||||||
app,
|
|
||||||
screen,
|
|
||||||
} from 'electron';
|
|
||||||
import Api from './api';
|
|
||||||
import robot from 'robotjs';
|
|
||||||
import './config';
|
import './config';
|
||||||
import ioHook from 'iohook';
|
import Listener from './listener';
|
||||||
|
|
||||||
const browsers = require("../browsers")();
|
|
||||||
const {picker, separator, superPanel, capture} = browsers;
|
|
||||||
// 需要在超级面板展示的插件
|
|
||||||
let optionPlugin = [];
|
|
||||||
|
|
||||||
let closePicker = () => {
|
|
||||||
if (picker.getWindow()) {
|
|
||||||
ipcMain.removeListener("closePicker", closePicker);
|
|
||||||
picker.getWindow().close();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function registerShortCut(mainWindow) {
|
|
||||||
const config = global.opConfig.get();
|
|
||||||
globalShortcut.unregisterAll();
|
|
||||||
// 注册偏好快捷键
|
|
||||||
globalShortcut.register(config.perf.shortCut.showAndHidden, () => {
|
|
||||||
const {x, y} = screen.getCursorScreenPoint();
|
|
||||||
const currentDisplay = screen.getDisplayNearestPoint({ x, y });
|
|
||||||
const wx = parseInt(currentDisplay.workArea.x + currentDisplay.workArea.width / 2 - 400);
|
|
||||||
const wy = parseInt(currentDisplay.workArea.y + currentDisplay.workArea.height / 2 - 200);
|
|
||||||
mainWindow.setVisibleOnAllWorkspaces(true);
|
|
||||||
mainWindow.focus();
|
|
||||||
mainWindow.setVisibleOnAllWorkspaces(false);
|
|
||||||
mainWindow.setPosition(wx, wy);
|
|
||||||
mainWindow.show();
|
|
||||||
});
|
|
||||||
|
|
||||||
globalShortcut.register(config.perf.shortCut.separate, () => {
|
|
||||||
mainWindow.webContents.send('new-window');
|
|
||||||
});
|
|
||||||
|
|
||||||
// 注册自定义全局快捷键
|
|
||||||
config.global.forEach(sc => {
|
|
||||||
if (!sc.key || !sc.value) return;
|
|
||||||
globalShortcut.register(sc.key, () => {
|
|
||||||
mainWindow.webContents.send('global-short-key', sc.value);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
globalShortcut.register('Esc', () => {
|
|
||||||
capture.close();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const getSelectedText = () => {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
const lastText = clipboard.readText('clipboard');
|
|
||||||
|
|
||||||
const platform = process.platform;
|
|
||||||
if (platform === 'darwin') {
|
|
||||||
robot.keyTap('c', 'command');
|
|
||||||
} else {
|
|
||||||
robot.keyTap('c', 'control');
|
|
||||||
}
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
const text = clipboard.readText('clipboard') || ''
|
|
||||||
const fileUrl = clipboard.read('public.file-url');
|
|
||||||
clipboard.writeText(lastText);
|
|
||||||
|
|
||||||
resolve({
|
|
||||||
text,
|
|
||||||
fileUrl
|
|
||||||
})
|
|
||||||
}, 300);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function init(mainWindow) {
|
export default function init(mainWindow) {
|
||||||
ipcMain.on('optionPlugin', (e, args) => {
|
const listener = new Listener();
|
||||||
optionPlugin = args;
|
|
||||||
});
|
|
||||||
ipcMain.on('right-down', async (e) => {
|
|
||||||
const copyResult = await getSelectedText();
|
|
||||||
let win = superPanel.getWindow();
|
|
||||||
|
|
||||||
if (win) {
|
|
||||||
win.webContents.send('trigger-super-panel', {
|
|
||||||
...copyResult,
|
|
||||||
optionPlugin: optionPlugin.plugins,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
superPanel.init(mainWindow);
|
|
||||||
win = superPanel.getWindow();
|
|
||||||
|
|
||||||
win.once('ready-to-show', () => {
|
|
||||||
win.webContents.send('trigger-super-panel', {
|
|
||||||
...copyResult,
|
|
||||||
optionPlugin: optionPlugin.plugins,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const pos = robot.getMousePos();
|
|
||||||
win.setPosition(parseInt(pos.x), parseInt(pos.y));
|
|
||||||
win.show();
|
|
||||||
});
|
|
||||||
|
|
||||||
// 注册快捷键
|
// 注册快捷键
|
||||||
registerShortCut(mainWindow);
|
listener.registerShortCut(mainWindow);
|
||||||
|
listener.init(mainWindow);
|
||||||
|
|
||||||
// 设置开机启动
|
// 设置开机启动
|
||||||
const config = global.opConfig.get();
|
const config = global.opConfig.get();
|
||||||
@ -127,92 +23,11 @@ export default function init(mainWindow) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.on('re-register', (event, arg) => {
|
|
||||||
registerShortCut(mainWindow);
|
|
||||||
});
|
|
||||||
|
|
||||||
ipcMain.on('changeWindowSize-rubick', (event, arg) => {
|
|
||||||
mainWindow.setSize(arg.width || 800, arg.height);
|
|
||||||
});
|
|
||||||
|
|
||||||
// 打包后,失焦隐藏
|
// 打包后,失焦隐藏
|
||||||
mainWindow.on('blur', () => {
|
mainWindow.on('blur', () => {
|
||||||
app.isPackaged && mainWindow.hide();
|
app.isPackaged && mainWindow.hide();
|
||||||
});
|
});
|
||||||
|
|
||||||
// 响应 preload.js 事件
|
|
||||||
ipcMain.on('msg-trigger', async (event, arg) => {
|
|
||||||
const window = arg.winId ? BrowserWindow.fromId(arg.winId) : mainWindow
|
|
||||||
const operators = arg.type.split('.');
|
|
||||||
let fn = Api;
|
|
||||||
operators.forEach((op) => {
|
|
||||||
fn = fn[op];
|
|
||||||
});
|
|
||||||
const data = await fn(arg, window);
|
|
||||||
event.sender.send(`msg-back-${arg.type}`, data);
|
|
||||||
});
|
|
||||||
|
|
||||||
// 窗口分离
|
|
||||||
ipcMain.on('new-window', (event, arg) => {
|
|
||||||
const opts = {
|
|
||||||
...arg,
|
|
||||||
searchType: 'subWindow',
|
|
||||||
}
|
|
||||||
separator.init(opts);
|
|
||||||
});
|
|
||||||
|
|
||||||
// 拾色器
|
|
||||||
ipcMain.on('start-picker', () => {
|
|
||||||
// 开启输入侦测
|
|
||||||
ioHook.start(false);
|
|
||||||
ioHook.load();
|
|
||||||
picker.init();
|
|
||||||
|
|
||||||
picker.getWindow().on('close', () => {
|
|
||||||
ioHook.stop();
|
|
||||||
ioHook.unload();
|
|
||||||
});
|
|
||||||
|
|
||||||
let pos = robot.getMousePos();
|
|
||||||
picker
|
|
||||||
.getWindow()
|
|
||||||
.setPosition(parseInt(pos.x) - 50, parseInt(pos.y) - 50);
|
|
||||||
|
|
||||||
picker
|
|
||||||
.getWindow()
|
|
||||||
.webContents.send(
|
|
||||||
"updatePicker",
|
|
||||||
robot.getPixelColor(pos.x, pos.y)
|
|
||||||
);
|
|
||||||
|
|
||||||
ipcMain.on("closePicker", closePicker);
|
|
||||||
});
|
|
||||||
|
|
||||||
ioHook.on('mousemove', e => {
|
|
||||||
let x = e.x
|
|
||||||
let y = e.y
|
|
||||||
if (!picker.getWindow()) return;
|
|
||||||
let color = "#" + robot.getPixelColor(parseInt(x), parseInt(y));
|
|
||||||
picker.getWindow().setPosition(parseInt(x) - 50, parseInt(y) - 50);
|
|
||||||
picker.getWindow().webContents.send("updatePicker", color);
|
|
||||||
})
|
|
||||||
|
|
||||||
ioHook.on('mouseup', e => {
|
|
||||||
if (e.button === 1) {
|
|
||||||
let x = e.x
|
|
||||||
let y = e.y
|
|
||||||
const color = "#" + robot.getPixelColor(parseInt(x), parseInt(y));
|
|
||||||
clipboard.writeText("#" + robot.getPixelColor(parseInt(x), parseInt(y)));
|
|
||||||
new Notification({ title: 'Rubick 通知', body: `${color} 已保存到剪切板` }).show();
|
|
||||||
closePicker();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
ioHook.on('mouseup', e => {
|
|
||||||
if (e.button === 3) {
|
|
||||||
closePicker()
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
265
src/main/common/listener.js
Normal file
265
src/main/common/listener.js
Normal file
@ -0,0 +1,265 @@
|
|||||||
|
import {BrowserWindow, clipboard, globalShortcut, ipcMain, Notification, screen} from "electron";
|
||||||
|
import {exec, spawn} from "child_process";
|
||||||
|
import robot from "robotjs";
|
||||||
|
import Api from "./api";
|
||||||
|
import ioHook from 'iohook';
|
||||||
|
|
||||||
|
const browsers = require("../browsers")();
|
||||||
|
const {picker, separator, superPanel} = browsers;
|
||||||
|
|
||||||
|
class Listener {
|
||||||
|
constructor() {
|
||||||
|
this.optionPlugin = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
getSelectedContent() {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const lastText = clipboard.readText('clipboard');
|
||||||
|
// todo 缓存文件
|
||||||
|
clipboard.clear();
|
||||||
|
|
||||||
|
// 复制选中文案
|
||||||
|
const platform = process.platform;
|
||||||
|
if (platform === 'darwin') {
|
||||||
|
robot.keyTap('c', 'command');
|
||||||
|
} else {
|
||||||
|
robot.keyTap('c', 'control');
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
// 延时一定时间才能从剪切板内读取到内容
|
||||||
|
const text = clipboard.readText('clipboard') || ''
|
||||||
|
const fileUrl = clipboard.read('public.file-url');
|
||||||
|
|
||||||
|
// 如果之前是文案,则回填
|
||||||
|
clipboard.writeText(lastText);
|
||||||
|
|
||||||
|
resolve({
|
||||||
|
text,
|
||||||
|
fileUrl
|
||||||
|
})
|
||||||
|
}, 300);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
registerShortCut(mainWindow) {
|
||||||
|
const config = global.opConfig.get();
|
||||||
|
globalShortcut.unregisterAll();
|
||||||
|
// 注册偏好快捷键
|
||||||
|
globalShortcut.register(config.perf.shortCut.showAndHidden, () => {
|
||||||
|
const {x, y} = screen.getCursorScreenPoint();
|
||||||
|
const currentDisplay = screen.getDisplayNearestPoint({ x, y });
|
||||||
|
const wx = parseInt(currentDisplay.workArea.x + currentDisplay.workArea.width / 2 - 400);
|
||||||
|
const wy = parseInt(currentDisplay.workArea.y + currentDisplay.workArea.height / 2 - 200);
|
||||||
|
mainWindow.setVisibleOnAllWorkspaces(true);
|
||||||
|
mainWindow.focus();
|
||||||
|
mainWindow.setVisibleOnAllWorkspaces(false);
|
||||||
|
mainWindow.setPosition(wx, wy);
|
||||||
|
mainWindow.show();
|
||||||
|
});
|
||||||
|
|
||||||
|
globalShortcut.register(config.perf.shortCut.separate, () => {
|
||||||
|
mainWindow.webContents.send('new-window');
|
||||||
|
});
|
||||||
|
|
||||||
|
// 注册自定义全局快捷键
|
||||||
|
config.global.forEach(sc => {
|
||||||
|
if (!sc.key || !sc.value) return;
|
||||||
|
globalShortcut.register(sc.key, () => {
|
||||||
|
mainWindow.webContents.send('global-short-key', sc.value);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
init(mainWindow) {
|
||||||
|
this.colorPicker();
|
||||||
|
this.initPlugin();
|
||||||
|
this.lockScreen();
|
||||||
|
this.separate();
|
||||||
|
this.initCapture();
|
||||||
|
this.superPanel(mainWindow);
|
||||||
|
this.reRegisterShortCut(mainWindow);
|
||||||
|
this.changeSize(mainWindow);
|
||||||
|
this.msgTrigger(mainWindow);
|
||||||
|
}
|
||||||
|
|
||||||
|
colorPicker() {
|
||||||
|
// 拾色器
|
||||||
|
ipcMain.on('start-picker', () => {
|
||||||
|
// 开启输入侦测
|
||||||
|
ioHook.start(false);
|
||||||
|
ioHook.load();
|
||||||
|
picker.init();
|
||||||
|
|
||||||
|
picker.getWindow().on('close', () => {
|
||||||
|
ioHook.stop();
|
||||||
|
ioHook.unload();
|
||||||
|
});
|
||||||
|
|
||||||
|
let pos = robot.getMousePos();
|
||||||
|
picker
|
||||||
|
.getWindow()
|
||||||
|
.setPosition(parseInt(pos.x) + 10, parseInt(pos.y) + 10);
|
||||||
|
|
||||||
|
const img = robot.screen.capture(parseInt(pos.x) - 5, parseInt(pos.y) - 5, 9, 9);
|
||||||
|
|
||||||
|
const colors = {}
|
||||||
|
|
||||||
|
for(let i = 0; i< 9; i++) {
|
||||||
|
colors[i] = {};
|
||||||
|
for (let j = 0; j < 9; j++) {
|
||||||
|
colors[i][j] = img.colorAt(j, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
picker
|
||||||
|
.getWindow()
|
||||||
|
.webContents.send(
|
||||||
|
"updatePicker",
|
||||||
|
colors
|
||||||
|
);
|
||||||
|
|
||||||
|
ipcMain.on("closePicker", () => {
|
||||||
|
this.closePicker();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
ioHook.on('mousemove', e => {
|
||||||
|
let x = e.x
|
||||||
|
let y = e.y
|
||||||
|
if (!picker.getWindow()) return;
|
||||||
|
let color = "#" + robot.getPixelColor(parseInt(x), parseInt(y));
|
||||||
|
picker.getWindow().setPosition(parseInt(x) + 10, parseInt(y) + 10);
|
||||||
|
|
||||||
|
|
||||||
|
const img = robot.screen.capture(parseInt(x) - 5, parseInt(y) - 5, 9, 9);
|
||||||
|
|
||||||
|
const colors = {}
|
||||||
|
|
||||||
|
for(let i = 0; i< 9; i++) {
|
||||||
|
colors[i] = {};
|
||||||
|
for (let j = 0; j < 9; j++) {
|
||||||
|
colors[i][j] = img.colorAt(j, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
picker.getWindow().webContents.send("updatePicker", colors);
|
||||||
|
})
|
||||||
|
|
||||||
|
ioHook.on('mouseup', e => {
|
||||||
|
if (e.button === 1) {
|
||||||
|
let x = e.x
|
||||||
|
let y = e.y
|
||||||
|
const color = "#" + robot.getPixelColor(parseInt(x), parseInt(y));
|
||||||
|
clipboard.writeText("#" + robot.getPixelColor(parseInt(x), parseInt(y)));
|
||||||
|
new Notification({ title: 'Rubick 通知', body: `${color} 已保存到剪切板` }).show();
|
||||||
|
this.closePicker();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ioHook.on('mouseup', e => {
|
||||||
|
if (e.button === 3) {
|
||||||
|
this.closePicker()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
closePicker() {
|
||||||
|
if (picker.getWindow()) {
|
||||||
|
ipcMain.removeListener("closePicker", this.closePicker);
|
||||||
|
picker.getWindow().close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
initPlugin() {
|
||||||
|
ipcMain.on('optionPlugin', (e, args) => {
|
||||||
|
this.optionPlugin = args;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
lockScreen() {
|
||||||
|
// 锁屏
|
||||||
|
ipcMain.on('lock-screen', () => {
|
||||||
|
const lockCommands = {
|
||||||
|
darwin: '/System/Library/CoreServices/"Menu Extras"/User.menu/Contents/Resources/CGSession -suspend',
|
||||||
|
win32: 'rundll32.exe user32.dll, LockWorkStation',
|
||||||
|
linux: '(hash gnome-screensaver-command 2>/dev/null && gnome-screensaver-command -l) || (hash dm-tool 2>/dev/null && dm-tool lock)'
|
||||||
|
};
|
||||||
|
exec(lockCommands[process.platform]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
superPanel(mainWindow) {
|
||||||
|
// 长按右击呼起超级面板
|
||||||
|
ipcMain.on('right-down', async () => {
|
||||||
|
const copyResult = await this.getSelectedContent();
|
||||||
|
let win = superPanel.getWindow();
|
||||||
|
|
||||||
|
if (win) {
|
||||||
|
win.webContents.send('trigger-super-panel', {
|
||||||
|
...copyResult,
|
||||||
|
optionPlugin: this.optionPlugin.plugins,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
superPanel.init(mainWindow);
|
||||||
|
win = superPanel.getWindow();
|
||||||
|
|
||||||
|
win.once('ready-to-show', () => {
|
||||||
|
win.webContents.send('trigger-super-panel', {
|
||||||
|
...copyResult,
|
||||||
|
optionPlugin: this.optionPlugin.plugins,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const pos = robot.getMousePos();
|
||||||
|
win.setPosition(parseInt(pos.x), parseInt(pos.y));
|
||||||
|
win.show();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
reRegisterShortCut(mainWindow) {
|
||||||
|
ipcMain.on('re-register', (event, arg) => {
|
||||||
|
this.registerShortCut(mainWindow);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
changeSize(mainWindow) {
|
||||||
|
// 修改窗口尺寸
|
||||||
|
ipcMain.on('changeWindowSize-rubick', (event, arg) => {
|
||||||
|
mainWindow.setSize(arg.width || 800, arg.height);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
msgTrigger(mainWindow) {
|
||||||
|
// 响应 preload.js 事件
|
||||||
|
ipcMain.on('msg-trigger', async (event, arg) => {
|
||||||
|
const window = arg.winId ? BrowserWindow.fromId(arg.winId) : mainWindow
|
||||||
|
const operators = arg.type.split('.');
|
||||||
|
let fn = Api;
|
||||||
|
operators.forEach((op) => {
|
||||||
|
fn = fn[op];
|
||||||
|
});
|
||||||
|
const data = await fn(arg, window);
|
||||||
|
event.sender.send(`msg-back-${arg.type}`, data);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
separate() {
|
||||||
|
// 窗口分离
|
||||||
|
ipcMain.on('new-window', (event, arg) => {
|
||||||
|
const opts = {
|
||||||
|
...arg,
|
||||||
|
searchType: 'subWindow',
|
||||||
|
}
|
||||||
|
separator.init(JSON.stringify(opts));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
initCapture() {
|
||||||
|
ipcMain.on('capture-screen', () => {
|
||||||
|
spawn('/usr/sbin/screencapture', ["-c", "-i", "-r"], {detached: !0});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Listener;
|
@ -36,7 +36,7 @@ function createTray(window) {
|
|||||||
click() {
|
click() {
|
||||||
dialog.showMessageBox({
|
dialog.showMessageBox({
|
||||||
title: '拉比克',
|
title: '拉比克',
|
||||||
message: '一站式前端开发工具箱',
|
message: '极简、插件化的现代桌面软件',
|
||||||
detail: `Version: ${pkg.version}\nAuthor: muwoo`
|
detail: `Version: ${pkg.version}\nAuthor: muwoo`
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -45,6 +45,14 @@ function createTray(window) {
|
|||||||
id: 7,
|
id: 7,
|
||||||
role: 'quit',
|
role: 'quit',
|
||||||
label: '退出'
|
label: '退出'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 7,
|
||||||
|
label: '重启',
|
||||||
|
click() {
|
||||||
|
app.relaunch();
|
||||||
|
app.exit();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
appIcon.on('click', () => {
|
appIcon.on('click', () => {
|
||||||
|
@ -47,6 +47,7 @@
|
|||||||
<span slot="title" v-html="renderTitle(item.name)" ></span>
|
<span slot="title" v-html="renderTitle(item.name)" ></span>
|
||||||
<a-avatar
|
<a-avatar
|
||||||
slot="avatar"
|
slot="avatar"
|
||||||
|
style="border-radius: 0;"
|
||||||
:src="item.icon"
|
:src="item.icon"
|
||||||
/>
|
/>
|
||||||
</a-list-item-meta>
|
</a-list-item-meta>
|
||||||
@ -58,11 +59,11 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="rubick-select-subMenu" v-else>
|
<div class="rubick-select-subMenu" v-else>
|
||||||
<div>
|
<div>
|
||||||
<img class="icon-tool-sub" v-if="query && query.icon" :src="query.icon" />
|
<img class="icon-tool-sub" v-if="pluginInfo.icon" :src="pluginInfo.icon" />
|
||||||
<a-input
|
<a-input
|
||||||
:placeholder="subPlaceHolder"
|
:placeholder="subPlaceHolder"
|
||||||
class="sub-input"
|
class="sub-input"
|
||||||
@change="(e) => search({value: e.target.value, searchType: $route.query.searchType})"
|
@change="(e) => search({value: e.target.value, searchType: pluginInfo.searchType})"
|
||||||
:value="searchValue"
|
:value="searchValue"
|
||||||
@keypress.enter="(e) => targetSearch({value: e.target.value, type: 'enter'})"
|
@keypress.enter="(e) => targetSearch({value: e.target.value, type: 'enter'})"
|
||||||
@keypress.space="(e) => targetSearch({value: e.target.value, type: 'space'})"
|
@keypress.space="(e) => targetSearch({value: e.target.value, type: 'space'})"
|
||||||
@ -71,7 +72,7 @@
|
|||||||
|
|
||||||
<div class="icon-container">
|
<div class="icon-container">
|
||||||
<a-icon class="icon" type="info-circle" />
|
<a-icon class="icon" type="info-circle" />
|
||||||
<a-icon class="icon" type="setting" />
|
<a-icon class="icon" @click="goMenu('separate')" type="setting" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<router-view></router-view>
|
<router-view></router-view>
|
||||||
@ -87,13 +88,21 @@ const {Menu, MenuItem} = remote;
|
|||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
searchType: this.$route.query.searchType ? 'subWindow' : '',
|
|
||||||
query: this.$route.query,
|
query: this.$route.query,
|
||||||
searchFn: null,
|
searchFn: null,
|
||||||
config: opConfig.get(),
|
config: opConfig.get(),
|
||||||
currentSelect: 0,
|
currentSelect: 0,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
created() {
|
||||||
|
window.setPluginInfo = (pluginInfo) => {
|
||||||
|
this.commonUpdate({
|
||||||
|
pluginInfo: pluginInfo,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
ipcRenderer.on('init-rubick', this.closeTag);
|
ipcRenderer.on('init-rubick', this.closeTag);
|
||||||
ipcRenderer.on('new-window', this.newWindow);
|
ipcRenderer.on('new-window', this.newWindow);
|
||||||
@ -173,6 +182,7 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
renderTitle(title) {
|
renderTitle(title) {
|
||||||
|
if (typeof title !== 'string') return;
|
||||||
const result = title.split(this.searchValue);
|
const result = title.split(this.searchValue);
|
||||||
return `<div>${result[0]}<span style="color: red">${this.searchValue}</span>${result[1]}</div>`
|
return `<div>${result[0]}<span style="color: red">${this.searchValue}</span>${result[1]}</div>`
|
||||||
},
|
},
|
||||||
@ -203,18 +213,13 @@ export default {
|
|||||||
},
|
},
|
||||||
newWindow() {
|
newWindow() {
|
||||||
ipcRenderer.send('new-window', {
|
ipcRenderer.send('new-window', {
|
||||||
...this.selected,
|
...this.pluginInfo
|
||||||
...this.$route.query,
|
|
||||||
});
|
});
|
||||||
this.closeTag();
|
this.closeTag();
|
||||||
},
|
},
|
||||||
goMenu() {
|
goMenu(type) {
|
||||||
if (this.selected && this.selected.key === 'plugin-container') {
|
if ((this.selected && this.selected.key === 'plugin-container') || type === 'separate') {
|
||||||
const pluginMenu = [
|
const pluginMenu = [
|
||||||
{
|
|
||||||
label: '分离窗口',
|
|
||||||
click: this.newWindow
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
label: '开发者工具',
|
label: '开发者工具',
|
||||||
click: () => {
|
click: () => {
|
||||||
@ -237,6 +242,12 @@ export default {
|
|||||||
label: '隐藏插件',
|
label: '隐藏插件',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
if (type !== 'separate') {
|
||||||
|
pluginMenu.unshift({
|
||||||
|
label: '分离窗口',
|
||||||
|
click: this.newWindow
|
||||||
|
})
|
||||||
|
}
|
||||||
let menu = Menu.buildFromTemplate(pluginMenu);
|
let menu = Menu.buildFromTemplate(pluginMenu);
|
||||||
menu.popup();
|
menu.popup();
|
||||||
return;
|
return;
|
||||||
@ -246,12 +257,15 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState('main', ['showMain', 'devPlugins', 'current', 'options', 'selected', 'searchValue', 'subPlaceHolder']),
|
...mapState('main', ['showMain', 'devPlugins', 'current', 'options', 'selected', 'searchValue', 'subPlaceHolder', 'pluginInfo']),
|
||||||
showOptions() {
|
showOptions() {
|
||||||
// 有选项值,且不在显示主页
|
// 有选项值,且不在显示主页
|
||||||
if (this.options.length && !this.showMain) {
|
if (this.options.length && !this.showMain) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
searchType() {
|
||||||
|
return this.pluginInfo.searchType ? 'subWindow' : ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
export default {
|
export default {
|
||||||
development: 'http://rubick-server.qa.91jkys.com',
|
development: 'http://118.195.176.247:8080',
|
||||||
production: 'http://rubick-server.qa.91jkys.com',
|
production: 'http://118.195.176.247:8080',
|
||||||
};
|
};
|
||||||
|
@ -5,7 +5,7 @@ const PRE_ITEM_HEIGHT = 60;
|
|||||||
const SYSTEM_PLUGINS = [
|
const SYSTEM_PLUGINS = [
|
||||||
{
|
{
|
||||||
"pluginName": "rubick 帮助文档",
|
"pluginName": "rubick 帮助文档",
|
||||||
"logo": "https://static.91jkys.com/activity/img/4eb6f2848b064f569c28fdf8495d5ec7.png",
|
"logo": require('../imgs/help.png'),
|
||||||
"features": [
|
"features": [
|
||||||
{
|
{
|
||||||
"code": "help",
|
"code": "help",
|
||||||
@ -17,7 +17,7 @@ const SYSTEM_PLUGINS = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pluginName": "屏幕颜色拾取",
|
"pluginName": "屏幕颜色拾取",
|
||||||
"logo": "https://static.91jkys.com/activity/img/6a1b4b8a17da45d680ea30b53a91aca8.png",
|
"logo": require('../imgs/picker.png'),
|
||||||
"features": [
|
"features": [
|
||||||
{
|
{
|
||||||
"code": "pick",
|
"code": "pick",
|
||||||
@ -29,7 +29,7 @@ const SYSTEM_PLUGINS = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pluginName": "截屏",
|
"pluginName": "截屏",
|
||||||
"logo": "https://static.91jkys.com/activity/img/b34d30b426f24eb2b77bf434b8493495.png",
|
"logo": require('../imgs/screenshot.png'),
|
||||||
"features": [
|
"features": [
|
||||||
{
|
{
|
||||||
"code": "shortCut",
|
"code": "shortCut",
|
||||||
@ -38,6 +38,18 @@ const SYSTEM_PLUGINS = [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
"tag": 'rubick-screen-short-cut',
|
"tag": 'rubick-screen-short-cut',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pluginName": "锁屏",
|
||||||
|
"logo": require('../imgs/lock.png'),
|
||||||
|
"features": [
|
||||||
|
{
|
||||||
|
"code": "lock",
|
||||||
|
"explain": "锁屏",
|
||||||
|
"cmds": [ "锁屏", "lock screen" ]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"tag": 'rubick-lock',
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -14,5 +14,10 @@ export default {
|
|||||||
shortCut() {
|
shortCut() {
|
||||||
ipcRenderer.send('capture-screen', {type: 'start'})
|
ipcRenderer.send('capture-screen', {type: 'start'})
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
'rubick-lock': {
|
||||||
|
lock() {
|
||||||
|
ipcRenderer.send('lock-screen');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -151,7 +151,7 @@ function find(p, target = 'plugin.json') {
|
|||||||
const fileLists = [];
|
const fileLists = [];
|
||||||
// 默认搜索目录
|
// 默认搜索目录
|
||||||
APP_FINDER_PATH.forEach((searchPath) => {
|
APP_FINDER_PATH.forEach((searchPath) => {
|
||||||
fs.readdir(searchPath, (err, files) => {
|
fs.readdir(searchPath, async (err, files) => {
|
||||||
try {
|
try {
|
||||||
for (let i = 0; i < files.length; i++) {
|
for (let i = 0; i < files.length; i++) {
|
||||||
const appName = files[i];
|
const appName = files[i];
|
||||||
@ -178,15 +178,14 @@ APP_FINDER_PATH.forEach((searchPath) => {
|
|||||||
const iconName = resourceList.filter(file => path.extname(file) === '.icns')[0];
|
const iconName = resourceList.filter(file => path.extname(file) === '.icns')[0];
|
||||||
iconPath = path.join(searchPath, `${appName}/Contents/Resources/${iconName}`);
|
iconPath = path.join(searchPath, `${appName}/Contents/Resources/${iconName}`);
|
||||||
}
|
}
|
||||||
nativeImage.createThumbnailFromPath(iconPath, {width: 64, height: 64}).then(img => {
|
const img = await nativeImage.createThumbnailFromPath(iconPath, {width: 64, height: 64});
|
||||||
fileLists.push({
|
fileLists.push({
|
||||||
name: appSubStr,
|
name: appSubStr,
|
||||||
value: 'plugin',
|
value: 'plugin',
|
||||||
icon: img.toDataURL(),
|
icon: img.toDataURL(),
|
||||||
desc: path.join(searchPath, appName),
|
desc: path.join(searchPath, appName),
|
||||||
type: 'app',
|
type: 'app',
|
||||||
action: `open ${path.join(searchPath, appName).replace(' ', '\\ ')}`
|
action: `open ${path.join(searchPath, appName).replace(' ', '\\ ')}`
|
||||||
})
|
|
||||||
})
|
})
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
}
|
}
|
||||||
|
BIN
src/renderer/assets/imgs/help.png
Normal file
BIN
src/renderer/assets/imgs/help.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.5 KiB |
BIN
src/renderer/assets/imgs/lock.png
Normal file
BIN
src/renderer/assets/imgs/lock.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 973 B |
BIN
src/renderer/assets/imgs/picker.png
Normal file
BIN
src/renderer/assets/imgs/picker.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.5 KiB |
BIN
src/renderer/assets/imgs/screenshot.png
Normal file
BIN
src/renderer/assets/imgs/screenshot.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 817 B |
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<webview v-if="!query.subType" id="webview" :src="path" :preload="preload"></webview>
|
<webview v-if="!pluginInfo.subType" id="webview" :src="path" :preload="preload"></webview>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<webview id="webview" :src="templatePath" :preload="preload"></webview>
|
<webview id="webview" :src="templatePath" :preload="preload"></webview>
|
||||||
</div>
|
</div>
|
||||||
@ -19,12 +19,9 @@ export default {
|
|||||||
name: "index.vue",
|
name: "index.vue",
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
path: `File://${this.$route.query.sourceFile}`,
|
|
||||||
preload: `File://${path.join(__static, './preload.js')}`,
|
preload: `File://${path.join(__static, './preload.js')}`,
|
||||||
webview: null,
|
webview: null,
|
||||||
query: this.$route.query,
|
|
||||||
config: {},
|
config: {},
|
||||||
templatePath: `File://${path.join(__static, './plugins/tpl/index.html')}?code=${JSON.parse(this.$route.query.detail).code}&targetFile=${encodeURIComponent(this.$route.query.sourceFile)}&preloadPath=${this.$route.query.preload}`,
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
@ -58,7 +55,7 @@ export default {
|
|||||||
if (event.channel === 'setFeature') {
|
if (event.channel === 'setFeature') {
|
||||||
this.commonUpdate({
|
this.commonUpdate({
|
||||||
devPlugins: this.devPlugins.map(plugin => {
|
devPlugins: this.devPlugins.map(plugin => {
|
||||||
if (plugin.name === this.query.name) {
|
if (plugin.name === this.pluginInfo.name) {
|
||||||
return {
|
return {
|
||||||
...plugin,
|
...plugin,
|
||||||
features: [...plugin.features, event.args[0].feature]
|
features: [...plugin.features, event.args[0].feature]
|
||||||
@ -71,7 +68,7 @@ export default {
|
|||||||
if (event.channel === 'removeFeature') {
|
if (event.channel === 'removeFeature') {
|
||||||
this.commonUpdate({
|
this.commonUpdate({
|
||||||
devPlugins: this.devPlugins.map(plugin => {
|
devPlugins: this.devPlugins.map(plugin => {
|
||||||
if (plugin.name === this.query.name) {
|
if (plugin.name === this.pluginInfo.name) {
|
||||||
return {
|
return {
|
||||||
...plugin,
|
...plugin,
|
||||||
features: plugin.features.filter(fe => fe.code !== event.args[0].code)
|
features: plugin.features.filter(fe => fe.code !== event.args[0].code)
|
||||||
@ -87,18 +84,24 @@ export default {
|
|||||||
...mapMutations('main', ['setSubPlaceHolder', 'commonUpdate']),
|
...mapMutations('main', ['setSubPlaceHolder', 'commonUpdate']),
|
||||||
},
|
},
|
||||||
beforeRouteUpdate() {
|
beforeRouteUpdate() {
|
||||||
this.path = `File://${this.$route.query.sourceFile}`;
|
this.path = `File://${this.pluginInfo.sourceFile}`;
|
||||||
this.webview.send('onPluginEnter', this.pluginInfo);
|
this.webview.send('onPluginEnter', this.pluginInfo);
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
const webview = document.querySelector('webview');
|
const webview = document.querySelector('webview');
|
||||||
webview && webview.send('onPluginOut', this.$route.query)
|
webview && webview.send('onPluginOut', this.pluginInfo)
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState('main', ['searchValue', 'devPlugins', 'pluginInfo']),
|
...mapState('main', ['searchValue', 'devPlugins', 'pluginInfo']),
|
||||||
pluginDetail() {
|
pluginDetail() {
|
||||||
return (this.devPlugins.filter(plugin => plugin.name === this.query.name)[0] || {}).features
|
return (this.devPlugins.filter(plugin => plugin.name === this.pluginInfo.name)[0] || {}).features
|
||||||
},
|
},
|
||||||
|
path() {
|
||||||
|
return `File://${this.pluginInfo.sourceFile}`
|
||||||
|
},
|
||||||
|
templatePath() {
|
||||||
|
return `File://${path.join(__static, './plugins/tpl/index.html')}?code=${JSON.parse(this.pluginInfo.detail).code}&targetFile=${encodeURIComponent(this.pluginInfo.sourceFile)}&preloadPath=${this.pluginInfo.preload}`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -22,7 +22,12 @@ const state = {
|
|||||||
searchValue: '',
|
searchValue: '',
|
||||||
devPlugins: mergePlugins(sysFile.getUserPlugins() || []),
|
devPlugins: mergePlugins(sysFile.getUserPlugins() || []),
|
||||||
subPlaceHolder: '',
|
subPlaceHolder: '',
|
||||||
pluginInfo: {},
|
pluginInfo: (() => {
|
||||||
|
try {
|
||||||
|
console.log(window.pluginInfo);
|
||||||
|
return window.pluginInfo || {}
|
||||||
|
} catch (e) {}
|
||||||
|
})(),
|
||||||
}
|
}
|
||||||
|
|
||||||
const mutations = {
|
const mutations = {
|
||||||
|
Binary file not shown.
@ -1,370 +0,0 @@
|
|||||||
*{margin: 0;padding: 0;list-style: none;}
|
|
||||||
/*
|
|
||||||
KISSY CSS Reset
|
|
||||||
理念:1. reset 的目的不是清除浏览器的默认样式,这仅是部分工作。清除和重置是紧密不可分的。
|
|
||||||
2. reset 的目的不是让默认样式在所有浏览器下一致,而是减少默认样式有可能带来的问题。
|
|
||||||
3. reset 期望提供一套普适通用的基础样式。但没有银弹,推荐根据具体需求,裁剪和修改后再使用。
|
|
||||||
特色:1. 适应中文;2. 基于最新主流浏览器。
|
|
||||||
维护:玉伯<lifesinger@gmail.com>, 正淳<ragecarrier@gmail.com>
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** 清除内外边距 **/
|
|
||||||
body, h1, h2, h3, h4, h5, h6, hr, p, blockquote, /* structural elements 结构元素 */
|
|
||||||
dl, dt, dd, ul, ol, li, /* list elements 列表元素 */
|
|
||||||
pre, /* text formatting elements 文本格式元素 */
|
|
||||||
form, fieldset, legend, button, input, textarea, /* form elements 表单元素 */
|
|
||||||
th, td /* table elements 表格元素 */ {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 设置默认字体 **/
|
|
||||||
body,
|
|
||||||
button, input, select, textarea /* for ie */ {
|
|
||||||
font: 12px/1.5 tahoma, arial, \5b8b\4f53, sans-serif;
|
|
||||||
}
|
|
||||||
h1, h2, h3, h4, h5, h6 { font-size: 100%; }
|
|
||||||
address, cite, dfn, em, var { font-style: normal; } /* 将斜体扶正 */
|
|
||||||
code, kbd, pre, samp { font-family: courier new, courier, monospace; } /* 统一等宽字体 */
|
|
||||||
small { font-size: 12px; } /* 小于 12px 的中文很难阅读,让 small 正常化 */
|
|
||||||
|
|
||||||
/** 重置列表元素 **/
|
|
||||||
ul, ol { list-style: none; }
|
|
||||||
|
|
||||||
/** 重置文本格式元素 **/
|
|
||||||
a { text-decoration: none; }
|
|
||||||
a:hover { text-decoration: underline; }
|
|
||||||
|
|
||||||
|
|
||||||
/** 重置表单元素 **/
|
|
||||||
legend { color: #000; } /* for ie6 */
|
|
||||||
fieldset, img { border: 0; } /* img 搭车:让链接里的 img 无边框 */
|
|
||||||
button, input, select, textarea { font-size: 100%; } /* 使得表单元素在 ie 下能继承字体大小 */
|
|
||||||
/* 注:optgroup 无法扶正 */
|
|
||||||
|
|
||||||
/** 重置表格元素 **/
|
|
||||||
table { border-collapse: collapse; border-spacing: 0; }
|
|
||||||
|
|
||||||
/* 清除浮动 */
|
|
||||||
.ks-clear:after, .clear:after {
|
|
||||||
content: '\20';
|
|
||||||
display: block;
|
|
||||||
height: 0;
|
|
||||||
clear: both;
|
|
||||||
}
|
|
||||||
.ks-clear, .clear {
|
|
||||||
*zoom: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.main {
|
|
||||||
padding: 30px 100px;
|
|
||||||
width: 960px;
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
.main h1{font-size:36px; color:#333; text-align:left;margin-bottom:30px; border-bottom: 1px solid #eee;}
|
|
||||||
|
|
||||||
.helps{margin-top:40px;}
|
|
||||||
.helps pre{
|
|
||||||
padding:20px;
|
|
||||||
margin:10px 0;
|
|
||||||
border:solid 1px #e7e1cd;
|
|
||||||
background-color: #fffdef;
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon_lists{
|
|
||||||
width: 100% !important;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon_lists li{
|
|
||||||
float:left;
|
|
||||||
width: 100px;
|
|
||||||
height:180px;
|
|
||||||
text-align: center;
|
|
||||||
list-style: none !important;
|
|
||||||
}
|
|
||||||
.icon_lists .icon{
|
|
||||||
font-size: 42px;
|
|
||||||
line-height: 100px;
|
|
||||||
margin: 10px 0;
|
|
||||||
color:#333;
|
|
||||||
-webkit-transition: font-size 0.25s ease-out 0s;
|
|
||||||
-moz-transition: font-size 0.25s ease-out 0s;
|
|
||||||
transition: font-size 0.25s ease-out 0s;
|
|
||||||
|
|
||||||
}
|
|
||||||
.icon_lists .icon:hover{
|
|
||||||
font-size: 100px;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.markdown {
|
|
||||||
color: #666;
|
|
||||||
font-size: 14px;
|
|
||||||
line-height: 1.8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.highlight {
|
|
||||||
line-height: 1.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown img {
|
|
||||||
vertical-align: middle;
|
|
||||||
max-width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown h1 {
|
|
||||||
color: #404040;
|
|
||||||
font-weight: 500;
|
|
||||||
line-height: 40px;
|
|
||||||
margin-bottom: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown h2,
|
|
||||||
.markdown h3,
|
|
||||||
.markdown h4,
|
|
||||||
.markdown h5,
|
|
||||||
.markdown h6 {
|
|
||||||
color: #404040;
|
|
||||||
margin: 1.6em 0 0.6em 0;
|
|
||||||
font-weight: 500;
|
|
||||||
clear: both;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown h1 {
|
|
||||||
font-size: 28px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown h2 {
|
|
||||||
font-size: 22px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown h3 {
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown h4 {
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown h5 {
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown h6 {
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown hr {
|
|
||||||
height: 1px;
|
|
||||||
border: 0;
|
|
||||||
background: #e9e9e9;
|
|
||||||
margin: 16px 0;
|
|
||||||
clear: both;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown p,
|
|
||||||
.markdown pre {
|
|
||||||
margin: 1em 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown > p,
|
|
||||||
.markdown > blockquote,
|
|
||||||
.markdown > .highlight,
|
|
||||||
.markdown > ol,
|
|
||||||
.markdown > ul {
|
|
||||||
width: 80%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown ul > li {
|
|
||||||
list-style: circle;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown > ul li,
|
|
||||||
.markdown blockquote ul > li {
|
|
||||||
margin-left: 20px;
|
|
||||||
padding-left: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown > ul li p,
|
|
||||||
.markdown > ol li p {
|
|
||||||
margin: 0.6em 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown ol > li {
|
|
||||||
list-style: decimal;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown > ol li,
|
|
||||||
.markdown blockquote ol > li {
|
|
||||||
margin-left: 20px;
|
|
||||||
padding-left: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown code {
|
|
||||||
margin: 0 3px;
|
|
||||||
padding: 0 5px;
|
|
||||||
background: #eee;
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown pre {
|
|
||||||
border-radius: 6px;
|
|
||||||
background: #f7f7f7;
|
|
||||||
padding: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown pre code {
|
|
||||||
border: none;
|
|
||||||
background: #f7f7f7;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown strong,
|
|
||||||
.markdown b {
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown > table {
|
|
||||||
border-collapse: collapse;
|
|
||||||
border-spacing: 0px;
|
|
||||||
empty-cells: show;
|
|
||||||
border: 1px solid #e9e9e9;
|
|
||||||
width: 95%;
|
|
||||||
margin-bottom: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown > table th {
|
|
||||||
white-space: nowrap;
|
|
||||||
color: #333;
|
|
||||||
font-weight: 600;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown > table th,
|
|
||||||
.markdown > table td {
|
|
||||||
border: 1px solid #e9e9e9;
|
|
||||||
padding: 8px 16px;
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown > table th {
|
|
||||||
background: #F7F7F7;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown blockquote {
|
|
||||||
font-size: 90%;
|
|
||||||
color: #999;
|
|
||||||
border-left: 4px solid #e9e9e9;
|
|
||||||
padding-left: 0.8em;
|
|
||||||
margin: 1em 0;
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown blockquote p {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown .anchor {
|
|
||||||
opacity: 0;
|
|
||||||
transition: opacity 0.3s ease;
|
|
||||||
margin-left: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown .waiting {
|
|
||||||
color: #ccc;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown h1:hover .anchor,
|
|
||||||
.markdown h2:hover .anchor,
|
|
||||||
.markdown h3:hover .anchor,
|
|
||||||
.markdown h4:hover .anchor,
|
|
||||||
.markdown h5:hover .anchor,
|
|
||||||
.markdown h6:hover .anchor {
|
|
||||||
opacity: 1;
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown > br,
|
|
||||||
.markdown > p > br {
|
|
||||||
clear: both;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.hljs {
|
|
||||||
display: block;
|
|
||||||
background: white;
|
|
||||||
padding: 0.5em;
|
|
||||||
color: #333333;
|
|
||||||
overflow-x: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-comment,
|
|
||||||
.hljs-meta {
|
|
||||||
color: #969896;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-string,
|
|
||||||
.hljs-variable,
|
|
||||||
.hljs-template-variable,
|
|
||||||
.hljs-strong,
|
|
||||||
.hljs-emphasis,
|
|
||||||
.hljs-quote {
|
|
||||||
color: #df5000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-keyword,
|
|
||||||
.hljs-selector-tag,
|
|
||||||
.hljs-type {
|
|
||||||
color: #a71d5d;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-literal,
|
|
||||||
.hljs-symbol,
|
|
||||||
.hljs-bullet,
|
|
||||||
.hljs-attribute {
|
|
||||||
color: #0086b3;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-section,
|
|
||||||
.hljs-name {
|
|
||||||
color: #63a35c;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-tag {
|
|
||||||
color: #333333;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-title,
|
|
||||||
.hljs-attr,
|
|
||||||
.hljs-selector-id,
|
|
||||||
.hljs-selector-class,
|
|
||||||
.hljs-selector-attr,
|
|
||||||
.hljs-selector-pseudo {
|
|
||||||
color: #795da3;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-addition {
|
|
||||||
color: #55a532;
|
|
||||||
background-color: #eaffea;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-deletion {
|
|
||||||
color: #bd2c00;
|
|
||||||
background-color: #ffecec;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-link {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre{
|
|
||||||
background: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,64 +0,0 @@
|
|||||||
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8"/>
|
|
||||||
<title>IconFont</title>
|
|
||||||
<link rel="stylesheet" href="demo.css">
|
|
||||||
<link rel="stylesheet" href="iconfont.css">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="main markdown">
|
|
||||||
<h1>IconFont 图标</h1>
|
|
||||||
<ul class="icon_lists clear">
|
|
||||||
|
|
||||||
<li>
|
|
||||||
<i class="icon iconfont icon-xiazai"></i>
|
|
||||||
<div class="name">下载</div>
|
|
||||||
<div class="fontclass">.icon-xiazai</div>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
<i class="icon iconfont icon-guanbi"></i>
|
|
||||||
<div class="name">关闭</div>
|
|
||||||
<div class="fontclass">.icon-guanbi</div>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
<i class="icon iconfont icon-zhongzhi"></i>
|
|
||||||
<div class="name">重置</div>
|
|
||||||
<div class="fontclass">.icon-zhongzhi</div>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
<i class="icon iconfont icon-duihao"></i>
|
|
||||||
<div class="name">对号</div>
|
|
||||||
<div class="fontclass">.icon-duihao</div>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<h2 id="font-class-">font-class引用</h2>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p>font-class是unicode使用方式的一种变种,主要是解决unicode书写不直观,语意不明确的问题。</p>
|
|
||||||
<p>与unicode使用方式相比,具有如下特点:</p>
|
|
||||||
<ul>
|
|
||||||
<li>兼容性良好,支持ie8+,及所有现代浏览器。</li>
|
|
||||||
<li>相比于unicode语意明确,书写更直观。可以很容易分辨这个icon是什么。</li>
|
|
||||||
<li>因为使用class来定义图标,所以当要替换图标时,只需要修改class里面的unicode引用。</li>
|
|
||||||
<li>不过因为本质上还是使用的字体,所以多色图标还是不支持的。</li>
|
|
||||||
</ul>
|
|
||||||
<p>使用步骤如下:</p>
|
|
||||||
<h3 id="-fontclass-">第一步:引入项目下面生成的fontclass代码:</h3>
|
|
||||||
|
|
||||||
|
|
||||||
<pre><code class="lang-js hljs javascript"><span class="hljs-comment"><link rel="stylesheet" type="text/css" href="./iconfont.css"></span></code></pre>
|
|
||||||
<h3 id="-">第二步:挑选相应图标并获取类名,应用于页面:</h3>
|
|
||||||
<pre><code class="lang-css hljs"><<span class="hljs-selector-tag">i</span> <span class="hljs-selector-tag">class</span>="<span class="hljs-selector-tag">iconfont</span> <span class="hljs-selector-tag">icon-xxx</span>"></<span class="hljs-selector-tag">i</span>></code></pre>
|
|
||||||
<blockquote>
|
|
||||||
<p>"iconfont"是你项目下的font-family。可以通过编辑项目查看,默认是"iconfont"。</p>
|
|
||||||
</blockquote>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -1,95 +0,0 @@
|
|||||||
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8"/>
|
|
||||||
<title>IconFont</title>
|
|
||||||
<link rel="stylesheet" href="demo.css">
|
|
||||||
<script src="iconfont.js"></script>
|
|
||||||
|
|
||||||
<style type="text/css">
|
|
||||||
.icon {
|
|
||||||
/* 通过设置 font-size 来改变图标大小 */
|
|
||||||
width: 1em; height: 1em;
|
|
||||||
/* 图标和文字相邻时,垂直对齐 */
|
|
||||||
vertical-align: -0.15em;
|
|
||||||
/* 通过设置 color 来改变 SVG 的颜色/fill */
|
|
||||||
fill: currentColor;
|
|
||||||
/* path 和 stroke 溢出 viewBox 部分在 IE 下会显示
|
|
||||||
normalize.css 中也包含这行 */
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="main markdown">
|
|
||||||
<h1>IconFont 图标</h1>
|
|
||||||
<ul class="icon_lists clear">
|
|
||||||
|
|
||||||
<li>
|
|
||||||
<svg class="icon" aria-hidden="true">
|
|
||||||
<use xlink:href="#icon-xiazai"></use>
|
|
||||||
</svg>
|
|
||||||
<div class="name">下载</div>
|
|
||||||
<div class="fontclass">#icon-xiazai</div>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
<svg class="icon" aria-hidden="true">
|
|
||||||
<use xlink:href="#icon-guanbi"></use>
|
|
||||||
</svg>
|
|
||||||
<div class="name">关闭</div>
|
|
||||||
<div class="fontclass">#icon-guanbi</div>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
<svg class="icon" aria-hidden="true">
|
|
||||||
<use xlink:href="#icon-zhongzhi"></use>
|
|
||||||
</svg>
|
|
||||||
<div class="name">重置</div>
|
|
||||||
<div class="fontclass">#icon-zhongzhi</div>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
<svg class="icon" aria-hidden="true">
|
|
||||||
<use xlink:href="#icon-duihao"></use>
|
|
||||||
</svg>
|
|
||||||
<div class="name">对号</div>
|
|
||||||
<div class="fontclass">#icon-duihao</div>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
|
|
||||||
<h2 id="symbol-">symbol引用</h2>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p>这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇<a href="">文章</a>
|
|
||||||
这种用法其实是做了一个svg的集合,与另外两种相比具有如下特点:</p>
|
|
||||||
<ul>
|
|
||||||
<li>支持多色图标了,不再受单色限制。</li>
|
|
||||||
<li>通过一些技巧,支持像字体那样,通过<code>font-size</code>,<code>color</code>来调整样式。</li>
|
|
||||||
<li>兼容性较差,支持 ie9+,及现代浏览器。</li>
|
|
||||||
<li>浏览器渲染svg的性能一般,还不如png。</li>
|
|
||||||
</ul>
|
|
||||||
<p>使用步骤如下:</p>
|
|
||||||
<h3 id="-symbol-">第一步:引入项目下面生成的symbol代码:</h3>
|
|
||||||
<pre><code class="lang-js hljs javascript"><span class="hljs-comment"><script src="./iconfont.js"></script></span></code></pre>
|
|
||||||
<h3 id="-css-">第二步:加入通用css代码(引入一次就行):</h3>
|
|
||||||
<pre><code class="lang-js hljs javascript"><style type=<span class="hljs-string">"text/css"</span>>
|
|
||||||
.icon {
|
|
||||||
width: <span class="hljs-number">1</span>em; height: <span class="hljs-number">1</span>em;
|
|
||||||
vertical-align: <span class="hljs-number">-0.15</span>em;
|
|
||||||
fill: currentColor;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
<<span class="hljs-regexp">/style></span></code></pre>
|
|
||||||
<h3 id="-">第三步:挑选相应图标并获取类名,应用于页面:</h3>
|
|
||||||
<pre><code class="lang-js hljs javascript"><svg <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"icon"</span> aria-hidden=<span class="hljs-string">"true"</span>><span class="xml"><span class="hljs-tag">
|
|
||||||
<<span class="hljs-name">use</span> <span class="hljs-attr">xlink:href</span>=<span class="hljs-string">"#icon-xxx"</span>></span><span class="hljs-tag"></<span class="hljs-name">use</span>></span>
|
|
||||||
</span><<span class="hljs-regexp">/svg>
|
|
||||||
</span></code></pre>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -1,102 +0,0 @@
|
|||||||
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8"/>
|
|
||||||
<title>IconFont</title>
|
|
||||||
<link rel="stylesheet" href="demo.css">
|
|
||||||
|
|
||||||
<style type="text/css">
|
|
||||||
|
|
||||||
@font-face {font-family: "iconfont";
|
|
||||||
src: url('iconfont.eot'); /* IE9*/
|
|
||||||
src: url('iconfont.eot#iefix') format('embedded-opentype'), /* IE6-IE8 */
|
|
||||||
url('iconfont.woff') format('woff'), /* chrome, firefox */
|
|
||||||
url('iconfont.ttf') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/
|
|
||||||
url('iconfont.svg#iconfont') format('svg'); /* iOS 4.1- */
|
|
||||||
}
|
|
||||||
|
|
||||||
.iconfont {
|
|
||||||
font-family:"iconfont" !important;
|
|
||||||
font-size:16px;
|
|
||||||
font-style:normal;
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
-webkit-text-stroke-width: 0.2px;
|
|
||||||
-moz-osx-font-smoothing: grayscale;
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="main markdown">
|
|
||||||
<h1>IconFont 图标</h1>
|
|
||||||
<ul class="icon_lists clear">
|
|
||||||
|
|
||||||
<li>
|
|
||||||
<i class="icon iconfont"></i>
|
|
||||||
<div class="name">下载</div>
|
|
||||||
<div class="code">&#xe627;</div>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
<i class="icon iconfont"></i>
|
|
||||||
<div class="name">关闭</div>
|
|
||||||
<div class="code">&#xe66c;</div>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
<i class="icon iconfont"></i>
|
|
||||||
<div class="name">重置</div>
|
|
||||||
<div class="code">&#xe633;</div>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
<i class="icon iconfont"></i>
|
|
||||||
<div class="name">对号</div>
|
|
||||||
<div class="code">&#xeeda;</div>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
</ul>
|
|
||||||
<h2 id="unicode-">unicode引用</h2>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p>unicode是字体在网页端最原始的应用方式,特点是:</p>
|
|
||||||
<ul>
|
|
||||||
<li>兼容性最好,支持ie6+,及所有现代浏览器。</li>
|
|
||||||
<li>支持按字体的方式去动态调整图标大小,颜色等等。</li>
|
|
||||||
<li>但是因为是字体,所以不支持多色。只能使用平台里单色的图标,就算项目里有多色图标也会自动去色。</li>
|
|
||||||
</ul>
|
|
||||||
<blockquote>
|
|
||||||
<p>注意:新版iconfont支持多色图标,这些多色图标在unicode模式下将不能使用,如果有需求建议使用symbol的引用方式</p>
|
|
||||||
</blockquote>
|
|
||||||
<p>unicode使用步骤如下:</p>
|
|
||||||
<h3 id="-font-face">第一步:拷贝项目下面生成的font-face</h3>
|
|
||||||
<pre><code class="lang-js hljs javascript">@font-face {
|
|
||||||
font-family: <span class="hljs-string">'iconfont'</span>;
|
|
||||||
src: url(<span class="hljs-string">'iconfont.eot'</span>);
|
|
||||||
src: url(<span class="hljs-string">'iconfont.eot?#iefix'</span>) format(<span class="hljs-string">'embedded-opentype'</span>),
|
|
||||||
url(<span class="hljs-string">'iconfont.woff'</span>) format(<span class="hljs-string">'woff'</span>),
|
|
||||||
url(<span class="hljs-string">'iconfont.ttf'</span>) format(<span class="hljs-string">'truetype'</span>),
|
|
||||||
url(<span class="hljs-string">'iconfont.svg#iconfont'</span>) format(<span class="hljs-string">'svg'</span>);
|
|
||||||
}
|
|
||||||
</code></pre>
|
|
||||||
<h3 id="-iconfont-">第二步:定义使用iconfont的样式</h3>
|
|
||||||
<pre><code class="lang-js hljs javascript">.iconfont{
|
|
||||||
font-family:<span class="hljs-string">"iconfont"</span> !important;
|
|
||||||
font-size:<span class="hljs-number">16</span>px;font-style:normal;
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
-webkit-text-stroke-width: <span class="hljs-number">0.2</span>px;
|
|
||||||
-moz-osx-font-smoothing: grayscale;
|
|
||||||
}
|
|
||||||
</code></pre>
|
|
||||||
<h3 id="-">第三步:挑选相应图标并获取字体编码,应用于页面</h3>
|
|
||||||
<pre><code class="lang-js hljs javascript"><i <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"iconfont"</span>>&#x33;<span class="xml"><span class="hljs-tag"></<span class="hljs-name">i</span>></span></span></code></pre>
|
|
||||||
|
|
||||||
<blockquote>
|
|
||||||
<p>"iconfont"是你项目下的font-family。可以通过编辑项目查看,默认是"iconfont"。</p>
|
|
||||||
</blockquote>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -1,25 +0,0 @@
|
|||||||
|
|
||||||
@font-face {font-family: "iconfont";
|
|
||||||
src: url('iconfont.eot?t=1538684099545'); /* IE9*/
|
|
||||||
src: url('iconfont.eot?t=1538684099545#iefix') format('embedded-opentype'), /* IE6-IE8 */
|
|
||||||
url('data:application/x-font-woff;charset=utf-8;base64,d09GRgABAAAAAAWQAAsAAAAACCQAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABHU1VCAAABCAAAADMAAABCsP6z7U9TLzIAAAE8AAAARAAAAFY8nVDMY21hcAAAAYAAAABrAAABsu3anlxnbHlmAAAB7AAAAZYAAAG869Cas2hlYWQAAAOEAAAALgAAADYS2G+AaGhlYQAAA7QAAAAcAAAAJAfeA4ZobXR4AAAD0AAAAA4AAAAUFAAAAGxvY2EAAAPgAAAADAAAAAwBEAFgbWF4cAAAA+wAAAAfAAAAIAESAENuYW1lAAAEDAAAAUUAAAJtPlT+fXBvc3QAAAVUAAAAPAAAAE0pDHeHeJxjYGRgYOBikGPQYWB0cfMJYeBgYGGAAJAMY05meiJQDMoDyrGAaQ4gZoOIAgCKIwNPAHicY2BkYWCcwMDKwMHUyXSGgYGhH0IzvmYwYuRgYGBiYGVmwAoC0lxTGByeqb+7xdzwv4EhhrmBoQEozAiSAwDxJgzseJztkbsNgDAMRF8+IBSxBw0dC2SgVIzLAC5ZIdgxBUNw0bPsU+LiAkxAUnYlQzgJmJq6YfiJMvxM1bmwEImyySHtvnqHb/8q6D0/1id9Ybtnfq2j1nfKlp5jacvh2I9IczQ77sshP1MOG7MAeJwdj0FrE1EUhe95z8zLvOnM9GVC0pSZmEybmSKYTdsZRIhKXRgQLfgTpIiLoJtCdZFqf4HQnRsLhazabNxamD/gyoIb/QkK3ehqUu/4Npdzz8c795AkfvKSR0gRZUSIrQgtS/WtJN/eSirVRbs/Qr49RO0eMt75MJWjTJrEymreZEJ+9hq4vVV+vLOBRrgkHmXiJBujZhbj1XM76Oi3JjJ444SW1ufMbxp/kuZC3t2Y+Mb4x8xinB375p2a6U5gT1BU+8X9iW3rjp5Jj0j8v/WpmJNNAVGA1ggpEg8DWF3kyIb4IR7qSOnywgnr4kn5RddDR+xoFYnD8oKHZr8errLBlNhhir8E0XUpL8Uv6rEYQnlQa+18jTtzdRZxknJKq80hI8jTzW/T6VnjtCg+NWf7R3Mp50fZ81t6ZVnovb8vXzzA9f6BH5xNi+L1h8pkZD1Worli71qPd39XedzjvTihZaJBnA6SEdo1ZF0oWApftb347tZ6HgwOdezqxav60jN15fRd5yf+uDd6bnmlBf0D1bBUzQAAeJxjYGRgYADi+Y6Xrsbz23xl4GZhAIHrd6YeRtD//7IwMIO4HAxMIAoAaF8MWwAAeJxjYGRgYG7438AQw8IAAkCSkQEVsAIARwsCbnicY2FgYGBBwwABBAAVAAAAAAAAAFYAggC6AN54nGNgZGBgYGUwZ2BmAAEmIOYCQgaG/2A+AwAOdQFWAHicZY9NTsMwEIVf+gekEqqoYIfkBWIBKP0Rq25YVGr3XXTfpk6bKokjx63UA3AejsAJOALcgDvwSCebNpbH37x5Y08A3OAHHo7fLfeRPVwyO3INF7gXrlN/EG6QX4SbaONVuEX9TdjHM6bCbXRheYPXuGL2hHdhDx18CNdwjU/hOvUv4Qb5W7iJO/wKt9Dx6sI+5l5XuI1HL/bHVi+cXqnlQcWhySKTOb+CmV7vkoWt0uqca1vEJlODoF9JU51pW91T7NdD5yIVWZOqCas6SYzKrdnq0AUb5/JRrxeJHoQm5Vhj/rbGAo5xBYUlDowxQhhkiMro6DtVZvSvsUPCXntWPc3ndFsU1P9zhQEC9M9cU7qy0nk6T4E9XxtSdXQrbsuelDSRXs1JErJCXta2VELqATZlV44RelzRiT8oZ0j/AAlabsgAAAB4nGNgYoAALgbsgJWRiZGZkYWRlZGNga0iM7EqMZMtvTQxLymToyojPy+9KiOTLaU0MyMxn4EBAMN8Cyw=') format('woff'),
|
|
||||||
url('iconfont.ttf?t=1538684099545') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/
|
|
||||||
url('iconfont.svg?t=1538684099545#iconfont') format('svg'); /* iOS 4.1- */
|
|
||||||
}
|
|
||||||
|
|
||||||
.iconfont {
|
|
||||||
font-family:"iconfont" !important;
|
|
||||||
font-size:16px;
|
|
||||||
font-style:normal;
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
-moz-osx-font-smoothing: grayscale;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon-xiazai:before { content: "\e627"; }
|
|
||||||
|
|
||||||
.icon-guanbi:before { content: "\e66c"; }
|
|
||||||
|
|
||||||
.icon-zhongzhi:before { content: "\e633"; }
|
|
||||||
|
|
||||||
.icon-duihao:before { content: "\eeda"; }
|
|
||||||
|
|
Binary file not shown.
@ -1 +0,0 @@
|
|||||||
(function(window){var svgSprite='<svg><symbol id="icon-xiazai" viewBox="0 0 1024 1024"><path d="M947.2 588.8c-19.2 0-32 12.8-32 32v108.8c0 51.2-25.6 96-96 96H204.8c-76.8 6.4-96-44.8-96-96V620.8c0-19.2-12.8-32-32-32s-25.6 12.8-25.6 32V768c0 70.4 57.6 128 128 128h672c70.4 0 128-57.6 128-128V620.8c-6.4-19.2-19.2-32-32-32zM518.4 716.8" fill="" ></path><path d="M544 710.4l172.8-166.4c12.8-12.8 12.8-32 0-44.8s-32-12.8-44.8 0L550.4 608v-448c0-19.2-12.8-32-32-32s-32 12.8-32 32v448L364.8 499.2c-12.8-12.8-38.4-12.8-44.8 0-12.8 12.8-12.8 32 0 44.8l172.8 166.4s25.6 25.6 51.2 0z" fill="" ></path></symbol><symbol id="icon-guanbi" viewBox="0 0 1024 1024"><path d="M220.3136 256.512l579.2768 579.2768a25.6 25.6 0 1 0 36.1984-36.1984L256.512 220.3136a25.6 25.6 0 1 0-36.1984 36.1984z" ></path><path d="M799.5904 220.3136L220.3136 799.5904a25.6 25.6 0 1 0 36.1984 36.1984L835.7888 256.512a25.6 25.6 0 1 0-36.1984-36.1984z" ></path></symbol><symbol id="icon-zhongzhi" viewBox="0 0 1024 1024"><path d="M931.07 384.75a368 368 0 0 0-704 95.25H64l192 192 192-192H288.91C312 333.51 439.12 221.13 592 221.13c169.21 0 306.87 137.66 306.87 306.87S761.21 834.87 592 834.87a307.37 307.37 0 0 1-194.56-69.55 30.57 30.57 0 0 0-38.79 47.25 368.1 368.1 0 0 0 572.42-427.82z" ></path></symbol><symbol id="icon-duihao" viewBox="0 0 1024 1024"><path d="M461.28 813.14a30 30 0 0 1-18.89-6.69L145 565.48a30 30 0 1 1 37.78-46.61l273.35 221.5 382.5-502.29a30 30 0 1 1 47.73 36.35L485.15 801.32a30 30 0 0 1-20.29 11.61 30.83 30.83 0 0 1-3.58 0.21z" ></path></symbol></svg>';var script=function(){var scripts=document.getElementsByTagName("script");return scripts[scripts.length-1]}();var shouldInjectCss=script.getAttribute("data-injectcss");var ready=function(fn){if(document.addEventListener){if(~["complete","loaded","interactive"].indexOf(document.readyState)){setTimeout(fn,0)}else{var loadFn=function(){document.removeEventListener("DOMContentLoaded",loadFn,false);fn()};document.addEventListener("DOMContentLoaded",loadFn,false)}}else if(document.attachEvent){IEContentLoaded(window,fn)}function IEContentLoaded(w,fn){var d=w.document,done=false,init=function(){if(!done){done=true;fn()}};var polling=function(){try{d.documentElement.doScroll("left")}catch(e){setTimeout(polling,50);return}init()};polling();d.onreadystatechange=function(){if(d.readyState=="complete"){d.onreadystatechange=null;init()}}}};var before=function(el,target){target.parentNode.insertBefore(el,target)};var prepend=function(el,target){if(target.firstChild){before(el,target.firstChild)}else{target.appendChild(el)}};function appendSvg(){var div,svg;div=document.createElement("div");div.innerHTML=svgSprite;svgSprite=null;svg=div.getElementsByTagName("svg")[0];if(svg){svg.setAttribute("aria-hidden","true");svg.style.position="absolute";svg.style.width=0;svg.style.height=0;svg.style.overflow="hidden";prepend(svg,document.body)}}if(shouldInjectCss&&!window.__iconfont__svg__cssinject__){window.__iconfont__svg__cssinject__=true;try{document.write("<style>.svgfont {display: inline-block;width: 1em;height: 1em;fill: currentColor;vertical-align: -0.1em;font-size:16px;}</style>")}catch(e){console&&console.log(e)}}ready(appendSvg)})(window)
|
|
@ -1,38 +0,0 @@
|
|||||||
<?xml version="1.0" standalone="no"?>
|
|
||||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
|
|
||||||
<!--
|
|
||||||
2013-9-30: Created.
|
|
||||||
-->
|
|
||||||
<svg>
|
|
||||||
<metadata>
|
|
||||||
Created by iconfont
|
|
||||||
</metadata>
|
|
||||||
<defs>
|
|
||||||
|
|
||||||
<font id="iconfont" horiz-adv-x="1024" >
|
|
||||||
<font-face
|
|
||||||
font-family="iconfont"
|
|
||||||
font-weight="500"
|
|
||||||
font-stretch="normal"
|
|
||||||
units-per-em="1024"
|
|
||||||
ascent="896"
|
|
||||||
descent="-128"
|
|
||||||
/>
|
|
||||||
<missing-glyph />
|
|
||||||
|
|
||||||
<glyph glyph-name="xiazai" unicode="" d="M947.2 307.2c-19.2 0-32-12.8-32-32v-108.8c0-51.2-25.6-96-96-96H204.8c-76.8-6.4-96 44.8-96 96V275.2c0 19.2-12.8 32-32 32s-25.6-12.8-25.6-32V128c0-70.4 57.6-128 128-128h672c70.4 0 128 57.6 128 128V275.2c-6.4 19.2-19.2 32-32 32zM518.4 179.2M544 185.6l172.8 166.4c12.8 12.8 12.8 32 0 44.8s-32 12.8-44.8 0L550.4 288v448c0 19.2-12.8 32-32 32s-32-12.8-32-32v-448L364.8 396.8c-12.8 12.8-38.4 12.8-44.8 0-12.8-12.8-12.8-32 0-44.8l172.8-166.4s25.6-25.6 51.2 0z" horiz-adv-x="1024" />
|
|
||||||
|
|
||||||
|
|
||||||
<glyph glyph-name="guanbi" unicode="" d="M220.3136 639.488l579.2768-579.2768a25.6 25.6 0 1 1 36.1984 36.1984L256.512 675.6864a25.6 25.6 0 1 1-36.1984-36.1984zM799.5904 675.6864L220.3136 96.4096a25.6 25.6 0 1 1 36.1984-36.1984L835.7888 639.488a25.6 25.6 0 1 1-36.1984 36.1984z" horiz-adv-x="1024" />
|
|
||||||
|
|
||||||
|
|
||||||
<glyph glyph-name="zhongzhi" unicode="" d="M931.07 511.25a368 368 0 0 1-704-95.25H64l192-192 192 192H288.91C312 562.49 439.12 674.87 592 674.87c169.21 0 306.87-137.66 306.87-306.87S761.21 61.13 592 61.13a307.37 307.37 0 0 0-194.56 69.55 30.57 30.57 0 0 1-38.79-47.25 368.1 368.1 0 0 1 572.42 427.82z" horiz-adv-x="1024" />
|
|
||||||
|
|
||||||
|
|
||||||
<glyph glyph-name="duihao" unicode="" d="M461.28 82.86a30 30 0 0 0-18.89 6.69L145 330.52a30 30 0 1 0 37.78 46.61l273.35-221.5 382.5 502.29a30 30 0 1 0 47.73-36.35L485.15 94.68a30 30 0 0 0-20.29-11.61 30.83 30.83 0 0 0-3.58-0.21z" horiz-adv-x="1024" />
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</font>
|
|
||||||
</defs></svg>
|
|
Before Width: | Height: | Size: 1.9 KiB |
Binary file not shown.
Binary file not shown.
@ -1,411 +0,0 @@
|
|||||||
const Event = require('events')
|
|
||||||
const { getCurrentScreen } = require('./utils')
|
|
||||||
|
|
||||||
const CREATE_RECT = 1
|
|
||||||
const MOVING_RECT = 2
|
|
||||||
const RESIZE = 3
|
|
||||||
|
|
||||||
const ANCHORS = [
|
|
||||||
{ row: 'x', col: 'y', cursor: 'nwse-resize' },
|
|
||||||
{ row: '', col: 'y', cursor: 'ns-resize' },
|
|
||||||
{ row: 'r', col: 'y', cursor: 'nesw-resize' },
|
|
||||||
|
|
||||||
{ row: 'x', col: '', cursor: 'ew-resize' },
|
|
||||||
{ row: 'r', col: '', cursor: 'ew-resize' },
|
|
||||||
|
|
||||||
{ row: 'x', col: 'b', cursor: 'nesw-resize' },
|
|
||||||
{ row: '', col: 'b', cursor: 'ns-resize' },
|
|
||||||
{ row: 'r', col: 'b', cursor: 'nwse-resize' },
|
|
||||||
]
|
|
||||||
|
|
||||||
class CaptureEditor extends Event {
|
|
||||||
|
|
||||||
constructor($canvas, $bg, imageSrc) {
|
|
||||||
super()
|
|
||||||
this.$canvas = $canvas
|
|
||||||
this.imageSrc = imageSrc
|
|
||||||
this.disabled = false
|
|
||||||
let currentScreen;
|
|
||||||
|
|
||||||
(async () => {
|
|
||||||
currentScreen = await getCurrentScreen();
|
|
||||||
this.scaleFactor = currentScreen.scaleFactor
|
|
||||||
this.screenWidth = currentScreen.bounds.width
|
|
||||||
this.screenHeight = currentScreen.bounds.height
|
|
||||||
this.init().then(() => {
|
|
||||||
// console.log('init')
|
|
||||||
})
|
|
||||||
})();
|
|
||||||
this.$bg = $bg
|
|
||||||
this.ctx = $canvas.getContext('2d')
|
|
||||||
|
|
||||||
this.onMouseDown = this.onMouseDown.bind(this)
|
|
||||||
this.onMouseMove = this.onMouseMove.bind(this)
|
|
||||||
this.onMouseUp = this.onMouseUp.bind(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
async init() {
|
|
||||||
this.$bg.style.backgroundImage = `url(${this.imageSrc})`
|
|
||||||
this.$bg.style.backgroundSize = `${this.screenWidth}px ${this.screenHeight}px`
|
|
||||||
let canvas = document.createElement('canvas')
|
|
||||||
let ctx = canvas.getContext('2d')
|
|
||||||
let img = await new Promise((resolve) => {
|
|
||||||
let img = new Image()
|
|
||||||
img.src = this.imageSrc
|
|
||||||
if (img.complete) {
|
|
||||||
resolve(img)
|
|
||||||
} else {
|
|
||||||
img.onload = () => resolve(img)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
canvas.width = img.width
|
|
||||||
canvas.height = img.height
|
|
||||||
ctx.drawImage(img, 0, 0)
|
|
||||||
this.bgCtx = ctx
|
|
||||||
|
|
||||||
document.addEventListener('mousedown', this.onMouseDown)
|
|
||||||
document.addEventListener('mousemove', this.onMouseMove)
|
|
||||||
document.addEventListener('mouseup', this.onMouseUp)
|
|
||||||
}
|
|
||||||
|
|
||||||
onMouseDown(e) {
|
|
||||||
if (this.disabled) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.mouseDown = true
|
|
||||||
const { pageX, pageY } = e
|
|
||||||
if (this.selectRect) {
|
|
||||||
const {
|
|
||||||
w, h, x, y, r, b,
|
|
||||||
} = this.selectRect
|
|
||||||
if (this.selectAnchorIndex !== -1) {
|
|
||||||
this.startPoint = {
|
|
||||||
x: pageX,
|
|
||||||
y: pageY,
|
|
||||||
moved: false,
|
|
||||||
selectRect: {
|
|
||||||
w, h, x, y, r, b,
|
|
||||||
},
|
|
||||||
rawRect: {
|
|
||||||
w, h, x, y, r, b,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
this.action = RESIZE
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.startPoint = {
|
|
||||||
x: e.pageX,
|
|
||||||
y: e.pageY,
|
|
||||||
moved: false,
|
|
||||||
}
|
|
||||||
if (pageX > x && pageX < r && pageY > y && pageY < b) {
|
|
||||||
this.action = MOVING_RECT
|
|
||||||
this.startDragRect = {
|
|
||||||
x: pageX,
|
|
||||||
y: pageY,
|
|
||||||
selectRect: {
|
|
||||||
x, y, w, h, r, b,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.action = CREATE_RECT
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.action = CREATE_RECT
|
|
||||||
this.startPoint = {
|
|
||||||
x: e.pageX,
|
|
||||||
y: e.pageY,
|
|
||||||
moved: false,
|
|
||||||
}
|
|
||||||
e.stopPropagation()
|
|
||||||
e.preventDefault()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onMouseDrag(e) {
|
|
||||||
if (this.disabled) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
e.stopPropagation()
|
|
||||||
e.preventDefault()
|
|
||||||
|
|
||||||
const { pageX, pageY } = e
|
|
||||||
let startDragging
|
|
||||||
let selectRect = this.selectRect
|
|
||||||
if (!this.startPoint.moved) {
|
|
||||||
if (Math.abs(this.startPoint.x - pageX) > 10 || Math.abs(this.startPoint.y - pageY) > 10) {
|
|
||||||
this.startPoint.moved = true
|
|
||||||
startDragging = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!this.startPoint.moved) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.action === MOVING_RECT) {
|
|
||||||
// 移动选区
|
|
||||||
if (startDragging) {
|
|
||||||
this.emit('start-dragging', selectRect)
|
|
||||||
}
|
|
||||||
this.emit('dragging', selectRect)
|
|
||||||
const { w, h } = selectRect
|
|
||||||
const { x: startX, y: startY } = this.startPoint
|
|
||||||
let newX = this.startDragRect.selectRect.x + pageX - startX
|
|
||||||
let newY = this.startDragRect.selectRect.y + pageY - startY
|
|
||||||
let newR = newX + w
|
|
||||||
let newB = newY + h
|
|
||||||
if (newX < 0) {
|
|
||||||
newX = 0
|
|
||||||
newR = w
|
|
||||||
} else if (newR > this.screenWidth) {
|
|
||||||
newR = this.screenWidth
|
|
||||||
newX = newR - w
|
|
||||||
}
|
|
||||||
if (newY < 0) {
|
|
||||||
newY = 0
|
|
||||||
newB = h
|
|
||||||
} else if (newB > this.screenHeight) {
|
|
||||||
newB = this.screenHeight
|
|
||||||
newY = newB - h
|
|
||||||
}
|
|
||||||
this.selectRect = {
|
|
||||||
w,
|
|
||||||
h,
|
|
||||||
x: newX,
|
|
||||||
y: newY,
|
|
||||||
r: newR,
|
|
||||||
b: newB,
|
|
||||||
}
|
|
||||||
this.drawRect()
|
|
||||||
} else if (this.action === RESIZE) {
|
|
||||||
this.emit('dragging', selectRect)
|
|
||||||
let { row, col } = ANCHORS[this.selectAnchorIndex]
|
|
||||||
if (row) {
|
|
||||||
this.startPoint.rawRect[row] = this.startPoint.selectRect[row] + pageX - this.startPoint.x
|
|
||||||
selectRect.x = this.startPoint.rawRect.x
|
|
||||||
selectRect.r = this.startPoint.rawRect.r
|
|
||||||
if (selectRect.x > selectRect.r) {
|
|
||||||
let x = selectRect.r
|
|
||||||
selectRect.r = selectRect.x
|
|
||||||
selectRect.x = x
|
|
||||||
}
|
|
||||||
selectRect.w = selectRect.r - selectRect.x
|
|
||||||
this.startPoint.rawRect.w = selectRect.w
|
|
||||||
}
|
|
||||||
if (col) {
|
|
||||||
this.startPoint.rawRect[col] = this.startPoint.selectRect[col] + pageY - this.startPoint.y
|
|
||||||
selectRect.y = this.startPoint.rawRect.y
|
|
||||||
selectRect.b = this.startPoint.rawRect.b
|
|
||||||
|
|
||||||
if (selectRect.y > selectRect.b) {
|
|
||||||
let y = selectRect.b
|
|
||||||
selectRect.b = selectRect.y
|
|
||||||
selectRect.y = y
|
|
||||||
}
|
|
||||||
selectRect.h = selectRect.b - selectRect.y
|
|
||||||
this.startPoint.rawRect.h = selectRect.h
|
|
||||||
}
|
|
||||||
this.drawRect()
|
|
||||||
} else {
|
|
||||||
// 生成选区
|
|
||||||
const { pageX, pageY } = e
|
|
||||||
let x, y, w, h, r, b
|
|
||||||
if (this.startPoint.x > pageX) {
|
|
||||||
x = pageX
|
|
||||||
r = this.startPoint.x
|
|
||||||
} else {
|
|
||||||
r = pageX
|
|
||||||
x = this.startPoint.x
|
|
||||||
}
|
|
||||||
if (this.startPoint.y > pageY) {
|
|
||||||
y = pageY
|
|
||||||
b = this.startPoint.y
|
|
||||||
} else {
|
|
||||||
b = pageY
|
|
||||||
y = this.startPoint.y
|
|
||||||
}
|
|
||||||
w = r - x
|
|
||||||
h = b - y
|
|
||||||
|
|
||||||
|
|
||||||
this.selectRect = {
|
|
||||||
x, y, w, h, r, b,
|
|
||||||
}
|
|
||||||
selectRect = this.selectRect
|
|
||||||
if (startDragging) {
|
|
||||||
this.emit('start-dragging', selectRect)
|
|
||||||
}
|
|
||||||
this.emit('dragging', selectRect)
|
|
||||||
this.drawRect(x, y, w, h)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
drawRect() {
|
|
||||||
if (this.disabled) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (!this.selectRect) {
|
|
||||||
this.$canvas.style.display = 'none'
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const {
|
|
||||||
x, y, w, h,
|
|
||||||
} = this.selectRect
|
|
||||||
|
|
||||||
const scaleFactor = this.scaleFactor
|
|
||||||
let margin = 7
|
|
||||||
let radius = 5
|
|
||||||
this.$canvas.style.left = `${x - margin}px`
|
|
||||||
this.$canvas.style.top = `${y - margin}px`
|
|
||||||
this.$canvas.style.width = `${w + margin * 2}px`
|
|
||||||
this.$canvas.style.height = `${h + margin * 2}px`
|
|
||||||
this.$canvas.style.display = 'block'
|
|
||||||
this.$canvas.width = (w + margin * 2) * scaleFactor
|
|
||||||
this.$canvas.height = (h + margin * 2) * scaleFactor
|
|
||||||
|
|
||||||
if (w && h) {
|
|
||||||
let imageData = this.bgCtx.getImageData(x * scaleFactor, y * scaleFactor, w * scaleFactor, h * scaleFactor)
|
|
||||||
this.ctx.putImageData(imageData, margin * scaleFactor, margin * scaleFactor)
|
|
||||||
}
|
|
||||||
this.ctx.fillStyle = '#ffffff'
|
|
||||||
this.ctx.strokeStyle = '#67bade'
|
|
||||||
this.ctx.lineWidth = 2 * this.scaleFactor
|
|
||||||
|
|
||||||
this.ctx.strokeRect(margin * scaleFactor, margin * scaleFactor, w * scaleFactor, h * scaleFactor)
|
|
||||||
this.drawAnchors(w, h, margin, scaleFactor, radius)
|
|
||||||
}
|
|
||||||
|
|
||||||
drawAnchors(w, h, margin, scaleFactor, radius) {
|
|
||||||
if (this.disabled) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (this.mouseDown && this.action === CREATE_RECT) {
|
|
||||||
this.anchors = null
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.ctx.beginPath()
|
|
||||||
let anchors = [
|
|
||||||
[0, 0],
|
|
||||||
[w * this.scaleFactor / 2, 0],
|
|
||||||
[w * this.scaleFactor, 0],
|
|
||||||
|
|
||||||
[0, h * this.scaleFactor / 2],
|
|
||||||
[w * this.scaleFactor, h * this.scaleFactor / 2],
|
|
||||||
|
|
||||||
[0, h * this.scaleFactor],
|
|
||||||
[w * this.scaleFactor / 2, h * this.scaleFactor],
|
|
||||||
[w * this.scaleFactor, h * this.scaleFactor],
|
|
||||||
]
|
|
||||||
this.anchors = anchors.map(([x, y]) => [this.selectRect.x + x / scaleFactor, this.selectRect.y + y / scaleFactor])
|
|
||||||
anchors.forEach(([x, y], i) => {
|
|
||||||
this.ctx.arc(x + margin * scaleFactor, y + margin * scaleFactor, radius * scaleFactor, 0, 2 * Math.PI)
|
|
||||||
let next = anchors[(i + 1) % anchors.length]
|
|
||||||
this.ctx.moveTo(next[0] + margin * scaleFactor + radius * scaleFactor, next[1] + margin * scaleFactor)
|
|
||||||
})
|
|
||||||
this.ctx.closePath()
|
|
||||||
this.ctx.fill()
|
|
||||||
this.ctx.stroke()
|
|
||||||
}
|
|
||||||
|
|
||||||
onMouseMove(e) {
|
|
||||||
if (this.disabled) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (this.mouseDown) {
|
|
||||||
this.onMouseDrag(e)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.selectAnchorIndex = -1
|
|
||||||
if (this.selectRect) {
|
|
||||||
const { pageX, pageY } = e
|
|
||||||
const {
|
|
||||||
x, y, r, b,
|
|
||||||
} = this.selectRect
|
|
||||||
let selectAnchor, selectIndex = -1
|
|
||||||
if (this.anchors) {
|
|
||||||
this.anchors.forEach(([x, y], i) => {
|
|
||||||
if (Math.abs(pageX - x) <= 10 && Math.abs(pageY - y) <= 10) {
|
|
||||||
selectAnchor = [x, y]
|
|
||||||
selectIndex = i
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if (selectAnchor) {
|
|
||||||
this.selectAnchorIndex = selectIndex
|
|
||||||
document.body.style.cursor = ANCHORS[selectIndex].cursor
|
|
||||||
this.emit('moving')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (pageX > x && pageX < r && pageY > y && pageY < b) {
|
|
||||||
document.body.style.cursor = 'move'
|
|
||||||
} else {
|
|
||||||
document.body.style.cursor = 'auto'
|
|
||||||
}
|
|
||||||
this.emit('moving')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onMouseUp(e) {
|
|
||||||
if (this.disabled) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (!this.mouseDown) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.mouseDown = false
|
|
||||||
e.stopPropagation()
|
|
||||||
e.preventDefault()
|
|
||||||
this.emit('mouse-up')
|
|
||||||
if (!this.startPoint.moved) {
|
|
||||||
this.emit('end-moving')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.emit('end-dragging')
|
|
||||||
this.drawRect()
|
|
||||||
this.startPoint = null
|
|
||||||
}
|
|
||||||
|
|
||||||
getImageUrl() {
|
|
||||||
const scaleFactor = this.scaleFactor
|
|
||||||
const {
|
|
||||||
x, y, w, h,
|
|
||||||
} = this.selectRect
|
|
||||||
if (w && h) {
|
|
||||||
let imageData = this.bgCtx.getImageData(x * scaleFactor, y * scaleFactor, w * scaleFactor, h * scaleFactor)
|
|
||||||
let canvas = document.createElement('canvas')
|
|
||||||
canvas.width = w
|
|
||||||
canvas.height = h
|
|
||||||
let ctx = canvas.getContext('2d')
|
|
||||||
ctx.putImageData(imageData, 0, 0)
|
|
||||||
return canvas.toDataURL()
|
|
||||||
}
|
|
||||||
return ''
|
|
||||||
}
|
|
||||||
|
|
||||||
disable() {
|
|
||||||
this.disabled = true
|
|
||||||
}
|
|
||||||
|
|
||||||
enable() {
|
|
||||||
this.disabled = false
|
|
||||||
}
|
|
||||||
|
|
||||||
reset() {
|
|
||||||
this.anchors = null
|
|
||||||
this.startPoint = null
|
|
||||||
this.selectRect = null
|
|
||||||
this.startDragRect = null
|
|
||||||
this.selectAnchorIndex = -1
|
|
||||||
this.drawRect()
|
|
||||||
this.emit('reset')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
exports.CaptureEditor = CaptureEditor
|
|
||||||
exports.CREATE_RECT = CREATE_RECT
|
|
||||||
exports.MOVING_RECT = MOVING_RECT
|
|
||||||
exports.RESIZE = RESIZE
|
|
@ -1,139 +0,0 @@
|
|||||||
const {ipcRenderer, clipboard, nativeImage, remote} = require('electron')
|
|
||||||
|
|
||||||
const fs = require('fs')
|
|
||||||
const { getScreenSources } = require('./desktop-capturer')
|
|
||||||
const { CaptureEditor } = require('./capture-editor')
|
|
||||||
const { getCurrentScreen } = require('./utils')
|
|
||||||
|
|
||||||
const $canvas = document.getElementById('js-canvas')
|
|
||||||
const $bg = document.getElementById('js-bg')
|
|
||||||
const $sizeInfo = document.getElementById('js-size-info')
|
|
||||||
const $toolbar = document.getElementById('js-toolbar')
|
|
||||||
const $jsMask= document.getElementById('js-mask')
|
|
||||||
|
|
||||||
const $btnClose = document.getElementById('js-tool-close')
|
|
||||||
const $btnOk = document.getElementById('js-tool-ok')
|
|
||||||
const $btnSave = document.getElementById('js-tool-save')
|
|
||||||
const $btnReset = document.getElementById('js-tool-reset')
|
|
||||||
|
|
||||||
let currentScreen;
|
|
||||||
|
|
||||||
(async () => {
|
|
||||||
currentScreen = await getCurrentScreen();
|
|
||||||
})();
|
|
||||||
// 右键取消截屏
|
|
||||||
document.body.addEventListener('mousedown', (e) => {
|
|
||||||
if (e.button === 2) {
|
|
||||||
window.close()
|
|
||||||
}
|
|
||||||
}, true)
|
|
||||||
|
|
||||||
// console.time('capture')
|
|
||||||
getScreenSources({}, (imgSrc) => {
|
|
||||||
$jsMask.style.display = 'block';
|
|
||||||
let capture = new CaptureEditor($canvas, $bg, imgSrc)
|
|
||||||
|
|
||||||
let onDrag = (selectRect) => {
|
|
||||||
$toolbar.style.display = 'none'
|
|
||||||
$sizeInfo.style.display = 'block'
|
|
||||||
$sizeInfo.innerText = `${selectRect.w} * ${selectRect.h}`
|
|
||||||
if (selectRect.y > 35) {
|
|
||||||
$sizeInfo.style.top = `${selectRect.y - 30}px`
|
|
||||||
} else {
|
|
||||||
$sizeInfo.style.top = `${selectRect.y + 10}px`
|
|
||||||
}
|
|
||||||
$sizeInfo.style.left = `${selectRect.x}px`
|
|
||||||
}
|
|
||||||
capture.on('start-dragging', onDrag)
|
|
||||||
capture.on('dragging', onDrag)
|
|
||||||
|
|
||||||
let onDragEnd = () => {
|
|
||||||
if (capture.selectRect) {
|
|
||||||
ipcRenderer.send('capture-screen', {
|
|
||||||
type: 'select',
|
|
||||||
screenId: currentScreen.id,
|
|
||||||
})
|
|
||||||
const {
|
|
||||||
r, b,
|
|
||||||
} = capture.selectRect
|
|
||||||
$toolbar.style.display = 'flex'
|
|
||||||
$toolbar.style.top = `${b + 15}px`
|
|
||||||
$toolbar.style.right = `${window.screen.width - r}px`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
capture.on('end-dragging', onDragEnd)
|
|
||||||
|
|
||||||
ipcRenderer.on('capture-screen', (e, { type, screenId }) => {
|
|
||||||
if (type === 'select') {
|
|
||||||
if (screenId && screenId !== currentScreen.id) {
|
|
||||||
capture.disable()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
capture.on('reset', () => {
|
|
||||||
$toolbar.style.display = 'none'
|
|
||||||
$sizeInfo.style.display = 'none'
|
|
||||||
})
|
|
||||||
|
|
||||||
$btnClose.addEventListener('click', () => {
|
|
||||||
ipcRenderer.send('capture-screen', {
|
|
||||||
type: 'complete',
|
|
||||||
})
|
|
||||||
window.close()
|
|
||||||
})
|
|
||||||
|
|
||||||
$btnReset.addEventListener('click', () => {
|
|
||||||
capture.reset()
|
|
||||||
})
|
|
||||||
|
|
||||||
let selectCapture = () => {
|
|
||||||
if (!capture.selectRect) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
let url = capture.getImageUrl()
|
|
||||||
remote.getCurrentWindow().hide()
|
|
||||||
clipboard.writeImage(nativeImage.createFromDataURL(url))
|
|
||||||
ipcRenderer.send('capture-screen', {
|
|
||||||
type: 'complete',
|
|
||||||
url,
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
||||||
$btnOk.addEventListener('click', selectCapture)
|
|
||||||
|
|
||||||
$btnSave.addEventListener('click', () => {
|
|
||||||
let url = capture.getImageUrl()
|
|
||||||
|
|
||||||
remote.getCurrentWindow().hide()
|
|
||||||
remote.dialog.showSaveDialog({
|
|
||||||
filters: [{
|
|
||||||
name: 'Images',
|
|
||||||
extensions: ['png', 'jpg', 'gif'],
|
|
||||||
}],
|
|
||||||
}).then(({filePath}) => {
|
|
||||||
if (filePath) {
|
|
||||||
fs.writeFile(filePath, new Buffer(url.replace('data:image/png;base64,', ''), 'base64'), () => {
|
|
||||||
ipcRenderer.send('capture-screen', {
|
|
||||||
type: 'complete'
|
|
||||||
})
|
|
||||||
window.close()
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
ipcRenderer.send('capture-screen', {
|
|
||||||
type: 'complete'
|
|
||||||
})
|
|
||||||
window.close()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
window.addEventListener('keypress', (e) => {
|
|
||||||
if (e.code === 'Enter') {
|
|
||||||
selectCapture()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
|||||||
const {desktopCapturer} = require('electron');
|
|
||||||
|
|
||||||
exports.getScreenSources = async ({ types = ['screen'] } = {}, callback) => {
|
|
||||||
let curScreen = await getCurrentScreen();
|
|
||||||
let screenWidth = curScreen.bounds.width
|
|
||||||
let screenHeight = curScreen.bounds.height
|
|
||||||
desktopCapturer.getSources({
|
|
||||||
types: ['screen'],
|
|
||||||
thumbnailSize: {
|
|
||||||
width: screenWidth * curScreen.scaleFactor,
|
|
||||||
height: screenHeight * curScreen.scaleFactor,
|
|
||||||
}
|
|
||||||
}).then((sources) => {
|
|
||||||
let imgSrc = sources.filter(s => s.id.indexOf(curScreen.id) >= 0)[0].thumbnail.toDataURL()
|
|
||||||
callback(imgSrc)
|
|
||||||
})
|
|
||||||
}
|
|
@ -1,88 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
|
||||||
<title>capture</title>
|
|
||||||
<style>
|
|
||||||
@import "./assets/iconfont/iconfont.css";
|
|
||||||
|
|
||||||
html, body, div {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mask {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
background: rgba(0, 0, 0, 0.5);
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bg {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.image-canvas {
|
|
||||||
position: absolute;
|
|
||||||
display: none;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.size-info {
|
|
||||||
position: absolute;
|
|
||||||
color: #ffffff;
|
|
||||||
font-size: 12px;
|
|
||||||
background: rgba(40, 40, 40, 0.8);
|
|
||||||
padding: 5px 10px;
|
|
||||||
border-radius: 2px;
|
|
||||||
font-family: Arial Consolas sans-serif;
|
|
||||||
display: none;
|
|
||||||
z-index: 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.toolbar {
|
|
||||||
position: absolute;
|
|
||||||
color: #343434;
|
|
||||||
font-size: 12px;
|
|
||||||
background: #f5f5f5;
|
|
||||||
padding: 5px 10px;
|
|
||||||
border-radius: 4px;
|
|
||||||
font-family: Arial Consolas sans-serif;
|
|
||||||
display: none;
|
|
||||||
box-shadow: 0 0 20px rgba(0, 0, 0, 0.4);
|
|
||||||
z-index: 2;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.toolbar .iconfont {
|
|
||||||
font-size: 24px;
|
|
||||||
padding: 2px 5px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div id="js-bg" class="bg"></div>
|
|
||||||
<div id="js-mask" class="mask"></div>
|
|
||||||
<canvas id="js-canvas" class="image-canvas"></canvas>
|
|
||||||
<div id="js-size-info" class="size-info"></div>
|
|
||||||
<div id="js-toolbar" class="toolbar">
|
|
||||||
<div class="iconfont icon-zhongzhi" id="js-tool-reset"></div>
|
|
||||||
<div class="iconfont icon-xiazai" id="js-tool-save"></div>
|
|
||||||
<div class="iconfont icon-guanbi" id="js-tool-close"></div>
|
|
||||||
<div class="iconfont icon-duihao" id="js-tool-ok"></div>
|
|
||||||
</div>
|
|
||||||
<script src="./capture-renderer.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 3.4 KiB |
@ -1,20 +0,0 @@
|
|||||||
const { remote, ipcRenderer } = require('electron');
|
|
||||||
|
|
||||||
let currentWindow = remote.getCurrentWindow()
|
|
||||||
|
|
||||||
exports.getCurrentScreen = () => {
|
|
||||||
let { x, y } = currentWindow.getBounds();
|
|
||||||
ipcRenderer.send('capture-screen', {
|
|
||||||
type: 'getAllDisplays',
|
|
||||||
winId: currentWindow.id,
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
});
|
|
||||||
return new Promise(resolve => {
|
|
||||||
ipcRenderer.on('getAllDisplays', (e, { type, winId, screen}) => {
|
|
||||||
if (winId === currentWindow.id) {
|
|
||||||
resolve(screen)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
@ -1,12 +1,114 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8"/>
|
||||||
<title>Picker</title>
|
<title>Picker</title>
|
||||||
<link rel="stylesheet" href="./picker.css" />
|
<link rel="stylesheet" href="./picker.css"/>
|
||||||
<script defer src="./picker.js"></script>
|
<script defer src="./picker.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<section id="picker"></section>
|
<div class="content">
|
||||||
|
<div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div class="center">
|
||||||
|
<div></div>
|
||||||
|
</div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -1,17 +1,12 @@
|
|||||||
* {
|
html, body{ margin: 0; user-select: none; overflow: hidden;}
|
||||||
margin: 0;
|
.content {width: 108px; height: 108px; background-color: #fff; border-radius: 5px; }
|
||||||
padding: 0;
|
.content>div{ display: flex; }
|
||||||
}
|
.content>div>div{ width: 12px; height: 12px; box-sizing: border-box; border-right: 1px solid #999; border-bottom: 1px solid #999; }
|
||||||
|
.content>div:first-child>div{ border-top: 1px solid #999; }
|
||||||
body {
|
.content>div>div:first-child { border-left: 1px solid #999; }
|
||||||
background: transparent;
|
.content>div:first-child>div:first-child { border-top-left-radius: 4px; }
|
||||||
cursor: crosshair;
|
.content>div:first-child>div:last-child { border-top-right-radius: 4px; }
|
||||||
overflow: hidden;
|
.content>div:last-child>div:first-child { border-bottom-left-radius: 4px; }
|
||||||
}
|
.content>div:last-child>div:last-child { border-bottom-right-radius: 4px; }
|
||||||
|
.center { position: relative; }
|
||||||
#picker {
|
.center>div{ position: absolute; top: -2px; left: -2px; width: 100%; height: 100%; border: 2px solid #fff; box-shadow: 0 0 1px #212121; }
|
||||||
width: 100px;
|
|
||||||
height: 100px;
|
|
||||||
border-radius: 120px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
@ -1,9 +1,19 @@
|
|||||||
|
const {ipcRenderer} = require("electron");
|
||||||
|
let colorDomBoxs = null;
|
||||||
|
|
||||||
const { ipcRenderer } = require("electron");
|
ipcRenderer.on("updatePicker", ((e, args) => {
|
||||||
|
if (!colorDomBoxs) {
|
||||||
document.querySelector(
|
colorDomBoxs = [];
|
||||||
"#picker"
|
document.querySelectorAll(".content>div").forEach((e => {
|
||||||
).style.border = `10px solid rgba(200, 200, 200, 0.3)`;
|
colorDomBoxs.push(e.querySelectorAll(":scope > div"))
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
for (let i = 0; i < 9; i ++){
|
||||||
|
for (let j = 0; j < 9; j ++) {
|
||||||
|
colorDomBoxs[i][j].style.background = '#' + args[i][j]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
document.addEventListener(
|
document.addEventListener(
|
||||||
"keydown",
|
"keydown",
|
||||||
@ -12,7 +22,3 @@ document.addEventListener(
|
|||||||
},
|
},
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
ipcRenderer.on("updatePicker", (event, color) => {
|
|
||||||
document.querySelector("#picker").style.border = `10px solid ${color}`;
|
|
||||||
});
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user