mirror of
https://gitee.com/ElemeFE/element.git
synced 2024-12-01 19:57:48 +08:00
Chore: Theme Extension (#16686)
This commit is contained in:
parent
8b8a1a2e87
commit
f29f49a17d
@ -1,6 +1,7 @@
|
||||
{
|
||||
"globals": {
|
||||
"ga": true
|
||||
"ga": true,
|
||||
"chrome": true
|
||||
},
|
||||
"plugins": ["html", "json"],
|
||||
"extends": "elemefe",
|
||||
|
33
build/webpack.extension.js
Normal file
33
build/webpack.extension.js
Normal file
@ -0,0 +1,33 @@
|
||||
const path = require('path');
|
||||
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||
const demoConfig = require('./webpack.demo');
|
||||
const webpack = require('webpack');
|
||||
const ProgressBarPlugin = require('progress-bar-webpack-plugin');
|
||||
const VueLoaderPlugin = require('vue-loader/lib/plugin');
|
||||
|
||||
demoConfig.entry = {
|
||||
background: path.join(process.cwd(), './examples/extension/src/background'),
|
||||
entry: path.join(process.cwd(), './examples/extension/src/entry')
|
||||
};
|
||||
demoConfig.output = {
|
||||
path: path.join(process.cwd(), './examples/extension/dist'),
|
||||
filename: '[name].js'
|
||||
};
|
||||
demoConfig.plugins = [
|
||||
new CopyWebpackPlugin([
|
||||
{ from: 'examples/extension/src/manifest.json' },
|
||||
{ from: 'examples/extension/src/icon.png' }
|
||||
]),
|
||||
new VueLoaderPlugin(),
|
||||
new ProgressBarPlugin(),
|
||||
new webpack.LoaderOptionsPlugin({
|
||||
vue: {
|
||||
compilerOptions: {
|
||||
preserveWhitespace: false
|
||||
}
|
||||
}
|
||||
}),
|
||||
new webpack.HotModuleReplacementPlugin()
|
||||
];
|
||||
demoConfig.module.rules.find(a => a.loader === 'url-loader').query = {};
|
||||
module.exports = demoConfig;
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<section class="config" :key="displayName">
|
||||
<div class="config-label">
|
||||
<el-tooltip :content="displayName">
|
||||
<el-tooltip :content="displayName" placement="top">
|
||||
<span>{{displayKeyName}}</span>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<section class="config" :key="displayName">
|
||||
<div class="config-label">
|
||||
<el-tooltip :content="displayName">
|
||||
<el-tooltip :content="displayName" placement="top">
|
||||
<span>{{displayKeyName}}</span>
|
||||
</el-tooltip>
|
||||
<el-button
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<section class="config" :key="displayName">
|
||||
<div class="config-label">
|
||||
<el-tooltip :content="displayName">
|
||||
<el-tooltip :content="displayName" placement="top">
|
||||
<span>{{displayKeyName}}</span>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<section class="config" :key="displayName">
|
||||
<div class="config-label">
|
||||
<el-tooltip :content="displayName">
|
||||
<el-tooltip :content="displayName" placement="top">
|
||||
<span>{{displayKeyName}}</span>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<section class="config" :key="displayName">
|
||||
<div class="config-label">
|
||||
<el-tooltip :content="displayName">
|
||||
<el-tooltip :content="displayName" placement="top">
|
||||
<span>{{displayKeyName}}</span>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<section class="config" :key="displayName">
|
||||
<div class="config-label">
|
||||
<el-tooltip :content="displayName">
|
||||
<el-tooltip :content="displayName" placement="top">
|
||||
<span>{{displayKeyName}}</span>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<section class="config" :key="displayName">
|
||||
<div class="config-label">
|
||||
<el-tooltip :content="displayName">
|
||||
<el-tooltip :content="displayName" placement="top">
|
||||
<span>{{displayKeyName}}</span>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
|
@ -102,7 +102,7 @@ export default {
|
||||
defaultConfig = res;
|
||||
})
|
||||
.catch(err => {
|
||||
this.onError(err);
|
||||
this.onError && this.onError(err);
|
||||
})
|
||||
.then(() => {
|
||||
setTimeout(() => {
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="main" ref="mainPanel">
|
||||
<div class="editor-main" ref="mainPanel">
|
||||
<!-- <span>{{configName}}</span> -->
|
||||
<div v-for="(config, key) in configByOrder" :key="key">
|
||||
<span
|
||||
@ -22,7 +22,7 @@
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.main {
|
||||
.editor-main {
|
||||
padding: 0 18px 15px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
@ -260,7 +260,8 @@ export default {
|
||||
base: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
from: String
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@ -308,6 +309,10 @@ export default {
|
||||
switch (e) {
|
||||
case 'preview':
|
||||
case 'edit':
|
||||
if (this.from) {
|
||||
this.$emit('action', e, this.config);
|
||||
return;
|
||||
}
|
||||
const { name, theme } = this.config;
|
||||
savePreviewToLocal({
|
||||
type: this.type,
|
||||
|
1
examples/extension/.gitignore
vendored
Normal file
1
examples/extension/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
dist
|
18
examples/extension/src/app.js
Normal file
18
examples/extension/src/app.js
Normal file
@ -0,0 +1,18 @@
|
||||
import Vue from 'vue';
|
||||
import App from './editor/index';
|
||||
import Element from 'main/index.js';
|
||||
import 'packages/theme-chalk/src/index.scss';
|
||||
|
||||
export default () => {
|
||||
Vue.use(Element, { zIndex: 100000 });
|
||||
const root = document.createElement('div');
|
||||
document.body.appendChild(root);
|
||||
|
||||
window.ga = function() {
|
||||
console.log(arguments);
|
||||
};
|
||||
|
||||
new Vue({ // eslint-disable-line
|
||||
render: h => h(App)
|
||||
}).$mount(root);
|
||||
};
|
6
examples/extension/src/background.js
Normal file
6
examples/extension/src/background.js
Normal file
@ -0,0 +1,6 @@
|
||||
chrome.browserAction.onClicked.addListener(tab => {
|
||||
chrome.tabs.executeScript(tab.id, {
|
||||
file: 'entry.js'
|
||||
});
|
||||
})
|
||||
;
|
212
examples/extension/src/editor/editor.vue
Normal file
212
examples/extension/src/editor/editor.vue
Normal file
@ -0,0 +1,212 @@
|
||||
<template>
|
||||
<div class="ext-panel" :class="{moving : moving}" :style="{top: `${top}px`, left: `${left}px`}" ref="editor" >
|
||||
<img class="entrance touch-icon" src="./icon-entrance.png" v-show="!showSidebar" @click="toggleSidebar" />
|
||||
<img class="close touch-icon" src="./icon-close.png" v-show="showSidebar" @click="toggleSidebar" />
|
||||
<div class="editor" :style="{height: `${height}px`}" v-show="showSidebar">
|
||||
<el-tabs v-model="activeTab" @tab-click="onTabClick">
|
||||
<el-tab-pane label="Config" name="config">
|
||||
<theme-configurator
|
||||
:themeConfig="themeConfig"
|
||||
:previewConfig="previewConfig"
|
||||
:onUserConfigUpdate="onUserConfigUpdate"
|
||||
from="extension"
|
||||
></theme-configurator>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="Gallery" name="gallery">
|
||||
<gallery
|
||||
ref='gallery'
|
||||
:height="height"
|
||||
:width="width - 7"
|
||||
@action="onGalleryAction"
|
||||
/>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ThemeConfigurator from '../../../components/theme-configurator';
|
||||
import themeLoader from '../../../components/theme/loader';
|
||||
import gallery from './gallery';
|
||||
import { loadUserThemeFromLocal, saveUserThemeToLocal } from './utils';
|
||||
import bus from '../../../bus.js';
|
||||
import {
|
||||
ACTION_APPLY_THEME
|
||||
} from '../../../components/theme/constant.js';
|
||||
|
||||
let initX;
|
||||
let initY;
|
||||
let leftX = 0;
|
||||
let topY = 25;
|
||||
export default {
|
||||
mixins: [themeLoader],
|
||||
components: {
|
||||
ThemeConfigurator,
|
||||
gallery
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showSidebar: true,
|
||||
previewConfig: {},
|
||||
themeConfig: {},
|
||||
top: topY,
|
||||
left: leftX,
|
||||
height: window.innerHeight - 30 * 2,
|
||||
width: 0,
|
||||
moving: false,
|
||||
activeTab: 'config',
|
||||
themeName: '',
|
||||
userTheme: []
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
const editor = this.$refs.editor;
|
||||
this.width = editor.offsetWidth;
|
||||
leftX = window.innerWidth - 20 - this.width;
|
||||
this.left = leftX;
|
||||
editor.addEventListener('mousedown', e => {
|
||||
initX = e.clientX;
|
||||
initY = e.clientY;
|
||||
leftX = this.left;
|
||||
topY = this.top;
|
||||
document.addEventListener('mousemove', this.moveFunc);
|
||||
});
|
||||
document.addEventListener('mouseup', e => {
|
||||
document.removeEventListener('mousemove', this.moveFunc);
|
||||
setTimeout(() => {this.moving = false;}, 0);
|
||||
});
|
||||
// chrome.storage.local.remove('ELEMENT_THEME_USER_CONFIG');
|
||||
loadUserThemeFromLocal()
|
||||
.then((result) => {
|
||||
if (result) {
|
||||
this.activeTab = 'gallery';
|
||||
this.userTheme = result;
|
||||
}
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
checkLocalThemeConfig() {}, // disable mixin auto loading
|
||||
toggleSidebar() {
|
||||
if (this.moving) return;
|
||||
this.showSidebar = !this.showSidebar;
|
||||
if (!this.showSidebar) {
|
||||
const windowWidth = window.innerWidth;
|
||||
if (this.left + this.width * 0.5 < windowWidth * 0.5) {
|
||||
this.left = 0;
|
||||
} else {
|
||||
this.left = windowWidth - 50;
|
||||
}
|
||||
} else {
|
||||
this.moveEditor(this.left, this.top);
|
||||
}
|
||||
},
|
||||
moveFunc(e) {
|
||||
e.preventDefault();
|
||||
const deltaX = initX - e.clientX;
|
||||
const deltaY = initY - e.clientY;
|
||||
if (Math.abs(deltaX) > 5 || Math.abs(deltaY) > 5) {
|
||||
this.moving = true;
|
||||
}
|
||||
this.moveEditor(leftX - deltaX, topY - deltaY);
|
||||
},
|
||||
moveEditor(x, y) {
|
||||
const showSidebar = this.showSidebar;
|
||||
let nextTop = y;
|
||||
if (nextTop < 0) nextTop = 0;
|
||||
const maxTop = window.innerHeight - (showSidebar ? (this.height + 5) : 50);
|
||||
if (nextTop > maxTop) nextTop = maxTop;
|
||||
this.top = nextTop;
|
||||
let nextLeft = x;
|
||||
if (nextLeft < 0) nextLeft = 0;
|
||||
const maxLeft = window.innerWidth - (showSidebar ? (this.width + 5) : 50);
|
||||
if (nextLeft > maxLeft) nextLeft = maxLeft;
|
||||
this.left = nextLeft;
|
||||
},
|
||||
onGalleryAction(key, value) {
|
||||
switch (key) {
|
||||
case 'edit':
|
||||
this.themeName = value.name;
|
||||
this.themeConfig = JSON.parse(value.theme);
|
||||
bus.$emit(ACTION_APPLY_THEME, this.themeConfig);
|
||||
this.activeTab = 'config';
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
},
|
||||
onTabClick(e) {
|
||||
if (e && e.name === 'gallery') {
|
||||
this.$refs.gallery.init();
|
||||
}
|
||||
},
|
||||
onUserConfigUpdate(userConfig) {
|
||||
if (this.themeName) {
|
||||
this.userTheme.forEach((config) => {
|
||||
if (config.name === this.themeName) {
|
||||
config.update = Date.now();
|
||||
config.theme = JSON.stringify(userConfig);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.themeName = `Theme-${Date.now()}`;
|
||||
this.userTheme.push({
|
||||
update: Date.now(),
|
||||
name: this.themeName,
|
||||
theme: JSON.stringify(userConfig)
|
||||
});
|
||||
}
|
||||
saveUserThemeToLocal(this.userTheme);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.ext-panel {
|
||||
position: fixed;
|
||||
background: transparent;
|
||||
user-select: none;
|
||||
z-index: 100000;
|
||||
}
|
||||
.ext-panel.moving{
|
||||
cursor: move;
|
||||
}
|
||||
.ext-panel.moving .touch-icon{
|
||||
cursor: move;
|
||||
}
|
||||
.ext-panel .touch-icon{
|
||||
cursor: pointer;
|
||||
}
|
||||
.ext-panel .close {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
z-index: 100001;
|
||||
}
|
||||
.ext-panel .entrance {
|
||||
height: 50px;
|
||||
width: 50px;
|
||||
}
|
||||
.ext-panel .editor {
|
||||
overflow: hidden;
|
||||
background: #f5f7fa;
|
||||
border: 1px solid #ebeef5;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1);
|
||||
margin: 5px 5px 0 0;
|
||||
min-width: 261px;
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
.ext-panel .editor .el-tabs__content, .ext-panel .editor .el-tabs--top, .ext-panel .editor .el-tab-pane {
|
||||
height: 100%;
|
||||
}
|
||||
.ext-panel .el-tabs__nav-scroll >div {
|
||||
transform: translateX(60px)!important;
|
||||
}
|
||||
.ext-panel .editor-main {
|
||||
padding: 0 18px 70px;
|
||||
}
|
||||
</style>
|
185
examples/extension/src/editor/gallery.vue
Normal file
185
examples/extension/src/editor/gallery.vue
Normal file
@ -0,0 +1,185 @@
|
||||
<template>
|
||||
<div :style="{
|
||||
height: `${height}px`,
|
||||
width: `${width}px`
|
||||
}"
|
||||
class="main"
|
||||
>
|
||||
<ul
|
||||
class="theme-card-list"
|
||||
>
|
||||
<li class="theme-card" v-for="item in userTheme" :key="item.name">
|
||||
<theme-card type="user" :config="item" @action="onAction" from="extension"></theme-card>
|
||||
</li>
|
||||
<li class="theme-card">
|
||||
<theme-card type="upload" :config="{name: 'upload'}" @action="onAction"></theme-card>
|
||||
</li>
|
||||
</ul>
|
||||
<el-dialog :visible.sync="copyDialogVisible" :modal-append-to-body="false">
|
||||
<el-form :model="copyForm" ref="copyForm" :rules="copyFormRule">
|
||||
<el-form-item label="主题名称" prop="name">
|
||||
<el-input v-model="copyForm.name"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="closeCopyForm">取消</el-button>
|
||||
<el-button type="primary" @click="copyToUser">确认</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
ul, li {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
.main {
|
||||
overflow: auto;
|
||||
}
|
||||
.theme-card-list {
|
||||
padding-bottom: 50px;
|
||||
width: 90%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.theme-card {
|
||||
display: inline-block;
|
||||
height: 140px;
|
||||
height: 15vw;
|
||||
width: 100%;
|
||||
max-height: 230px;
|
||||
flex: 0 0 24%;
|
||||
cursor: default;
|
||||
vertical-align: bottom;
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
.theme-card .theme-card-item {
|
||||
margin-top: 0;
|
||||
}
|
||||
.theme-card .theme-card-item.is-upload {
|
||||
height: 80%
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import ThemeCard from '../../../components/theme/theme-card.vue';
|
||||
import { loadUserThemeFromLocal, saveUserThemeToLocal } from './utils';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
height: Number,
|
||||
width: Number
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
userTheme: [],
|
||||
copyDialogVisible: false,
|
||||
copyForm: {},
|
||||
copyFormRule: {
|
||||
name: [{
|
||||
validator: this.validateCopyName,
|
||||
trigger: 'blur'
|
||||
}]
|
||||
}
|
||||
};
|
||||
},
|
||||
components: {
|
||||
ThemeCard
|
||||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
loadUserThemeFromLocal().then(result => {
|
||||
if (!result) return;
|
||||
this.userTheme = result;
|
||||
});
|
||||
},
|
||||
onAction(key, value) {
|
||||
switch (key) {
|
||||
case 'copy':
|
||||
this.openCopyForm(value.theme);
|
||||
break;
|
||||
case 'upload':
|
||||
this.openCopyForm(value);
|
||||
break;
|
||||
case 'delete':
|
||||
this.$confirm('确定要删除这个主题?', '提示', {
|
||||
confirmButtonText: '确认',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.deleteUserThemeByName(value.name);
|
||||
}).catch(() => {});
|
||||
break;
|
||||
case 'rename':
|
||||
this.openRenameForm(value.name);
|
||||
break;
|
||||
default:
|
||||
this.$emit('action', key, value);
|
||||
return;
|
||||
}
|
||||
},
|
||||
openCopyForm(theme) {
|
||||
this.copyForm.theme = theme;
|
||||
this.copyDialogVisible = true;
|
||||
},
|
||||
openRenameForm(name) {
|
||||
this.copyForm.oldname = name;
|
||||
this.copyDialogVisible = true;
|
||||
},
|
||||
closeCopyForm() {
|
||||
this.copyDialogVisible = false;
|
||||
this.$nextTick(() => {
|
||||
this.copyForm = {};
|
||||
});
|
||||
},
|
||||
validateCopyName(rule, value, callback) {
|
||||
if (!value) {
|
||||
callback(new Error('主题名称是必填项'));
|
||||
} else if (this.filterUserThemeByName(value).length > 0) {
|
||||
callback(new Error('主题名称重复'));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
},
|
||||
copyToUser() {
|
||||
this.$refs.copyForm.validate((valid) => {
|
||||
if (valid) {
|
||||
const { theme, name, oldname } = this.copyForm;
|
||||
if (theme) {
|
||||
// copy
|
||||
this.userTheme.push({
|
||||
update: Date.now(),
|
||||
name,
|
||||
theme
|
||||
});
|
||||
} else {
|
||||
// rename
|
||||
this.userTheme.forEach((config) => {
|
||||
if (config.name === oldname) {
|
||||
config.update = Date.now();
|
||||
config.name = name;
|
||||
}
|
||||
});
|
||||
}
|
||||
this.saveToLocal();
|
||||
this.closeCopyForm();
|
||||
}
|
||||
});
|
||||
},
|
||||
filterUserThemeByName(name, include = true) {
|
||||
return this.userTheme.filter((theme) => (include ? theme.name === name : theme.name !== name));
|
||||
},
|
||||
saveToLocal() {
|
||||
saveUserThemeToLocal(this.userTheme);
|
||||
},
|
||||
deleteUserThemeByName(name) {
|
||||
this.userTheme = this.filterUserThemeByName(name, false);
|
||||
this.saveToLocal();
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
BIN
examples/extension/src/editor/icon-close.png
Normal file
BIN
examples/extension/src/editor/icon-close.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.1 KiB |
BIN
examples/extension/src/editor/icon-entrance.png
Normal file
BIN
examples/extension/src/editor/icon-entrance.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.2 KiB |
13
examples/extension/src/editor/index.vue
Normal file
13
examples/extension/src/editor/index.vue
Normal file
@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<editor />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import editor from './editor';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
editor
|
||||
}
|
||||
};
|
||||
</script>
|
18
examples/extension/src/editor/utils.js
Normal file
18
examples/extension/src/editor/utils.js
Normal file
@ -0,0 +1,18 @@
|
||||
const ELEMENT_THEME_USER_CONFIG = 'ELEMENT_THEME_USER_CONFIG';
|
||||
export const loadFromLocal = (key) => {
|
||||
return new window.Promise((resolve) => {
|
||||
chrome.storage.local.get([key], (result) => {
|
||||
resolve(result[key]);
|
||||
});
|
||||
});
|
||||
};
|
||||
export const saveToLocal = (key, value) => {
|
||||
chrome.storage.local.set({[key]: value});
|
||||
};
|
||||
|
||||
export const loadUserThemeFromLocal = () => {
|
||||
return loadFromLocal(ELEMENT_THEME_USER_CONFIG);
|
||||
};
|
||||
export const saveUserThemeToLocal = (value) => {
|
||||
saveToLocal(ELEMENT_THEME_USER_CONFIG, value);
|
||||
};
|
7
examples/extension/src/entry.js
Normal file
7
examples/extension/src/entry.js
Normal file
@ -0,0 +1,7 @@
|
||||
import init from './app';
|
||||
|
||||
if (!window.ElementThemeRollerInit) {
|
||||
window.ElementThemeRollerInit = true;
|
||||
init();
|
||||
}
|
||||
|
BIN
examples/extension/src/icon.png
Normal file
BIN
examples/extension/src/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
27
examples/extension/src/manifest.json
Normal file
27
examples/extension/src/manifest.json
Normal file
@ -0,0 +1,27 @@
|
||||
{
|
||||
"name": "Element Theme Roller",
|
||||
"version": "0.0.9",
|
||||
"description": "Customize all Design Tokens of Element UI and preview in real-time",
|
||||
"web_accessible_resources": ["entry.js"],
|
||||
"background": {
|
||||
"scripts": [
|
||||
"background.js"
|
||||
],
|
||||
"persistent": true
|
||||
},
|
||||
"icons": {
|
||||
"128": "icon.png"
|
||||
},
|
||||
"browser_action": {
|
||||
"default_icon": "icon.png",
|
||||
"default_title": "Element Theme Roller"
|
||||
},
|
||||
"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",
|
||||
"manifest_version": 2,
|
||||
"permissions": [
|
||||
"activeTab",
|
||||
"storage",
|
||||
"https://*.ele.me/",
|
||||
"https://*.elenet.me/"
|
||||
]
|
||||
}
|
@ -18,6 +18,8 @@
|
||||
"build:umd": "node build/bin/build-locale.js",
|
||||
"clean": "rimraf lib && rimraf packages/*/lib && rimraf test/**/coverage",
|
||||
"deploy:build": "npm run build:file && cross-env NODE_ENV=production webpack --config build/webpack.demo.js && echo element.eleme.io>>examples/element-ui/CNAME",
|
||||
"deploy:extension": "cross-env NODE_ENV=production webpack --config build/webpack.extension.js",
|
||||
"dev:extension": "rimraf examples/extension/dist && cross-env NODE_ENV=development webpack --watch --config build/webpack.extension.js",
|
||||
"dev": "npm run bootstrap && npm run build:file && cross-env NODE_ENV=development webpack-dev-server --config build/webpack.demo.js & node build/bin/template.js",
|
||||
"dev:play": "npm run build:file && cross-env NODE_ENV=development PLAY_ENV=true webpack-dev-server --config build/webpack.demo.js",
|
||||
"dist": "npm run clean && npm run build:file && npm run lint && webpack --config build/webpack.conf.js && webpack --config build/webpack.common.js && webpack --config build/webpack.component.js && npm run build:utils && npm run build:umd && npm run build:theme",
|
||||
|
Loading…
Reference in New Issue
Block a user