wip: simple ui

This commit is contained in:
daief
2020-12-10 13:47:41 +08:00
parent 80a7fbd86e
commit 49bf7cd278
16 changed files with 418 additions and 78 deletions

View File

@@ -11,18 +11,13 @@
// @grant GM_log
// @grant GM_xmlhttpRequest
// @connect 127.0.0.1
// @match *://localhost*/*
// ==/UserScript==
const code = GM_getValue('code');
if (code) {
eval(code);
}
const loop = () => {
GM_xmlhttpRequest({
url: 'http://127.0.0.1:7777/index.js',
onload: e => {
console.log('check');
const res = e.responseText;
if (e.status === 200 && code !== res) {
GM_setValue('code', res);
@@ -33,4 +28,9 @@ const loop = () => {
};
setInterval(loop, 3000);
const code = GM_getValue('code');
if (code) {
eval(code);
}
```

View File

@@ -4,6 +4,7 @@ import { VueLoaderPlugin } from 'vue-loader';
import TerserPlugin from 'terser-webpack-plugin';
import { GMPlugin } from './GMPlugin';
import pkg from '../package.json';
import globalVars from './less-variables';
const nodeEnv: Configuration['mode'] = process.env.NODE_ENV as any;
@@ -27,7 +28,6 @@ const config: Configuration = {
},
{
test: /\.less$/,
exclude: /\.lazy\.less$/i,
use: [
{
loader: 'style-loader',
@@ -40,6 +40,8 @@ const config: Configuration = {
options: {
lessOptions: {
strictMath: true,
javascriptEnabled: true,
globalVars: globalVars,
},
},
},

35
config/less-variables.ts Normal file
View File

@@ -0,0 +1,35 @@
import { generate, gold, red } from '@ant-design/colors';
import Color from 'color';
const primary = '#f6438a';
const grey = '#bfbfbf';
// https://ant.design/docs/spec/colors-cn
// color1, color2, color3, color4, color5, color7, color8, color9, color10
const generateColors = (mainColor: string, name: string) =>
generate(mainColor).reduce<Record<string, string>>((result, curr, i) => {
i = i + 1;
if (i !== 6) {
result[`${name}${i}`] = curr;
}
return result;
}, {});
// https://github.com/ant-design/ant-design/blob/5ab2783ff0/components/style/themes/default.less
export default {
prefix: 'gm-rp',
...generateColors(primary, 'color'),
primary,
...generateColors(grey, 'grey'),
grey,
textColor: Color('#000').alpha(0.65).string(),
textColorSecondary: Color('#000').alpha(0.45).string(),
textColorWarning: gold[6],
textColorDanger: red[6],
textColorInverse: '#fff',
fontSize: '14px',
fontSizeLg: '16px',
fontSizeSm: '12px',
baseFamily:
"Penrose, 'PingFang SC', 'Hiragino Sans GB', Tahoma, Arial, 'Lantinghei SC', 'Microsoft YaHei', '\\5FAE软雅黑', sans-serif",
};

View File

@@ -18,6 +18,7 @@
"build": "cross-env NODE_ENV=production yarn runpack"
},
"devDependencies": {
"@types/lodash": "^4.14.165",
"@types/node": "^14.14.10",
"@types/webpack": "^4.41.25",
"@vue/compiler-sfc": "^3.0.3",
@@ -35,6 +36,10 @@
"webpack-cli": "^4.2.0"
},
"dependencies": {
"@ant-design/colors": "^5.0.0",
"@types/color": "^3.0.1",
"color": "^3.1.3",
"lodash": "^4.17.20",
"vue": "3.0.3",
"vuex": "^4.0.0-rc.2"
}

0
src/@types/vue-extend.d.ts vendored Normal file
View File

View File

@@ -1,57 +0,0 @@
<template>
<div v-show="show" class="root" @click.self="show = false">
<div class="container">{{ state.matchedSetList.length }}1</div>
</div>
</template>
<script lang="ts">
import { ISet } from '@/data';
import { defineComponent, reactive } from 'vue';
export default defineComponent({
data() {
return {
show: false,
};
},
setup() {
const state = reactive<{
matchedSetList: ISet[];
}>({
matchedSetList: [],
});
return {
state,
};
},
});
</script>
<style scoped lang="less">
.root {
overflow: hidden auto;
right: 0;
bottom: 0;
top: 0;
left: 0;
outline: none;
position: fixed;
z-index: 1000;
background-color: rgba(0, 0, 0, 0.2);
}
.container {
position: absolute;
left: 50%;
box-sizing: border-box;
pointer-events: auto;
top: 40%;
transform: translate(-50%, -40%);
background: #fff;
border-radius: 4px;
box-shadow: 0 0 24px 0 rgba(102, 102, 102, 0.08);
min-height: 360px;
max-width: 100%;
width: 720px;
}
</style>

136
src/Setting/Root.vue Normal file
View File

@@ -0,0 +1,136 @@
<template>
<div v-show="show" :class="cls" @click.self="close">
<div :class="`${cls}--container`">
<Button type="primary" :onClick="handleAdd">+</Button>
<br />
<div
v-for="(it, idx) in state.matchedSetList"
:key="idx"
:class="`${cls}--set-wrap`"
>
<div>
<label>domainTest:</label>
<input :value="it.domainTest" />
<Button type="primary" :onClick="() => handleAddRule(idx)">
Add rule
</Button>
</div>
<hr />
<div v-for="(rule, idx2) in it.rules" :key="idx2">
<div>
<label>rule-{{ idx2 }}:</label>
<div>apiTest: <input v-model="rule.apiTest" /></div>
<div>apiTest2: <input v-model="rule.apiTest" /></div>
<div>response: <textarea v-model="rule.response" /></div>
</div>
</div>
</div>
</div>
</div>
</template>
<script lang="ts">
import { Store } from '@/data';
import type { ISet } from '@/data';
import { defineComponent, onMounted, reactive, ref, watch } from 'vue';
import Button from '@/compts/Button.vue';
import { ns, uuid4 } from '@/common';
export default defineComponent({
components: { Button },
setup() {
const state = reactive<{
matchedSetList: ISet[];
}>({
matchedSetList: [],
});
onMounted(() => {
state.matchedSetList = Store.getMatchedSetList();
console.log(state.matchedSetList);
});
watch(
() => state.matchedSetList,
() => {
Store.updateSetList(state.matchedSetList);
},
{ deep: true }
);
const show = ref(false);
return {
cls: ns('root'),
state,
show,
open: () => {
show.value = true;
},
close: () => {
show.value = false;
},
handleAdd: () => {
state.matchedSetList = [
{
domainTest: location.hostname,
rules: [],
id: uuid4(),
},
...state.matchedSetList,
];
},
handleAddRule: (i: number) => {
state.matchedSetList[i].rules.push({
id: uuid4(),
apiTest: '',
response: '',
disabled: false,
});
},
};
},
});
</script>
<style scoped lang="less">
.@{prefix}__root {
overflow: hidden auto;
right: 0;
bottom: 0;
top: 0;
left: 0;
outline: none;
position: fixed;
z-index: 1000;
background-color: rgba(0, 0, 0, 0.65);
&--container {
position: absolute;
left: 50%;
box-sizing: border-box;
pointer-events: auto;
top: 40%;
transform: translate(-50%, -40%);
background: #fff;
border-radius: 4px;
box-shadow: 0 0 24px 0 rgba(102, 102, 102, 0.08);
min-height: 360px;
max-width: 100%;
width: 720px;
}
&--set-wrap {
border: @color5 1px solid;
border-radius: 4px;
margin: 10px;
padding: 16px;
& + & {
margin-top: 10px;
}
}
}
</style>

View File

@@ -1,17 +1,18 @@
import { createApp } from 'vue';
import Panel from './Panel.vue';
import Root from './Root.vue';
export function render(el: any) {
const vm = createApp(Panel);
const vm = createApp(Root);
const $root = vm.mount(el);
return {
$root,
open: () => {
($root.$data as any).show = true;
return ($root as any).open();
},
close: () => {
($root.$data as any).show = false;
return ($root as any).close();
},
};
}

View File

@@ -10,5 +10,11 @@ export const cache = new WeakMap<
export const NAMESPACE = location.host;
export const PREFIX = 'gm-rp';
export const vmCtx: Window & typeof globalThis =
typeof unsafeWindow !== 'undefined' ? unsafeWindow : window;
export function ns(c = '') {
return `${PREFIX}__${c}`;
}

View File

@@ -5,3 +5,19 @@ export function safeParse(str: string) {
return str;
}
}
export function isPromise(obj: any) {
return (
!!obj &&
(typeof obj === 'object' || typeof obj === 'function') &&
typeof obj.then === 'function'
);
}
export function uuid4() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
var r = (Math.random() * 16) | 0,
v = c == 'x' ? r : (r & 0x3) | 0x8;
return v.toString(16);
});
}

98
src/compts/Button.vue Normal file
View File

@@ -0,0 +1,98 @@
<template>
<button :class="[cls, `${cls}--${type}`]" @click="handleClick">
<slot />
</button>
</template>
<script lang="ts">
import { ns } from '@/common';
import { defineComponent, ref } from 'vue';
export default defineComponent({
name: 'RPButton',
props: {
type: {
type: String,
default: 'secondary',
},
onClick: {
type: Function,
default: () => null,
},
},
setup(props) {
const innerLoading = ref(false);
const handleClick = async (e: any) => {
if (innerLoading.value) return;
try {
innerLoading.value = true;
await props.onClick(e);
} catch (_) {
} finally {
innerLoading.value = false;
}
};
return {
cls: ns('button'),
handleClick,
};
},
});
</script>
<style scoped lang="less">
.@{prefix}__button {
text-transform: none;
position: relative;
display: inline-block;
white-space: nowrap;
text-align: center;
cursor: pointer;
transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
user-select: none;
touch-action: manipulation;
height: 32px;
padding: 4px 15px;
font-size: 14px;
border-radius: 2px;
border: 1px solid #d9d9d9;
outline: 0;
color: #fff;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.12);
box-shadow: 0 2px 0 rgba(0, 0, 0, 0.045);
&--primary {
background-color: @primary;
border-color: @primary;
&:hover {
background-color: @color5;
border-color: @color5;
}
&:active {
background-color: @color9;
border-color: @color9;
}
}
&--secondary {
color: @textColor;
background-color: #fff;
border-color: @grey;
&:hover {
border-color: @color5;
color: @color5;
}
&:active {
border-color: @color8;
color: @color8;
}
}
}
</style>

View File

@@ -1,12 +1,15 @@
import { NAMESPACE } from '@/common';
import { NAMESPACE, uuid4 } from '@/common';
import values from 'lodash/values';
export interface IPrxyRule {
id: string;
disabled: boolean;
apiTest: string;
response: string;
}
export interface ISet {
id: string;
domainTest: string;
rules: IPrxyRule[];
}
@@ -16,8 +19,11 @@ const KEY_SET = 'all_set';
export const Store = {
NAMESPACE,
getStoreObject(): Record<string, ISet> {
return GM_getValue(KEY_SET) || {};
},
getSetList(): ISet[] {
let res = GM_getValue(KEY_SET);
let res = values(Store.getStoreObject());
res = Array.isArray(res) ? res : [];
return res;
},
@@ -30,9 +36,21 @@ export const Store = {
const ruleSet = Store.getSetList().find(it =>
new RegExp(it.domainTest, 'ig').test(location.host)
) || {
id: uuid4(),
domainTest: location.host,
rules: [],
};
return ruleSet;
},
updateSetList(input: ISet[]) {
const store = Store.getStoreObject();
input.forEach(it => {
const target = store[it.id];
if (target) {
return Object.assign(target, it);
}
store[it.id] = it;
});
GM_setValue(KEY_SET, store);
},
};

View File

@@ -1,4 +1,14 @@
.response-proxy-page-root-fixed-button {
[class*='@{prefix}__'] {
font-size: @fontSize;
font-family: @baseFamily;
box-sizing: border-box;
margin: 0;
padding: 0;
font-feature-settings: 'tnum';
font-weight: 400;
}
.@{prefix}__page-root-fixed-button {
position: fixed;
top: 148px;
left: 0;
@@ -6,13 +16,14 @@
height: 40px;
z-index: 4000;
cursor: pointer;
background-color: #6cf;
opacity: 0.5;
transition: opacity 0.3s;
box-shadow: 0 0 10px 0px rgb(0 0 0 / 35%);
display: flex;
align-items: center;
justify-content: center;
background-color: @color2;
color: @textColor;
&:hover {
opacity: 1;

0
src/hooks/index.ts Normal file
View File

View File

@@ -17,7 +17,7 @@ function bootstrap() {
const el = document.createElement('div');
el.innerText = 'o_O||';
el.className = 'response-proxy-page-root-fixed-button';
el.className = 'gm-rp__page-root-fixed-button';
function onClickEl(_e: MouseEvent) {
if (isMove) {
@@ -77,6 +77,11 @@ function bootstrap() {
document.body.appendChild(el);
document.body.appendChild(elForMount);
if (process.env.NODE_ENV === 'development') {
// TODO rm
onClickEl({} as any);
}
}
if (document.readyState === 'loading') {

View File

@@ -2,6 +2,13 @@
# yarn lockfile v1
"@ant-design/colors@^5.0.0":
version "5.0.0"
resolved "https://registry.npm.taobao.org/@ant-design/colors/download/@ant-design/colors-5.0.0.tgz?cache=0&sync_timestamp=1605154041862&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40ant-design%2Fcolors%2Fdownload%2F%40ant-design%2Fcolors-5.0.0.tgz#46b73b4cc6935b35fc8b84555e8e42c8cfc190e6"
integrity sha1-Rrc7TMaTWzX8i4RVXo5CyM/BkOY=
dependencies:
"@ctrl/tinycolor" "^3.1.6"
"@babel/helper-validator-identifier@^7.10.4":
version "7.10.4"
resolved "https://registry.npm.taobao.org/@babel/helper-validator-identifier/download/@babel/helper-validator-identifier-7.10.4.tgz?cache=0&sync_timestamp=1593521376709&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-validator-identifier%2Fdownload%2F%40babel%2Fhelper-validator-identifier-7.10.4.tgz#a78c7a7251e01f616512d31b10adcf52ada5e0d2"
@@ -21,11 +28,35 @@
lodash "^4.17.19"
to-fast-properties "^2.0.0"
"@ctrl/tinycolor@^3.1.6":
version "3.2.0"
resolved "https://registry.npm.taobao.org/@ctrl/tinycolor/download/@ctrl/tinycolor-3.2.0.tgz?cache=0&sync_timestamp=1606352054130&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40ctrl%2Ftinycolor%2Fdownload%2F%40ctrl%2Ftinycolor-3.2.0.tgz#77a8a33edb2fdc02318c828be78f6fb3d6c65eb2"
integrity sha1-d6ijPtsv3AIxjIKL549vs9bGXrI=
"@types/anymatch@*":
version "1.3.1"
resolved "https://registry.npm.taobao.org/@types/anymatch/download/@types/anymatch-1.3.1.tgz#336badc1beecb9dacc38bea2cf32adf627a8421a"
integrity sha1-M2utwb7sudrMOL6izzKt9ieoQho=
"@types/color-convert@*":
version "2.0.0"
resolved "https://registry.npm.taobao.org/@types/color-convert/download/@types/color-convert-2.0.0.tgz#8f5ee6b9e863dcbee5703f5a517ffb13d3ea4e22"
integrity sha1-j17muehj3L7lcD9aUX/7E9PqTiI=
dependencies:
"@types/color-name" "*"
"@types/color-name@*":
version "1.1.1"
resolved "https://registry.npm.taobao.org/@types/color-name/download/@types/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0"
integrity sha1-HBJhu+qhCoBVu8XYq4S3sq/IRqA=
"@types/color@^3.0.1":
version "3.0.1"
resolved "https://registry.npm.taobao.org/@types/color/download/@types/color-3.0.1.tgz#2900490ed04da8116c5058cd5dba3572d5a25071"
integrity sha1-KQBJDtBNqBFsUFjNXbo1ctWiUHE=
dependencies:
"@types/color-convert" "*"
"@types/eslint-scope@^3.7.0":
version "3.7.0"
resolved "https://registry.npm.taobao.org/@types/eslint-scope/download/@types/eslint-scope-3.7.0.tgz#4792816e31119ebd506902a482caec4951fabd86"
@@ -52,6 +83,11 @@
resolved "https://registry.npm.taobao.org/@types/json-schema/download/@types/json-schema-7.0.6.tgz#f4c7ec43e81b319a9815115031709f26987891f0"
integrity sha1-9MfsQ+gbMZqYFRFQMXCfJph4kfA=
"@types/lodash@^4.14.165":
version "4.14.165"
resolved "https://registry.npm.taobao.org/@types/lodash/download/@types/lodash-4.14.165.tgz?cache=0&sync_timestamp=1604603009372&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Flodash%2Fdownload%2F%40types%2Flodash-4.14.165.tgz#74d55d947452e2de0742bad65270433b63a8c30f"
integrity sha1-dNVdlHRS4t4HQrrWUnBDO2Ooww8=
"@types/node@*", "@types/node@^14.14.10":
version "14.14.10"
resolved "https://registry.npm.taobao.org/@types/node/download/@types/node-14.14.10.tgz#5958a82e41863cfc71f2307b3748e3491ba03785"
@@ -456,7 +492,7 @@ chrome-trace-event@^1.0.2:
dependencies:
tslib "^1.9.0"
color-convert@^1.9.0:
color-convert@^1.9.0, color-convert@^1.9.1:
version "1.9.3"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
@@ -475,11 +511,27 @@ color-name@1.1.3:
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
color-name@~1.1.4:
color-name@^1.0.0, color-name@~1.1.4:
version "1.1.4"
resolved "https://registry.npm.taobao.org/color-name/download/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
integrity sha1-wqCah6y95pVD3m9j+jmVyCbFNqI=
color-string@^1.5.4:
version "1.5.4"
resolved "https://registry.npm.taobao.org/color-string/download/color-string-1.5.4.tgz#dd51cd25cfee953d138fe4002372cc3d0e504cb6"
integrity sha1-3VHNJc/ulT0Tj+QAI3LMPQ5QTLY=
dependencies:
color-name "^1.0.0"
simple-swizzle "^0.2.2"
color@^3.1.3:
version "3.1.3"
resolved "https://registry.npm.taobao.org/color/download/color-3.1.3.tgz?cache=0&sync_timestamp=1602228725017&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcolor%2Fdownload%2Fcolor-3.1.3.tgz#ca67fb4e7b97d611dcde39eceed422067d91596e"
integrity sha1-ymf7TnuX1hHc3jns7tQiBn2RWW4=
dependencies:
color-convert "^1.9.1"
color-string "^1.5.4"
colorette@^1.2.1:
version "1.2.1"
resolved "https://registry.npm.taobao.org/colorette/download/colorette-1.2.1.tgz#4d0b921325c14faf92633086a536db6e89564b1b"
@@ -810,6 +862,11 @@ interpret@^2.2.0:
resolved "https://registry.yarnpkg.com/interpret/-/interpret-2.2.0.tgz#1a78a0b5965c40a5416d007ad6f50ad27c417df9"
integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==
is-arrayish@^0.3.1:
version "0.3.2"
resolved "https://registry.npm.taobao.org/is-arrayish/download/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03"
integrity sha1-RXSirlb3qyBolvtDHq7tBm/fjwM=
is-core-module@^2.1.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.2.0.tgz#97037ef3d52224d85163f5597b2b63d9afed981a"
@@ -939,10 +996,10 @@ lodash.camelcase@^4.3.0:
resolved "https://registry.npm.taobao.org/lodash.camelcase/download/lodash.camelcase-4.3.0.tgz?cache=0&sync_timestamp=1577806297529&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flodash.camelcase%2Fdownload%2Flodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY=
lodash@^4.17.15, lodash@^4.17.19:
lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20:
version "4.17.20"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52"
integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==
resolved "https://registry.npm.taobao.org/lodash/download/lodash-4.17.20.tgz?cache=0&sync_timestamp=1597336082988&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flodash%2Fdownload%2Flodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52"
integrity sha1-tEqbYpe8tpjxxRo1RaKzs2jVnFI=
lru-cache@^5.1.1:
version "5.1.1"
@@ -1368,6 +1425,13 @@ signal-exit@^3.0.2:
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==
simple-swizzle@^0.2.2:
version "0.2.2"
resolved "https://registry.npm.taobao.org/simple-swizzle/download/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a"
integrity sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=
dependencies:
is-arrayish "^0.3.1"
source-list-map@^2.0.1:
version "2.0.1"
resolved "https://registry.npm.taobao.org/source-list-map/download/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34"