Commit ac3aa995 authored by iamkun's avatar iamkun Committed by hetech

Chore: support theme configuration (#15190)

parent 792979b5
<?xml version="1.0" encoding="UTF-8"?>
<svg width="13px" height="12px" viewBox="0 0 13 12" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 54.1 (76490) - https://sketchapp.com -->
<title>icon-redo</title>
<desc>Created with Sketch.</desc>
<g id="theme" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="element-theme-editor" transform="translate(-1118.000000, -167.000000)" fill="#606266" fill-rule="nonzero">
<g id="custom" transform="translate(1060.000000, 146.000000)">
<g id="Group-2" transform="translate(30.000000, 15.000000)">
<g id="Group" transform="translate(0.000000, 4.000000)">
<g id="icon-clockwise" transform="translate(26.000000, 0.000000)">
<path d="M12.2585,3.59833136 L12.2585,2.3085 L13.2585,2.3085 L13.2585,5.6365 L9.9295,5.6365 L9.9295,4.6365 L11.8833737,4.6365 C10.9510824,3.62012881 9.6272717,3.0179 8.2,3.0179 C5.43814237,3.0179 3.2,5.25604237 3.2,8.0179 C3.2,10.7797576 5.43814237,13.0179 8.2,13.0179 C10.9618576,13.0179 13.2,10.7797576 13.2,8.0179 L14.2,8.0179 C14.2,11.3320424 11.5141424,14.0179 8.2,14.0179 C4.88585763,14.0179 2.2,11.3320424 2.2,8.0179 C2.2,4.70375763 4.88585763,2.0179 8.2,2.0179 C9.73531163,2.0179 11.1716793,2.59926473 12.2585,3.59833136 Z" id="icon-redo"></path>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="13px" height="12px" viewBox="0 0 13 12" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 54.1 (76490) - https://sketchapp.com -->
<title>icon-undo</title>
<desc>Created with Sketch.</desc>
<g id="theme" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="element-theme-editor" transform="translate(-1092.000000, -167.000000)" fill="#606266" fill-rule="nonzero">
<g id="custom" transform="translate(1060.000000, 146.000000)">
<g id="Group-2" transform="translate(30.000000, 15.000000)">
<g id="Group" transform="translate(0.000000, 4.000000)">
<g id="icon-clockwise">
<path d="M12.2585,3.59833136 L12.2585,2.3085 L13.2585,2.3085 L13.2585,5.6365 L9.9295,5.6365 L9.9295,4.6365 L11.8833737,4.6365 C10.9510824,3.62012881 9.6272717,3.0179 8.2,3.0179 C5.43814237,3.0179 3.2,5.25604237 3.2,8.0179 C3.2,10.7797576 5.43814237,13.0179 8.2,13.0179 C10.9618576,13.0179 13.2,10.7797576 13.2,8.0179 L14.2,8.0179 C14.2,11.3320424 11.5141424,14.0179 8.2,14.0179 C4.88585763,14.0179 2.2,11.3320424 2.2,8.0179 C2.2,4.70375763 4.88585763,2.0179 8.2,2.0179 C9.73531163,2.0179 11.1716793,2.59926473 12.2585,3.59833136 Z" id="icon-undo" transform="translate(8.200000, 8.017900) scale(-1, 1) translate(-8.200000, -8.017900) "></path>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="26px" height="26px" viewBox="0 0 26 26" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 54.1 (76490) - https://sketchapp.com -->
<title>icon_upload</title>
<desc>Created with Sketch.</desc>
<g id="theme" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="element-theme" transform="translate(-207.000000, -662.000000)" fill="#909399">
<g id="section" transform="translate(70.000000, 511.000000)">
<g id="card" transform="translate(0.000000, 60.000000)">
<g id="btn" transform="translate(108.000000, 91.000000)">
<g id="icon-upload" transform="translate(29.000000, 0.000000)">
<path d="M13,-0.000600000001 L3.015,9.9854 L4.429,11.3984 L12,3.8284 L12,20.4854 L14.001,20.4854 L14.001,3.8284 L21.572,11.3984 L22.986,9.9854 L14.415,1.4144 L13,-0.000600000001 Z M13,2.8284 L13.158,2.9844 L12.843,2.9844 L13,2.8284 Z M24.001,19.9854 L24.001,23.9854 L2,23.9854 L2,19.9854 L0,19.9854 L0,25.9854 L26.001,25.9854 L26.001,19.9854 L24.001,19.9854 Z" id="icon_upload"></path>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
......@@ -301,6 +301,15 @@
:to="`/${ lang }/component`">{{ langConfig.components }}
</router-link>
</li>
<li
class="nav-item"
v-if="showThemeConfigurator"
>
<router-link
active-class="active"
:to="`/${ lang }/theme`">{{ langConfig.theme }}
</router-link>
</li>
<li class="nav-item">
<router-link
active-class="active"
......@@ -364,8 +373,7 @@
<!--theme picker-->
<li class="nav-item nav-theme-switch" v-show="isComponentPage">
<theme-configurator :key="lang" v-if="showThemeConfigurator"></theme-configurator>
<theme-picker v-else></theme-picker>
<theme-picker v-if="!showThemeConfigurator"></theme-picker>
</li>
</ul>
</div>
......@@ -374,12 +382,13 @@
</template>
<script>
import ThemePicker from './theme-picker.vue';
import ThemeConfigurator from './theme-configurator';
import AlgoliaSearch from './search.vue';
import compoLang from '../i18n/component.json';
import Element from 'main/index.js';
import { getVars } from './theme-configurator/utils/api.js';
import themeLoader from './theme/loader';
import { getVars } from './theme/loader/api.js';
import bus from '../bus';
import { ACTION_USER_CONFIG_UPDATE } from './theme/constant.js';
const { version } = Element;
......@@ -401,9 +410,10 @@
};
},
mixins: [themeLoader],
components: {
ThemePicker,
ThemeConfigurator,
AlgoliaSearch
},
......@@ -470,7 +480,7 @@
xhr.open('GET', '/versions.json');
xhr.send();
let primaryLast = '#409EFF';
bus.$on('user-theme-config-update', (val) => {
bus.$on(ACTION_USER_CONFIG_UPDATE, (val) => {
let primaryColor = val.global['$--color-primary'];
if (!primaryColor) primaryColor = '#409EFF';
const base64svg = 'data:image/svg+xml;base64,';
......
<template>
<div class="configurator-action">
<div class="action-group">
<el-tooltip :content="getActionDisplayName('undo')">
<img
src="../../assets/images/icon-undo.svg"
@click="onUndo"
:class="{ 'active': userConfigHistory.length > 0 }"
/>
</el-tooltip>
<el-tooltip :content="getActionDisplayName('redo')">
<img
src="../../assets/images/icon-redo.svg"
@click="onRedo"
:class="{ 'active': userConfigRedoHistory.length > 0 }"
/>
</el-tooltip>
<div class="button-group">
<el-button
class="reset"
type="primary"
round
size="mini"
:disabled="isOfficial"
@click="onReset"
>
{{getActionDisplayName('reset-theme')}}
</el-button>
<el-button
class="download"
type="primary"
round
size="mini"
:disabled="downloadDisabled"
@click="onDownload"
>
{{getActionDisplayName('download-theme')}}
</el-button>
</div>
</div>
<el-select v-model="selectedComponent" class="selector">
<el-option
v-for="item in selectOptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
<div class="line"></div>
</div>
</template>
<style lang="scss">
.configurator-action {
padding: 15px 18px 0;
.action-group {
padding: 5px 0;
img {
cursor: not-allowed;
width: 16px;
height: 16px;
padding: 7px 0;
margin-left: 5px;
opacity: .5;
&.active {
opacity: 1;
cursor: pointer;
}
&:last-of-type {
margin-left: 10px;
}
}
.button-group {
float: right;
.el-button {
padding: 6px 15px;
&.is-disabled {
color: #C0C4CC;
background-color: #fff;
border-color: #EBEEF5;
}
}
.reset {
background: #E6F1FC;
color: #1989FA;
border-color: #A2CFFC;
}
.download {
background: #1989FA;
color: #FFF;
border-color: #1989FA
}
}
}
.selector {
width: 100%;
input {
background: #f5f7fa;
border: none;
font-size: 18px;
padding-left: 0;
color: #606266;
}
}
.line {
width: 100%;
height: 0;
border-bottom: 1px solid #DCDFE6;
}
}
</style>
<script>
import { getActionDisplayName } from './utils/utils';
export default {
props: {
selectOptions: Array,
userConfigHistory: Array,
userConfigRedoHistory: Array,
isOfficial: Boolean,
onUndo: Function,
onRedo: Function
},
data() {
return {
selectedComponent: 'color',
downloadDisabled: false
};
},
watch: {
selectedComponent: {
handler(val) {
this.$emit('select', val);
}
}
},
methods: {
getActionDisplayName(key) {
return getActionDisplayName(key);
},
onReset() {
this.$parent.onReset();
},
onDownload() {
this.downloadDisabled = true;
this.$parent.onDownload();
setTimeout(() => {
this.downloadDisabled = false;
}, 2500);
}
}
};
</script>
\ No newline at end of file
<template>
<div class="action-area">
<div class="action-area-main">
<div class="action-button">
<el-button type="warning" @click.stop="onReset">{{getActionDisplayName("reset-theme")}}</el-button>
</div>
<div class="action-button">
<el-button
type="primary"
:loading=downloading
style="background: #66b1ff;border-color: #66b1ff"
@click.stop="onDownload">
{{getActionDisplayName("download-theme")}}
</el-button>
</div>
</div>
</div>
</template>
<style>
.action-area {
width: 24%;
max-width: 400px;
position: fixed;
right: 0;
bottom: 0;
padding-right: 1%;
}
@media (min-width: 1600px) {
.action-area {
padding-right: calc((100% - 1600px) / 2);
}
}
.action-area-main {
opacity: .95;
background: #F5F7FA;
height: 70px;
bottom: 0;
width: 97%;
box-sizing: border-box;
margin: 0 .5% 0 5%;
}
.action-button {
width: 50%;
text-align: center;
display: inline-block;
padding-top: 15px;
}
</style>
<script>
import { getActionDisplayName } from './utils/utils.js';
export default {
data() {
return {
downloading: false
};
},
methods: {
onReset() {
this.$parent.onReset();
},
getActionDisplayName(key) {
return getActionDisplayName(key);
},
onDownload() {
this.downloading = true;
this.$parent.onDownload()
.then()
.catch((err) => {
this.$parent.onError(err);
})
.then(() => {
this.downloading = false;
});
ga('send', 'event', 'ThemeConfigurator', 'Download');
}
}
};
</script>
\ No newline at end of file
<template>
<section class="config" :key="displayName">
<div class="config-label">
{{displayName}}
<el-tooltip :content="displayName">
<span>{{displayKeyName}}</span>
</el-tooltip>
</div>
<div class="config-content">
<theme-input
......@@ -10,6 +12,7 @@
@change="onChange"
></theme-input>
<el-select
size="medium"
v-if="!isGlobal"
v-model="value"
class="select"
......
<template>
<section class="config" :key="displayName">
<div class="config-label">
{{displayName}}
<el-tooltip :content="displayName">
<span>{{displayKeyName}}</span>
</el-tooltip>
<el-button
class="plus-button"
size="mini"
......
......@@ -29,6 +29,7 @@
<el-button
plain
size="mini"
type="primary"
class="el-color-dropdown__btn"
@click="confirmValue">
{{ t('el.colorpicker.confirm') }}
......
<template>
<section class="config" :key="displayName">
<div class="config-label">
{{displayName}}
<el-tooltip :content="displayName">
<span>{{displayKeyName}}</span>
</el-tooltip>
</div>
<div class="config-content">
<div class="content-80">
<el-input
size="medium"
:value=displayValue
readonly
slot="reference"
......@@ -14,6 +17,7 @@
</div>
<div class="content-20">
<color-picker
size="medium"
ref="colorPicker"
class="colorPicker"
v-model="pickerColor"
......
<template>
<section class="config" :key="displayName">
<div class="config-label">
{{displayName}}
<el-tooltip :content="displayName">
<span>{{displayKeyName}}</span>
</el-tooltip>
</div>
<div class="config-content">
<el-select
v-model="value"
class="select"
size="medium"
@change="onSelectChange"
>
<el-option
......
<template>
<section class="config" :key="displayName">
<div class="config-label">
{{displayName}}
<el-tooltip :content="displayName">
<span>{{displayKeyName}}</span>
</el-tooltip>
</div>
<div class="config-content">
<el-select
v-model="value"
class="select"
size="medium"
@change="onSelectChange"
>
<el-option
......@@ -34,6 +37,7 @@ const defaultFontSize = [
'16px',
'18px',
'20px',
'22px',
'28px',
'36px',
'48px'
......
<template>
<section class="config" :key="displayName">
<div class="config-label">
{{displayName}}
<el-tooltip :content="displayName">
<span>{{displayKeyName}}</span>
</el-tooltip>
</div>
<div class="config-content">
<el-select
v-model="value"
class="select"
size="medium"
@change="onSelectChange"
>
<el-option
......
......@@ -5,7 +5,7 @@
.config-label {
color: #606266;;
font-size: 14px;
padding-bottom: 5px;
padding-bottom: 8px;
position: relative;
}
.config-content {
......@@ -59,6 +59,12 @@ export default {
displayName() {
return getStyleDisplayName(this.config, this.componentName);
},
displayKeyName() {
if (this.config.name) {
return this.config.key.replace('$--', '');
}
return this.config.key.replace(`$--${this.componentName}-`, '');
},
isGlobal() {
return !this.config.value.startsWith('$');
}
......
<template>
<section class="config" :key="displayName">
<div class="config-label">
{{displayName}}
<el-tooltip :content="displayName">
<span>{{displayKeyName}}</span>
</el-tooltip>
</div>
<div class="config-content">
<theme-input
:val="value"
size="medium"
@change="onChange"
></theme-input>
</div>
......
<template>
<div class="main">
<div class="main" ref="mainPanel">
<!-- <span>{{configName}}</span> -->
<div v-for="(config, key) in configByOrder" :key="key">
<span
v-if="showCategory(config.category, key + 1)"
class="category-name"
>
{{getCategoryDisplayName(config.category)}}
{{config.category}}
</span>
<component
:is="editorComponent(config.type)"
......@@ -23,14 +23,14 @@
<style>
.main {
margin-bottom: 140px;
padding: 10px;
padding: 0 18px 15px;
overflow-y: auto;
}
.category-name {
color: #C0C4CC;
font-size: 18px;
display: block;
margin: 8px 0 4px 0;
margin: 13px 0 3px 0;
}
</style>
......@@ -42,7 +42,7 @@ import fontLineHeightEditor from './editor/fontLineHeight';
import borderRadiusEditor from './editor/borderRadius';
import boxShadowEditor from './editor/boxShadow';
import simpleTextEditor from './editor/simpleText';
import { filterConfigType, getCategoryDisplayName } from './utils/utils.js';
import { filterConfigType } from './utils/utils.js';
export default {
components: {
......@@ -80,9 +80,6 @@ export default {
}
},
methods: {
getCategoryDisplayName(key) {
return getCategoryDisplayName(key);
},
editorComponent(type) {
switch (type) {
case 'color':
......@@ -119,6 +116,15 @@ export default {
return {
categoryDisplay: {}
};
},
watch: {
currentConfig: {
handler() {
this.$nextTick(() => {
this.$refs.mainPanel.scrollTo(0, 0);
});
}
}
}
};
</script>
\ No newline at end of file
......@@ -55,7 +55,7 @@ export const getStyleDisplayName = (config, componentName) => {
if (config.name) {
return getVariableDisplayName(config.key.replace('$--', ''));
}
let displayName = config.key.replace(`$--${componentName}-`, '').replace();
let displayName = config.key.replace(`$--${componentName}-`, '');
Object.keys(displayNameMap).forEach((name) => {
displayName = displayName.replace(name, displayNameMap[name]);
});
......@@ -66,17 +66,3 @@ export const getStyleDisplayName = (config, componentName) => {
export const getActionDisplayName = (key) => {
return getNameFromI18N('action')[key] || key;
};
export const getCategoryDisplayName = (key) => {
return getNameFromI18N('category')[key] || key;
};
export const updateDomHeadStyle = (id, styleContent) => {
let styleTag = document.getElementById(id);
if (!styleTag) {
styleTag = document.createElement('style');
styleTag.setAttribute('id', id);
document.head.appendChild(styleTag);
}
styleTag.innerText = styleContent.replace(/@font-face{[^}]+}/, '');
};
<style lang="scss">
.component-preview {
.heading>div{
margin-bottom: 15px;
}
.title {
font-size: 18px;
font-weight:400;
padding: 0 20px
}
.paragraph {
padding: 0 20px
}
.demo-color-box {
margin: 0;
}
.color {
margin-right: -12%;
}
}
</style>
<template>
<div class="component-preview">
<h4>Color</h4>
<div class="color">
<el-row :gutter="12">
<el-col :span="4" v-for="(color, key) in colorLine" :key="key">
<div class="demo-color-box" :style="{ background: dataProxy(color) }">
{{color}}
<div class="value">{{dataProxy(color)}}</div>
<div class="bg-color-sub">
<div
class="bg-success-sub-item"
v-for="(item, key) in Array(2)"
:key="key"
:style="{ background: tintColor(dataProxy(color), (key + 8) / 10) }"
></div>
</div>
</div>
</el-col>
</el-row>
<el-row :gutter="12">
<el-col :span="4">
<div class="demo-color-box demo-color-box-other" :style="{ background: color_text_primary }">
Primary Text
<div class="value">{{color_text_primary}}</div>
</div>
</el-col>
<el-col :span="4">
<div class="demo-color-box demo-color-box-other" :style="{ background: color_text_regular }">
Regular Text
<div class="value">{{color_text_regular}}</div>
</div>
</el-col>
<el-col :span="4">
<div class="demo-color-box demo-color-box-other" :style="{ background: color_text_secondary }">
Secondary Text
<div class="value">{{color_text_secondary}}</div>
</div>
</el-col>
<el-col :span="4">
<div class="demo-color-box demo-color-box-other" :style="{ background: color_text_placeholder }">
Placeholder
<div class="value">{{color_text_placeholder}}</div>
</div>
</el-col>
</el-row>
<el-row :gutter="12">
<el-col :span="4">
<div
class="demo-color-box demo-color-box-other demo-color-box-lite"
:style="{ background: border_color_base }"
>
Border Base
<div class="value">{{border_color_base}}</div>
</div>
</el-col>
<el-col :span="4">
<div
class="demo-color-box demo-color-box-other demo-color-box-lite"
:style="{ background: border_color_light }"
>
Border Light
<div class="value">{{border_color_light}}</div>
</div>
</el-col>
<el-col :span="4">
<div
class="demo-color-box demo-color-box-other demo-color-box-lite"
:style="{ background: border_color_lighter }"
>
Border Lighter
<div class="value">{{border_color_lighter}}</div>
</div>
</el-col>
<el-col :span="4">
<div
class="demo-color-box demo-color-box-other demo-color-box-lite"
:style="{ background: border_color_extra_light }"
>
Border Extralight
<div class="value">{{border_color_extra_light}}</div>
</div>
</el-col>
</el-row>
<el-row :gutter="12">
<el-col :span="4">
<div class="demo-color-box demo-color-box-other" :style="{ background: color_black }">
Background B
<div class="value">{{color_black}}</div>
</div>
</el-col>
<el-col :span="4">
<div
class="demo-color-box demo-color-box-other"
:style="{ background: color_white, color: '#303133', border: '1px solid #eee' }"
>
Background W
<div class="value">{{color_white}}</div>
</div>
</el-col>
<el-col :span="4">
<div class="demo-color-box demo-color-box-other bg-transparent">
Background
<div class="value">Transparent</div>
</div>
</el-col>
</el-row>
</div>
<h4>Typography</h4>
<el-row :gutter="12">
<el-col :span="6" class="heading">
<div :style="{ fontSize: font_size_extra_large }">Heading1</div>
<div :style="{ fontSize: font_size_large }">Heading2</div>
<div :style="{ fontSize: font_size_medium }">Heading3</div>
<div :style="{ fontSize: font_size_base }">Heading4</div>
<div :style="{ fontSize: font_size_small }">Heading5</div>
<div :style="{ fontSize: font_size_extra_small }">Heading6</div>
</el-col>
<el-col :span="9">
<div class="title">Example body text</div>
<p
class="paragraph"
:style="{
fontSize: font_size_base,
fontWeight: font_weight_primary,
lineHeight: font_line_height_primary
}" >
With MySpace becoming more popular every day, there is the constant need to be different. There are millions of users. If MySpace layouts are chosen well, then you can enhance your profile a great deal.</p>
</el-col>
<el-col :span="9">
<div class="title">Example small text</div>
<p
class="paragraph"
:style="{
fontSize: font_size_small,
fontWeight: font_weight_secondary,
lineHeight: font_line_height_secondary
}" >
Computers have become ubiquitous in almost every facet of our lives. At work, desk jockeys spend hours in front of their desktops, while delivery people scan bar codes with handhelds and workers in the field stay in touch with the central office via their notebooks. Computer hardware weaves itself through the fabric of our lives.</p>
</el-col>
</el-row>
</div>
</template>
<script>
import bus from '../../bus';
import { tintColor } from '../../color.js';
import {
ACTION_COMPONECT_SELECT,
ACTION_USER_CONFIG_UPDATE
} from './constant.js';
const original = {
'color_primary': '#409EFF',
'color_success': '#67C23A',
'color_warning': '#E6A23C',
'color_danger': '#F56C6C',
'color_info': '#909399',
'color_white': '#FFFFFF',
'color_black': '#000000',
'color_text_primary': '#303133',
'color_text_regular': '#606266',
'color_text_secondary': '#909399',
'color_text_placeholder': '#C0C4CC',
'border_color_base': '#DCDFE6',
'border_color_light': '#E4E7ED',
'border_color_lighter': '#EBEEF5',
'border_color_extra_light': '#F2F6FC',
'font_size_extra_large': '20px',
'font_size_large': '18px',
'font_size_medium': '16px',
'font_size_base': '14px',
'font_size_small': '13px',
'font_size_extra_small': '12px',
'font_weight_primary': 500,
'font_weight_secondary': 100,
'font_line_height_primary': '24px',
'font_line_height_secondary': '16px'
};
export default {
created() {
bus.$on(ACTION_USER_CONFIG_UPDATE, this.setGlobal);
bus.$on(ACTION_COMPONECT_SELECT, (val) => {
this.$nextTick(() => {
const getSelectElement = Array.from(document.querySelectorAll('h4')).filter((el) => (el.innerText.toLowerCase() === val));
if (getSelectElement[0]) {
const elementTop = getSelectElement[0].getBoundingClientRect().top;
window.scrollTo(0, window.pageYOffset + elementTop - 20); // 20 for padding
}
});
});
},
mounted() {
this.setGlobal();
},
methods: {
tintColor(a, b) {
return tintColor(a, b);
},
dataProxy(value) {
return this[`color_${value.toLowerCase()}`];
},
setGlobal() {
if (window.userThemeConfig) {
this.global = window.userThemeConfig.global;
}
}
},
watch: {
global: {
immediate: true,
handler(value) {
Object.keys(original).forEach((v) => {
const key = `$--${v.replace(/_/g, '-')}`;
if (value[key]) {
this[v] = value[key];
} else {
this[v] = original[v];
}
});
}
}
},
data() {
return {
global: {},
colorLine: ['Primary', 'Success', 'Warning', 'Danger', 'Info'],
'color_primary': '',
'color_success': '',
'color_warning': '',
'color_danger': '',
'color_info': '',
'color_white': '',
'color_black': '',
'color_text_primary': '',
'color_text_regular': '',
'color_text_secondary': '',
'color_text_placeholder': '',
'border_color_base': '',
'border_color_light': '',
'border_color_lighter': '',
'border_color_extra_light': '',
'font_size_extra_large': '',
'font_size_large': '',
'font_size_medium': '',
'font_size_base': '',
'font_size_small': '',
'font_size_extra_small': '',
'font_weight_primary': 0,
'font_weight_secondary': 0,
'font_line_height_primary': '',
'font_line_height_secondary': ''
};
}
};
</script>
This diff is collapsed.
export const DEFAULT_THEME_CONFIG = {
global: {},
local: {}
};
export const ELEMENT_THEME_USER_CONFIG = 'ELEMENT_THEME_USER_CONFIG';
export const ELEMENT_THEME_PREVIEW_CONFIG = 'ELEMENT_THEME_PREVIEW_CONFIG';
export const ACTION_DOWNLOAD_THEME = 'ELEMENT_THEME_ACTION_DOWNLOAD';
export const ACTION_APPLY_THEME = 'ELEMENT_THEME_ACTION_ALLPY_CSS';
export const ACTION_COMPONECT_SELECT = 'ELEMENT_THEME_ACTION_COMPONECT_SELECT';
export const ACTION_USER_CONFIG_UPDATE = 'ELEMENT_THEME_USER_CONFIG_UPDATE';
<script>
const ORIGINAL_THEME = '#409EFF';
import { get as ajaxGet } from './utils/ajax';
import { updateDomHeadStyle } from './utils/utils.js';
import { get as ajaxGet } from './ajax.js';
import { updateDomHeadStyle } from '../utils.js';
export default {
data() {
return {
......
<script>
import bus from '../../../bus.js';
import Loading from './loading';
import DocStyle from './docStyle';
import { updateVars } from './api.js';
import { updateDomHeadStyle } from '../utils.js';
import {
ACTION_APPLY_THEME,
ACTION_DOWNLOAD_THEME,
ACTION_USER_CONFIG_UPDATE
} from '../constant.js';
import {
loadUserThemeFromLocal,
loadPreviewFromLocal
} from '../localstorage.js';
import { getActionDisplayName } from '../../theme-configurator/utils/utils';
export default {
mixins: [Loading, DocStyle],
mounted() {
this.checkLocalThemeConfig();
bus.$on(ACTION_APPLY_THEME, val => {
this.userConfig = val;
this.onAction();
});
bus.$on(ACTION_DOWNLOAD_THEME, val => {
this.onDownload(val);
});
},
data() {
return {
userConfig: {},
lastApply: 0
};
},
methods: {
applyStyle(res, time) {
if (time < this.lastApply) return;
this.updateDocs(() => {
updateDomHeadStyle('chalk-style', res);
});
this.lastApply = time;
},
onDownload(themeConfig) {
this.triggertProgressBar(true);
updateVars(
Object.assign({}, themeConfig, { download: true }),
xhr => {
xhr.responseType = 'blob';
}
).then()
.catch((err) => {
this.onError(err);
})
.then(() => {
this.triggertProgressBar(false);
});
ga('send', 'event', 'ThemeConfigurator', 'Download');
},
onAction() {
this.triggertProgressBar(true);
const time = +new Date();
updateVars(this.userConfig)
.then(res => {
this.applyStyle(res, time);
})
.catch(err => {
this.onError(err);
})
.then(() => {
this.triggertProgressBar(false);
});
},
onError(err) {
let message;
try {
message = JSON.parse(err).message;
} catch (e) {
message = err;
}
this.$message.error(message);
},
triggertProgressBar(isLoading) {
bus.$emit('user-theme-config-loading', isLoading);
},
updateDocs(cb) {
window.userThemeConfig = JSON.parse(JSON.stringify(this.userConfig));
bus.$emit(ACTION_USER_CONFIG_UPDATE, this.userConfig);
this.updateDocStyle(this.userConfig, cb);
},
checkLocalThemeConfig() {
// load user local theme
const previewConfig = loadPreviewFromLocal();
if (previewConfig.type === 'user') {
const userConfig = loadUserThemeFromLocal();
this.$message(getActionDisplayName('load-local-theme-config'));
const config = userConfig.filter(theme => (theme.name === previewConfig.name));
if (config && config[0]) {
this.userConfig = JSON.parse(config[0].theme);
this.onAction();
}
}
}
}
};
</script>
\ No newline at end of file
......@@ -9,7 +9,7 @@
</style>
<script>
import bus from '../../bus.js';
import bus from '../../../../bus.js';
import './progress.js';
export default {
......
import {
ELEMENT_THEME_PREVIEW_CONFIG,
ELEMENT_THEME_USER_CONFIG
} from './constant';
export const saveToLocal = (key, value) => {
localStorage.setItem(key, JSON.stringify(value));
};
export const loadFromLocal = (key) => {
try {
return JSON.parse(localStorage.getItem(key));
} catch (e) {
console.error(e);
return null;
}
};
export const savePreviewToLocal = (value) => {
saveToLocal(ELEMENT_THEME_PREVIEW_CONFIG, value);
};
export const loadPreviewFromLocal = () => {
return loadFromLocal(ELEMENT_THEME_PREVIEW_CONFIG) || {};
};
export const removePreviewFromLocal = () => {
return localStorage.removeItem(ELEMENT_THEME_PREVIEW_CONFIG);
};
export const saveUserThemeToLocal = (value) => {
saveToLocal(ELEMENT_THEME_USER_CONFIG, value);
};
export const loadUserThemeFromLocal = () => {
return loadFromLocal(ELEMENT_THEME_USER_CONFIG);
};
This diff is collapsed.
const themeList = [
{
name: 'Element',
author: 'Element',
theme: '{"global":{"$--color-primary":"#409EFF"},"local":{}}'
},
{
name: 'Napos',
author: 'Element',
theme: '{"global":{"$--color-primary":"#1989FA"},"local":{}}'
}
];
export default themeList;
export const isEmptyObject = (obj) => (JSON.stringify(obj) === '{}');
export const getThemeConfigObject = (config) => {
try {
const conf = JSON.parse(config);
const { global, local } = conf;
if (!isEmptyObject(global) || !isEmptyObject(local)) {
return conf;
}
return false;
} catch (e) {
return false;
}
};
export const updateDomHeadStyle = (id, styleContent) => {
let styleTag = document.getElementById(id);
if (!styleTag) {
styleTag = document.createElement('style');
styleTag.setAttribute('id', id);
document.head.appendChild(styleTag);
}
styleTag.innerText = styleContent.replace(/@font-face{[^}]+}/, '');
};
<script>
import bus from '../../bus';
import { ACTION_USER_CONFIG_UPDATE } from '../../components/theme/constant.js';
const varMap = {
'$--box-shadow-light': 'boxShadowLight',
'$--box-shadow-base': 'boxShadowBase',
......@@ -14,7 +15,7 @@
}
export default {
created() {
bus.$on('user-theme-config-update', this.setGlobal);
bus.$on(ACTION_USER_CONFIG_UPDATE, this.setGlobal);
},
mounted() {
this.setGlobal();
......
<script>
import bus from '../../bus';
import { tintColor } from '../../color.js';
import { ACTION_USER_CONFIG_UPDATE } from '../../components/theme/constant.js';
const varMap = {
'primary': '$--color-primary',
'success': '$--color-success',
......@@ -37,7 +38,7 @@
}
export default {
created() {
bus.$on('user-theme-config-update', this.setGlobal);
bus.$on(ACTION_USER_CONFIG_UPDATE, this.setGlobal);
},
mounted() {
this.setGlobal();
......
<script>
import bus from '../../bus';
import { ACTION_USER_CONFIG_UPDATE } from '../../components/theme/constant.js';
const varMap = [
'$--font-size-extra-large',
'$--font-size-large',
......@@ -18,7 +19,7 @@
}
export default {
created() {
bus.$on('user-theme-config-update', this.setGlobal);
bus.$on(ACTION_USER_CONFIG_UPDATE, this.setGlobal);
},
mounted() {
this.setGlobal();
......
<script>
import bus from '../../bus';
import { ACTION_USER_CONFIG_UPDATE } from '../../components/theme/constant.js';
const varMap = {
'$--box-shadow-light': 'boxShadowLight',
'$--box-shadow-base': 'boxShadowBase',
......@@ -14,7 +15,7 @@
}
export default {
created() {
bus.$on('user-theme-config-update', this.setGlobal);
bus.$on(ACTION_USER_CONFIG_UPDATE, this.setGlobal);
},
mounted() {
this.setGlobal();
......
<script>
import bus from '../../bus';
import { tintColor } from '../../color.js';
import { ACTION_USER_CONFIG_UPDATE } from '../../components/theme/constant.js';
const varMap = {
'primary': '$--color-primary',
'success': '$--color-success',
......@@ -37,7 +38,7 @@
}
export default {
created() {
bus.$on('user-theme-config-update', this.setGlobal);
bus.$on(ACTION_USER_CONFIG_UPDATE, this.setGlobal);
},
mounted() {
this.setGlobal();
......
<script>
import bus from '../../bus';
import { ACTION_USER_CONFIG_UPDATE } from '../../components/theme/constant.js';
const varMap = [
'$--font-size-extra-large',
'$--font-size-large',
......@@ -18,7 +19,7 @@
}
export default {
created() {
bus.$on('user-theme-config-update', this.setGlobal);
bus.$on(ACTION_USER_CONFIG_UPDATE, this.setGlobal);
},
mounted() {
this.setGlobal();
......
<script>
import bus from '../../bus';
import { ACTION_USER_CONFIG_UPDATE } from '../../components/theme/constant.js';
const varMap = {
'$--box-shadow-light': 'boxShadowLight',
'$--box-shadow-base': 'boxShadowBase',
......@@ -14,7 +15,7 @@
}
export default {
created() {
bus.$on('user-theme-config-update', this.setGlobal);
bus.$on(ACTION_USER_CONFIG_UPDATE, this.setGlobal);
},
mounted() {
this.setGlobal();
......
<script>
import bus from '../../bus';
import { tintColor } from '../../color.js';
import { ACTION_USER_CONFIG_UPDATE } from '../../components/theme/constant.js';
const varMap = {
'primary': '$--color-primary',
'success': '$--color-success',
......@@ -37,7 +38,7 @@
}
export default {
created() {
bus.$on('user-theme-config-update', this.setGlobal);
bus.$on(ACTION_USER_CONFIG_UPDATE, this.setGlobal);
},
mounted() {
this.setGlobal();
......
<script>
import bus from '../../bus';
import { ACTION_USER_CONFIG_UPDATE } from '../../components/theme/constant.js';
const varMap = [
'$--font-size-extra-large',
'$--font-size-large',
......@@ -18,7 +19,7 @@
}
export default {
created() {
bus.$on('user-theme-config-update', this.setGlobal);
bus.$on(ACTION_USER_CONFIG_UPDATE, this.setGlobal);
},
mounted() {
this.setGlobal();
......
<script>
import bus from '../../bus';
import { ACTION_USER_CONFIG_UPDATE } from '../../components/theme/constant.js';
const varMap = {
'$--box-shadow-light': 'boxShadowLight',
'$--box-shadow-base': 'boxShadowBase',
......@@ -14,7 +15,7 @@
}
export default {
created() {
bus.$on('user-theme-config-update', this.setGlobal);
bus.$on(ACTION_USER_CONFIG_UPDATE, this.setGlobal);
},
mounted() {
this.setGlobal();
......
<script>
import bus from '../../bus';
import { tintColor } from '../../color.js';
import { ACTION_USER_CONFIG_UPDATE } from '../../components/theme/constant.js';
const varMap = {
'primary': '$--color-primary',
'success': '$--color-success',
......@@ -37,7 +38,7 @@
}
export default {
created() {
bus.$on('user-theme-config-update', this.setGlobal);
bus.$on(ACTION_USER_CONFIG_UPDATE, this.setGlobal);
},
mounted() {
this.setGlobal();
......
<script>
import bus from '../../bus';
import { ACTION_USER_CONFIG_UPDATE } from '../../components/theme/constant.js';
const varMap = [
'$--font-size-extra-large',
'$--font-size-large',
......@@ -18,7 +19,7 @@
}
export default {
created() {
bus.$on('user-theme-config-update', this.setGlobal);
bus.$on(ACTION_USER_CONFIG_UPDATE, this.setGlobal);
},
mounted() {
this.setGlobal();
......
......@@ -24,6 +24,7 @@
"header": {
"guide": "指南",
"components": "组件",
"theme": "主题",
"resource": "资源"
},
"nav": {
......@@ -55,6 +56,7 @@
"header": {
"guide": "Guide",
"components": "Component",
"theme": "Theme",
"resource": "Resource"
},
"nav": {
......@@ -86,6 +88,7 @@
"header": {
"guide": "Guía",
"components": "Componentes",
"theme": "Theme",
"resource": "Recursos"
},
"nav": {
......@@ -117,6 +120,7 @@
"header": {
"guide": "Guide",
"components": "Composants",
"theme": "Theme",
"resource": "Ressources"
},
"nav": {
......
......@@ -17,6 +17,15 @@
"paraSize": "18"
},
"component": {},
"theme": {
"1": "官方主题",
"2": "我的主题",
"3": "主题名称"
},
"theme-preview": {
"1": "返回"
},
"theme-nav": {},
"changelog": {
"1": "更新日志",
"2": "zh-CN"
......@@ -109,6 +118,15 @@
"paraSize": "18"
},
"component": {},
"theme": {
"1": "Official Theme",
"2": "My Theme",
"3": "Theme name"
},
"theme-preview": {
"1": "Back"
},
"theme-nav": {},
"changelog": {
"1": "Changelog",
"2": "en-US"
......@@ -201,6 +219,15 @@
"paraSize": "18"
},
"component": {},
"theme": {
"1": "Official Theme",
"2": "My Theme",
"3": "Theme name"
},
"theme-preview": {
"1": "Back"
},
"theme-nav": {},
"changelog": {
"1": "Lista de cambios",
"2": "es"
......@@ -293,6 +320,15 @@
"paraSize": "18"
},
"component": {},
"theme": {
"1": "Official Theme",
"2": "My Theme",
"3": "Theme name"
},
"theme-preview": {
"1": "Back"
},
"theme-nav": {},
"changelog": {
"1": "Changelog",
"2": "fr-FR"
......
This diff is collapsed.
......@@ -135,38 +135,6 @@
}
}
@media (min-width: 1140px) {
.page-component__content {
transition:padding-right 0.3s ease;
&.theme-config {
padding-right: 26%;
}
}
.page-container.page-component {
transition:all 0.3s ease;
&.theme-config {
width: 98%;
.page-component__nav {
animation-delay: 1s;
padding-left: 2%;
}
}
}
}
@media (min-width: 1600px) {
.page-component__content {
&.theme-config {
padding-right: 25%;
}
}
.page-container.page-component {
&.theme-config {
width: 1600px;
}
}
}
@media (max-width: 768px) {
.page-component {
.page-component__nav {
......@@ -197,11 +165,11 @@
</style>
<template>
<el-scrollbar class="page-component__scroll" ref="componentScrollBar">
<div class="page-container page-component" :class="{'theme-config': isThemeConfigVisible}">
<div class="page-container page-component">
<el-scrollbar class="page-component__nav">
<side-nav :data="navsData[lang]" :base="`/${ lang }/component`"></side-nav>
</el-scrollbar>
<div class="page-component__content" :class="{'theme-config': isThemeConfigVisible}">
<div class="page-component__content">
<router-view class="content"></router-view>
<footer-nav></footer-nav>
</div>
......@@ -234,8 +202,7 @@
scrollTop: 0,
showHeader: true,
componentScrollBar: null,
componentScrollBoxElement: null,
isThemeConfigVisible: false
componentScrollBoxElement: null
};
},
watch: {
......@@ -296,14 +263,8 @@
bus.$on('navFade', val => {
this.navFaded = val;
});
bus.$on('user-theme-config-visible', val => {
this.isThemeConfigVisible = val;
});
},
mounted() {
if (window.userThemeConfigVisible) {
this.isThemeConfigVisible = window.userThemeConfigVisible;
}
this.componentScrollBar = this.$refs.componentScrollBar;
this.componentScrollBox = this.componentScrollBar.$el.querySelector('.el-scrollbar__wrap');
this.throttledScrollHandler = throttle(300, this.handleScroll);
......
<template>
<router-view></router-view>
</template>
\ No newline at end of file
<style lang="scss">
.page-container.page-theme-preview {
padding-top: 30px;
.display {
width: 75%;
display: inline-block;
vertical-align: top;
h3 {
font-size: 28px;
margin: 30px 0 0 0;
}
}
.side {
display: inline-block;
width: 25%;
.editor {
overflow: hidden;
background: #f5f7fa;
border: 1px solid #ebeef5;
border-radius: 5px;
margin-bottom: 20px;
&.fixed {
position: fixed;
width: 285px;
box-sizing: border-box;
}
}
}
}
</style>
<template>
<div class="page-container page-theme-preview" ref="themePreview">
<section class="display">
<el-button type="text" icon="el-icon-back" @click="navBack">
<%= 1 >
</el-button>
<h3>{{previewConfig.name}}</h3>
<basic-tokens-preview>
</basic-tokens-preview>
<components-preview>
</components-preview>
</section>
<aside class="side">
<section class="editor" :style="{top: `${editorTop}px`, height: `${editorHeight}px`}" :class="{'fixed': isFixed}">
<theme-configurator
:isOfficial="isOfficial"
:themeConfig="themeConfig"
:onUserConfigUpdate="onUserConfigUpdate"
>
</theme-configurator>
</section>
</aside>
</div>
</template>
<script>
import bus from '../../bus.js';
import ThemeConfigurator from '../../components/theme-configurator';
import ComponentsPreview from '../../components/theme/components-preview';
import BasicTokensPreview from '../../components/theme/basic-tokens-preview';
import {
loadPreviewFromLocal,
loadUserThemeFromLocal,
saveUserThemeToLocal
} from '../../components/theme/localstorage';
import {
getThemeConfigObject
} from '../../components/theme/utils';
import {
ACTION_APPLY_THEME
} from '../../components/theme/constant.js';
import throttle from 'throttle-debounce/throttle';
import { getActionDisplayName } from '../../components/theme-configurator/utils/utils';
const maxUserTheme = 8;
export default {
components: {
ThemeConfigurator,
BasicTokensPreview,
ComponentsPreview
},
data() {
return {
previewConfig: {},
themeConfig: {},
userTheme: [],
editorTop: 0,
editorHeight: 1000,
isFixed: false
};
},
computed: {
isOfficial() {
return this.previewConfig.type === 'official';
}
},
created() {
this.throttledHandleScroll = throttle(10, true, index => {
this.handleScroll(index);
});
},
methods: {
navBack() {
this.$router.go(-1);
this.$nextTick(() => {
window.scrollTo(0, 0);
});
},
getNewUserThemeName(originName) {
let n = 1;
let name;
while (true) {
name = `${originName}-${n}`;
if (this.userTheme.filter(theme => (theme.name === name)).length === 0) {
break;
}
n += 1;
}
return name;
},
onUserConfigUpdate(userConfig) {
const themeConfig = JSON.stringify(userConfig);
const { type, name } = this.previewConfig;
if (this.isOfficial) {
if (this.userTheme.length >= maxUserTheme) {
this.$message.error(getActionDisplayName('max-user-theme'));
return;
}
const autoUserName = this.getNewUserThemeName(name);
this.previewConfig.name = autoUserName;
this.previewConfig.type = 'user';
this.userTheme.push({
update: Date.now(),
name: autoUserName,
theme: themeConfig
});
saveUserThemeToLocal(this.userTheme);
return;
}
if (type === 'user') {
this.userTheme.forEach((config) => {
if (config.name === name) {
config.update = Date.now();
config.theme = themeConfig;
}
});
saveUserThemeToLocal(this.userTheme);
}
},
handleScroll() {
const rect = this.$refs.themePreview.getBoundingClientRect();
let offsetTop = rect.top;
let offsetBottom = rect.bottom;
const calHeight = this.editorHeight + 30 + 20;
if (offsetTop < 0) {
this.isFixed = true;
if (offsetBottom < calHeight) {
this.editorTop = 30 - calHeight + offsetBottom;
} else {
this.editorTop = 30;
}
} else {
this.isFixed = false;
this.editorTop = 0;
}
}
},
beforeDestroy() {
window.removeEventListener('scroll', this.throttledHandleScroll);
},
mounted() {
this.editorHeight = window.innerHeight - 40 - 5;
window.addEventListener('scroll', this.throttledHandleScroll);
this.userTheme = loadUserThemeFromLocal();
const previewConfig = loadPreviewFromLocal();
const pageRefer = this.$route.params.refer;
if (!previewConfig || !pageRefer) {
this.$alert(getActionDisplayName('no-preview-config'), getActionDisplayName('notice'), {
confirmButtonText: getActionDisplayName('confirm'),
callback: action => {
const newPath = this.$route.path.replace('/preview', '');
this.$router.replace(newPath);
}
});
return;
}
this.previewConfig = previewConfig;
const themeConfig = getThemeConfigObject(previewConfig.theme);
if (themeConfig) {
this.themeConfig = themeConfig;
bus.$emit(ACTION_APPLY_THEME, themeConfig);
}
}
};
</script>
<style lang="scss">
.page-theme {
&:last-child {
margin-bottom: 55px;
}
h2 {
font-size: 28px;
line-height: 28px;
margin: 0;
}
ul {
list-style: none;
padding: 0;
margin: 0;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.theme-card {
display: inline-block;
height: 150px;
height: 16vw;
max-height: 230px;
flex: 0 0 24%;
cursor: default;
vertical-align: bottom;
}
.theme-section {
margin-bottom: 20px;
}
.second-section {
margin-top: 60px;
}
}
</style>
<template>
<div class="page-container page-theme">
<section class="theme-section">
<h2><%= 1 ></h2>
<ul>
<li class="theme-card" v-for="item in officialTheme" :key="item.name">
<theme-card
type="official"
:config="item"
@action="onAction"
></theme-card>
</li>
</ul>
</section>
<section class="theme-section second-section">
<h2><%= 2 > ({{userThemeCount}}/{{maxUserTheme}})</h2>
<ul>
<li class="theme-card" v-if="showUserUpload">
<theme-card
type="upload"
:config="{name: 'upload'}"
@action="onAction"
></theme-card>
</li>
<li class="theme-card" v-for="item in displayUserTheme" :key="item.name">
<theme-card
type="user"
:config="item"
@action="onAction"
></theme-card>
</li>
</ul>
</section>
<el-dialog :visible.sync="copyDialogVisible">
<el-form :model="copyForm" ref="copyForm" :rules="copyFormRule">
<el-form-item label="<%= 3 >" 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">{{getActionDisplayName('cancel')}}</el-button>
<el-button type="primary" @click="copyToUser">{{getActionDisplayName('confirm')}}</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import ThemeCard from '../../components/theme/theme-card.vue';
import ThemeList from '../../components/theme/theme-list.js';
import { saveUserThemeToLocal, loadUserThemeFromLocal } from '../../components/theme/localstorage';
import { getActionDisplayName } from '../../components/theme-configurator/utils/utils';
const maxUserTheme = 8;
export default {
components: {
ThemeCard
},
mounted() {
this.userTheme = loadUserThemeFromLocal();
if (!Array.isArray(this.userTheme)) {
this.userTheme = [];
saveUserThemeToLocal(this.userTheme);
}
},
data() {
return {
officialTheme: this.padEmpeyTheme(ThemeList),
userTheme: [],
maxUserTheme,
copyDialogVisible: false,
copyForm: {},
copyFormRule: {
name: [{
validator: this.validateCopyName,
trigger: 'blur'
}]
}
};
},
computed: {
userThemeCount() {
return this.userTheme.length;
},
showUserUpload() {
return this.userThemeCount < maxUserTheme;
},
displayUserTheme() {
return this.padEmpeyTheme(this.userTheme, this.showUserUpload ? 1 : 0);
}
},
methods: {
getActionDisplayName(key) {
return getActionDisplayName(key);
},
validateCopyName(rule, value, callback) {
if (!value) {
callback(new Error(this.getActionDisplayName('require-them-name')));
} else if (this.filterUserThemeByName(value).length > 0) {
callback(new Error(this.getActionDisplayName('duplicate-them-name')));
} else {
callback();
}
},
filterUserThemeByName(name, include = true) {
return this.userTheme.filter((theme) => (include ? theme.name === name : theme.name !== name));
},
padEmpeyTheme(theme, add = 0) {
if (!theme.length) return [];
const pad = 4 - ((theme.length + add) % 4);
if (pad < 4) return theme.concat(Array(pad).fill({}));
return theme;
},
onAction(name, item) {
switch (name) {
case 'copy':
this.openCopyForm(item.theme);
break;
case 'upload':
this.openCopyForm(item);
break;
case 'rename':
this.openRenameForm(item.name);
break;
case 'delete':
this.$confirm(this.getActionDisplayName('confirm-delete-theme'), this.getActionDisplayName('notice'), {
confirmButtonText: this.getActionDisplayName('confirm'),
cancelButtonText: this.getActionDisplayName('cancel'),
type: 'warning'
}).then(() => {
this.deleteUserThemeByName(item.name);
}).catch(() => {});
break;
default:
return;
}
},
deleteUserThemeByName(name) {
this.userTheme = this.filterUserThemeByName(name, false);
this.saveToLocal();
},
openRenameForm(name) {
this.copyForm.oldname = name;
this.copyDialogVisible = true;
},
openCopyForm(theme) {
if (this.userTheme.length >= 8) {
this.$message.error(this.getActionDisplayName('max-user-theme'));
return;
}
this.copyForm.theme = theme;
this.copyDialogVisible = true;
},
closeCopyForm() {
this.copyDialogVisible = false;
this.$nextTick(() => {
this.copyForm = {};
});
},
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();
}
});
},
saveToLocal() {
saveUserThemeToLocal(this.userTheme);
}
}
};
</script>
......@@ -123,6 +123,24 @@ const generateMiscRoutes = function(lang) {
}]
};
let themeRoute = {
path: `/${ lang }/theme`,
component: load(lang, 'theme-nav'),
children: [
{
path: '/', // 主题管理
name: 'theme' + lang,
meta: { lang },
component: load(lang, 'theme')
},
{
path: 'preview', // 主题预览编辑
name: 'theme-preview-' + lang,
meta: { lang },
component: load(lang, 'theme-preview')
}]
};
let resourceRoute = {
path: `/${ lang }/resource`, // 资源
meta: { lang },
......@@ -137,7 +155,7 @@ const generateMiscRoutes = function(lang) {
component: load(lang, 'index')
};
return [guideRoute, resourceRoute, indexRoute];
return [guideRoute, resourceRoute, themeRoute, indexRoute];
};
langs.forEach(lang => {
......
......@@ -7,7 +7,7 @@
display: inline-block;
@include e(content) {
background-color: $--badge-fill;
background-color: $--badge-background-color;
border-radius: $--badge-radius;
color: $--color-white;
display: inline-block;
......
......@@ -105,7 +105,7 @@
@include when(disabled) {
.el-checkbox__inner {
background-color: $--checkbox-disabled-input-fill;
border-color: $--checkbox-disabled-input-border-color;
border-color: $--checkbox-disabled-border-color;
cursor: not-allowed;
&::after {
......@@ -149,7 +149,7 @@
@include when(checked) {
.el-checkbox__inner {
background-color: $--checkbox-checked-input-background-color;
background-color: $--checkbox-checked-background-color;
border-color: $--checkbox-checked-input-border-color;
&::after {
......@@ -168,7 +168,7 @@
}
@include when(indeterminate) {
.el-checkbox__inner {
background-color: $--checkbox-checked-input-background-color;
background-color: $--checkbox-checked-background-color;
border-color: $--checkbox-checked-input-border-color;
&::before {
......@@ -193,11 +193,11 @@
display: inline-block;
position: relative;
border: $--checkbox-input-border;
border-radius: $--checkbox-input-border-radius;
border-radius: $--checkbox-border-radius;
box-sizing: border-box;
width: $--checkbox-input-width;
height: $--checkbox-input-height;
background-color: $--checkbox-input-background-color;
background-color: $--checkbox-background-color;
z-index: $--index-normal;
transition: border-color .25s cubic-bezier(.71,-.46,.29,1.46),
background-color .25s cubic-bezier(.71,-.46,.29,1.46);
......
......@@ -18,11 +18,11 @@
align-items: center;
height: $--collapse-header-height;
line-height: $--collapse-header-height;
background-color: $--collapse-header-fill;
color: $--collapse-header-color;
background-color: $--collapse-header-background-color;
color: $--collapse-header-font-color;
cursor: pointer;
border-bottom: 1px solid $--collapse-border-color;
font-size: $--collapse-header-size;
font-size: $--collapse-header-font-size;
font-weight: 500;
transition: border-bottom-color .3s;
outline: none;
......@@ -44,7 +44,7 @@
@include e(wrap) {
will-change: height;
background-color: $--collapse-content-fill;
background-color: $--collapse-content-background-color;
overflow: hidden;
box-sizing: border-box;
border-bottom: 1px solid $--collapse-border-color;
......@@ -52,8 +52,8 @@
@include e(content) {
padding-bottom: 25px;
font-size: $--collapse-content-size;
color: $--collapse-content-color;
font-size: $--collapse-content-font-size;
color: $--collapse-content-font-color;
line-height: 1.769230769230769;
}
......
This diff is collapsed.
......@@ -67,7 +67,7 @@
color: $--color-text-regular;
&:hover {
color: $--datepicker-text-hover-color;
color: $--datepicker-hover-font-color;
}
&.active {
......
......@@ -9,7 +9,7 @@
.el-date-table__row {
&:hover {
div {
background-color: $--datepicker-inrange-color;
background-color: $--datepicker-inrange-background-color;
}
td.available:hover {
color: $--datepicker-font-color;
......@@ -27,7 +27,7 @@
}
&.current div {
background-color: $--datepicker-inrange-color;
background-color: $--datepicker-inrange-background-color;
}
}
}
......@@ -77,13 +77,13 @@
}
&.available:hover {
color: $--datepicker-text-hover-color;
color: $--datepicker-hover-font-color;
}
&.in-range div {
background-color: $--datepicker-inrange-color;
background-color: $--datepicker-inrange-background-color;
&:hover {
background-color: $--datepicker-inrange-hover-color;
background-color: $--datepicker-inrange-hover-background-color;
}
}
......@@ -123,10 +123,10 @@
&.selected div {
margin-left: 5px;
margin-right: 5px;
background-color: $--datepicker-inrange-color;
background-color: $--datepicker-inrange-background-color;
border-radius: 15px;
&:hover {
background-color: $--datepicker-inrange-hover-color;
background-color: $--datepicker-inrange-hover-background-color;
}
}
......
......@@ -44,14 +44,14 @@
margin: 0 auto;
border-radius: 18px;
&:hover {
color: $--datepicker-text-hover-color;
color: $--datepicker-hover-font-color;
}
}
&.in-range div {
background-color: $--datepicker-inrange-color;
background-color: $--datepicker-inrange-background-color;
&:hover {
background-color: $--datepicker-inrange-hover-color;
background-color: $--datepicker-inrange-hover-background-color;
}
}
&.start-date div,
......
......@@ -45,7 +45,7 @@
cursor: pointer;
&:hover {
color: $--datepicker-text-hover-color;
color: $--datepicker-hover-font-color;
}
&.active {
......@@ -81,7 +81,7 @@
margin-top: 8px;
&:hover {
color: $--datepicker-text-hover-color;
color: $--datepicker-hover-font-color;
}
@include when(disabled) {
......
......@@ -40,7 +40,7 @@
margin: 0 auto;
&:hover {
color: $--datepicker-text-hover-color;
color: $--datepicker-hover-font-color;
}
}
......
......@@ -66,7 +66,7 @@
@include e(body) {
padding: 30px 20px;
color: $--color-text-regular;
font-size: $--dialog-font-size;
font-size: $--dialog-content-font-size;
word-break: break-all;
}
......
......@@ -7,7 +7,7 @@
height: 56px;
line-height: 56px;
font-size: $--menu-item-font-size;
color: $--menu-item-color;
color: $--menu-item-font-color;
padding: 0 20px;
list-style: none;
cursor: pointer;
......@@ -43,7 +43,7 @@
position: relative;
margin: 0;
padding-left: 0;
background-color: $--menu-item-fill;
background-color: $--menu-background-color;
@include utils-clearfix;
&.el-menu--horizontal {
border-bottom: solid 1px #e6e6e6;
......
......@@ -12,7 +12,7 @@
background-color: $--color-white;
border-radius: $--msgbox-border-radius;
border: 1px solid $--border-color-lighter;
font-size: $--msgbox-font-size;
font-size: $--messagebox-font-size;
box-shadow: $--box-shadow-light;
text-align: left;
overflow: hidden;
......@@ -44,9 +44,9 @@
@include e(title) {
padding-left: 0;
margin-bottom: 0;
font-size: $--msgbox-font-size;
font-size: $--messagebox-font-size;
line-height: 1;
color: $--color-text-primary;
color: $--messagebox-title-color;
}
@include e(headerbtn) {
......@@ -75,8 +75,8 @@
@include e(content) {
position: relative;
padding: 10px $--msgbox-padding-primary;
color: $--msgbox-content-color;
font-size: $--msgbox-content-font-size;
color: $--messagebox-content-color;
font-size: $--messagebox-content-font-size;
}
@include e(input) {
......@@ -107,19 +107,19 @@
}
&.el-icon-success {
color: $--msgbox-success-color;
color: $--messagebox-success-color;
}
&.el-icon-info {
color: $--msgbox-info-color;
color: $--messagebox-info-color;
}
&.el-icon-warning {
color: $--msgbox-warning-color;
color: $--messagebox-warning-color;
}
&.el-icon-error {
color: $--msgbox-danger-color;
color: $--messagebox-danger-color;
}
}
......@@ -134,7 +134,7 @@
@include e(errormsg) {
color: $--color-danger;
font-size: $--msgbox-error-font-size;
font-size: $--messagebox-error-font-size;
min-height: 18px;
margin-top: 2px;
}
......
......@@ -35,7 +35,7 @@
@include m(info) {
.el-message__content {
color: $--message-info-color;
color: $--message-info-font-color;
}
}
......@@ -44,7 +44,7 @@
border-color: $--color-success-light;
.el-message__content {
color: $--message-success-color;
color: $--message-success-font-color;
}
}
......@@ -53,7 +53,7 @@
border-color: $--color-warning-light;
.el-message__content {
color: $--message-warning-color;
color: $--message-warning-font-color;
}
}
......@@ -62,7 +62,7 @@
border-color: $--color-danger-light;
.el-message__content {
color: $--message-danger-color;
color: $--message-danger-font-color;
}
}
......@@ -85,7 +85,7 @@
right: 15px;
transform: translateY(-50%);
cursor: pointer;
color: $--message-close-color;
color: $--message-close-icon-color;
font-size: $--message-close-size;
&:focus {
......@@ -97,19 +97,19 @@
}
& .el-icon-success {
color: $--message-success-color;
color: $--message-success-font-color;
}
& .el-icon-error {
color: $--message-danger-color;
color: $--message-danger-font-color;
}
& .el-icon-info {
color: $--message-info-color;
color: $--message-info-font-color;
}
& .el-icon-warning {
color: $--message-warning-color;
color: $--message-warning-font-color;
}
}
......
......@@ -35,10 +35,10 @@
}
@include e(content) {
font-size: $--notification-font-size;
font-size: $--notification-content-font-size;
line-height: 21px;
margin: 6px 0 0 0;
color: $--notification-color;
color: $--notification-content-color;
text-align: justify;
p {
......@@ -66,19 +66,19 @@
}
.el-icon-success {
color: $--notification-success-color;
color: $--notification-success-icon-color;
}
.el-icon-error {
color: $--notification-danger-color;
color: $--notification-danger-icon-color;
}
.el-icon-info {
color: $--notification-info-color;
color: $--notification-info-icon-color;
}
.el-icon-warning {
color: $--notification-warning-color;
color: $--notification-warning-icon-color;
}
}
......
......@@ -6,7 +6,7 @@
@include b(pagination) {
white-space: nowrap;
padding: 2px 5px;
color: $--pagination-color;
color: $--pagination-font-color;
font-weight: bold;
@include utils-clearfix;
......@@ -53,12 +53,12 @@
}
&:hover {
color: $--pagination-hover-fill;
color: $--pagination-hover-color;
}
&:disabled {
color: $--pagination-button-disabled-color;
background-color: $--pagination-button-disabled-fill;
background-color: $--pagination-button-disabled-background-color;
cursor: not-allowed;
}
}
......@@ -67,7 +67,7 @@
.btn-next {
background: center center no-repeat;
background-size: 16px;
background-color: $--pagination-fill;
background-color: $--pagination-background-color;
cursor: pointer;
margin: 0;
color: $--pagination-button-color;
......@@ -139,7 +139,7 @@
padding-left: 8px;
&:hover {
border-color: $--pagination-hover-fill;
border-color: $--pagination-hover-color;
}
}
}
......@@ -214,7 +214,7 @@
.el-pager li:not(.disabled) {
&:hover {
color: $--pagination-hover-fill;
color: $--pagination-hover-color;
}
&.active {
......@@ -249,7 +249,7 @@
li {
padding: 0 4px;
background: $--pagination-fill;
background: $--pagination-background-color;
vertical-align: top;
display: inline-block;
font-size: $--pagination-font-size;
......@@ -284,11 +284,11 @@
}
&:hover {
color: $--pagination-hover-fill;
color: $--pagination-hover-color;
}
&.active {
color: $--pagination-hover-fill;
color: $--pagination-hover-color;
cursor: default;
}
}
......
......@@ -4,7 +4,7 @@
@include b(popover) {
position: absolute;
background: $--popover-fill;
background: $--popover-background-color;
min-width: 150px;
border-radius: 4px;
border: 1px solid $--popover-border-color;
......@@ -22,7 +22,7 @@
}
@include e(title) {
color: $--popover-title-color;
color: $--popover-title-font-color;
font-size: $--popover-title-font-size;
line-height: 1;
margin-bottom: 12px;
......
......@@ -36,7 +36,7 @@
&::after {
bottom: 1px;
margin-left: -$--popover-arrow-size;
border-top-color: $--popover-fill;
border-top-color: $--popover-background-color;
border-bottom-width: 0;
}
}
......@@ -56,7 +56,7 @@
top: 1px;
margin-left: -$--popover-arrow-size;
border-top-width: 0;
border-bottom-color: $--popover-fill;
border-bottom-color: $--popover-background-color;
}
}
......@@ -74,7 +74,7 @@
&::after {
bottom: -$--popover-arrow-size;
left: 1px;
border-right-color: $--popover-fill;
border-right-color: $--popover-background-color;
border-left-width: 0;
}
}
......@@ -95,7 +95,7 @@
bottom: -$--popover-arrow-size;
margin-left: -$--popover-arrow-size;
border-right-width: 0;
border-left-color: $--popover-fill;
border-left-color: $--popover-background-color;
}
}
}
\ No newline at end of file
......@@ -103,7 +103,7 @@
}
thead {
color: $--table-header-color;
color: $--table-header-font-color;
font-weight: 500;
&.is-group {
......
......@@ -33,7 +33,7 @@
}
&:hover {
background-color: $--tag-background-color;
background-color: $--tag-default-hover-background-color;
color: $--color-white;
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment