Jelajahi Sumber

chore: init theme (#14508)

* chore: init theme

* chore: update faas config
iamkun 6 tahun lalu
induk
melakukan
febdd3bbb4
63 mengubah file dengan 5536 tambahan dan 789 penghapusan
  1. 3 0
      build/webpack.demo.js
  2. TEMPAT SAMPAH
      examples/assets/images/term-arial.png
  3. TEMPAT SAMPAH
      examples/assets/images/term-helvetica.png
  4. TEMPAT SAMPAH
      examples/assets/images/term-hiragino.png
  5. TEMPAT SAMPAH
      examples/assets/images/term-microsoft.png
  6. TEMPAT SAMPAH
      examples/assets/images/term-pingfang.png
  7. TEMPAT SAMPAH
      examples/assets/images/term-sf.png
  8. TEMPAT SAMPAH
      examples/assets/images/theme-no-config.png
  9. TEMPAT SAMPAH
      examples/assets/images/typography.png
  10. 18 0
      examples/color.js
  11. 29 7
      examples/components/header.vue
  12. 55 0
      examples/components/theme-configurator/docStyle.vue
  13. 76 0
      examples/components/theme-configurator/download.vue
  14. 86 0
      examples/components/theme-configurator/editor/borderRadius.vue
  15. 155 0
      examples/components/theme-configurator/editor/boxShadow.vue
  16. 8 0
      examples/components/theme-configurator/editor/color-picker/index.js
  17. 316 0
      examples/components/theme-configurator/editor/color-picker/src/color.js
  18. 132 0
      examples/components/theme-configurator/editor/color-picker/src/components/alpha-slider.vue
  19. 113 0
      examples/components/theme-configurator/editor/color-picker/src/components/color-list.vue
  20. 123 0
      examples/components/theme-configurator/editor/color-picker/src/components/hue-slider.vue
  21. 134 0
      examples/components/theme-configurator/editor/color-picker/src/components/picker-dropdown.vue
  22. 61 0
      examples/components/theme-configurator/editor/color-picker/src/components/predefine.vue
  23. 100 0
      examples/components/theme-configurator/editor/color-picker/src/components/sv-panel.vue
  24. 36 0
      examples/components/theme-configurator/editor/color-picker/src/draggable.js
  25. 190 0
      examples/components/theme-configurator/editor/color-picker/src/main.vue
  26. 89 0
      examples/components/theme-configurator/editor/color.vue
  27. 101 0
      examples/components/theme-configurator/editor/fontLineHeight.vue
  28. 101 0
      examples/components/theme-configurator/editor/fontSize.vue
  29. 106 0
      examples/components/theme-configurator/editor/fontWeight.vue
  30. 45 0
      examples/components/theme-configurator/editor/input.vue
  31. 75 0
      examples/components/theme-configurator/editor/mixin.vue
  32. 38 0
      examples/components/theme-configurator/editor/simpleText.vue
  33. 232 0
      examples/components/theme-configurator/index.vue
  34. 35 0
      examples/components/theme-configurator/loading.vue
  35. 124 0
      examples/components/theme-configurator/main.vue
  36. 6 0
      examples/components/theme-configurator/progress.js
  37. 108 0
      examples/components/theme-configurator/progress.vue
  38. 65 0
      examples/components/theme-configurator/utils/ajax.js
  39. 20 0
      examples/components/theme-configurator/utils/api.js
  40. 59 0
      examples/components/theme-configurator/utils/boxShadow.js
  41. 80 0
      examples/components/theme-configurator/utils/utils.js
  42. 181 0
      examples/docs/en-US/border.md
  43. 245 52
      examples/docs/en-US/color.md
  44. 150 119
      examples/docs/en-US/typography.md
  45. 181 0
      examples/docs/es/border.md
  46. 245 53
      examples/docs/es/color.md
  47. 150 119
      examples/docs/es/typography.md
  48. 181 0
      examples/docs/fr-FR/border.md
  49. 244 52
      examples/docs/fr-FR/color.md
  50. 151 118
      examples/docs/fr-FR/typography.md
  51. 181 0
      examples/docs/zh-CN/border.md
  52. 244 52
      examples/docs/zh-CN/color.md
  53. 152 120
      examples/docs/zh-CN/typography.md
  54. 75 0
      examples/i18n/theme-editor.json
  55. 16 0
      examples/nav.config.json
  56. 41 3
      examples/pages/template/component.tpl
  57. 16 3
      package.json
  58. 13 13
      packages/theme-chalk/src/button.scss
  59. 6 6
      packages/theme-chalk/src/checkbox.scss
  60. 134 61
      packages/theme-chalk/src/common/var.scss
  61. 1 1
      packages/theme-chalk/src/dialog.scss
  62. 7 7
      packages/theme-chalk/src/radio-button.scss
  63. 3 3
      packages/theme-chalk/src/radio.scss

+ 3 - 0
build/webpack.demo.js

@@ -172,6 +172,9 @@ const webpackConfig = {
     ]),
     ]),
     new ProgressBarPlugin(),
     new ProgressBarPlugin(),
     new VueLoaderPlugin(),
     new VueLoaderPlugin(),
+    new webpack.DefinePlugin({
+      'process.env.FAAS_ENV': JSON.stringify(process.env.FAAS_ENV)
+    }),
     new webpack.LoaderOptionsPlugin({
     new webpack.LoaderOptionsPlugin({
       vue: {
       vue: {
         compilerOptions: {
         compilerOptions: {

TEMPAT SAMPAH
examples/assets/images/term-arial.png


TEMPAT SAMPAH
examples/assets/images/term-helvetica.png


TEMPAT SAMPAH
examples/assets/images/term-hiragino.png


TEMPAT SAMPAH
examples/assets/images/term-microsoft.png


TEMPAT SAMPAH
examples/assets/images/term-pingfang.png


TEMPAT SAMPAH
examples/assets/images/term-sf.png


TEMPAT SAMPAH
examples/assets/images/theme-no-config.png


TEMPAT SAMPAH
examples/assets/images/typography.png


+ 18 - 0
examples/color.js

@@ -0,0 +1,18 @@
+export const tintColor = (c, tint) => {
+  const color = c.replace('#', '');
+  let red = parseInt(color.slice(0, 2), 16);
+  let green = parseInt(color.slice(2, 4), 16);
+  let blue = parseInt(color.slice(4, 6), 16);
+
+  if (tint === 0) { // when primary color is in its rgb space
+    return [red, green, blue].join(',');
+  } else {
+    red += Math.round(tint * (255 - red));
+    green += Math.round(tint * (255 - green));
+    blue += Math.round(tint * (255 - blue));
+    red = red.toString(16);
+    green = green.toString(16);
+    blue = blue.toString(16);
+    return `#${ red }${ green }${ blue }`;
+  }
+};

+ 29 - 7
examples/components/header.vue

@@ -17,6 +17,7 @@
     .container {
     .container {
       height: 100%;
       height: 100%;
       box-sizing: border-box;
       box-sizing: border-box;
+      border-bottom: 1px solid #DCDFE6;
     }
     }
 
 
     .nav-lang-spe {
     .nav-lang-spe {
@@ -122,23 +123,24 @@
 
 
       a {
       a {
         text-decoration: none;
         text-decoration: none;
-        color: #888;
+        color: #1989FA;
+        opacity: 0.5;
         display: block;
         display: block;
         padding: 0 22px;
         padding: 0 22px;
 
 
         &.active,
         &.active,
         &:hover {
         &:hover {
-          color: #333;
+          opacity: 1;
         }
         }
 
 
         &.active::after {
         &.active::after {
           content: '';
           content: '';
           display: inline-block;
           display: inline-block;
           position: absolute;
           position: absolute;
-          bottom: 15px;
-          left: calc(50% - 7px);
-          width: 14px;
-          height: 4px;
+          bottom: 0;
+          left: calc(50% - 15px);
+          width: 30px;
+          height: 2px;
           background: #409EFF;
           background: #409EFF;
         }
         }
       }
       }
@@ -356,7 +358,8 @@
           
           
           <!--theme picker-->
           <!--theme picker-->
           <li class="nav-item nav-theme-switch" v-show="isComponentPage">
           <li class="nav-item nav-theme-switch" v-show="isComponentPage">
-            <theme-picker></theme-picker>
+            <theme-configurator :key="lang" v-if="showThemeConfigurator"></theme-configurator>
+            <theme-picker v-else></theme-picker>
           </li>
           </li>
         </ul>
         </ul>
       </div>
       </div>
@@ -365,9 +368,12 @@
 </template>
 </template>
 <script>
 <script>
   import ThemePicker from './theme-picker.vue';
   import ThemePicker from './theme-picker.vue';
+  import ThemeConfigurator from './theme-configurator';
   import AlgoliaSearch from './search.vue';
   import AlgoliaSearch from './search.vue';
   import compoLang from '../i18n/component.json';
   import compoLang from '../i18n/component.json';
   import Element from 'main/index.js';
   import Element from 'main/index.js';
+  import bus from '../bus';
+
   const { version } = Element;
   const { version } = Element;
 
 
   export default {
   export default {
@@ -389,6 +395,7 @@
 
 
     components: {
     components: {
       ThemePicker,
       ThemePicker,
+      ThemeConfigurator,
       AlgoliaSearch
       AlgoliaSearch
     },
     },
 
 
@@ -404,6 +411,10 @@
       },
       },
       isComponentPage() {
       isComponentPage() {
         return /^component/.test(this.$route.name);
         return /^component/.test(this.$route.name);
+      },
+      showThemeConfigurator() {
+        const host = location.hostname;
+        return host.match('localhost') || host.match('elenet');
       }
       }
     },
     },
 
 
@@ -441,6 +452,17 @@
       };
       };
       xhr.open('GET', '/versions.json');
       xhr.open('GET', '/versions.json');
       xhr.send();
       xhr.send();
+      let primaryLast = '#409EFF';
+      bus.$on('user-theme-config-update', (val) => {
+        let primaryColor = val.global['$--color-primary'];
+        if (!primaryColor) primaryColor = '#409EFF';
+        const base64svg = 'data:image/svg+xml;base64,';
+        const imgSet = document.querySelectorAll('h1 img');
+        imgSet.forEach((img) => {
+          img.src = `${base64svg}${window.btoa(window.atob(img.src.replace(base64svg, '')).replace(primaryLast, primaryColor))}`;
+        });
+        primaryLast = primaryColor;
+      });
     }
     }
   };
   };
 </script>
 </script>

+ 55 - 0
examples/components/theme-configurator/docStyle.vue

@@ -0,0 +1,55 @@
+<script>
+const ORIGINAL_THEME = '#409EFF';
+import { get as ajaxGet } from './utils/ajax';
+import { updateDomHeadStyle } from './utils/utils.js';
+export default {
+  data() {
+    return {
+      docs: '', // content of docs css
+      theme: ORIGINAL_THEME
+    };
+  },
+  methods: {
+    updateDocStyle(e) {
+      const val = e.global['$--color-primary'] || ORIGINAL_THEME;
+      const oldVal = this.theme;
+      const getHandler = (variable, id) => {
+        return () => {
+          let newStyle = this.updateStyle(this[variable], ORIGINAL_THEME, val);
+          updateDomHeadStyle(id, newStyle);
+        };
+      };
+      const docsHandler = getHandler('docs', 'docs-style');
+      if (!this.docs) {
+        const links = [].filter.call(document.querySelectorAll('link'), link => {
+          return /docs\..+\.css/.test(link.href || '');
+        });
+        links[0] && this.getCSSString(links[0].href, docsHandler, 'docs');
+      } else {
+        docsHandler();
+      }
+
+      const styles = [].slice.call(document.querySelectorAll('style'))
+        .filter(style => {
+          const text = style.innerText;
+          return new RegExp(oldVal, 'i').test(text) && !/Chalk Variables/.test(text);
+        });
+      styles.forEach(style => {
+        const { innerText } = style;
+        if (typeof innerText !== 'string') return;
+        style.innerText = this.updateStyle(innerText, oldVal, val);
+      });
+      this.theme = val;
+    },
+    updateStyle(style, oldColor, newColor) {
+      return style.replace(new RegExp(oldColor, 'ig'), newColor);
+    },
+    getCSSString(url, callback, variable) {
+      ajaxGet(url).then((res) => {
+        this[variable] = res;
+        callback();
+      });
+    }
+  }
+};
+</script>

+ 76 - 0
examples/components/theme-configurator/download.vue

@@ -0,0 +1,76 @@
+<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
+        @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;
+        });
+    }
+  }
+};
+</script>

+ 86 - 0
examples/components/theme-configurator/editor/borderRadius.vue

@@ -0,0 +1,86 @@
+<template>
+  <section class="config" :key="displayName">
+    <div class="config-label">
+      {{displayName}}
+    </div>
+    <div class="config-content">
+      <theme-input 
+        v-if="isGlobal"
+        :val="value"
+        @change="onChange"
+      ></theme-input>
+      <el-select 
+        v-if="!isGlobal"
+        v-model="value" 
+        class="select"
+        @change="onSelectChange"
+      >
+        <el-option
+          v-for="item in options"
+          :key="item.value"
+          :label="item.label"
+          :value="item.value">
+        </el-option>
+      </el-select>
+    </div>
+  </section>
+</template>
+
+<style>
+.select {
+  width: 100%;
+}
+</style>
+
+<script>
+import Mixin from './mixin';
+import Input from './input';
+import { getStyleDisplayName } from '../utils/utils.js';
+
+export default {
+  data() {
+    return {
+      options: [],
+      value: ''
+    };
+  },
+  components: {
+    themeInput: Input
+  },
+  mixins: [Mixin],
+  computed: {
+    isGlobalInputValue() {
+      return this.config.value.startsWith('$');
+    }
+  },
+  methods: {
+    onSelectChange(e) {
+      this.onChange(e);
+    },
+    initSelectOption() {
+      this.options = [];
+      const golbalV = this.golbalValue.border;
+      if (golbalV) {
+        Object.keys(golbalV).forEach((font) => {
+          if (font.includes('border-radius')) {
+            const size = golbalV[font];
+            this.options.push({
+              value: size.key,
+              label: getStyleDisplayName(size)
+            });
+          }
+        });
+      }
+    }
+  },
+  watch: {
+    'mergedValue': {
+      immediate: true,
+      handler(value) {
+        this.initSelectOption();
+        this.value = this.mergedValue;
+      }
+    }
+  }
+};
+</script>

+ 155 - 0
examples/components/theme-configurator/editor/boxShadow.vue

@@ -0,0 +1,155 @@
+<template>
+  <section class="config" :key="displayName">
+    <div class="config-label">
+      {{displayName}} 
+      <el-button 
+        class="plus-button" 
+        size="mini" 
+        round 
+        icon="el-icon-plus"
+        @click.stop="onAddShadow"
+      >
+      </el-button>
+    </div>
+    <div class="config-content" v-for="(each, key) in valueArr" :key="key">
+      <div class="content-10">
+        <color-picker 
+          size="mini"
+          class="colorPicker"
+          v-model="each.color" 
+          @change="val => onInputChange(val, key, 'color')"
+          show-alpha
+        ></color-picker>
+        <span class="content-tip">Color</span>
+      </div>
+      <div class="content-20">
+        <theme-input  
+          size="mini"
+          :val="each.offsetX" 
+          @change="val => onInputChange(Number(val), key, 'offsetX')"
+        >
+        </theme-input>
+        <span class="content-tip">X-px</span>
+      </div>
+      <div class="content-20">
+        <theme-input 
+          size="mini"
+          :val="each.offsetY" 
+          @change="val => onInputChange(Number(val), key, 'offsetY')"
+        >
+        </theme-input>
+        <span class="content-tip">Y-px</span>
+      </div>
+      <div class="content-20">
+        <theme-input 
+          size="mini"
+          :val="each.spreadRadius" 
+          @change="val => onInputChange(Number(val), key, 'spreadRadius')"
+        >
+        </theme-input>
+        <span class="content-tip">Spread</span>
+      </div>
+      <div class="content-20">
+        <theme-input 
+          size="mini"
+          :val="each.blurRadius" 
+          @change="val => onInputChange(Number(val), key, 'blurRadius')"
+        >
+        </theme-input>
+        <span class="content-tip">Blur</span>
+      </div>
+      <div class="content-10">
+        <el-button 
+          size="mini" 
+          round 
+          icon="el-icon-minus"
+          @click.stop="val => onMinusShadow(key)"
+        ></el-button>
+      </div>
+    </div>
+  </section>
+</template>
+
+<style scoped>
+.plus-button {
+  position: absolute;
+  left: 90%;
+}
+.colorPicker {
+  margin-left: 0;
+}
+.content-20 .el-input__suffix-inner span{
+  line-height: 28px;
+}
+.content-20 {
+  padding: 0 3px;
+}
+.content-10 { 
+  vertical-align: top;
+}
+.content-tip {
+  color: #909399;
+  font-size: 12px;
+}
+.config-content {
+  padding: 5px 0;
+}
+/* Element buton style override */
+.el-button--mini.is-round {
+  padding: 3px 3px;  
+}
+</style>
+<script>
+import Mixin from './mixin';
+import Input from './input';
+import { parse as parseShaodw, stringify as stringifyShaodw } from '../utils/boxShadow.js';
+import ColorPicker from './color-picker';
+
+export default {
+  components: {
+    ColorPicker,
+    themeInput: Input
+  },
+  data() {
+    return {
+      valueArr: []
+    };
+  },
+  mixins: [Mixin],
+  methods: {
+    onAddShadow() {
+      this.valueArr.push({
+        offsetX: 0,
+        offsetY: 0,
+        spreadRadius: 0,
+        blurRadius: 0,
+        color: 'rgba(0,0,0,0)',
+        inset: false
+      });
+    },
+    onMinusShadow(index) {
+      this.valueArr.splice(index, 1);
+      this.onShadowChange();
+    },
+    onInputChange(e, index, key) {
+      const arr = this.valueArr[index];
+      arr[key] = e;
+      this.valueArr.splice(index, 1, arr);
+      this.onShadowChange();
+    },
+    onShadowChange() {
+      this.onChange(
+        stringifyShaodw(this.valueArr)
+      );
+    }
+  },
+  watch: {
+    'mergedValue': {
+      immediate: true,
+      handler(value) {
+        this.valueArr = parseShaodw(value);
+      }
+    }
+  }
+};
+</script>

+ 8 - 0
examples/components/theme-configurator/editor/color-picker/index.js

@@ -0,0 +1,8 @@
+import ColorPicker from './src/main';
+
+/* istanbul ignore next */
+ColorPicker.install = function(Vue) {
+  Vue.component(ColorPicker.name, ColorPicker);
+};
+
+export default ColorPicker;

+ 316 - 0
examples/components/theme-configurator/editor/color-picker/src/color.js

@@ -0,0 +1,316 @@
+const hsv2hsl = function(hue, sat, val) {
+  return [
+    hue,
+    (sat * val / ((hue = (2 - sat) * val) < 1 ? hue : 2 - hue)) || 0,
+    hue / 2
+  ];
+};
+
+// Need to handle 1.0 as 100%, since once it is a number, there is no difference between it and 1
+// <http://stackoverflow.com/questions/7422072/javascript-how-to-detect-number-as-a-decimal-including-1-0>
+const isOnePointZero = function(n) {
+  return typeof n === 'string' && n.indexOf('.') !== -1 && parseFloat(n) === 1;
+};
+
+const isPercentage = function(n) {
+  return typeof n === 'string' && n.indexOf('%') !== -1;
+};
+
+// Take input from [0, n] and return it as [0, 1]
+const bound01 = function(value, max) {
+  if (isOnePointZero(value)) value = '100%';
+
+  const processPercent = isPercentage(value);
+  value = Math.min(max, Math.max(0, parseFloat(value)));
+
+  // Automatically convert percentage into number
+  if (processPercent) {
+    value = parseInt(value * max, 10) / 100;
+  }
+
+  // Handle floating point rounding errors
+  if ((Math.abs(value - max) < 0.000001)) {
+    return 1;
+  }
+
+  // Convert into [0, 1] range if it isn't already
+  return (value % max) / parseFloat(max);
+};
+
+const INT_HEX_MAP = { 10: 'A', 11: 'B', 12: 'C', 13: 'D', 14: 'E', 15: 'F' };
+
+const toHex = function({ r, g, b }) {
+  const hexOne = function(value) {
+    value = Math.min(Math.round(value), 255);
+    const high = Math.floor(value / 16);
+    const low = value % 16;
+    return '' + (INT_HEX_MAP[high] || high) + (INT_HEX_MAP[low] || low);
+  };
+
+  if (isNaN(r) || isNaN(g) || isNaN(b)) return '';
+
+  return '#' + hexOne(r) + hexOne(g) + hexOne(b);
+};
+
+const HEX_INT_MAP = { A: 10, B: 11, C: 12, D: 13, E: 14, F: 15 };
+
+const parseHexChannel = function(hex) {
+  if (hex.length === 2) {
+    return (HEX_INT_MAP[hex[0].toUpperCase()] || +hex[0]) * 16 + (HEX_INT_MAP[hex[1].toUpperCase()] || +hex[1]);
+  }
+
+  return HEX_INT_MAP[hex[1].toUpperCase()] || +hex[1];
+};
+
+const hsl2hsv = function(hue, sat, light) {
+  sat = sat / 100;
+  light = light / 100;
+  let smin = sat;
+  const lmin = Math.max(light, 0.01);
+  let sv;
+  let v;
+
+  light *= 2;
+  sat *= (light <= 1) ? light : 2 - light;
+  smin *= lmin <= 1 ? lmin : 2 - lmin;
+  v = (light + sat) / 2;
+  sv = light === 0 ? (2 * smin) / (lmin + smin) : (2 * sat) / (light + sat);
+
+  return {
+    h: hue,
+    s: sv * 100,
+    v: v * 100
+  };
+};
+
+// `rgbToHsv`
+// Converts an RGB color value to HSV
+// *Assumes:* r, g, and b are contained in the set [0, 255] or [0, 1]
+// *Returns:* { h, s, v } in [0,1]
+const rgb2hsv = function(r, g, b) {
+  r = bound01(r, 255);
+  g = bound01(g, 255);
+  b = bound01(b, 255);
+
+  const max = Math.max(r, g, b);
+  const min = Math.min(r, g, b);
+  let h, s;
+  let v = max;
+
+  const d = max - min;
+  s = max === 0 ? 0 : d / max;
+
+  if (max === min) {
+    h = 0; // achromatic
+  } else {
+    switch (max) {
+      case r:
+        h = (g - b) / d + (g < b ? 6 : 0);
+        break;
+      case g:
+        h = (b - r) / d + 2;
+        break;
+      case b:
+        h = (r - g) / d + 4;
+        break;
+    }
+    h /= 6;
+  }
+
+  return { h: h * 360, s: s * 100, v: v * 100 };
+};
+
+// `hsvToRgb`
+// Converts an HSV color value to RGB.
+// *Assumes:* h is contained in [0, 1] or [0, 360] and s and v are contained in [0, 1] or [0, 100]
+// *Returns:* { r, g, b } in the set [0, 255]
+const hsv2rgb = function(h, s, v) {
+  h = bound01(h, 360) * 6;
+  s = bound01(s, 100);
+  v = bound01(v, 100);
+
+  const i = Math.floor(h);
+  const f = h - i;
+  const p = v * (1 - s);
+  const q = v * (1 - f * s);
+  const t = v * (1 - (1 - f) * s);
+  const mod = i % 6;
+  const r = [v, q, p, p, t, v][mod];
+  const g = [t, v, v, q, p, p][mod];
+  const b = [p, p, t, v, v, q][mod];
+
+  return {
+    r: Math.round(r * 255),
+    g: Math.round(g * 255),
+    b: Math.round(b * 255)
+  };
+};
+
+export default class Color {
+  constructor(options) {
+    this._hue = 0;
+    this._saturation = 100;
+    this._value = 100;
+    this._alpha = 100;
+
+    this.enableAlpha = false;
+    this.format = 'hex';
+    this.value = '';
+
+    options = options || {};
+
+    for (let option in options) {
+      if (options.hasOwnProperty(option)) {
+        this[option] = options[option];
+      }
+    }
+
+    this.doOnChange();
+  }
+
+  set(prop, value) {
+    if (arguments.length === 1 && typeof prop === 'object') {
+      for (let p in prop) {
+        if (prop.hasOwnProperty(p)) {
+          this.set(p, prop[p]);
+        }
+      }
+
+      return;
+    }
+
+    this['_' + prop] = value;
+    this.doOnChange();
+  }
+
+  get(prop) {
+    return this['_' + prop];
+  }
+
+  toRgb() {
+    return hsv2rgb(this._hue, this._saturation, this._value);
+  }
+
+  fromString(value) {
+    if (!value) {
+      this._hue = 0;
+      this._saturation = 100;
+      this._value = 100;
+
+      this.doOnChange();
+      return;
+    }
+
+    const fromHSV = (h, s, v) => {
+      this._hue = Math.max(0, Math.min(360, h));
+      this._saturation = Math.max(0, Math.min(100, s));
+      this._value = Math.max(0, Math.min(100, v));
+
+      this.doOnChange();
+    };
+
+    if (value.indexOf('hsl') !== -1) {
+      const parts = value.replace(/hsla|hsl|\(|\)/gm, '')
+        .split(/\s|,/g).filter((val) => val !== '').map((val, index) => index > 2 ? parseFloat(val) : parseInt(val, 10));
+
+      if (parts.length === 4) {
+        this._alpha = Math.floor(parseFloat(parts[3]) * 100);
+      } else if (parts.length === 3) {
+        this._alpha = 100;
+      }
+      if (parts.length >= 3) {
+        const { h, s, v } = hsl2hsv(parts[0], parts[1], parts[2]);
+        fromHSV(h, s, v);
+      }
+    } else if (value.indexOf('hsv') !== -1) {
+      const parts = value.replace(/hsva|hsv|\(|\)/gm, '')
+        .split(/\s|,/g).filter((val) => val !== '').map((val, index) => index > 2 ? parseFloat(val) : parseInt(val, 10));
+
+      if (parts.length === 4) {
+        this._alpha = Math.floor(parseFloat(parts[3]) * 100);
+      } else if (parts.length === 3) {
+        this._alpha = 100;
+      }
+      if (parts.length >= 3) {
+        fromHSV(parts[0], parts[1], parts[2]);
+      }
+    } else if (value.indexOf('rgb') !== -1) {
+      const parts = value.replace(/rgba|rgb|\(|\)/gm, '')
+        .split(/\s|,/g).filter((val) => val !== '').map((val, index) => index > 2 ? parseFloat(val) : parseInt(val, 10));
+
+      if (parts.length === 4) {
+        this._alpha = Math.floor(parseFloat(parts[3]) * 100);
+      } else if (parts.length === 3) {
+        this._alpha = 100;
+      }
+      if (parts.length >= 3) {
+        const { h, s, v } = rgb2hsv(parts[0], parts[1], parts[2]);
+        fromHSV(h, s, v);
+      }
+    } else if (value.indexOf('#') !== -1) {
+      const hex = value.replace('#', '').trim();
+      let r, g, b;
+
+      if (hex.length === 3) {
+        r = parseHexChannel(hex[0] + hex[0]);
+        g = parseHexChannel(hex[1] + hex[1]);
+        b = parseHexChannel(hex[2] + hex[2]);
+      } else if (hex.length === 6 || hex.length === 8) {
+        r = parseHexChannel(hex.substring(0, 2));
+        g = parseHexChannel(hex.substring(2, 4));
+        b = parseHexChannel(hex.substring(4, 6));
+      }
+
+      if (hex.length === 8) {
+        this._alpha = Math.floor(parseHexChannel(hex.substring(6)) / 255 * 100);
+      } else if (hex.length === 3 || hex.length === 6) {
+        this._alpha = 100;
+      }
+
+      const { h, s, v } = rgb2hsv(r, g, b);
+      fromHSV(h, s, v);
+    }
+  }
+
+  compare(color) {
+    return Math.abs(color._hue - this._hue) < 2 &&
+      Math.abs(color._saturation - this._saturation) < 1 &&
+      Math.abs(color._value - this._value) < 1 &&
+      Math.abs(color._alpha - this._alpha) < 1;
+  }
+
+  doOnChange() {
+    const { _hue, _saturation, _value, _alpha, format } = this;
+
+    if (this.enableAlpha) {
+      switch (format) {
+        case 'hsl':
+          const hsl = hsv2hsl(_hue, _saturation / 100, _value / 100);
+          this.value = `hsla(${ _hue }, ${ Math.round(hsl[1] * 100) }%, ${ Math.round(hsl[2] * 100) }%, ${ _alpha / 100})`;
+          break;
+        case 'hsv':
+          this.value = `hsva(${ _hue }, ${ Math.round(_saturation) }%, ${ Math.round(_value) }%, ${ _alpha / 100})`;
+          break;
+        default:
+          const { r, g, b } = hsv2rgb(_hue, _saturation, _value);
+          this.value = `rgba(${r}, ${g}, ${b}, ${ _alpha / 100 })`;
+      }
+    } else {
+      switch (format) {
+        case 'hsl':
+          const hsl = hsv2hsl(_hue, _saturation / 100, _value / 100);
+          this.value = `hsl(${ _hue }, ${ Math.round(hsl[1] * 100) }%, ${ Math.round(hsl[2] * 100) }%)`;
+          break;
+        case 'hsv':
+          this.value = `hsv(${ _hue }, ${ Math.round(_saturation) }%, ${ Math.round(_value) }%)`;
+          break;
+        case 'rgb':
+          const { r, g, b } = hsv2rgb(_hue, _saturation, _value);
+          this.value = `rgb(${r}, ${g}, ${b})`;
+          break;
+        default:
+          this.value = toHex(hsv2rgb(_hue, _saturation, _value));
+      }
+    }
+  }
+};

+ 132 - 0
examples/components/theme-configurator/editor/color-picker/src/components/alpha-slider.vue

@@ -0,0 +1,132 @@
+<template>
+  <div class="el-color-alpha-slider" :class="{ 'is-vertical': vertical }">
+    <div class="el-color-alpha-slider__bar"
+         @click="handleClick"
+         ref="bar"
+         :style="{
+           background: background
+         }">
+    </div>
+    <div class="el-color-alpha-slider__thumb"
+         ref="thumb"
+         :style="{
+           left: thumbLeft + 'px',
+           top: thumbTop + 'px'
+         }">
+    </div>
+  </div>
+</template>
+
+<script>
+  import draggable from '../draggable';
+
+  export default {
+    name: 'el-color-alpha-slider',
+
+    props: {
+      color: {
+        required: true
+      },
+      vertical: Boolean
+    },
+
+    watch: {
+      'color._alpha'() {
+        this.update();
+      },
+
+      'color.value'() {
+        this.update();
+      }
+    },
+
+    methods: {
+      handleClick(event) {
+        const thumb = this.$refs.thumb;
+        const target = event.target;
+
+        if (target !== thumb) {
+          this.handleDrag(event);
+        }
+      },
+
+      handleDrag(event) {
+        const rect = this.$el.getBoundingClientRect();
+        const { thumb } = this.$refs;
+
+        if (!this.vertical) {
+          let left = event.clientX - rect.left;
+          left = Math.max(thumb.offsetWidth / 2, left);
+          left = Math.min(left, rect.width - thumb.offsetWidth / 2);
+
+          this.color.set('alpha', Math.round((left - thumb.offsetWidth / 2) / (rect.width - thumb.offsetWidth) * 100));
+        } else {
+          let top = event.clientY - rect.top;
+          top = Math.max(thumb.offsetHeight / 2, top);
+          top = Math.min(top, rect.height - thumb.offsetHeight / 2);
+
+          this.color.set('alpha', Math.round((top - thumb.offsetHeight / 2) / (rect.height - thumb.offsetHeight) * 100));
+        }
+      },
+
+      getThumbLeft() {
+        if (this.vertical) return 0;
+        const el = this.$el;
+        const alpha = this.color._alpha;
+
+        if (!el) return 0;
+        const thumb = this.$refs.thumb;
+        return Math.round(alpha * (el.offsetWidth - thumb.offsetWidth / 2) / 100);
+      },
+
+      getThumbTop() {
+        if (!this.vertical) return 0;
+        const el = this.$el;
+        const alpha = this.color._alpha;
+
+        if (!el) return 0;
+        const thumb = this.$refs.thumb;
+        return Math.round(alpha * (el.offsetHeight - thumb.offsetHeight / 2) / 100);
+      },
+
+      getBackground() {
+        if (this.color && this.color.value) {
+          const { r, g, b } = this.color.toRgb();
+          return `linear-gradient(to right, rgba(${r}, ${g}, ${b}, 0) 0%, rgba(${r}, ${g}, ${b}, 1) 100%)`;
+        }
+        return null;
+      },
+
+      update() {
+        this.thumbLeft = this.getThumbLeft();
+        this.thumbTop = this.getThumbTop();
+        this.background = this.getBackground();
+      }
+    },
+
+    data() {
+      return {
+        thumbLeft: 0,
+        thumbTop: 0,
+        background: null
+      };
+    },
+
+    mounted() {
+      const { bar, thumb } = this.$refs;
+
+      const dragConfig = {
+        drag: (event) => {
+          this.handleDrag(event);
+        },
+        end: (event) => {
+          this.handleDrag(event);
+        }
+      };
+
+      draggable(bar, dragConfig);
+      draggable(thumb, dragConfig);
+      this.update();
+    }
+  };
+</script>

+ 113 - 0
examples/components/theme-configurator/editor/color-picker/src/components/color-list.vue

@@ -0,0 +1,113 @@
+<template>
+  <div class="el-color-predefine color-list-container">
+    <div class="el-color-predefine__colors color-list">
+      <div class="color-list-item"
+           :class="{selected: item.selected, 'is-alpha': item._alpha < 100}"
+           v-for="(item, index) in rgbaColors"
+           :key="colors[index].variable"
+           @click="handleSelect(index)">
+        <span class="color-list-item-ball" :style="{'background-color': item.value}">
+        </span>
+        <div class="color-list-item-label">
+          {{item.info.label}} 
+        </div>
+        <div class="color-list-item-value">
+          {{item.info.value}} 
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+<style>
+  .color-list-container {
+    border-top: 1px solid #EBEEF5;
+    margin-top: 15px;
+    padding-top: 10px;
+    width: 100%;
+  }
+  .color-list {
+    max-height: 138px;
+    overflow: auto;
+  }
+  .color-list-item {
+    height: 24px;
+    width: 100%;
+    cursor: pointer;
+    margin: 2px 0;
+  }
+  .color-list-item:hover {
+    background: #efefef;
+  }
+  .color-list-item-ball {
+    height: 20px;
+    width: 20px;
+    margin-top: 2px;
+    margin-left: 5px;
+    border-radius: 100%;
+    display: inline-block;
+  }
+  .color-list-item-label {
+    margin-left: 15px;
+    font-size: 13px;
+    line-height: 24px;
+    display: inline-block;
+    vertical-align: super;
+    width: 30%;
+  }
+  .color-list-item-value { 
+    margin-left: 15px;
+    font-size: 13px;
+    line-height: 24px;
+    display: inline-block;
+    vertical-align: super;
+  }
+</style>
+
+<script>
+  import Color from '../color';
+
+  export default {
+    props: {
+      colors: { type: Array, required: true },
+      color: { required: true }
+    },
+    data() {
+      return {
+        rgbaColors: this.parseColors(this.colors, this.color)
+      };
+    },
+    methods: {
+      handleSelect(index) {
+        this.color.fromString(this.colors[index].value);
+        this.$emit('select', this.colors[index]);
+      },
+      parseColors(colors, color) {
+        return colors.map(value => {
+          const c = new Color();
+          c.enableAlpha = true;
+          c.format = 'rgba';
+          c.fromString(value.value);
+          c.info = value;
+          c.selected = c.value === color.value;
+          return c;
+        });
+      }
+    },
+    watch: {
+      '$parent.currentColor'(val) {
+        const color = new Color();
+        color.fromString(val);
+
+        this.rgbaColors.forEach(item => {
+          item.selected = color.compare(item);
+        });
+      },
+      colors(newVal) {
+        this.rgbaColors = this.parseColors(newVal, this.color);
+      },
+      color(newVal) {
+        this.rgbaColors = this.parseColors(this.colors, newVal);
+      }
+    }
+  };
+</script>

+ 123 - 0
examples/components/theme-configurator/editor/color-picker/src/components/hue-slider.vue

@@ -0,0 +1,123 @@
+<template>
+  <div class="el-color-hue-slider" :class="{ 'is-vertical': vertical }">
+    <div class="el-color-hue-slider__bar" @click="handleClick" ref="bar"></div>
+    <div class="el-color-hue-slider__thumb"
+         :style="{
+           left: thumbLeft + 'px',
+           top: thumbTop + 'px'
+         }"
+         ref="thumb">
+    </div>
+  </div>
+</template>
+
+<script>
+  import draggable from '../draggable';
+
+  export default {
+    name: 'el-color-hue-slider',
+
+    props: {
+      color: {
+        required: true
+      },
+
+      vertical: Boolean
+    },
+
+    data() {
+      return {
+        thumbLeft: 0,
+        thumbTop: 0
+      };
+    },
+
+    computed: {
+      hueValue() {
+        const hue = this.color.get('hue');
+        return hue;
+      }
+    },
+
+    watch: {
+      hueValue() {
+        this.update();
+      }
+    },
+
+    methods: {
+      handleClick(event) {
+        const thumb = this.$refs.thumb;
+        const target = event.target;
+
+        if (target !== thumb) {
+          this.handleDrag(event);
+        }
+      },
+
+      handleDrag(event) {
+        const rect = this.$el.getBoundingClientRect();
+        const { thumb } = this.$refs;
+        let hue;
+
+        if (!this.vertical) {
+          let left = event.clientX - rect.left;
+          left = Math.min(left, rect.width - thumb.offsetWidth / 2);
+          left = Math.max(thumb.offsetWidth / 2, left);
+
+          hue = Math.round((left - thumb.offsetWidth / 2) / (rect.width - thumb.offsetWidth) * 360);
+        } else {
+          let top = event.clientY - rect.top;
+          top = Math.min(top, rect.height - thumb.offsetHeight / 2);
+          top = Math.max(thumb.offsetHeight / 2, top);
+
+          hue = Math.round((top - thumb.offsetHeight / 2) / (rect.height - thumb.offsetHeight) * 360);
+        }
+
+        this.color.set('hue', hue);
+      },
+
+      getThumbLeft() {
+        if (this.vertical) return 0;
+        const el = this.$el;
+        const hue = this.color.get('hue');
+
+        if (!el) return 0;
+        const thumb = this.$refs.thumb;
+        return Math.round(hue * (el.offsetWidth - thumb.offsetWidth / 2) / 360);
+      },
+
+      getThumbTop() {
+        if (!this.vertical) return 0;
+        const el = this.$el;
+        const hue = this.color.get('hue');
+
+        if (!el) return 0;
+        const thumb = this.$refs.thumb;
+        return Math.round(hue * (el.offsetHeight - thumb.offsetHeight / 2) / 360);
+      },
+
+      update() {
+        this.thumbLeft = this.getThumbLeft();
+        this.thumbTop = this.getThumbTop();
+      }
+    },
+
+    mounted() {
+      const { bar, thumb } = this.$refs;
+
+      const dragConfig = {
+        drag: (event) => {
+          this.handleDrag(event);
+        },
+        end: (event) => {
+          this.handleDrag(event);
+        }
+      };
+
+      draggable(bar, dragConfig);
+      draggable(thumb, dragConfig);
+      this.update();
+    }
+  };
+</script>

+ 134 - 0
examples/components/theme-configurator/editor/color-picker/src/components/picker-dropdown.vue

@@ -0,0 +1,134 @@
+<template>
+  <transition name="el-zoom-in-top" @after-leave="doDestroy">
+    <div
+      class="el-color-dropdown"
+      v-show="showPopper">
+      <div class="el-color-dropdown__main-wrapper">
+        <hue-slider ref="hue" :color="color" vertical style="float: right;"></hue-slider>
+        <sv-panel ref="sl" :color="color"></sv-panel>
+      </div>
+      <alpha-slider v-if="showAlpha" ref="alpha" :color="color"></alpha-slider>
+      <predefine v-if="predefine" :color="color" :colors="predefine"></predefine>
+      <div class="el-color-dropdown__btns">
+        <span class="el-color-dropdown__value">
+          <el-input
+            v-model="customInput"
+            @keyup.native.enter="handleConfirm"
+            @blur="handleConfirm"
+            :validate-event="false"
+            size="mini">
+          </el-input>
+        </span>
+        <!-- <el-button
+          size="mini"
+          type="text"
+          class="el-color-dropdown__link-btn"
+          @click="$emit('clear')">
+          {{ t('el.colorpicker.clear') }}
+        </el-button> -->
+        <el-button
+          plain
+          size="mini"
+          class="el-color-dropdown__btn"
+          @click="confirmValue">
+          {{ t('el.colorpicker.confirm') }}
+        </el-button>
+      </div>
+      <color-list 
+        v-if="colorList && colorList.length > 0" 
+        :color="color" 
+        :colors="colorList"
+        @select=onColorListSelect
+      ></color-list>
+    </div>
+  </transition>
+</template>
+
+<script>
+  import SvPanel from './sv-panel';
+  import HueSlider from './hue-slider';
+  import AlphaSlider from './alpha-slider';
+  import Predefine from './predefine';
+  import ColorList from './color-list';
+  import Popper from 'element-ui/src/utils/vue-popper';
+  import Locale from 'element-ui/src/mixins/locale';
+  import ElInput from 'element-ui/packages/input';
+  import ElButton from 'element-ui/packages/button';
+
+  export default {
+    name: 'el-color-picker-dropdown',
+
+    mixins: [Popper, Locale],
+
+    components: {
+      SvPanel,
+      HueSlider,
+      AlphaSlider,
+      ElInput,
+      ElButton,
+      Predefine,
+      ColorList
+    },
+
+    props: {
+      color: {
+        required: true
+      },
+      showAlpha: Boolean,
+      predefine: Array,
+      colorList: Array
+    },
+
+    data() {
+      return {
+        customInput: ''
+      };
+    },
+
+    computed: {
+      currentColor() {
+        const parent = this.$parent;
+        return !parent.value && !parent.showPanelColor ? '' : parent.color.value;
+      }
+    },
+
+    methods: {
+      confirmValue() {
+        this.$emit('pick');
+      },
+
+      onColorListSelect(e) {
+        this.$emit('pick', e);
+      },
+
+      handleConfirm() {
+        this.color.fromString(this.customInput);
+      }
+    },
+
+    mounted() {
+      this.$parent.popperElm = this.popperElm = this.$el;
+      this.referenceElm = this.$parent.$el;
+    },
+
+    watch: {
+      showPopper(val) {
+        if (val === true) {
+          this.$nextTick(() => {
+            const { sl, hue, alpha } = this.$refs;
+            sl && sl.update();
+            hue && hue.update();
+            alpha && alpha.update();
+          });
+        }
+      },
+
+      currentColor: {
+        immediate: true,
+        handler(val) {
+          this.customInput = val;
+        }
+      }
+    }
+  };
+</script>

+ 61 - 0
examples/components/theme-configurator/editor/color-picker/src/components/predefine.vue

@@ -0,0 +1,61 @@
+<template>
+  <div class="el-color-predefine">
+    <div class="el-color-predefine__colors">
+      <div class="el-color-predefine__color-selector"
+           :class="{selected: item.selected, 'is-alpha': item._alpha < 100}"
+           v-for="(item, index) in rgbaColors"
+           :key="colors[index]"
+           @click="handleSelect(index)">
+        <div :style="{'background-color': item.value}">
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+  import Color from '../color';
+
+  export default {
+    props: {
+      colors: { type: Array, required: true },
+      color: { required: true }
+    },
+    data() {
+      return {
+        rgbaColors: this.parseColors(this.colors, this.color)
+      };
+    },
+    methods: {
+      handleSelect(index) {
+        this.color.fromString(this.colors[index]);
+      },
+      parseColors(colors, color) {
+        return colors.map(value => {
+          const c = new Color();
+          c.enableAlpha = true;
+          c.format = 'rgba';
+          c.fromString(value);
+          c.selected = c.value === color.value;
+          return c;
+        });
+      }
+    },
+    watch: {
+      '$parent.currentColor'(val) {
+        const color = new Color();
+        color.fromString(val);
+
+        this.rgbaColors.forEach(item => {
+          item.selected = color.compare(item);
+        });
+      },
+      colors(newVal) {
+        this.rgbaColors = this.parseColors(newVal, this.color);
+      },
+      color(newVal) {
+        this.rgbaColors = this.parseColors(this.colors, newVal);
+      }
+    }
+  };
+</script>

+ 100 - 0
examples/components/theme-configurator/editor/color-picker/src/components/sv-panel.vue

@@ -0,0 +1,100 @@
+<template>
+  <div class="el-color-svpanel"
+      :style="{
+        backgroundColor: background
+      }">
+    <div class="el-color-svpanel__white"></div>
+    <div class="el-color-svpanel__black"></div>
+    <div class="el-color-svpanel__cursor"
+      :style="{
+        top: cursorTop + 'px',
+        left: cursorLeft + 'px'
+      }">
+      <div></div>
+    </div>
+  </div>
+</template>
+
+<script>
+  import draggable from '../draggable';
+
+  export default {
+    name: 'el-sl-panel',
+
+    props: {
+      color: {
+        required: true
+      }
+    },
+
+    computed: {
+      colorValue() {
+        const hue = this.color.get('hue');
+        const value = this.color.get('value');
+        return { hue, value };
+      }
+    },
+
+    watch: {
+      colorValue() {
+        this.update();
+      }
+    },
+
+    methods: {
+      update() {
+        const saturation = this.color.get('saturation');
+        const value = this.color.get('value');
+
+        const el = this.$el;
+        let { clientWidth: width, clientHeight: height } = el;
+
+        this.cursorLeft = saturation * width / 100;
+        this.cursorTop = (100 - value) * height / 100;
+
+        this.background = 'hsl(' + this.color.get('hue') + ', 100%, 50%)';
+      },
+
+      handleDrag(event) {
+        const el = this.$el;
+        const rect = el.getBoundingClientRect();
+
+        let left = event.clientX - rect.left;
+        let top = event.clientY - rect.top;
+        left = Math.max(0, left);
+        left = Math.min(left, rect.width);
+
+        top = Math.max(0, top);
+        top = Math.min(top, rect.height);
+
+        this.cursorLeft = left;
+        this.cursorTop = top;
+        this.color.set({
+          saturation: left / rect.width * 100,
+          value: 100 - top / rect.height * 100
+        });
+      }
+    },
+
+    mounted() {
+      draggable(this.$el, {
+        drag: (event) => {
+          this.handleDrag(event);
+        },
+        end: (event) => {
+          this.handleDrag(event);
+        }
+      });
+
+      this.update();
+    },
+
+    data() {
+      return {
+        cursorTop: 0,
+        cursorLeft: 0,
+        background: 'hsl(0, 100%, 50%)'
+      };
+    }
+  };
+</script>

+ 36 - 0
examples/components/theme-configurator/editor/color-picker/src/draggable.js

@@ -0,0 +1,36 @@
+import Vue from 'vue';
+let isDragging = false;
+
+export default function(element, options) {
+  if (Vue.prototype.$isServer) return;
+  const moveFn = function(event) {
+    if (options.drag) {
+      options.drag(event);
+    }
+  };
+  const upFn = function(event) {
+    document.removeEventListener('mousemove', moveFn);
+    document.removeEventListener('mouseup', upFn);
+    document.onselectstart = null;
+    document.ondragstart = null;
+
+    isDragging = false;
+
+    if (options.end) {
+      options.end(event);
+    }
+  };
+  element.addEventListener('mousedown', function(event) {
+    if (isDragging) return;
+    document.onselectstart = function() { return false; };
+    document.ondragstart = function() { return false; };
+
+    document.addEventListener('mousemove', moveFn);
+    document.addEventListener('mouseup', upFn);
+    isDragging = true;
+
+    if (options.start) {
+      options.start(event);
+    }
+  });
+}

+ 190 - 0
examples/components/theme-configurator/editor/color-picker/src/main.vue

@@ -0,0 +1,190 @@
+<template>
+  <div
+    :class="[
+      'el-color-picker',
+      colorDisabled ? 'is-disabled' : '',
+      colorSize ? `el-color-picker--${ colorSize }` : ''
+    ]"
+    v-clickoutside="hide">
+    <div class="el-color-picker__mask" v-if="colorDisabled"></div>
+    <div class="el-color-picker__trigger" @click="handleTrigger">
+      <span class="el-color-picker__color" :class="{ 'is-alpha': showAlpha }">
+        <span class="el-color-picker__color-inner"
+          :style="{
+            backgroundColor: displayedColor
+          }"></span>
+        <span class="el-color-picker__empty el-icon-close" v-if="!value && !showPanelColor"></span>
+      </span>
+      <span class="el-color-picker__icon el-icon-arrow-down" v-show="value || showPanelColor"></span>
+    </div>
+    <picker-dropdown
+       ref="dropdown"
+       :class="['el-color-picker__panel', popperClass || '']"
+       v-model="showPicker"
+       @pick="confirmValue"
+       @clear="clearValue"
+       :color="color"
+       :show-alpha="showAlpha"
+       :predefine="predefine"
+       :colorList="colorList">
+    </picker-dropdown>
+  </div>
+</template>
+
+<script>
+  import Color from './color';
+  import PickerDropdown from './components/picker-dropdown.vue';
+  import Clickoutside from 'element-ui/src/utils/clickoutside';
+  import Emitter from 'element-ui/src/mixins/emitter';
+
+  export default {
+    name: 'ElColorPicker',
+
+    mixins: [Emitter],
+
+    props: {
+      value: String,
+      showAlpha: Boolean,
+      colorFormat: String,
+      disabled: Boolean,
+      size: String,
+      popperClass: String,
+      predefine: Array,
+      colorList: Array
+    },
+
+    inject: {
+      elForm: {
+        default: ''
+      },
+      elFormItem: {
+        default: ''
+      }
+    },
+
+    directives: { Clickoutside },
+
+    computed: {
+      displayedColor() {
+        if (!this.value && !this.showPanelColor) {
+          return 'transparent';
+        }
+
+        return this.displayedRgb(this.color, this.showAlpha);
+      },
+
+      _elFormItemSize() {
+        return (this.elFormItem || {}).elFormItemSize;
+      },
+
+      colorSize() {
+        return this.size || this._elFormItemSize || (this.$ELEMENT || {}).size;
+      },
+
+      colorDisabled() {
+        return this.disabled || (this.elForm || {}).disabled;
+      }
+    },
+
+    watch: {
+      value(val) {
+        if (!val) {
+          this.showPanelColor = false;
+        } else if (val && val !== this.color.value) {
+          this.color.fromString(val);
+        }
+      },
+      color: {
+        deep: true,
+        handler() {
+          this.showPanelColor = true;
+        }
+      },
+      displayedColor(val) {
+        if (!this.showPicker) return;
+        const currentValueColor = new Color({
+          enableAlpha: this.showAlpha,
+          format: this.colorFormat
+        });
+        currentValueColor.fromString(this.value);
+
+        const currentValueColorRgb = this.displayedRgb(currentValueColor, this.showAlpha);
+        if (val !== currentValueColorRgb) {
+          this.$emit('active-change', val);
+        }
+      }
+    },
+
+    methods: {
+      handleTrigger() {
+        if (this.colorDisabled) return;
+        this.showPicker = !this.showPicker;
+      },
+      confirmValue(selection) {
+        const value = selection || this.color.value;
+        this.$emit('input', value);
+        this.$emit('change', value);
+        this.dispatch('ElFormItem', 'el.form.change', value);
+        this.showPicker = false;
+      },
+      clearValue() {
+        this.$emit('input', null);
+        this.$emit('change', null);
+        if (this.value !== null) {
+          this.dispatch('ElFormItem', 'el.form.change', null);
+        }
+        this.showPanelColor = false;
+        this.showPicker = false;
+        this.resetColor();
+      },
+      hide() {
+        this.showPicker = false;
+        this.resetColor();
+      },
+      resetColor() {
+        this.$nextTick(_ => {
+          if (this.value) {
+            this.color.fromString(this.value);
+          } else {
+            this.showPanelColor = false;
+          }
+        });
+      },
+      displayedRgb(color, showAlpha) {
+        if (!(color instanceof Color)) {
+          throw Error('color should be instance of Color Class');
+        }
+
+        const { r, g, b } = color.toRgb();
+        return showAlpha
+          ? `rgba(${ r }, ${ g }, ${ b }, ${ color.get('alpha') / 100 })`
+          : `rgb(${ r }, ${ g }, ${ b })`;
+      }
+    },
+
+    mounted() {
+      const value = this.value;
+      if (value) {
+        this.color.fromString(value);
+      }
+      this.popperElm = this.$refs.dropdown.$el;
+    },
+
+    data() {
+      const color = new Color({
+        enableAlpha: this.showAlpha,
+        format: this.colorFormat
+      });
+
+      return {
+        color,
+        showPicker: false,
+        showPanelColor: false
+      };
+    },
+
+    components: {
+      PickerDropdown
+    }
+  };
+</script>

+ 89 - 0
examples/components/theme-configurator/editor/color.vue

@@ -0,0 +1,89 @@
+<template>
+  <section class="config" :key="displayName">
+    <div class="config-label">
+      {{displayName}}
+    </div>
+    <div class="config-content">
+      <div class="content-80">
+        <el-input
+          :value=displayValue
+          readonly
+          slot="reference"
+          @click.native="onInputClick"
+        ></el-input>
+      </div>
+      <div class="content-20">
+        <color-picker 
+          ref="colorPicker"
+          class="colorPicker"
+          v-model="pickerColor" 
+          @change=onPickerChange
+          :colorList="golbalColorList"
+        ></color-picker>
+      </div>
+    </div>
+  </section>
+</template>
+
+<style>
+input {
+  cursor: pointer;
+}
+.colorPicker {
+  margin-left: 10px;
+  vertical-align: bottom;
+}
+</style>
+
+<script>
+import Mixin from './mixin';
+import { getStyleDisplayValue, getStyleDisplayName } from '../utils/utils.js';
+import ColorPicker from './color-picker';
+
+export default {
+  components: {
+    ColorPicker
+  },
+  data() {
+    return {
+      pickerColor: ''
+    };
+  },
+  mixins: [Mixin],
+  watch: {
+    displayValue: {
+      immediate: true,
+      handler(value) {
+        if (value.startsWith('#')) {
+          this.pickerColor = value;
+        }
+      }
+    }
+  },
+  computed: {
+    golbalColor() {
+      return this.golbalValue.color;
+    },
+    displayValue() {
+      return getStyleDisplayValue(this.mergedValue, this.golbalColor);
+    },
+    golbalColorList() {
+      return this.isGlobal ? [] : Object.keys(this.golbalColor).map((c) => (
+        {
+          label: getStyleDisplayName(this.golbalColor[c]),
+          value: this.golbalColor[c].value,
+          variable: c
+        }
+      ));
+    }
+  },
+  methods: {
+    onInputClick() {
+      this.$refs.colorPicker && this.$refs.colorPicker.handleTrigger();
+    },
+    onPickerChange(e) {
+      this.onChange(e.variable || e);
+    }
+  }
+};
+</script>

+ 101 - 0
examples/components/theme-configurator/editor/fontLineHeight.vue

@@ -0,0 +1,101 @@
+<template>
+  <section class="config" :key="displayName">
+    <div class="config-label">
+      {{displayName}}
+    </div>
+    <div class="config-content">
+      <el-select 
+        v-model="value" 
+        class="select"
+        @change="onSelectChange"
+      >
+        <el-option
+          v-for="item in options"
+          :key="item.value"
+          :label="item.label"
+          :value="item.value">
+        </el-option>
+      </el-select>
+    </div>
+  </section>
+</template>
+
+<style>
+.select {
+  width: 100%;
+}
+</style>
+
+<script>
+const defaultFontLineHeight = [
+  '1',
+  '1.3',
+  '1.5',
+  '1.7',
+  '12px',
+  '16px',
+  '20px',
+  '24px',
+  '28px'
+];
+import Mixin from './mixin';
+import { getStyleDisplayName } from '../utils/utils.js';
+
+export default {
+  props: {
+    componentName: {
+      type: String
+    },
+    golbalValue: {
+      type: Object
+    }
+  },
+  data() {
+    return {
+      options: [],
+      value: ''
+    };
+  },
+  mixins: [Mixin],
+  computed: {
+    isGlobalInputValue() {
+      return this.config.value.startsWith('$');
+    }
+  },
+  methods: {
+    onSelectChange(e) {
+      this.onChange(e);
+    },
+    initSelectOption() {
+      this.options = [];
+      defaultFontLineHeight.forEach((size) => {
+        this.options.push({
+          value: size,
+          label: size
+        });
+      });
+      const golbalTypography = this.golbalValue.typography;
+      if (this.isGlobalInputValue && golbalTypography) {
+        Object.keys(golbalTypography).forEach((font) => {
+          if (font.includes('font-line-height')) {
+            const size = golbalTypography[font];
+            this.options.push({
+              value: size.key,
+              label: getStyleDisplayName(size)
+            });
+          }
+        });
+      }
+    }
+  },
+  watch: {
+    'mergedValue': {
+      immediate: true,
+      handler(value) {
+        this.initSelectOption();
+        this.value = this.mergedValue;
+      }
+    }
+  }
+};
+</script>

+ 101 - 0
examples/components/theme-configurator/editor/fontSize.vue

@@ -0,0 +1,101 @@
+<template>
+  <section class="config" :key="displayName">
+    <div class="config-label">
+      {{displayName}}
+    </div>
+    <div class="config-content">
+      <el-select 
+        v-model="value" 
+        class="select"
+        @change="onSelectChange"
+      >
+        <el-option
+          v-for="item in options"
+          :key="item.value"
+          :label="item.label"
+          :value="item.value">
+        </el-option>
+      </el-select>
+    </div>
+  </section>
+</template>
+
+<style>
+.select {
+  width: 100%;
+}
+</style>
+
+<script>
+const defaultFontSize = [
+  '12px',
+  '13px',
+  '14px',
+  '16px',
+  '18px',
+  '20px',
+  '28px',
+  '36px',
+  '48px'
+];
+import Mixin from './mixin';
+import { getStyleDisplayName } from '../utils/utils.js';
+
+export default {
+  props: {
+    componentName: {
+      type: String
+    },
+    golbalValue: {
+      type: Object
+    }
+  },
+  data() {
+    return {
+      options: [],
+      value: ''
+    };
+  },
+  mixins: [Mixin],
+  computed: {
+    isGlobalInputValue() {
+      return this.config.value.startsWith('$');
+    }
+  },
+  methods: {
+    onSelectChange(e) {
+      this.onChange(e);
+    },
+    initSelectOption() {
+      this.options = [];
+      defaultFontSize.forEach((size) => {
+        this.options.push({
+          value: size,
+          label: size
+        });
+      });
+      const golbalTypography = this.golbalValue.typography;
+      if (this.isGlobalInputValue && golbalTypography) {
+        Object.keys(golbalTypography).forEach((font) => {
+          if (font.includes('font-size')) {
+            const size = golbalTypography[font];
+            this.options.push({
+              value: size.key,
+              label: getStyleDisplayName(size)
+            });
+          }
+        });
+      }
+    }
+  },
+  watch: {
+    'mergedValue': {
+      immediate: true,
+      handler(value) {
+        this.initSelectOption();
+        this.value = this.mergedValue;
+      }
+    }
+  }
+};
+</script>

+ 106 - 0
examples/components/theme-configurator/editor/fontWeight.vue

@@ -0,0 +1,106 @@
+<template>
+  <section class="config" :key="displayName">
+    <div class="config-label">
+      {{displayName}}
+    </div>
+    <div class="config-content">
+      <el-select 
+        v-model="value" 
+        class="select"
+        @change="onSelectChange"
+      >
+        <el-option
+          v-for="item in options"
+          :key="item.value"
+          :label="item.label"
+          :value="item.value">
+        </el-option>
+      </el-select>
+    </div>
+  </section>
+</template>
+
+<style>
+.select {
+  width: 100%;
+}
+</style>
+
+<script>
+const defaultFontWeight = [
+  'normal',
+  'bold',
+  'bolder',
+  'lighter',
+  '100',
+  '200',
+  '300',
+  '400',
+  '500',
+  '600',
+  '700',
+  '800',
+  '900',
+  'inherit'
+];
+import Mixin from './mixin';
+import { getStyleDisplayName } from '../utils/utils.js';
+
+export default {
+  props: {
+    componentName: {
+      type: String
+    },
+    golbalValue: {
+      type: Object
+    }
+  },
+  data() {
+    return {
+      options: [],
+      value: ''
+    };
+  },
+  mixins: [Mixin],
+  computed: {
+    isGlobalInputValue() {
+      return this.config.value.startsWith('$');
+    }
+  },
+  methods: {
+    onSelectChange(e) {
+      this.onChange(e);
+    },
+    initSelectOption() {
+      this.options = [];
+      defaultFontWeight.forEach((weight) => {
+        this.options.push({
+          value: weight,
+          label: weight
+        });
+      });
+      const golbalTypography = this.golbalValue.typography;
+      if (this.isGlobalInputValue && golbalTypography) {
+        Object.keys(golbalTypography).forEach((font) => {
+          if (font.includes('font-weight')) {
+            const weight = golbalTypography[font];
+            this.options.push({
+              value: weight.key,
+              label: getStyleDisplayName(weight)
+            });
+          }
+        });
+      }
+    }
+  },
+  watch: {
+    'mergedValue': {
+      immediate: true,
+      handler(value) {
+        this.initSelectOption();
+        this.value = this.mergedValue;
+      }
+    }
+  }
+};
+</script>

+ 45 - 0
examples/components/theme-configurator/editor/input.vue

@@ -0,0 +1,45 @@
+<template>
+  <el-input 
+    @keyup.enter.native="onUpdate"
+    v-model="value"
+    @blur="onUpdate"
+    v-bind="$attrs"
+  >
+    <template slot="suffix">
+      <slot name="suffix"></slot>
+    </template>
+  </el-input>
+</template>
+
+<script>
+
+export default {
+  props: ['val', 'onChange'],
+  data() {
+    return {
+      value: '',
+      oldValue: ''
+    };
+  },
+  methods: {
+    onUpdate(e) {
+      const { value } = e.target;
+      if (value !== this.oldValue) {
+        this.oldValue = value;
+        this.$emit('change', value);
+      }
+    }
+  },
+  watch: {
+    val: {
+      immediate: true,
+      handler(value) {
+        this.value = value;
+        if (!this.oldValue) {
+          this.oldValue = value;
+        }
+      }
+    }
+  }
+};
+</script>

+ 75 - 0
examples/components/theme-configurator/editor/mixin.vue

@@ -0,0 +1,75 @@
+<style>
+    .config {
+      padding: 5px 0;
+    }
+    .config-label {
+      color: #606266;;
+      font-size: 14px;
+      padding-bottom: 5px;
+      position: relative;
+    }
+    .config-content {
+
+    }
+    .content-80 {
+      box-sizing: border-box;
+      display: inline-block;
+      width: 80%;
+    }
+    .content-20 {
+      box-sizing: border-box;
+      display: inline-block;
+      width: 20%;
+      vertical-align: bottom;
+    }
+    .content-10 {
+      box-sizing: border-box;
+      display: inline-block;
+      width: 10%;
+      vertical-align: bottom;
+    }
+    .content-15 {
+      box-sizing: border-box;
+      display: inline-block;
+      width: 15%;
+      vertical-align: bottom;
+    }
+</style>
+<script>
+import { getStyleDisplayName } from '../utils/utils.js';
+export default {
+  props: {
+    config: {
+      type: Object
+    },
+    userConfig: {
+      type: Object
+    },
+    golbalValue: {
+      type: Object
+    },
+    componentName: {
+      type: String
+    }
+  },
+  computed: {
+    mergedValue() {
+      return this.userConfig[this.config.key] || this.config.value;
+    },
+    displayName() {
+      return getStyleDisplayName(this.config, this.componentName);
+    },
+    isGlobal() {
+      return !this.config.value.startsWith('$');
+    }
+  },
+  methods: {
+    onChange(value) {
+      this.$emit('onChange', {
+        key: this.config.key,
+        value
+      });
+    }
+  }
+};
+</script>

+ 38 - 0
examples/components/theme-configurator/editor/simpleText.vue

@@ -0,0 +1,38 @@
+<template>
+  <section class="config" :key="displayName">
+    <div class="config-label">
+      {{displayName}}
+    </div>
+    <div class="config-content">
+      <theme-input 
+        :val="value"
+        @change="onChange"
+      ></theme-input>
+    </div>
+  </section>
+</template>
+
+<script>
+import Input from './input';
+import Mixin from './mixin';
+
+export default {
+  components: {
+    themeInput: Input
+  },
+  data() {
+    return {
+      value: ''
+    };
+  },
+  mixins: [Mixin],
+  watch: {
+    'mergedValue': {
+      immediate: true,
+      handler(value) {
+        this.value = this.mergedValue;
+      }
+    }
+  }
+};
+</script>

+ 232 - 0
examples/components/theme-configurator/index.vue

@@ -0,0 +1,232 @@
+<template>
+  <div>
+    <el-button
+      round
+      type="primary"
+      size="mini"
+      @click.stop="showConfigurator"
+    >{{getActionDisplayName("theme-editor")}}</el-button>
+    <transition name="fade">
+      <div v-show="visible" class="configurator" ref="configurator">
+        <div 
+          class="main-configurator"
+          ref="mainConfigurator"
+        >
+          <div v-if="currentConfig">
+            <main-panel
+              :currentConfig="currentConfig"
+              :defaultConfig="defaultConfig"
+              :userConfig="userConfig"
+              :globalValue="globalValue"
+              @onChange="userConfigChange"
+            ></main-panel>
+          </div>
+          <div v-if="init && !currentConfig" class="no-config">
+            <img src="../../assets/images/theme-no-config.png" alt>
+            <span>{{getActionDisplayName("no-config")}}</span>
+          </div>
+          <download-area></download-area>
+        </div>
+      </div>
+    </transition>
+  </div>
+</template>
+
+<style>
+.configurator {
+  height: 100%;
+  width: 24%;
+  max-width: 400px;
+  position: fixed;
+  overflow-y: auto;
+  top: 79px;
+  right: 0;
+  bottom: 0;
+  background: #fff;
+  color: #666;
+  line-height: 24px;
+  padding-right: 1%;
+}
+.configurator .main-configurator {
+  height: 100%;
+  overflow: auto;
+  background: #F5F7FA;
+  border: 1px solid #EBEEF5;
+  box-shadow: 0 2px 10px 0 rgba(0,0,0,0.06);
+  border-radius: 8px;
+  width: 97%;
+  box-sizing: border-box;
+  margin: 0 .5% 0 5%;
+}
+.no-config {
+  margin-top: 130px;
+  text-align: center;
+  img {
+    width: 50%;
+    display: block;
+    margin: 0 auto;
+  }
+  span {
+    margin-top: 10px;
+    display: block;
+    color: #909399;
+    font-size: 14px;
+  }
+}
+.fade-enter,.fade-leave-to {
+    transform:translateX(100%);
+}
+.fade-enter-active ,.fade-leave-active {
+    transition:all 0.3s ease;
+}
+
+@media (min-width: 1600px) {
+  .configurator {
+    padding-right: calc((100% - 1600px) / 2);
+  }
+}
+
+</style>
+
+<script>
+import bus from '../../bus';
+import { getVars, updateVars } from './utils/api.js';
+import mainPanel from './main';
+import {
+  filterConfigType,
+  filterGlobalValue,
+  updateDomHeadStyle,
+  getActionDisplayName
+} from './utils/utils.js';
+import DocStyle from './docStyle';
+import Loading from './loading';
+import DownloadArea from './download';
+
+export default {
+  components: {
+    mainPanel,
+    DownloadArea
+  },
+  data() {
+    return {
+      init: false,
+      visible: false,
+      defaultConfig: null,
+      currentConfig: null,
+      userConfig: {
+        global: {},
+        local: {}
+      },
+      lastApply: 0
+    };
+  },
+  mixins: [DocStyle, Loading],
+  computed: {
+    globalValue() {
+      return filterGlobalValue(this.defaultConfig, this.userConfig);
+    }
+  },
+  methods: {
+    getActionDisplayName(key) {
+      return getActionDisplayName(key);
+    },
+    showConfigurator() {
+      this.visible = !this.visible;
+      bus.$emit('user-theme-config-visible', this.visible);
+      window.userThemeConfigVisible = Boolean(this.visible);
+      if (this.init) return;
+      this.$nextTick(() => {
+        const loading = this.$loading({
+          target: this.$refs.configurator
+        });
+        let defaultConfig;
+        getVars()
+          .then((res) => {
+            defaultConfig = res;
+          })
+          .catch((err) => {
+            this.onError(err);
+          })
+          .then(() => {
+            setTimeout(() => {
+              if (defaultConfig) {
+                this.defaultConfig = defaultConfig;
+                this.filterCurrentConfig();
+                this.init = true;
+              }
+              loading.close();
+            }, 300); // action after transition
+          });
+      });
+    },
+    filterCurrentConfig() {
+      this.currentConfig = this.defaultConfig.find((config) => {
+        return config.name === this.$route.path.split('/').pop().toLowerCase();
+      });
+    },
+    userConfigChange(e) {
+      this.$set(this.userConfig[filterConfigType(this.currentConfig.name)], e.key, e.value);
+      this.onAction();
+    },
+    applyStyle(res, time) {
+      if (time < this.lastApply) return;
+      this.updateDocs();
+      updateDomHeadStyle('chalk-style', res);
+      this.lastApply = time;
+    },
+    onDownload() {
+      return updateVars(Object.assign({}, this.userConfig, {download: true}), (xhr) => {
+        xhr.responseType = 'blob';
+      });
+    },
+    onReset() {
+      this.userConfig = {
+        global: {},
+        local: {}
+      };
+      this.onAction();
+    },
+    onAction() {
+      this.triggerComponentLoading(true);
+      const time = +new Date();
+      updateVars(this.userConfig)
+        .then((res) => {
+          this.applyStyle(res, time);
+        })
+        .catch((err) => {
+          this.onError(err);
+        })
+        .then(() => {
+          this.triggerComponentLoading(false);
+        });
+    },
+    onError(err) {
+      let message;
+      try {
+        message = JSON.parse(err).message;
+      } catch (e) {
+        message = err;
+      }
+      this.$message.error(message);
+    },
+    triggerComponentLoading(val) {
+      bus.$emit('user-theme-config-loading', val);
+    },
+    updateDocs() {
+      window.userThemeConfig = JSON.parse(JSON.stringify(this.userConfig));
+      bus.$emit('user-theme-config-update', this.userConfig);
+      this.updateDocStyle(this.userConfig);
+    }
+  },
+  watch: {
+    '$route.path'() {
+      this.defaultConfig && this.filterCurrentConfig();
+      if (!this.$refs.mainConfigurator) return;
+      this.$nextTick(() => {
+        this.$refs.mainConfigurator.scrollTop = 0;
+      });
+
+    }
+  }
+};
+</script>

+ 35 - 0
examples/components/theme-configurator/loading.vue

@@ -0,0 +1,35 @@
+<style>
+  .loadingClass {
+    z-index: 0!important;
+    .el-loading-spinner {
+      top: 0%;
+      margin-top: 30%;
+    }
+  }
+</style>
+<script>
+
+import bus from '../../bus.js';
+import './progress.js';
+
+export default {
+  data() {
+    return {
+      count: 0
+    };
+  },
+  created() {
+    bus.$on('user-theme-config-loading', val => {
+      if (val) {
+        this.count++;
+        if (this.count > 1) return;
+        this.$bar.start();
+      } else {
+        this.count--;
+        if (this.count) return;
+        this.$bar.finish();
+      }
+    });
+  }
+};
+</script>

+ 124 - 0
examples/components/theme-configurator/main.vue

@@ -0,0 +1,124 @@
+<template>
+  <div class="main">
+    <!-- <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)}}
+      </span>
+      <component 
+        :is="editorComponent(config.type)"
+        :componentName=configName
+        :config=config
+        :userConfig=userConfigByType
+        :golbalValue=globalValue
+        @onChange=onChange
+      >
+      </component>
+    </div>
+  </div>
+</template>
+
+<style>
+.main {
+  margin-bottom: 140px;
+  padding: 10px;
+}
+.category-name {
+  color: #C0C4CC;
+  font-size: 18px;
+  display: block;
+  margin: 8px 0 4px 0;
+}
+</style>
+
+<script>
+import ColorEditor from './editor/color';
+import fontWeightEditor from './editor/fontWeight';
+import fontSizeEditor from './editor/fontSize';
+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';
+
+export default {
+  components: {
+    ColorEditor,
+    fontSizeEditor,
+    fontLineHeightEditor,
+    simpleTextEditor,
+    borderRadiusEditor,
+    boxShadowEditor,
+    fontWeightEditor
+  },
+  props: {
+    defaultConfig: {
+      type: Array
+    },
+    currentConfig: {
+      type: Object
+    },
+    userConfig: {
+      type: Object
+    },
+    globalValue: {
+      type: Object
+    }
+  },
+  computed: {
+    configName() {
+      return this.currentConfig.name;
+    },
+    userConfigByType() {
+      return this.userConfig[filterConfigType(this.configName)];
+    },
+    configByOrder() {
+      return this.currentConfig.config.sort((a, b) => (a.order - b.order));
+    }
+  },
+  methods: {
+    getCategoryDisplayName(key) {
+      return getCategoryDisplayName(key);
+    },
+    editorComponent(type) {
+      switch (type) {
+        case 'color':
+          return ColorEditor;
+        case 'fontWeight':
+          return fontWeightEditor;
+        case 'fontSize':
+          return fontSizeEditor;
+        case 'fontLineHeight':
+          return fontLineHeightEditor;
+        case 'borderRadius':
+          return borderRadiusEditor;
+        case 'boxShadow':
+          return boxShadowEditor;
+        default:
+          return simpleTextEditor;
+      }
+    },
+    onChange(e) {
+      this.$emit('onChange', e);
+    },
+    showCategory(name, key) {
+      if (!name) {
+        return false;
+      }
+      if (!this.categoryDisplay[name] || this.categoryDisplay[name] === key) {
+        this.categoryDisplay[name] = key;
+        return true;
+      }
+      return false;
+    }
+  },
+  data() {
+    return {
+      categoryDisplay: {}
+    };
+  }
+};
+</script>

+ 6 - 0
examples/components/theme-configurator/progress.js

@@ -0,0 +1,6 @@
+import Vue from 'vue';
+import ProgressBar from './progress.vue';
+
+Vue.prototype.$bar = new Vue(ProgressBar).$mount();
+
+document.body.appendChild(Vue.prototype.$bar.$el);

+ 108 - 0
examples/components/theme-configurator/progress.vue

@@ -0,0 +1,108 @@
+<template>
+  <div class="progress" :style="{
+    'width': percent+'%',
+    'height': height,
+    'background-color': canSuccess? successColor() : failedColor(),
+    'opacity': show ? 1 : 0
+  }"></div>
+</template>
+
+<script>
+/* eslint-disable */
+export default {
+  data () {
+    return {
+      percent: 0,
+      show: false,
+      canSuccess: true,
+      duration: 3000,
+      height: '2px'
+    }
+  },
+  methods: {
+    successColor() {
+      return this.userSelectColor()['$--color-primary'] || '#409EFF';
+    },
+    failedColor() {
+      return this.userSelectColor()['$--color-danger'] || '#F56C6C';
+    },
+    userSelectColor() {
+      return window.userThemeConfig && window.userThemeConfig.global || {}
+    },
+    start () {
+      this.show = true
+      this.canSuccess = true
+      if (this._timer) {
+        clearInterval(this._timer)
+        this.percent = 0
+      }
+      // Code from Nuxt.js!
+      this._cut = 10000 / Math.floor(this.duration)
+      this._timer = setInterval(() => {
+        this.increase(this._cut * Math.random())
+        if (this.percent >= 90) {
+          this.percent = 90;
+        }
+      }, 100)
+      return this
+    },
+    set (num) {
+      this.show = true
+      this.canSuccess = true
+      this.percent = Math.floor(num)
+      return this
+    },
+    get () {
+      return Math.floor(this.percent)
+    },
+    increase (num) {
+      this.percent = this.percent + Math.floor(num)
+      return this
+    },
+    decrease (num) {
+      this.percent = this.percent - Math.floor(num)
+      return this
+    },
+    finish () {
+      this.percent = 100
+      this.hide()
+      return this
+    },
+    pause () {
+      clearInterval(this._timer)
+      return this
+    },
+    hide () {
+      clearInterval(this._timer)
+      this._timer = null
+      setTimeout(() => {
+        this.show = false
+        this.$nextTick(() => {
+          setTimeout(() => {
+            this.percent = 0
+          }, 200)
+        })
+      }, 500)
+      return this
+    },
+    fail () {
+      this.canSuccess = false
+      return this
+    }
+  }
+}
+</script>
+
+<style scoped>
+.progress {
+  position: fixed;
+  top: 0px;
+  left: 0px;
+  right: 0px;
+  height: 2px;
+  width: 0%;
+  transition: width 0.2s, opacity 0.4s;
+  opacity: 1;
+  z-index: 999999;
+}
+</style>

+ 65 - 0
examples/components/theme-configurator/utils/ajax.js

@@ -0,0 +1,65 @@
+const defaultError = 'Server Error 500';
+const defaultTimeout = 'Request Timeout';
+const xhr = (method, url, data = null, cb) => {
+  return new window.Promise((resolve, reject) => {
+    const xhr = new XMLHttpRequest();
+    const doReject = (xhr) => {
+      reject(xhr.response || xhr.statusText || defaultError);
+    };
+    xhr.open(method, url);
+    xhr.setRequestHeader('Content-Type', 'application/json');
+    xhr.timeout = 10000;
+    if (cb) cb(xhr);
+    xhr.onload = () => {
+      if (xhr.readyState === 4) {
+        if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
+          let response = xhr.response;
+          const type = xhr.getResponseHeader('Content-Type');
+          if (type.indexOf('zip') > -1) {
+            let filename = 'style.zip';
+            const disposition = xhr.getResponseHeader('content-disposition');
+            if (disposition && disposition.indexOf('attachment') !== -1) {
+              var filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
+              var matches = filenameRegex.exec(disposition);
+              if (matches != null && matches[1]) {
+                filename = matches[1].replace(/['"]/g, '');
+              }
+            }
+            var blob = new Blob([response], { type });
+            var zipUrl = URL.createObjectURL(blob);
+            var link = document.createElement('a');
+            link.href = zipUrl;
+            link.download = filename;
+            link.click();
+            resolve(response);
+            return;
+          }
+          try {
+            response = JSON.parse(xhr.response);
+          } catch (e) {}
+          resolve(response);
+        } else {
+          doReject(xhr);
+        }
+      } else {
+        doReject(xhr);
+      }
+    };
+    xhr.onerror = () => {
+      doReject(xhr);
+    };
+    xhr.ontimeout = () => {
+      xhr.abort();
+      reject(defaultTimeout);
+    };
+    xhr.send(JSON.stringify(data));
+  });
+};
+
+export const post = (url, data, cb) => {
+  return xhr('POST', url, data, cb);
+};
+
+export const get = (url) => {
+  return xhr('GET', url);
+};

+ 20 - 0
examples/components/theme-configurator/utils/api.js

@@ -0,0 +1,20 @@
+import Element from 'main/index.js';
+import { post, get } from './ajax';
+
+const { version } = Element;
+
+const hostList = {
+  local: 'http://localhost:3008/',
+  alpha: 'https://ssr.alpha.elenet.me/element-theme-server/',
+  production: 'https://ssr.elenet.me/element-theme-server/'
+};
+
+const host = hostList[process.env.FAAS_ENV] || hostList.production;
+
+export const getVars = () => {
+  return get(`${host}getVariable?version=${version}`);
+};
+
+export const updateVars = (data, cb) => {
+  return post(`${host}updateVariable?version=${version}`, data, cb);
+};

+ 59 - 0
examples/components/theme-configurator/utils/boxShadow.js

@@ -0,0 +1,59 @@
+const VALUES_REG = /,(?![^\(]*\))/;
+const PARTS_REG = /\s(?![^(]*\))/;
+const LENGTH_REG = /^[0-9]+[a-zA-Z%]+?$/;
+
+const parseValue = str => {
+  const parts = str.split(PARTS_REG);
+  const inset = parts.includes('inset');
+  const last = parts.slice(-1)[0];
+  const color = !isLength(last) ? last : undefined;
+
+  const nums = parts
+    .filter(n => n !== 'inset')
+    .filter(n => n !== color)
+    .map(toNum);
+  const [ offsetX, offsetY, blurRadius, spreadRadius ] = nums;
+
+  return {
+    inset,
+    offsetX,
+    offsetY,
+    blurRadius,
+    spreadRadius,
+    color
+  };
+};
+
+const stringifyValue = obj => {
+  const {
+    inset,
+    offsetX = 0,
+    offsetY = 0,
+    blurRadius = 0,
+    spreadRadius,
+    color
+  } = obj || {};
+
+  return [
+    (inset ? 'inset' : null),
+    offsetX,
+    offsetY,
+    blurRadius,
+    spreadRadius,
+    color
+  ].filter(v => v !== null && v !== undefined)
+    .map(toPx)
+    .map(s => ('' + s).trim())
+    .join(' ');
+};
+
+const isLength = v => v === '0' || LENGTH_REG.test(v);
+const toNum = v => {
+  if (!/px$/.test(v) && v !== '0') return v;
+  const n = parseFloat(v);
+  return !isNaN(n) ? n : v;
+};
+const toPx = n => typeof n === 'number' && n !== 0 ? (n + 'px') : n;
+
+export const parse = str => str.split(VALUES_REG).map(s => s.trim()).map(parseValue);
+export const stringify = arr => arr.map(stringifyValue).join(', ');

+ 80 - 0
examples/components/theme-configurator/utils/utils.js

@@ -0,0 +1,80 @@
+import deepmerge from 'deepmerge';
+import constant from '../../../i18n/theme-editor.json';
+
+export const filterConfigType = (name) => {
+  switch (name) {
+    case 'color':
+    case 'typography':
+    case 'border':
+      return 'global';
+    default:
+      return 'local';
+  }
+};
+
+export const filterGlobalValue = (defaultConfig, userConfig) => {
+  const valueObject = {};
+  const globalArr = ['color', 'typography', 'border'];
+  globalArr.forEach((global) => {
+    const configObj = {};
+    defaultConfig
+      .find(config => (config.name === global))
+      .config.forEach(c => (configObj[c.key] = deepmerge({}, c)));
+    valueObject[global] = configObj;
+    Object.keys(configObj).forEach((c) => {
+      if (userConfig.global[c]) {
+        configObj[c].value = userConfig.global[c];
+      }
+    });
+  });
+  return valueObject;
+};
+
+export const getStyleDisplayValue = (displayValue, global) => {
+  if (displayValue.startsWith('$')) {
+    return global[displayValue].value;
+  }
+  return displayValue;
+};
+
+const getLang = () => {
+  return location.hash.replace('#', '').split('/')[1] || 'zh-CN';
+};
+
+const getNameFromI18N = (name) => {
+  const lang = getLang();
+  return constant.filter(config => config.lang === lang)[0][name];
+};
+
+export const getStyleDisplayName = (config, componentName) => {
+  const displayNameMap = getNameFromI18N('display-name');
+  if (config.name !== '[]') {
+    const langIndex = {'zh-CN': '0', 'es': 2, 'fr-FR': 3}[getLang()] || 1;
+    const nameArr = config.name.replace(/\[?\]?/g, '').split(',');
+    return nameArr[langIndex] || nameArr[1];
+  }
+  let displayName = config.key.replace(`$--${componentName}-`, '').replace();
+  Object.keys(displayNameMap).forEach((name) => {
+    displayName = displayName.replace(name, displayNameMap[name]);
+  });
+  displayName = displayName.replace(/-/g, ' ');
+  return displayName.trim();
+};
+
+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{[^}]+}/, '');
+};

+ 181 - 0
examples/docs/en-US/border.md

@@ -0,0 +1,181 @@
+<script>
+  import bus from '../../bus';
+  const varMap = {
+    '$--box-shadow-light': 'boxShadowLight',
+    '$--box-shadow-base': 'boxShadowBase',
+    '$--border-radius-base': 'borderRadiusBase',
+    '$--border-radius-small': 'borderRadiusSmall'
+  };
+  const original = {
+    boxShadowLight: '0 2px 12px 0 rgba(0, 0, 0, 0.1)',
+    boxShadowBase: '0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04)',
+    borderRadiusBase: '4px',
+    borderRadiusSmall: '2px'
+  }
+  export default {
+    created() {
+      bus.$on('user-theme-config-update', this.setGlobal);
+    },
+    mounted() {
+      this.setGlobal();
+    },
+    methods: {
+      setGlobal() {
+        if (window.userThemeConfig) {
+          this.global = window.userThemeConfig.global;
+        }
+      }
+    },
+    data() {
+      return {
+        global: {},
+        boxShadowLight: '',
+        boxShadowBase: '',
+        borderRadiusBase: '',
+        borderRadiusSmall: ''
+      }
+    },
+    watch: {
+      global: {
+        immediate: true,
+        handler(value) {
+          Object.keys(varMap).forEach((c) => {
+            if (value[c]) {
+              this[varMap[c]] = value[c]
+            } else {
+              this[varMap[c]] = original[varMap[c]]
+            }
+          });
+        }
+      }
+    }
+  }
+</script>
+
+<style>
+.demo-border .text {
+  width: 15%;
+}
+.demo-border .line {
+  width: 70%;
+}
+.demo-border .line div{
+  width: 100%;
+  height: 0;
+  border: 1px solid #EEE;
+}
+.demo-border .line .dashed{ 
+  border: 2px dashed #EEE;
+}
+.demo-shadow {
+  height: 100px;
+  width: 50%;
+  border: 1px solid #eee;
+}
+.demo-shadow-text {
+  line-height: 50px;
+  color: #666;
+  font-size: 14px;
+}
+.demo-radius .title{
+  color: #666;
+  font-size: 18px;
+  margin: 10px 0;
+}
+.demo-radius .value{
+  color: #333;
+  font-size: 16px;
+  margin: 10px 0;
+}
+.demo-radius .radius {
+  height: 60px;
+  width: 70%;
+  border: 1px solid #D7DAE2;
+  border-radius: 0;
+  margin-top: 20px;
+}
+.demo-radius .radius-30 {
+  border-radius: 30px;
+}
+</style>
+
+## Border
+
+We standardize the borders that can be used in buttons, cards, pop-ups and other components.
+
+### Border
+
+There are few border styles to choose.
+
+<table class="demo-border">
+  <tbody>
+    <tr>
+      <td class="text">Name</td>
+      <td class="text">Thickness</td>
+      <td class="line">Demo</td>
+    </tr>
+    <tr>
+      <td class="text">Solid</td>
+      <td class="text">1px</td>
+      <td class="line">
+        <div></div>
+      </td>
+    </tr>
+    <tr>
+      <td class="text">Dashed</td>
+      <td class="text">2px</td>
+      <td class="line">
+        <div class="dashed"></div>
+      </td>
+    </tr>
+  </tbody>
+</table>
+
+### Radius
+
+There are few radius styles to choose.
+
+<el-row :gutter="12" class="demo-radius">
+  <el-col :span="6" :xs="{span: 12}">
+    <div class="title">No Radius</div>
+    <div class="value">border-radius: 0px</div>
+    <div class="radius"></div>
+  </el-col>
+  <el-col :span="6" :xs="{span: 12}">
+    <div class="title">Small Radius</div>
+    <div class="value">border-radius: {{borderRadiusSmall}}</div>
+    <div 
+      class="radius" 
+      :style="{ borderRadius: borderRadiusSmall }"
+    ></div>
+  </el-col>
+  <el-col :span="6" :xs="{span: 12}">
+    <div class="title">Large Radius</div>
+    <div class="value">border-radius: {{borderRadiusBase}}</div>
+    <div 
+      class="radius"
+      :style="{ borderRadius: borderRadiusBase }"
+    ></div>
+  </el-col>
+  <el-col :span="6" :xs="{span: 12}">
+    <div class="title">Round Radius</div>
+    <div class="value">border-radius: 30px</div>
+    <div class="radius radius-30"></div>
+  </el-col>
+</el-row>
+
+### Shadow
+
+There are few shaodw styles to choose.
+
+<div 
+class="demo-shadow"
+:style="{ boxShadow: boxShadowBase }"
+></div>
+<span class="demo-shadow-text">Basic Shaodw box-shadow: {{boxShadowBase}}</span>
+
+<div 
+class="demo-shadow"
+:style="{ boxShadow: boxShadowLight }"
+></div>
+<span class="demo-shadow-text">Light Shadow box-shadow: {{boxShadowLight}}</span>

+ 245 - 52
examples/docs/en-US/color.md

@@ -1,9 +1,101 @@
+<script>
+  import bus from '../../bus';
+  import { tintColor } from '../../color.js';
+  const varMap = {
+    'primary': '$--color-primary',
+    'success': '$--color-success',
+    'warning': '$--color-warning',
+    'danger': '$--color-danger',
+    'info': '$--color-info',
+    'white': '$--color-white',
+    'black': '$--color-black',
+    'textPrimary': '$--color-text-primary',
+    'textRegular': '$--color-text-regular',
+    'textSecondary': '$--color-text-secondary',
+    'textPlaceholder': '$--color-text-placeholder',
+    'borderBase': '$--border-color-base',
+    'borderLight': '$--border-color-light',
+    'borderLighter': '$--border-color-lighter',
+    'borderExtraLight': '$--border-color-extra-light'
+  };
+  const original = {
+    primary: '#409EFF',
+    success: '#67C23A',
+    warning: '#E6A23C',
+    danger: '#F56C6C',
+    info: '#909399',
+    white: '#FFFFFF',
+    black: '#000000',
+    textPrimary: '#303133',
+    textRegular: '#606266',
+    textSecondary: '#909399',
+    textPlaceholder: '#C0C4CC',
+    borderBase: '#DCDFE6',
+    borderLight: '#E4E7ED',
+    borderLighter: '#EBEEF5',
+    borderExtraLight: '#F2F6FC'
+  }
+  export default {
+    created() {
+      bus.$on('user-theme-config-update', this.setGlobal);
+    },
+    mounted() {
+      this.setGlobal();
+    },
+    methods: {
+      tintColor(color, tint) {
+        return tintColor(color, tint);
+      },
+      setGlobal() {
+        if (window.userThemeConfig) {
+          this.global = window.userThemeConfig.global;
+        }
+      }
+    },
+    data() {
+      return {
+        global: {},
+        primary: '',
+        success: '',
+        warning: '',
+        danger: '',
+        info: '',
+        white: '',
+        black: '',
+        textPrimary: '',
+        textRegular: '',
+        textSecondary: '',
+        textPlaceholder: '',
+        borderBase: '',
+        borderLight: '',
+        borderLighter: '',
+        borderExtraLight: ''
+      }
+    },
+    watch: {
+      global: {
+        immediate: true,
+        handler(value) {
+          Object.keys(original).forEach((o) => {
+            if (value[varMap[o]]) {
+              this[o] = value[varMap[o]]
+            } else {
+              this[o] = original[o]
+            }
+          });
+        }
+      }
+    },
+  }
+</script>
+
 <style>
 <style>
   .demo-color-box {
   .demo-color-box {
+    position: relative;
     border-radius: 4px;
     border-radius: 4px;
     padding: 20px;
     padding: 20px;
     margin: 5px 0;
     margin: 5px 0;
-    height: 74px;
+    height: 114px;
     box-sizing: border-box;
     box-sizing: border-box;
     color: #fff;
     color: #fff;
     font-size: 14px;
     font-size: 14px;
@@ -14,6 +106,12 @@
       line-height: 24px;
       line-height: 24px;
     }
     }
   }
   }
+  .demo-color-box-other {
+    height: 74px;
+    margin: 10px 0!important;
+    border-radius: 4px 4px 4px 4px!important;
+    padding: 15px 20px;
+  }
   .demo-color-box-group {
   .demo-color-box-group {
     .demo-color-box {
     .demo-color-box {
       border-radius: 0;
       border-radius: 0;
@@ -26,55 +124,48 @@
       border-radius: 0 0 4px 4px;
       border-radius: 0 0 4px 4px;
     }
     }
   }
   }
-  .bg-blue {
-    background-color: #409EFF;
-  }
-
-  .bg-success {
-    background-color: #13CE66;
+  .bg-color-sub {
+    width: 100%;
+    height: 40px;
+    left: 0;
+    bottom: 0;
+    position: absolute;
+    border-radius: 0 0 4px 4px;
   }
   }
-  .bg-warning {
-    background-color: #f7ba2a;
+  .bg-blue-sub-item {
+    width: 11.1111111%;
+    height: 100%;
+    display: inline-block;
   }
   }
-  .bg-danger {
-    background-color: #ff4949;
+  .bg-blue-sub-item:first-child {
+    border-radius: 0 0 0 4px;
   }
   }
-  .bg-info {
-    background-color: #909399;
-  }
-
-  .bg-text-primary {
-    background-color: #303133;
-  }
-  .bg-text-regular {
-    background-color: #606266;
-  }
-  .bg-text-secondary {
-    background-color: #909399;
-  }
-  .bg-text-placeholder {
-    background-color: #c0c4cc;
-  }
-
-  .bg-border-base {
-    background-color: #dcdfe6;
+  .bg-success-sub-item {
+    width: 50%;
+    height: 100%;
+    display: inline-block;
   }
   }
-  .bg-border-light {
-    background-color: #e4e7ed;
+  .bg-success-sub-item:first-child {
+    border-radius: 0 0 0 4px;
   }
   }
-  .bg-border-lighter {
-    background-color: #ebeef5;
+  .bg-success-sub-item:last-child {
+    border-radius: 0 0 4px 0;
   }
   }
-  .bg-border-extra-light {
-    background-color: #f2f6fc;
+  .bg-transparent {
+    border: 1px solid #FCC3C3;
+    color: #303133;
+    background: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' version='1.1' preserveAspectRatio='none' viewBox='0 0 100 100'><path d='M0 98 L100 0 L100 1 L1 98' fill='%23FCC3C3' /></svg>");
+    background-repeat:no-repeat;
+    background-position:center center;
+    background-size: 100% 100%, auto;
   }
   }
-
-  [class*=" bg-border-"] {
+  .demo-color-box-lite {
     color: #303133;
     color: #303133;
   }
   }
 </style>
 </style>
 
 
 ## Color
 ## Color
+
 Element uses a specific set of palettes to specify colors to provide a consistent look and feel for the products you build.
 Element uses a specific set of palettes to specify colors to provide a consistent look and feel for the products you build.
 
 
 ### Main Color
 ### Main Color
@@ -82,8 +173,24 @@ Element uses a specific set of palettes to specify colors to provide a consisten
 The main color of Element is bright and friendly blue.
 The main color of Element is bright and friendly blue.
 
 
 <el-row :gutter="12">
 <el-row :gutter="12">
-  <el-col :span="6" :xs="{span: 12}">
-    <div class="demo-color-box bg-blue">Blue<div class="value">#409EFF</div></div>
+  <el-col :span="10" :xs="{span: 12}">
+    <div 
+      class="demo-color-box"
+      :style="{ background: primary }"
+    >
+      Brand Color<div class="value">#409EFF</div>
+    <div 
+      class="bg-color-sub"
+      :style="{ background: tintColor(primary, 0.9) }"
+    >
+    <div 
+      class="bg-blue-sub-item" 
+      v-for="(item, key) in Array(8)"
+      :key="key"
+      :style="{ background: tintColor(primary, (key + 1) / 10) }"
+        >
+    </div>
+    </div>
   </el-col>
   </el-col>
 </el-row>
 </el-row>
 
 
@@ -93,16 +200,72 @@ Besides the main color, you need to use different scene colors in different scen
 
 
 <el-row :gutter="12">
 <el-row :gutter="12">
   <el-col :span="6" :xs="{span: 12}">
   <el-col :span="6" :xs="{span: 12}">
-    <div class="demo-color-box bg-success">Success<div class="value">#67C23A</div></div>
+    <div class="demo-color-box"
+    :style="{ background: success }"
+    >Success<div class="value">#67C23A</div>
+      <div 
+        class="bg-color-sub"
+      >
+        <div 
+          class="bg-success-sub-item" 
+          v-for="(item, key) in Array(2)"
+          :key="key"
+          :style="{ background: tintColor(success, (key + 8) / 10) }"
+            >
+        </div>
+      </div>
+    </div>
   </el-col>
   </el-col>
   <el-col :span="6" :xs="{span: 12}">
   <el-col :span="6" :xs="{span: 12}">
-    <div class="demo-color-box bg-warning">Warning<div class="value">#E6A23C</div></div>
+    <div class="demo-color-box"
+    :style="{ background: warning }"
+    >Warning<div class="value">#E6A23C</div>
+      <div 
+          class="bg-color-sub"
+        >
+        <div 
+          class="bg-success-sub-item" 
+          v-for="(item, key) in Array(2)"
+          :key="key"
+          :style="{ background: tintColor(warning, (key + 8) / 10) }"
+            >
+        </div>
+      </div>
+    </div>
   </el-col>
   </el-col>
   <el-col :span="6" :xs="{span: 12}">
   <el-col :span="6" :xs="{span: 12}">
-    <div class="demo-color-box bg-danger">Danger<div class="value">#F56C6C</div></div>
+    <div class="demo-color-box"
+    :style="{ background: danger }"
+    >Danger<div class="value">#F56C6C</div>
+      <div 
+          class="bg-color-sub"
+        >
+        <div 
+          class="bg-success-sub-item" 
+          v-for="(item, key) in Array(2)"
+          :key="key"
+          :style="{ background: tintColor(danger, (key + 8) / 10) }"
+            >
+        </div>
+      </div>
+    </div>
   </el-col>
   </el-col>
   <el-col :span="6" :xs="{span: 12}">
   <el-col :span="6" :xs="{span: 12}">
-    <div class="demo-color-box bg-info">Info<div class="value">#909399</div></div>
+    <div class="demo-color-box"
+    :style="{ background: info }"
+    >Info<div class="value">#909399</div>
+      <div 
+          class="bg-color-sub"
+        >
+        <div 
+          class="bg-success-sub-item" 
+          v-for="(item, key) in Array(2)"
+          :key="key"
+          :style="{ background: tintColor(info, (key + 8) / 10) }"
+            >
+        </div>
+      </div>
+    </div>
   </el-col>
   </el-col>
 </el-row>
 </el-row>
 
 
@@ -113,18 +276,48 @@ Neutral colors are for text, background and border colors. You can use different
 <el-row :gutter="12">
 <el-row :gutter="12">
   <el-col :span="6" :xs="{span: 12}">
   <el-col :span="6" :xs="{span: 12}">
     <div class="demo-color-box-group">
     <div class="demo-color-box-group">
-      <div class="demo-color-box bg-text-primary">Primary Text<div class="value">#303133</div></div>
-      <div class="demo-color-box bg-text-regular">Regular Text<div class="value">#606266</div></div>
-      <div class="demo-color-box bg-text-secondary">Secondary Text<div class="value">#909399</div></div>
-      <div class="demo-color-box bg-text-placeholder">Placeholder Text<div class="value">#C0C4CC</div></div>
+      <div class="demo-color-box demo-color-box-other"
+      :style="{ background: textPrimary }"
+      >Primary Text<div class="value">{{textPrimary}}</div></div>
+      <div class="demo-color-box demo-color-box-other"
+      :style="{ background: textRegular }"
+      >
+      Regular Text<div class="value">{{textRegular}}</div></div>
+      <div class="demo-color-box demo-color-box-other"
+      :style="{ background: textSecondary }"
+      >Secondary Text<div class="value">{{textSecondary}}</div></div>
+      <div class="demo-color-box demo-color-box-other"
+      :style="{ background: textPlaceholder }"
+      >Placeholder Text<div class="value">{{textPlaceholder}}</div></div>
+    </div>
+  </el-col>
+  <el-col :span="6" :xs="{span: 12}">
+    <div class="demo-color-box-group">
+      <div class="demo-color-box demo-color-box-other demo-color-box-lite"
+      :style="{ background: borderBase }"
+      >Base Border<div class="value">{{borderBase}}</div></div>
+      <div class="demo-color-box demo-color-box-other demo-color-box-lite"
+      :style="{ background: borderLight }"
+      >Light Border<div class="value">{{borderLight}}</div></div>
+      <div class="demo-color-box demo-color-box-other demo-color-box-lite"
+      :style="{ background: borderLighter }"
+      >Lighter Border<div class="value">{{borderLighter}}</div></div>
+      <div class="demo-color-box demo-color-box-other demo-color-box-lite"
+      :style="{ background: borderExtraLight }"
+      >Extra Light Border<div class="value">{{borderExtraLight}}</div></div>
     </div>
     </div>
   </el-col>
   </el-col>
   <el-col :span="6" :xs="{span: 12}">
   <el-col :span="6" :xs="{span: 12}">
     <div class="demo-color-box-group">
     <div class="demo-color-box-group">
-      <div class="demo-color-box bg-border-base">Base Border<div class="value">#DCDFE6</div></div>
-      <div class="demo-color-box bg-border-light">Light Border<div class="value">#E4E7ED</div></div>
-      <div class="demo-color-box bg-border-lighter">Lighter Border<div class="value">#EBEEF5</div></div>
-      <div class="demo-color-box bg-border-extra-light">Extra Light Border<div class="value">#F2F6FC</div></div>
+      <div 
+      class="demo-color-box demo-color-box-other"
+      :style="{ background: black }"
+      >Basic Black<div class="value">{{black}}</div></div>
+      <div
+      class="demo-color-box demo-color-box-other"
+      :style="{ background: white, color: '#303133', border: '1px solid #eee' }"
+      >Basic White<div class="value">{{white}}</div></div>
+      <div class="demo-color-box demo-color-box-other bg-transparent">Transparent<div class="value">Transparent</div>
     </div>
     </div>
   </el-col>
   </el-col>
 </el-row>
 </el-row>

+ 150 - 119
examples/docs/en-US/typography.md

@@ -1,74 +1,96 @@
-<style>
-  .demo-typo-box {
-    height: 200px;
-    width: 200px;
-    position: relative;
-    border: 1px solid #eaeefb;
-    font-size: 40px;
-    color: #1f2d3d;
-    text-align: center;
-    line-height: 162px;
-    padding-bottom: 36px;
-    box-sizing: border-box;
-    display: inline-block;
-    margin-right: 17px;
-    border-radius: 4px;
-
-    .name {
-      position: absolute;
-      bottom: 0;
-      width: 100%;
-      height: 35px;
-      border-top: 1px solid #eaeefb;
-      font-size: 14px;
-      color: #8492a6;
-      line-height: 35px;
-      text-align: left;
-      text-indent: 10px;
-      font-family: 'Helvetica Neue';
-    }
+<script>
+  import bus from '../../bus';
+  const varMap = [
+    '$--font-size-extra-large',
+    '$--font-size-large',
+    '$--font-size-medium',
+    '$--font-size-base',
+    '$--font-size-small',
+    '$--font-size-extra-small'
+  ];
+  const original = {
+    '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'
+  }
+  export default {
+    created() {
+      bus.$on('user-theme-config-update', this.setGlobal);
+    },
+    mounted() {
+      this.setGlobal();
+    },
+    methods: {
+      tintColor(color, tint) {
+        return tintColor(color, tint);
+      },
+      setGlobal() {
+        if (window.userThemeConfig) {
+          this.global = window.userThemeConfig.global;
+        }
+      }
+    },
+    data() {
+      return {
+        global: {},
+        'font_size_extra_large': '',
+        'font_size_large': '',
+        'font_size_medium': '',
+        'font_size_base': '',
+        'font_size_small': '',
+        'font_size_extra_small': ''
+      }
+    },
+    watch: {
+      global: {
+        immediate: true,
+        handler(value) {
+          varMap.forEach((v) => {
+            const key = v.replace('$--', '').replace(/-/g, '_')
+            if (value[v]) {
+              this[key] = value[v]
+            } else {
+              this[key] = original[key]
+            }
+          });
+        }
+      }
+    },
   }
   }
+</script>
+<style>
   .demo-typo-size {
   .demo-typo-size {
-    .h1 {
-      font-size: 20px;
-    }
-    .h2 {
-      font-size: 18px;
-    }
-    .h3 {
-      font-size: 16px;
-    }
-    .text-regular {
-      font-size: 14px;
-    }
-    .text-small {
-      font-size: 13px;
-    }
-    .text-smaller {
-      font-size: 12px;
-    }
     .color-dark-light {
     .color-dark-light {
       color: #99a9bf;
       color: #99a9bf;
     }
     }
   }
   }
-  .typo-PingFang {
-    font-family: 'PingFang SC';
-  }
-  .typo-Hiragino {
-    font-family: 'Hiragino Sans GB';
+  .demo-term-box img{
+    width: 24%;
+    margin: 0 4% 20px 0;
   }
   }
-  .typo-Microsoft {
-    font-family: 'Microsoft YaHei';
+
+  .lineH-left {
+    display: inline-block;
+    height: 80px
   }
   }
-  /* 英文 */
-  .typo-Helvetica-Neue {
-    font-family: 'Helvetica Neue';
+  .lineH-right {
+    display: inline-block;
+    list-style: none;
+    padding: 0 0 0 90px;
+    margin: 0;
+    vertical-align: top;
   }
   }
-  .typo-Helvetica {
-    font-family: 'Helvetica';
+  .lineH-right li{
+    font-size: 13px;
+    color: #666;
+    height: 20px;
+    line-height: 20px;
   }
   }
-  .typo-Arial {
-    font-family: 'Arial';
+  .lineH-right li span{
+    padding-left: 40px;
   }
   }
 </style>
 </style>
 
 
@@ -76,76 +98,85 @@
 
 
 We create a font convention to ensure the best presentation across different platforms.
 We create a font convention to ensure the best presentation across different platforms.
 
 
-### Chinese Font
-
-<div class="demo-typo-box typo-PingFang">
-  和畅惠风
-  <div class="name">PingFang SC</div>
-</div>
-<div class="demo-typo-box typo-Hiragino">
-  和畅惠风
-  <div class="name">Hiragino Sans GB</div>
+### Font
+<div class="demo-term-box">
+<img src="../../assets/images/term-pingfang.png" alt="">
+<img src="../../assets/images/term-hiragino.png" alt="">
+<img src="../../assets/images/term-microsoft.png" alt="">
+<img src="../../assets/images/term-sf.png" alt="">
+<img src="../../assets/images/term-helvetica.png" alt="">
+<img src="../../assets/images/term-arial.png" alt="">
 </div>
 </div>
-<div class="demo-typo-box typo-Microsoft">
-  和畅惠风
-  <div class="name">Microsoft YaHei</div>
-</div>
-
-### English / Numberic Font
-
-<div class="demo-typo-box typo-Helvetica-neue">
-  RGag
-  <div class="name">Helvetica Neue</div>
-</div>
-<div class="demo-typo-box typo-Helvetica">
-  RGag
-  <div class="name">Helvetica</div>
-</div>
-<div class="demo-typo-box typo-Arial">
-  RGag
-  <div class="name">Arial</div>
-</div>
-
-### Font-family
-
-```css
-font-family: "Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","微软雅黑",Arial,sans-serif;
-```
 
 
 ### Font Convention
 ### Font Convention
 
 
 <table class="demo-typo-size">
 <table class="demo-typo-size">
   <tbody>
   <tbody>
-    <tr>
-      <td class="h1">Main Title</td>
-      <td class="h1">Build with Element</td>
-      <td class="color-dark-light">20px  Extra large</td>
+  <tr
+    >
+      <td>Level</td>
+      <td>Font Size</td>
+      <td class="color-dark-light">Demo</td>
     </tr>
     </tr>
-    <tr>
-      <td class="h2">Title</td>
-      <td class="h2">Build with Element</td>
-      <td class="color-dark-light">18px large</td>
+    <tr
+    :style="{ fontSize: font_size_extra_small }"
+    >
+      <td>Supplementary text</td>
+      <td class="color-dark-light">{{font_size_extra_small}} Extra Small</td>
+      <td>Build with Element</td>
     </tr>
     </tr>
-    <tr>
-      <td class="h3">Small Title</td>
-      <td class="h3">Build with Element</td>
-      <td class="color-dark-light">16px Medium</td>
+    <tr
+    :style="{ fontSize: font_size_small }"
+    >
+      <td>Body (small)</td>
+      <td class="color-dark-light">{{font_size_small}} Small</td>
+      <td>Build with Element</td>
     </tr>
     </tr>
-    <tr>
-      <td class="text-regular">Body</td>
-      <td class="text-regular">Build with Element</td>
-      <td class="color-dark-light">14px Small</td>
+    <tr
+    :style="{ fontSize: font_size_base }"
+    >
+      <td>Body</td>
+      <td class="color-dark-light">{{font_size_base}} Base</td>
+      <td>Build with Element</td>
     </tr>
     </tr>
-    <tr>
-      <td class="text-small">Body (small)</td>
-      <td class="text-small">Build with Element</td>
-      <td class="color-dark-light">13px Extra Small</td>
+    <tr
+    :style="{ fontSize: font_size_medium }"
+    >
+      <td >Small Title</td>
+      <td class="color-dark-light">{{font_size_medium}} Medium</td>
+      <td>Build with Element</td>
     </tr>
     </tr>
-    <tr>
-      <td class="text-smaller">Supplementary text</td>
-      <td class="text-smaller">Build with Element</td>
-      <td class="color-dark-light">12px Extra Extra Small</td>
+    <tr
+    :style="{ fontSize: font_size_large }"
+    >
+      <td>Title</td>
+      <td class="color-dark-light">{{font_size_large}} large</td>
+      <td>Build with Element</td>
+    </tr>
+    <tr
+    :style="{ fontSize: font_size_extra_large }"
+    >
+      <td>Main Title</td>
+      <td class="color-dark-light">{{font_size_extra_large}} Extra large</td>
+      <td>Build with Element</td>
     </tr>
     </tr>
   </tbody>
   </tbody>
 </table>
 </table>
 
 
+### Font Line Height
+
+<div>
+<img class="lineH-left" src="~examples/assets/images/typography.png" />
+<ul class="lineH-right">
+<li>line-height:1 <span>No line height</span></li>
+<li>line-height:1.3 <span>Compact</span></li>
+<li>line-height:1.5 <span>Regular</span></li>
+<li>line-height:1.7 <span>Loose</span></li>
+</ul>
+</div>
+
+### Font-family
+
+```css
+font-family: "Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","微软雅黑",Arial,sans-serif;
+```

+ 181 - 0
examples/docs/es/border.md

@@ -0,0 +1,181 @@
+<script>
+  import bus from '../../bus';
+  const varMap = {
+    '$--box-shadow-light': 'boxShadowLight',
+    '$--box-shadow-base': 'boxShadowBase',
+    '$--border-radius-base': 'borderRadiusBase',
+    '$--border-radius-small': 'borderRadiusSmall'
+  };
+  const original = {
+    boxShadowLight: '0 2px 12px 0 rgba(0, 0, 0, 0.1)',
+    boxShadowBase: '0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04)',
+    borderRadiusBase: '4px',
+    borderRadiusSmall: '2px'
+  }
+  export default {
+    created() {
+      bus.$on('user-theme-config-update', this.setGlobal);
+    },
+    mounted() {
+      this.setGlobal();
+    },
+    methods: {
+      setGlobal() {
+        if (window.userThemeConfig) {
+          this.global = window.userThemeConfig.global;
+        }
+      }
+    },
+    data() {
+      return {
+        global: {},
+        boxShadowLight: '',
+        boxShadowBase: '',
+        borderRadiusBase: '',
+        borderRadiusSmall: ''
+      }
+    },
+    watch: {
+      global: {
+        immediate: true,
+        handler(value) {
+          Object.keys(varMap).forEach((c) => {
+            if (value[c]) {
+              this[varMap[c]] = value[c]
+            } else {
+              this[varMap[c]] = original[varMap[c]]
+            }
+          });
+        }
+      }
+    }
+  }
+</script>
+
+<style>
+.demo-border .text {
+  width: 15%;
+}
+.demo-border .line {
+  width: 70%;
+}
+.demo-border .line div{
+  width: 100%;
+  height: 0;
+  border: 1px solid #EEE;
+}
+.demo-border .line .dashed{ 
+  border: 2px dashed #EEE;
+}
+.demo-shadow {
+  height: 100px;
+  width: 50%;
+  border: 1px solid #eee;
+}
+.demo-shadow-text {
+  line-height: 50px;
+  color: #666;
+  font-size: 14px;
+}
+.demo-radius .title{
+  color: #666;
+  font-size: 18px;
+  margin: 10px 0;
+}
+.demo-radius .value{
+  color: #333;
+  font-size: 16px;
+  margin: 10px 0;
+}
+.demo-radius .radius {
+  height: 60px;
+  width: 70%;
+  border: 1px solid #D7DAE2;
+  border-radius: 0;
+  margin-top: 20px;
+}
+.demo-radius .radius-30 {
+  border-radius: 30px;
+}
+</style>
+
+## Border
+
+We standardize the borders that can be used in buttons, cards, pop-ups and other components.
+
+### Border
+
+There are few border styles to choose.
+
+<table class="demo-border">
+  <tbody>
+    <tr>
+      <td class="text">Name</td>
+      <td class="text">Thickness</td>
+      <td class="line">Demo</td>
+    </tr>
+    <tr>
+      <td class="text">Solid</td>
+      <td class="text">1px</td>
+      <td class="line">
+        <div></div>
+      </td>
+    </tr>
+    <tr>
+      <td class="text">Dashed</td>
+      <td class="text">2px</td>
+      <td class="line">
+        <div class="dashed"></div>
+      </td>
+    </tr>
+  </tbody>
+</table>
+
+### Radius
+
+There are few radius styles to choose.
+
+<el-row :gutter="12" class="demo-radius">
+  <el-col :span="6" :xs="{span: 12}">
+    <div class="title">No Radius</div>
+    <div class="value">border-radius: 0px</div>
+    <div class="radius"></div>
+  </el-col>
+  <el-col :span="6" :xs="{span: 12}">
+    <div class="title">Small Radius</div>
+    <div class="value">border-radius: {{borderRadiusSmall}}</div>
+    <div 
+      class="radius" 
+      :style="{ borderRadius: borderRadiusSmall }"
+    ></div>
+  </el-col>
+  <el-col :span="6" :xs="{span: 12}">
+    <div class="title">Large Radius</div>
+    <div class="value">border-radius: {{borderRadiusBase}}</div>
+    <div 
+      class="radius"
+      :style="{ borderRadius: borderRadiusBase }"
+    ></div>
+  </el-col>
+  <el-col :span="6" :xs="{span: 12}">
+    <div class="title">Round Radius</div>
+    <div class="value">border-radius: 30px</div>
+    <div class="radius radius-30"></div>
+  </el-col>
+</el-row>
+
+### Shadow
+
+There are few shaodw styles to choose.
+
+<div 
+class="demo-shadow"
+:style="{ boxShadow: boxShadowBase }"
+></div>
+<span class="demo-shadow-text">Basic Shaodw box-shadow: {{boxShadowBase}}</span>
+
+<div 
+class="demo-shadow"
+:style="{ boxShadow: boxShadowLight }"
+></div>
+<span class="demo-shadow-text">Light Shadow box-shadow: {{boxShadowLight}}</span>

+ 245 - 53
examples/docs/es/color.md

@@ -1,19 +1,117 @@
+<script>
+  import bus from '../../bus';
+  import { tintColor } from '../../color.js';
+  const varMap = {
+    'primary': '$--color-primary',
+    'success': '$--color-success',
+    'warning': '$--color-warning',
+    'danger': '$--color-danger',
+    'info': '$--color-info',
+    'white': '$--color-white',
+    'black': '$--color-black',
+    'textPrimary': '$--color-text-primary',
+    'textRegular': '$--color-text-regular',
+    'textSecondary': '$--color-text-secondary',
+    'textPlaceholder': '$--color-text-placeholder',
+    'borderBase': '$--border-color-base',
+    'borderLight': '$--border-color-light',
+    'borderLighter': '$--border-color-lighter',
+    'borderExtraLight': '$--border-color-extra-light'
+  };
+  const original = {
+    primary: '#409EFF',
+    success: '#67C23A',
+    warning: '#E6A23C',
+    danger: '#F56C6C',
+    info: '#909399',
+    white: '#FFFFFF',
+    black: '#000000',
+    textPrimary: '#303133',
+    textRegular: '#606266',
+    textSecondary: '#909399',
+    textPlaceholder: '#C0C4CC',
+    borderBase: '#DCDFE6',
+    borderLight: '#E4E7ED',
+    borderLighter: '#EBEEF5',
+    borderExtraLight: '#F2F6FC'
+  }
+  export default {
+    created() {
+      bus.$on('user-theme-config-update', this.setGlobal);
+    },
+    mounted() {
+      this.setGlobal();
+    },
+    methods: {
+      tintColor(color, tint) {
+        return tintColor(color, tint);
+      },
+      setGlobal() {
+        if (window.userThemeConfig) {
+          this.global = window.userThemeConfig.global;
+        }
+      }
+    },
+    data() {
+      return {
+        global: {},
+        primary: '',
+        success: '',
+        warning: '',
+        danger: '',
+        info: '',
+        white: '',
+        black: '',
+        textPrimary: '',
+        textRegular: '',
+        textSecondary: '',
+        textPlaceholder: '',
+        borderBase: '',
+        borderLight: '',
+        borderLighter: '',
+        borderExtraLight: ''
+      }
+    },
+    watch: {
+      global: {
+        immediate: true,
+        handler(value) {
+          Object.keys(original).forEach((o) => {
+            if (value[varMap[o]]) {
+              this[o] = value[varMap[o]]
+            } else {
+              this[o] = original[o]
+            }
+          });
+        }
+      }
+    },
+  }
+</script>
+
 <style>
 <style>
   .demo-color-box {
   .demo-color-box {
+    position: relative;
     border-radius: 4px;
     border-radius: 4px;
     padding: 20px;
     padding: 20px;
     margin: 5px 0;
     margin: 5px 0;
-    height: 74px;
+    height: 114px;
     box-sizing: border-box;
     box-sizing: border-box;
     color: #fff;
     color: #fff;
     font-size: 14px;
     font-size: 14px;
-    
+
     & .value {
     & .value {
       font-size: 12px;
       font-size: 12px;
       opacity: 0.69;
       opacity: 0.69;
       line-height: 24px;
       line-height: 24px;
     }
     }
   }
   }
+  .demo-color-box-other {
+    height: 74px;
+    margin: 10px 0!important;
+    border-radius: 4px 4px 4px 4px!important;
+    padding: 15px 20px;
+  }
   .demo-color-box-group {
   .demo-color-box-group {
     .demo-color-box {
     .demo-color-box {
       border-radius: 0;
       border-radius: 0;
@@ -26,50 +124,42 @@
       border-radius: 0 0 4px 4px;
       border-radius: 0 0 4px 4px;
     }
     }
   }
   }
-  .bg-blue {
-    background-color: #409EFF;
+  .bg-color-sub {
+    width: 100%;
+    height: 40px;
+    left: 0;
+    bottom: 0;
+    position: absolute;
+    border-radius: 0 0 4px 4px;
   }
   }
-
-  .bg-success {
-    background-color: #13CE66;
+  .bg-blue-sub-item {
+    width: 11.1111111%;
+    height: 100%;
+    display: inline-block;
   }
   }
-  .bg-warning {
-    background-color: #f7ba2a;
+  .bg-blue-sub-item:first-child {
+    border-radius: 0 0 0 4px;
   }
   }
-  .bg-danger {
-    background-color: #ff4949;
+  .bg-success-sub-item {
+    width: 50%;
+    height: 100%;
+    display: inline-block;
   }
   }
-  .bg-info {
-    background-color: #909399;
-  }
-
-  .bg-text-primary {
-    background-color: #303133;
-  }
-  .bg-text-regular {
-    background-color: #606266;
-  }
-  .bg-text-secondary {
-    background-color: #909399;
-  }
-  .bg-text-placeholder {
-    background-color: #c0c4cc;
-  }
-
-  .bg-border-base {
-    background-color: #dcdfe6;
+  .bg-success-sub-item:first-child {
+    border-radius: 0 0 0 4px;
   }
   }
-  .bg-border-light {
-    background-color: #e4e7ed;
+  .bg-success-sub-item:last-child {
+    border-radius: 0 0 4px 0;
   }
   }
-  .bg-border-lighter {
-    background-color: #ebeef5;
-  }
-  .bg-border-extra-light {
-    background-color: #f2f6fc;
+  .bg-transparent {
+    border: 1px solid #FCC3C3;
+    color: #303133;
+    background: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' version='1.1' preserveAspectRatio='none' viewBox='0 0 100 100'><path d='M0 98 L100 0 L100 1 L1 98' fill='%23FCC3C3' /></svg>");
+    background-repeat:no-repeat;
+    background-position:center center;
+    background-size: 100% 100%, auto;
   }
   }
-
-  [class*=" bg-border-"] {
+  .demo-color-box-lite {
     color: #303133;
     color: #303133;
   }
   }
 </style>
 </style>
@@ -82,8 +172,24 @@ Element utiliza un conjunto de paletas para especificar colores, y así, proporc
 El color principal de Element es el azul brillante y amigable.
 El color principal de Element es el azul brillante y amigable.
 
 
 <el-row :gutter="12">
 <el-row :gutter="12">
-  <el-col :span="6" :xs="{span: 12}">
-    <div class="demo-color-box bg-blue">Azul<div class="value">#409EFF</div></div>
+  <el-col :span="10" :xs="{span: 12}">
+    <div 
+      class="demo-color-box"
+      :style="{ background: primary }"
+    >
+      Brand Color<div class="value">#409EFF</div>
+    <div 
+      class="bg-color-sub"
+      :style="{ background: tintColor(primary, 0.9) }"
+    >
+    <div 
+      class="bg-blue-sub-item" 
+      v-for="(item, key) in Array(8)"
+      :key="key"
+      :style="{ background: tintColor(primary, (key + 1) / 10) }"
+        >
+    </div>
+    </div>
   </el-col>
   </el-col>
 </el-row>
 </el-row>
 
 
@@ -93,16 +199,72 @@ Además del color principal, se necesitan utilizar distintos colores para difere
 
 
 <el-row :gutter="12">
 <el-row :gutter="12">
   <el-col :span="6" :xs="{span: 12}">
   <el-col :span="6" :xs="{span: 12}">
-    <div class="demo-color-box bg-success">Éxito<div class="value">#67C23A</div></div>
+    <div class="demo-color-box"
+    :style="{ background: success }"
+    >Success<div class="value">#67C23A</div>
+      <div 
+        class="bg-color-sub"
+      >
+        <div 
+          class="bg-success-sub-item" 
+          v-for="(item, key) in Array(2)"
+          :key="key"
+          :style="{ background: tintColor(success, (key + 8) / 10) }"
+            >
+        </div>
+      </div>
+    </div>
   </el-col>
   </el-col>
   <el-col :span="6" :xs="{span: 12}">
   <el-col :span="6" :xs="{span: 12}">
-    <div class="demo-color-box bg-warning">Precaución<div class="value">#E6A23C</div></div>
+    <div class="demo-color-box"
+    :style="{ background: warning }"
+    >Warning<div class="value">#E6A23C</div>
+      <div 
+          class="bg-color-sub"
+        >
+        <div 
+          class="bg-success-sub-item" 
+          v-for="(item, key) in Array(2)"
+          :key="key"
+          :style="{ background: tintColor(warning, (key + 8) / 10) }"
+            >
+        </div>
+      </div>
+    </div>
   </el-col>
   </el-col>
   <el-col :span="6" :xs="{span: 12}">
   <el-col :span="6" :xs="{span: 12}">
-    <div class="demo-color-box bg-danger">Peligro<div class="value">#F56C6C</div></div>
+    <div class="demo-color-box"
+    :style="{ background: danger }"
+    >Danger<div class="value">#F56C6C</div>
+      <div 
+          class="bg-color-sub"
+        >
+        <div 
+          class="bg-success-sub-item" 
+          v-for="(item, key) in Array(2)"
+          :key="key"
+          :style="{ background: tintColor(danger, (key + 8) / 10) }"
+            >
+        </div>
+      </div>
+    </div>
   </el-col>
   </el-col>
   <el-col :span="6" :xs="{span: 12}">
   <el-col :span="6" :xs="{span: 12}">
-    <div class="demo-color-box bg-info">Info<div class="value">#909399</div></div>
+    <div class="demo-color-box"
+    :style="{ background: info }"
+    >Info<div class="value">#909399</div>
+      <div 
+          class="bg-color-sub"
+        >
+        <div 
+          class="bg-success-sub-item" 
+          v-for="(item, key) in Array(2)"
+          :key="key"
+          :style="{ background: tintColor(info, (key + 8) / 10) }"
+            >
+        </div>
+      </div>
+    </div>
   </el-col>
   </el-col>
 </el-row>
 </el-row>
 
 
@@ -113,18 +275,48 @@ Los colores neutrales son para texto, fondos y bordes. Puede usar diferentes col
 <el-row :gutter="12">
 <el-row :gutter="12">
   <el-col :span="6" :xs="{span: 12}">
   <el-col :span="6" :xs="{span: 12}">
     <div class="demo-color-box-group">
     <div class="demo-color-box-group">
-      <div class="demo-color-box bg-text-primary">Texto primario<div class="value">#303133</div></div>
-      <div class="demo-color-box bg-text-regular">Texto regular<div class="value">#606266</div></div>
-      <div class="demo-color-box bg-text-secondary">Texto secundario<div class="value">#909399</div></div>
-      <div class="demo-color-box bg-text-placeholder">Texto de placeholder<div class="value">#C0C4CC</div></div>
+      <div class="demo-color-box demo-color-box-other"
+      :style="{ background: textPrimary }"
+      >Texto primario<div class="value">{{textPrimary}}</div></div>
+      <div class="demo-color-box demo-color-box-other"
+      :style="{ background: textRegular }"
+      >
+      Texto regular<div class="value">{{textRegular}}</div></div>
+      <div class="demo-color-box demo-color-box-other"
+      :style="{ background: textSecondary }"
+      >Texto secundario<div class="value">{{textSecondary}}</div></div>
+      <div class="demo-color-box demo-color-box-other"
+      :style="{ background: textPlaceholder }"
+      >Texto de placeholder<div class="value">{{textPlaceholder}}</div></div>
+    </div>
+  </el-col>
+  <el-col :span="6" :xs="{span: 12}">
+    <div class="demo-color-box-group">
+      <div class="demo-color-box demo-color-box-other demo-color-box-lite"
+      :style="{ background: borderBase }"
+      >Borde base<div class="value">{{borderBase}}</div></div>
+      <div class="demo-color-box demo-color-box-other demo-color-box-lite"
+      :style="{ background: borderLight }"
+      >Borde ligero<div class="value">{{borderLight}}</div></div>
+      <div class="demo-color-box demo-color-box-other demo-color-box-lite"
+      :style="{ background: borderLighter }"
+      >Borde claro<div class="value">{{borderLighter}}</div></div>
+      <div class="demo-color-box demo-color-box-other demo-color-box-lite"
+      :style="{ background: borderExtraLight }"
+      >Borde extra claro<div class="value">{{borderExtraLight}}</div></div>
     </div>
     </div>
   </el-col>
   </el-col>
   <el-col :span="6" :xs="{span: 12}">
   <el-col :span="6" :xs="{span: 12}">
     <div class="demo-color-box-group">
     <div class="demo-color-box-group">
-      <div class="demo-color-box bg-border-base">Borde base<div class="value">#DCDFE6</div></div>
-      <div class="demo-color-box bg-border-light">Borde ligero<div class="value">#E4E7ED</div></div>
-      <div class="demo-color-box bg-border-lighter">Borde claro<div class="value">#EBEEF5</div></div>
-      <div class="demo-color-box bg-border-extra-light">Borde extra claro<div class="value">#F2F6FC</div></div>
+      <div 
+      class="demo-color-box demo-color-box-other"
+      :style="{ background: black }"
+      >Basic Black<div class="value">{{black}}</div></div>
+      <div
+      class="demo-color-box demo-color-box-other"
+      :style="{ background: white, color: '#303133', border: '1px solid #eee' }"
+      >Basic White<div class="value">{{white}}</div></div>
+      <div class="demo-color-box demo-color-box-other bg-transparent">Transparent<div class="value">Transparent</div>
     </div>
     </div>
   </el-col>
   </el-col>
 </el-row>
 </el-row>

+ 150 - 119
examples/docs/es/typography.md

@@ -1,74 +1,96 @@
-<style>
-  .demo-typo-box {
-    height: 200px;
-    width: 200px;
-    position: relative;
-    border: 1px solid #eaeefb;
-    font-size: 40px;
-    color: #1f2d3d;
-    text-align: center;
-    line-height: 162px;
-    padding-bottom: 36px;
-    box-sizing: border-box;
-    display: inline-block;
-    margin-right: 17px;
-    border-radius: 4px;
-    
-    .name {
-      position: absolute;
-      bottom: 0;
-      width: 100%;
-      height: 35px;
-      border-top: 1px solid #eaeefb;
-      font-size: 14px;
-      color: #8492a6;
-      line-height: 35px;
-      text-align: left;
-      text-indent: 10px;
-      font-family: 'Helvetica Neue';
-    }
+<script>
+  import bus from '../../bus';
+  const varMap = [
+    '$--font-size-extra-large',
+    '$--font-size-large',
+    '$--font-size-medium',
+    '$--font-size-base',
+    '$--font-size-small',
+    '$--font-size-extra-small'
+  ];
+  const original = {
+    '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'
   }
   }
+  export default {
+    created() {
+      bus.$on('user-theme-config-update', this.setGlobal);
+    },
+    mounted() {
+      this.setGlobal();
+    },
+    methods: {
+      tintColor(color, tint) {
+        return tintColor(color, tint);
+      },
+      setGlobal() {
+        if (window.userThemeConfig) {
+          this.global = window.userThemeConfig.global;
+        }
+      }
+    },
+    data() {
+      return {
+        global: {},
+        'font_size_extra_large': '',
+        'font_size_large': '',
+        'font_size_medium': '',
+        'font_size_base': '',
+        'font_size_small': '',
+        'font_size_extra_small': ''
+      }
+    },
+    watch: {
+      global: {
+        immediate: true,
+        handler(value) {
+          varMap.forEach((v) => {
+            const key = v.replace('$--', '').replace(/-/g, '_')
+            if (value[v]) {
+              this[key] = value[v]
+            } else {
+              this[key] = original[key]
+            }
+          });
+        }
+      }
+    },
+  }
+</script>
+<style>
   .demo-typo-size {
   .demo-typo-size {
-    .h1 {
-      font-size: 20px;
-    }
-    .h2 {
-      font-size: 18px;
-    }
-    .h3 {
-      font-size: 16px;
-    }
-    .text-regular {
-      font-size: 14px;
-    }
-    .text-small {
-      font-size: 13px;
-    }
-    .text-smaller {
-      font-size: 12px;
-    }
     .color-dark-light {
     .color-dark-light {
       color: #99a9bf;
       color: #99a9bf;
     }
     }
   }
   }
-  .typo-PingFang {
-    font-family: 'PingFang SC';
-  }
-  .typo-Hiragino {
-    font-family: 'Hiragino Sans GB';
+  .demo-term-box img{
+    width: 24%;
+    margin: 0 4% 20px 0;
   }
   }
-  .typo-Microsoft {
-    font-family: 'Microsoft YaHei';
+
+  .lineH-left {
+    display: inline-block;
+    height: 80px
   }
   }
-  /* 英文 */
-  .typo-Helvetica-Neue {
-    font-family: 'Helvetica Neue';
+  .lineH-right {
+    display: inline-block;
+    list-style: none;
+    padding: 0 0 0 90px;
+    margin: 0;
+    vertical-align: top;
   }
   }
-  .typo-Helvetica {
-    font-family: 'Helvetica';
+  .lineH-right li{
+    font-size: 13px;
+    color: #666;
+    height: 20px;
+    line-height: 20px;
   }
   }
-  .typo-Arial {
-    font-family: 'Arial';
+  .lineH-right li span{
+    padding-left: 40px;
   }
   }
 </style>
 </style>
 
 
@@ -76,76 +98,85 @@
 
 
 Creamos una convención de fuentes para asegurar la mejor presentación en diferentes plataformas.
 Creamos una convención de fuentes para asegurar la mejor presentación en diferentes plataformas.
 
 
-### Fuente en chino
-
-<div class="demo-typo-box typo-PingFang">
-  和畅惠风
-  <div class="name">PingFang SC</div>
-</div>
-<div class="demo-typo-box typo-Hiragino">
-  和畅惠风
-  <div class="name">Hiragino Sans GB</div>
-</div>
-<div class="demo-typo-box typo-Microsoft">
-  和畅惠风
-  <div class="name">Microsoft YaHei</div>
-</div>
-
-### Inglés / Fuente Numérica
-
-<div class="demo-typo-box typo-Helvetica-neue">
-  RGag
-  <div class="name">Helvetica Neue</div>
-</div>
-<div class="demo-typo-box typo-Helvetica">
-  RGag
-  <div class="name">Helvetica</div>
+### Fuente
+<div class="demo-term-box">
+<img src="../../assets/images/term-pingfang.png" alt="">
+<img src="../../assets/images/term-hiragino.png" alt="">
+<img src="../../assets/images/term-microsoft.png" alt="">
+<img src="../../assets/images/term-sf.png" alt="">
+<img src="../../assets/images/term-helvetica.png" alt="">
+<img src="../../assets/images/term-arial.png" alt="">
 </div>
 </div>
-<div class="demo-typo-box typo-Arial">
-  RGag
-  <div class="name">Arial</div>
-</div>
-
-### Font-family
-
-```css
-font-family: "Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","微软雅黑",Arial,sans-serif;
-```
 
 
 ### Convención de fuentes
 ### Convención de fuentes
 
 
 <table class="demo-typo-size">
 <table class="demo-typo-size">
   <tbody>
   <tbody>
-    <tr>
-      <td class="h1">Main Title</td>
-      <td class="h1">Build with Element</td>
-      <td class="color-dark-light">20px  Extra large</td>
+  <tr
+    >
+      <td>Level</td>
+      <td>Font Size</td>
+      <td class="color-dark-light">Demo</td>
     </tr>
     </tr>
-    <tr>
-      <td class="h2">Title</td>
-      <td class="h2">Build with Element</td>
-      <td class="color-dark-light">18px large</td>
+    <tr
+    :style="{ fontSize: font_size_extra_small }"
+    >
+      <td>Supplementary text</td>
+      <td class="color-dark-light">{{font_size_extra_small}} Extra Small</td>
+      <td>Build with Element</td>
     </tr>
     </tr>
-    <tr>
-      <td class="h3">Small Title</td>
-      <td class="h3">Build with Element</td>
-      <td class="color-dark-light">16px Medium</td>
+    <tr
+    :style="{ fontSize: font_size_small }"
+    >
+      <td>Body (small)</td>
+      <td class="color-dark-light">{{font_size_small}} Small</td>
+      <td>Build with Element</td>
     </tr>
     </tr>
-    <tr>
-      <td class="text-regular">Body</td>
-      <td class="text-regular">Build with Element</td>
-      <td class="color-dark-light">14px Small</td>
+    <tr
+    :style="{ fontSize: font_size_base }"
+    >
+      <td>Body</td>
+      <td class="color-dark-light">{{font_size_base}} Base</td>
+      <td>Build with Element</td>
     </tr>
     </tr>
-    <tr>
-      <td class="text-small">Body (small)</td>
-      <td class="text-small">Build with Element</td>
-      <td class="color-dark-light">13px Extra Small</td>
+    <tr
+    :style="{ fontSize: font_size_medium }"
+    >
+      <td >Small Title</td>
+      <td class="color-dark-light">{{font_size_medium}} Medium</td>
+      <td>Build with Element</td>
     </tr>
     </tr>
-    <tr>
-      <td class="text-smaller">Supplementary text</td>
-      <td class="text-smaller">Build with Element</td>
-      <td class="color-dark-light">12px Extra Extra Small</td>
+    <tr
+    :style="{ fontSize: font_size_large }"
+    >
+      <td>Title</td>
+      <td class="color-dark-light">{{font_size_large}} large</td>
+      <td>Build with Element</td>
+    </tr>
+    <tr
+    :style="{ fontSize: font_size_extra_large }"
+    >
+      <td>Main Title</td>
+      <td class="color-dark-light">{{font_size_extra_large}} Extra large</td>
+      <td>Build with Element</td>
     </tr>
     </tr>
   </tbody>
   </tbody>
 </table>
 </table>
 
 
+### Font Line Height
+
+<div>
+<img class="lineH-left" src="~examples/assets/images/typography.png" />
+<ul class="lineH-right">
+<li>line-height:1 <span>No line height</span></li>
+<li>line-height:1.3 <span>Compact</span></li>
+<li>line-height:1.5 <span>Regular</span></li>
+<li>line-height:1.7 <span>Loose</span></li>
+</ul>
+</div>
+
+### Font-family
+
+```css
+font-family: "Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","微软雅黑",Arial,sans-serif;
+```

+ 181 - 0
examples/docs/fr-FR/border.md

@@ -0,0 +1,181 @@
+<script>
+  import bus from '../../bus';
+  const varMap = {
+    '$--box-shadow-light': 'boxShadowLight',
+    '$--box-shadow-base': 'boxShadowBase',
+    '$--border-radius-base': 'borderRadiusBase',
+    '$--border-radius-small': 'borderRadiusSmall'
+  };
+  const original = {
+    boxShadowLight: '0 2px 12px 0 rgba(0, 0, 0, 0.1)',
+    boxShadowBase: '0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04)',
+    borderRadiusBase: '4px',
+    borderRadiusSmall: '2px'
+  }
+  export default {
+    created() {
+      bus.$on('user-theme-config-update', this.setGlobal);
+    },
+    mounted() {
+      this.setGlobal();
+    },
+    methods: {
+      setGlobal() {
+        if (window.userThemeConfig) {
+          this.global = window.userThemeConfig.global;
+        }
+      }
+    },
+    data() {
+      return {
+        global: {},
+        boxShadowLight: '',
+        boxShadowBase: '',
+        borderRadiusBase: '',
+        borderRadiusSmall: ''
+      }
+    },
+    watch: {
+      global: {
+        immediate: true,
+        handler(value) {
+          Object.keys(varMap).forEach((c) => {
+            if (value[c]) {
+              this[varMap[c]] = value[c]
+            } else {
+              this[varMap[c]] = original[varMap[c]]
+            }
+          });
+        }
+      }
+    }
+  }
+</script>
+
+<style>
+.demo-border .text {
+  width: 15%;
+}
+.demo-border .line {
+  width: 70%;
+}
+.demo-border .line div{
+  width: 100%;
+  height: 0;
+  border: 1px solid #EEE;
+}
+.demo-border .line .dashed{ 
+  border: 2px dashed #EEE;
+}
+.demo-shadow {
+  height: 100px;
+  width: 50%;
+  border: 1px solid #eee;
+}
+.demo-shadow-text {
+  line-height: 50px;
+  color: #666;
+  font-size: 14px;
+}
+.demo-radius .title{
+  color: #666;
+  font-size: 18px;
+  margin: 10px 0;
+}
+.demo-radius .value{
+  color: #333;
+  font-size: 16px;
+  margin: 10px 0;
+}
+.demo-radius .radius {
+  height: 60px;
+  width: 70%;
+  border: 1px solid #D7DAE2;
+  border-radius: 0;
+  margin-top: 20px;
+}
+.demo-radius .radius-30 {
+  border-radius: 30px;
+}
+</style>
+
+## Border
+
+We standardize the borders that can be used in buttons, cards, pop-ups and other components.
+
+### Border
+
+There are few border styles to choose.
+
+<table class="demo-border">
+  <tbody>
+    <tr>
+      <td class="text">Name</td>
+      <td class="text">Thickness</td>
+      <td class="line">Demo</td>
+    </tr>
+    <tr>
+      <td class="text">Solid</td>
+      <td class="text">1px</td>
+      <td class="line">
+        <div></div>
+      </td>
+    </tr>
+    <tr>
+      <td class="text">Dashed</td>
+      <td class="text">2px</td>
+      <td class="line">
+        <div class="dashed"></div>
+      </td>
+    </tr>
+  </tbody>
+</table>
+
+### Radius
+
+There are few radius styles to choose.
+
+<el-row :gutter="12" class="demo-radius">
+  <el-col :span="6" :xs="{span: 12}">
+    <div class="title">No Radius</div>
+    <div class="value">border-radius: 0px</div>
+    <div class="radius"></div>
+  </el-col>
+  <el-col :span="6" :xs="{span: 12}">
+    <div class="title">Small Radius</div>
+    <div class="value">border-radius: {{borderRadiusSmall}}</div>
+    <div 
+      class="radius" 
+      :style="{ borderRadius: borderRadiusSmall }"
+    ></div>
+  </el-col>
+  <el-col :span="6" :xs="{span: 12}">
+    <div class="title">Large Radius</div>
+    <div class="value">border-radius: {{borderRadiusBase}}</div>
+    <div 
+      class="radius"
+      :style="{ borderRadius: borderRadiusBase }"
+    ></div>
+  </el-col>
+  <el-col :span="6" :xs="{span: 12}">
+    <div class="title">Round Radius</div>
+    <div class="value">border-radius: 30px</div>
+    <div class="radius radius-30"></div>
+  </el-col>
+</el-row>
+
+### Shadow
+
+There are few shaodw styles to choose.
+
+<div 
+class="demo-shadow"
+:style="{ boxShadow: boxShadowBase }"
+></div>
+<span class="demo-shadow-text">Basic Shaodw box-shadow: {{boxShadowBase}}</span>
+
+<div 
+class="demo-shadow"
+:style="{ boxShadow: boxShadowLight }"
+></div>
+<span class="demo-shadow-text">Light Shadow box-shadow: {{boxShadowLight}}</span>

+ 244 - 52
examples/docs/fr-FR/color.md

@@ -1,9 +1,101 @@
+<script>
+  import bus from '../../bus';
+  import { tintColor } from '../../color.js';
+  const varMap = {
+    'primary': '$--color-primary',
+    'success': '$--color-success',
+    'warning': '$--color-warning',
+    'danger': '$--color-danger',
+    'info': '$--color-info',
+    'white': '$--color-white',
+    'black': '$--color-black',
+    'textPrimary': '$--color-text-primary',
+    'textRegular': '$--color-text-regular',
+    'textSecondary': '$--color-text-secondary',
+    'textPlaceholder': '$--color-text-placeholder',
+    'borderBase': '$--border-color-base',
+    'borderLight': '$--border-color-light',
+    'borderLighter': '$--border-color-lighter',
+    'borderExtraLight': '$--border-color-extra-light'
+  };
+  const original = {
+    primary: '#409EFF',
+    success: '#67C23A',
+    warning: '#E6A23C',
+    danger: '#F56C6C',
+    info: '#909399',
+    white: '#FFFFFF',
+    black: '#000000',
+    textPrimary: '#303133',
+    textRegular: '#606266',
+    textSecondary: '#909399',
+    textPlaceholder: '#C0C4CC',
+    borderBase: '#DCDFE6',
+    borderLight: '#E4E7ED',
+    borderLighter: '#EBEEF5',
+    borderExtraLight: '#F2F6FC'
+  }
+  export default {
+    created() {
+      bus.$on('user-theme-config-update', this.setGlobal);
+    },
+    mounted() {
+      this.setGlobal();
+    },
+    methods: {
+      tintColor(color, tint) {
+        return tintColor(color, tint);
+      },
+      setGlobal() {
+        if (window.userThemeConfig) {
+          this.global = window.userThemeConfig.global;
+        }
+      }
+    },
+    data() {
+      return {
+        global: {},
+        primary: '',
+        success: '',
+        warning: '',
+        danger: '',
+        info: '',
+        white: '',
+        black: '',
+        textPrimary: '',
+        textRegular: '',
+        textSecondary: '',
+        textPlaceholder: '',
+        borderBase: '',
+        borderLight: '',
+        borderLighter: '',
+        borderExtraLight: ''
+      }
+    },
+    watch: {
+      global: {
+        immediate: true,
+        handler(value) {
+          Object.keys(original).forEach((o) => {
+            if (value[varMap[o]]) {
+              this[o] = value[varMap[o]]
+            } else {
+              this[o] = original[o]
+            }
+          });
+        }
+      }
+    },
+  }
+</script>
+
 <style>
 <style>
   .demo-color-box {
   .demo-color-box {
+    position: relative;
     border-radius: 4px;
     border-radius: 4px;
     padding: 20px;
     padding: 20px;
     margin: 5px 0;
     margin: 5px 0;
-    height: 74px;
+    height: 114px;
     box-sizing: border-box;
     box-sizing: border-box;
     color: #fff;
     color: #fff;
     font-size: 14px;
     font-size: 14px;
@@ -14,6 +106,12 @@
       line-height: 24px;
       line-height: 24px;
     }
     }
   }
   }
+  .demo-color-box-other {
+    height: 74px;
+    margin: 10px 0!important;
+    border-radius: 4px 4px 4px 4px!important;
+    padding: 15px 20px;
+  }
   .demo-color-box-group {
   .demo-color-box-group {
     .demo-color-box {
     .demo-color-box {
       border-radius: 0;
       border-radius: 0;
@@ -26,50 +124,42 @@
       border-radius: 0 0 4px 4px;
       border-radius: 0 0 4px 4px;
     }
     }
   }
   }
-  .bg-blue {
-    background-color: #409EFF;
-  }
-
-  .bg-success {
-    background-color: #13CE66;
-  }
-  .bg-warning {
-    background-color: #f7ba2a;
-  }
-  .bg-danger {
-    background-color: #ff4949;
-  }
-  .bg-info {
-    background-color: #909399;
-  }
-
-  .bg-text-primary {
-    background-color: #303133;
-  }
-  .bg-text-regular {
-    background-color: #606266;
+  .bg-color-sub {
+    width: 100%;
+    height: 40px;
+    left: 0;
+    bottom: 0;
+    position: absolute;
+    border-radius: 0 0 4px 4px;
   }
   }
-  .bg-text-secondary {
-    background-color: #909399;
+  .bg-blue-sub-item {
+    width: 11.1111111%;
+    height: 100%;
+    display: inline-block;
   }
   }
-  .bg-text-placeholder {
-    background-color: #c0c4cc;
+  .bg-blue-sub-item:first-child {
+    border-radius: 0 0 0 4px;
   }
   }
-
-  .bg-border-base {
-    background-color: #dcdfe6;
+  .bg-success-sub-item {
+    width: 50%;
+    height: 100%;
+    display: inline-block;
   }
   }
-  .bg-border-light {
-    background-color: #e4e7ed;
+  .bg-success-sub-item:first-child {
+    border-radius: 0 0 0 4px;
   }
   }
-  .bg-border-lighter {
-    background-color: #ebeef5;
+  .bg-success-sub-item:last-child {
+    border-radius: 0 0 4px 0;
   }
   }
-  .bg-border-extra-light {
-    background-color: #f2f6fc;
+  .bg-transparent {
+    border: 1px solid #FCC3C3;
+    color: #303133;
+    background: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' version='1.1' preserveAspectRatio='none' viewBox='0 0 100 100'><path d='M0 98 L100 0 L100 1 L1 98' fill='%23FCC3C3' /></svg>");
+    background-repeat:no-repeat;
+    background-position:center center;
+    background-size: 100% 100%, auto;
   }
   }
-
-  [class*=" bg-border-"] {
+  .demo-color-box-lite {
     color: #303133;
     color: #303133;
   }
   }
 </style>
 </style>
@@ -82,8 +172,24 @@ Element utilise un ensemble de palettes spécifiques afin de fournir un style co
 La couleur principale d'Element est un bleu clair et agréable.
 La couleur principale d'Element est un bleu clair et agréable.
 
 
 <el-row :gutter="12">
 <el-row :gutter="12">
-  <el-col :span="6" :xs="{span: 12}">
-    <div class="demo-color-box bg-blue">Bleu<div class="value">#409EFF</div></div>
+  <el-col :span="10" :xs="{span: 12}">
+    <div 
+      class="demo-color-box"
+      :style="{ background: primary }"
+    >
+      Brand Color<div class="value">#409EFF</div>
+    <div 
+      class="bg-color-sub"
+      :style="{ background: tintColor(primary, 0.9) }"
+    >
+    <div 
+      class="bg-blue-sub-item" 
+      v-for="(item, key) in Array(8)"
+      :key="key"
+      :style="{ background: tintColor(primary, (key + 1) / 10) }"
+        >
+    </div>
+    </div>
   </el-col>
   </el-col>
 </el-row>
 </el-row>
 
 
@@ -93,16 +199,72 @@ En plus de la couleur principale, vous devrez sans doute utiliser d'autres coule
 
 
 <el-row :gutter="12">
 <el-row :gutter="12">
   <el-col :span="6" :xs="{span: 12}">
   <el-col :span="6" :xs="{span: 12}">
-    <div class="demo-color-box bg-success">Succès<div class="value">#67C23A</div></div>
+    <div class="demo-color-box"
+    :style="{ background: success }"
+    >Success<div class="value">#67C23A</div>
+      <div 
+        class="bg-color-sub"
+      >
+        <div 
+          class="bg-success-sub-item" 
+          v-for="(item, key) in Array(2)"
+          :key="key"
+          :style="{ background: tintColor(success, (key + 8) / 10) }"
+            >
+        </div>
+      </div>
+    </div>
   </el-col>
   </el-col>
   <el-col :span="6" :xs="{span: 12}">
   <el-col :span="6" :xs="{span: 12}">
-    <div class="demo-color-box bg-warning">Avertissement<div class="value">#E6A23C</div></div>
+    <div class="demo-color-box"
+    :style="{ background: warning }"
+    >Warning<div class="value">#E6A23C</div>
+      <div 
+          class="bg-color-sub"
+        >
+        <div 
+          class="bg-success-sub-item" 
+          v-for="(item, key) in Array(2)"
+          :key="key"
+          :style="{ background: tintColor(warning, (key + 8) / 10) }"
+            >
+        </div>
+      </div>
+    </div>
   </el-col>
   </el-col>
   <el-col :span="6" :xs="{span: 12}">
   <el-col :span="6" :xs="{span: 12}">
-    <div class="demo-color-box bg-danger">Danger<div class="value">#F56C6C</div></div>
+    <div class="demo-color-box"
+    :style="{ background: danger }"
+    >Danger<div class="value">#F56C6C</div>
+      <div 
+          class="bg-color-sub"
+        >
+        <div 
+          class="bg-success-sub-item" 
+          v-for="(item, key) in Array(2)"
+          :key="key"
+          :style="{ background: tintColor(danger, (key + 8) / 10) }"
+            >
+        </div>
+      </div>
+    </div>
   </el-col>
   </el-col>
   <el-col :span="6" :xs="{span: 12}">
   <el-col :span="6" :xs="{span: 12}">
-    <div class="demo-color-box bg-info">Information<div class="value">#909399</div></div>
+    <div class="demo-color-box"
+    :style="{ background: info }"
+    >Info<div class="value">#909399</div>
+      <div 
+          class="bg-color-sub"
+        >
+        <div 
+          class="bg-success-sub-item" 
+          v-for="(item, key) in Array(2)"
+          :key="key"
+          :style="{ background: tintColor(info, (key + 8) / 10) }"
+            >
+        </div>
+      </div>
+    </div>
   </el-col>
   </el-col>
 </el-row>
 </el-row>
 
 
@@ -113,18 +275,48 @@ Les couleurs neutres sont les couleurs du fond, du texte et des bordures. Vous p
 <el-row :gutter="12">
 <el-row :gutter="12">
   <el-col :span="6" :xs="{span: 12}">
   <el-col :span="6" :xs="{span: 12}">
     <div class="demo-color-box-group">
     <div class="demo-color-box-group">
-      <div class="demo-color-box bg-text-primary">Texte principal<div class="value">#303133</div></div>
-      <div class="demo-color-box bg-text-regular">Texte normal<div class="value">#606266</div></div>
-      <div class="demo-color-box bg-text-secondary">Texte secondaire<div class="value">#909399</div></div>
-      <div class="demo-color-box bg-text-placeholder">Texte de placeholder<div class="value">#C0C4CC</div></div>
+      <div class="demo-color-box demo-color-box-other"
+      :style="{ background: textPrimary }"
+      >Texte principal<div class="value">{{textPrimary}}</div></div>
+      <div class="demo-color-box demo-color-box-other"
+      :style="{ background: textRegular }"
+      >
+      Texte normal<div class="value">{{textRegular}}</div></div>
+      <div class="demo-color-box demo-color-box-other"
+      :style="{ background: textSecondary }"
+      >Texte secondaire<div class="value">{{textSecondary}}</div></div>
+      <div class="demo-color-box demo-color-box-other"
+      :style="{ background: textPlaceholder }"
+      >Texte de placeholder<div class="value">{{textPlaceholder}}</div></div>
+    </div>
+  </el-col>
+  <el-col :span="6" :xs="{span: 12}">
+    <div class="demo-color-box-group">
+      <div class="demo-color-box demo-color-box-other demo-color-box-lite"
+      :style="{ background: borderBase }"
+      >Bordure de base<div class="value">{{borderBase}}</div></div>
+      <div class="demo-color-box demo-color-box-other demo-color-box-lite"
+      :style="{ background: borderLight }"
+      >Bordure claire<div class="value">{{borderLight}}</div></div>
+      <div class="demo-color-box demo-color-box-other demo-color-box-lite"
+      :style="{ background: borderLighter }"
+      >Bordure très claire<div class="value">{{borderLighter}}</div></div>
+      <div class="demo-color-box demo-color-box-other demo-color-box-lite"
+      :style="{ background: borderExtraLight }"
+      >Bordure extra claire<div class="value">{{borderExtraLight}}</div></div>
     </div>
     </div>
   </el-col>
   </el-col>
   <el-col :span="6" :xs="{span: 12}">
   <el-col :span="6" :xs="{span: 12}">
     <div class="demo-color-box-group">
     <div class="demo-color-box-group">
-      <div class="demo-color-box bg-border-base">Bordure de base<div class="value">#DCDFE6</div></div>
-      <div class="demo-color-box bg-border-light">Bordure claire<div class="value">#E4E7ED</div></div>
-      <div class="demo-color-box bg-border-lighter">Bordure très claire<div class="value">#EBEEF5</div></div>
-      <div class="demo-color-box bg-border-extra-light">Bordure extra claire<div class="value">#F2F6FC</div></div>
+      <div 
+      class="demo-color-box demo-color-box-other"
+      :style="{ background: black }"
+      >Basic Black<div class="value">{{black}}</div></div>
+      <div
+      class="demo-color-box demo-color-box-other"
+      :style="{ background: white, color: '#303133', border: '1px solid #eee' }"
+      >Basic White<div class="value">{{white}}</div></div>
+      <div class="demo-color-box demo-color-box-other bg-transparent">Transparent<div class="value">Transparent</div>
     </div>
     </div>
   </el-col>
   </el-col>
 </el-row>
 </el-row>

+ 151 - 118
examples/docs/fr-FR/typography.md

@@ -1,74 +1,96 @@
-<style>
-  .demo-typo-box {
-    height: 200px;
-    width: 200px;
-    position: relative;
-    border: 1px solid #eaeefb;
-    font-size: 40px;
-    color: #1f2d3d;
-    text-align: center;
-    line-height: 162px;
-    padding-bottom: 36px;
-    box-sizing: border-box;
-    display: inline-block;
-    margin-right: 17px;
-    border-radius: 4px;
-
-    .name {
-      position: absolute;
-      bottom: 0;
-      width: 100%;
-      height: 35px;
-      border-top: 1px solid #eaeefb;
-      font-size: 14px;
-      color: #8492a6;
-      line-height: 35px;
-      text-align: left;
-      text-indent: 10px;
-      font-family: 'Helvetica Neue';
-    }
+<script>
+  import bus from '../../bus';
+  const varMap = [
+    '$--font-size-extra-large',
+    '$--font-size-large',
+    '$--font-size-medium',
+    '$--font-size-base',
+    '$--font-size-small',
+    '$--font-size-extra-small'
+  ];
+  const original = {
+    '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'
+  }
+  export default {
+    created() {
+      bus.$on('user-theme-config-update', this.setGlobal);
+    },
+    mounted() {
+      this.setGlobal();
+    },
+    methods: {
+      tintColor(color, tint) {
+        return tintColor(color, tint);
+      },
+      setGlobal() {
+        if (window.userThemeConfig) {
+          this.global = window.userThemeConfig.global;
+        }
+      }
+    },
+    data() {
+      return {
+        global: {},
+        'font_size_extra_large': '',
+        'font_size_large': '',
+        'font_size_medium': '',
+        'font_size_base': '',
+        'font_size_small': '',
+        'font_size_extra_small': ''
+      }
+    },
+    watch: {
+      global: {
+        immediate: true,
+        handler(value) {
+          varMap.forEach((v) => {
+            const key = v.replace('$--', '').replace(/-/g, '_')
+            if (value[v]) {
+              this[key] = value[v]
+            } else {
+              this[key] = original[key]
+            }
+          });
+        }
+      }
+    },
   }
   }
+</script>
+<style>
   .demo-typo-size {
   .demo-typo-size {
-    .h1 {
-      font-size: 20px;
-    }
-    .h2 {
-      font-size: 18px;
-    }
-    .h3 {
-      font-size: 16px;
-    }
-    .text-regular {
-      font-size: 14px;
-    }
-    .text-small {
-      font-size: 13px;
-    }
-    .text-smaller {
-      font-size: 12px;
-    }
     .color-dark-light {
     .color-dark-light {
       color: #99a9bf;
       color: #99a9bf;
     }
     }
   }
   }
-  .typo-PingFang {
-    font-family: 'PingFang SC';
-  }
-  .typo-Hiragino {
-    font-family: 'Hiragino Sans GB';
+  .demo-term-box img{
+    width: 24%;
+    margin: 0 4% 20px 0;
   }
   }
-  .typo-Microsoft {
-    font-family: 'Microsoft YaHei';
+
+  .lineH-left {
+    display: inline-block;
+    height: 80px
   }
   }
-  /* 英文 \*/
-  .typo-Helvetica-Neue {
-    font-family: 'Helvetica Neue';
+  .lineH-right {
+    display: inline-block;
+    list-style: none;
+    padding: 0 0 0 90px;
+    margin: 0;
+    vertical-align: top;
   }
   }
-  .typo-Helvetica {
-    font-family: 'Helvetica';
+  .lineH-right li{
+    font-size: 13px;
+    color: #666;
+    height: 20px;
+    line-height: 20px;
   }
   }
-  .typo-Arial {
-    font-family: 'Arial';
+  .lineH-right li span{
+    padding-left: 40px;
   }
   }
 </style>
 </style>
 
 
@@ -76,75 +98,86 @@
 
 
 Nous avons créé une convention de police d'écriture afin d'assurer la meilleur présentation possible sur toutes le plateformes.
 Nous avons créé une convention de police d'écriture afin d'assurer la meilleur présentation possible sur toutes le plateformes.
 
 
-### Police chinoise
+### Police
 
 
-<div class="demo-typo-box typo-PingFang">
-  和畅惠风
-  <div class="name">PingFang SC</div>
-</div>
-<div class="demo-typo-box typo-Hiragino">
-  和畅惠风
-  <div class="name">Hiragino Sans GB</div>
-</div>
-<div class="demo-typo-box typo-Microsoft">
-  和畅惠风
-  <div class="name">Microsoft YaHei</div>
+<div class="demo-term-box">
+<img src="../../assets/images/term-pingfang.png" alt="">
+<img src="../../assets/images/term-hiragino.png" alt="">
+<img src="../../assets/images/term-microsoft.png" alt="">
+<img src="../../assets/images/term-sf.png" alt="">
+<img src="../../assets/images/term-helvetica.png" alt="">
+<img src="../../assets/images/term-arial.png" alt="">
 </div>
 </div>
 
 
-### Police anglaise / numérique
-
-<div class="demo-typo-box typo-Helvetica-neue">
-  RGag
-  <div class="name">Helvetica Neue</div>
-</div>
-<div class="demo-typo-box typo-Helvetica">
-  RGag
-  <div class="name">Helvetica</div>
-</div>
-<div class="demo-typo-box typo-Arial">
-  RGag
-  <div class="name">Arial</div>
-</div>
-
-### Font-family
-
-```css
-font-family: "Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","微软雅黑",Arial,sans-serif;
-```
-
 ### Convention des polices
 ### Convention des polices
 
 
 <table class="demo-typo-size">
 <table class="demo-typo-size">
   <tbody>
   <tbody>
-    <tr>
-      <td class="h1">Titre principal</td>
-      <td class="h1">Construit avec Element</td>
-      <td class="color-dark-light">20px  Extra large</td>
+  <tr
+    >
+      <td>Level</td>
+      <td>Font Size</td>
+      <td class="color-dark-light">Demo</td>
+    </tr>
+    <tr
+    :style="{ fontSize: font_size_extra_small }"
+    >
+      <td>Supplementary text</td>
+      <td class="color-dark-light">{{font_size_extra_small}} Extra Small</td>
+      <td>Build with Element</td>
     </tr>
     </tr>
-    <tr>
-      <td class="h2">Titre</td>
-      <td class="h2">Construit avec Element</td>
-      <td class="color-dark-light">18px large</td>
+    <tr
+    :style="{ fontSize: font_size_small }"
+    >
+      <td>Body (small)</td>
+      <td class="color-dark-light">{{font_size_small}} Small</td>
+      <td>Build with Element</td>
     </tr>
     </tr>
-    <tr>
-      <td class="h3">Sous-titre</td>
-      <td class="h3">Construit avec Element</td>
-      <td class="color-dark-light">16px Medium</td>
+    <tr
+    :style="{ fontSize: font_size_base }"
+    >
+      <td>Body</td>
+      <td class="color-dark-light">{{font_size_base}} Base</td>
+      <td>Build with Element</td>
     </tr>
     </tr>
-    <tr>
-      <td class="text-regular">Body</td>
-      <td class="text-regular">Construit avec Element</td>
-      <td class="color-dark-light">14px Small</td>
+    <tr
+    :style="{ fontSize: font_size_medium }"
+    >
+      <td >Small Title</td>
+      <td class="color-dark-light">{{font_size_medium}} Medium</td>
+      <td>Build with Element</td>
     </tr>
     </tr>
-    <tr>
-      <td class="text-small">Body (petit)</td>
-      <td class="text-small">Construit avec Element</td>
-      <td class="color-dark-light">13px Extra Small</td>
+    <tr
+    :style="{ fontSize: font_size_large }"
+    >
+      <td>Title</td>
+      <td class="color-dark-light">{{font_size_large}} large</td>
+      <td>Build with Element</td>
     </tr>
     </tr>
-    <tr>
-      <td class="text-smaller">Texte supplémentaire</td>
-      <td class="text-smaller">Construit avec Element</td>
-      <td class="color-dark-light">12px Extra Extra Small</td>
+    <tr
+    :style="{ fontSize: font_size_extra_large }"
+    >
+      <td>Main Title</td>
+      <td class="color-dark-light">{{font_size_extra_large}} Extra large</td>
+      <td>Build with Element</td>
     </tr>
     </tr>
   </tbody>
   </tbody>
 </table>
 </table>
+
+### Font Line Height
+
+<div>
+<img class="lineH-left" src="~examples/assets/images/typography.png" />
+<ul class="lineH-right">
+<li>line-height:1 <span>No line height</span></li>
+<li>line-height:1.3 <span>Compact</span></li>
+<li>line-height:1.5 <span>Regular</span></li>
+<li>line-height:1.7 <span>Loose</span></li>
+</ul>
+</div>
+
+### Font-family
+
+```css
+font-family: "Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","微软雅黑",Arial,sans-serif;
+```

+ 181 - 0
examples/docs/zh-CN/border.md

@@ -0,0 +1,181 @@
+<script>
+  import bus from '../../bus';
+  const varMap = {
+    '$--box-shadow-light': 'boxShadowLight',
+    '$--box-shadow-base': 'boxShadowBase',
+    '$--border-radius-base': 'borderRadiusBase',
+    '$--border-radius-small': 'borderRadiusSmall'
+  };
+  const original = {
+    boxShadowLight: '0 2px 12px 0 rgba(0, 0, 0, 0.1)',
+    boxShadowBase: '0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04)',
+    borderRadiusBase: '4px',
+    borderRadiusSmall: '2px'
+  }
+  export default {
+    created() {
+      bus.$on('user-theme-config-update', this.setGlobal);
+    },
+    mounted() {
+      this.setGlobal();
+    },
+    methods: {
+      setGlobal() {
+        if (window.userThemeConfig) {
+          this.global = window.userThemeConfig.global;
+        }
+      }
+    },
+    data() {
+      return {
+        global: {},
+        boxShadowLight: '',
+        boxShadowBase: '',
+        borderRadiusBase: '',
+        borderRadiusSmall: ''
+      }
+    },
+    watch: {
+      global: {
+        immediate: true,
+        handler(value) {
+          Object.keys(varMap).forEach((c) => {
+            if (value[c]) {
+              this[varMap[c]] = value[c]
+            } else {
+              this[varMap[c]] = original[varMap[c]]
+            }
+          });
+        }
+      }
+    }
+  }
+</script>
+
+<style>
+.demo-border .text {
+  width: 15%;
+}
+.demo-border .line {
+  width: 70%;
+}
+.demo-border .line div{
+  width: 100%;
+  height: 0;
+  border: 1px solid #EEE;
+}
+.demo-border .line .dashed{ 
+  border: 2px dashed #EEE;
+}
+.demo-shadow {
+  height: 100px;
+  width: 50%;
+  border: 1px solid #eee;
+}
+.demo-shadow-text {
+  line-height: 50px;
+  color: #666;
+  font-size: 14px;
+}
+.demo-radius .title{
+  color: #666;
+  font-size: 18px;
+  margin: 10px 0;
+}
+.demo-radius .value{
+  color: #333;
+  font-size: 16px;
+  margin: 10px 0;
+}
+.demo-radius .radius {
+  height: 60px;
+  width: 70%;
+  border: 1px solid #D7DAE2;
+  border-radius: 0;
+  margin-top: 20px;
+}
+.demo-radius .radius-30 {
+  border-radius: 30px;
+}
+</style>
+
+## Border 边框
+
+我们对边框进行统一规范,可用于按钮、卡片、弹窗等组件里。
+
+### 边框
+
+我们提供了一下几种边框样式,以供选择。
+
+<table class="demo-border">
+  <tbody>
+    <tr>
+      <td class="text">名称</td>
+      <td class="text">粗细</td>
+      <td class="line">举例</td>
+    </tr>
+    <tr>
+      <td class="text">实线</td>
+      <td class="text">1px</td>
+      <td class="line">
+        <div></div>
+      </td>
+    </tr>
+    <tr>
+      <td class="text">虚线</td>
+      <td class="text">2px</td>
+      <td class="line">
+        <div class="dashed"></div>
+      </td>
+    </tr>
+  </tbody>
+</table>
+
+### 圆角
+
+我们提供了一下几种圆角样式,以供选择。
+
+<el-row :gutter="12" class="demo-radius">
+  <el-col :span="6" :xs="{span: 12}">
+    <div class="title">无圆角</div>
+    <div class="value">border-radius: 0px</div>
+    <div class="radius"></div>
+  </el-col>
+  <el-col :span="6" :xs="{span: 12}">
+    <div class="title">小圆角</div>
+    <div class="value">border-radius: {{borderRadiusSmall}}</div>
+    <div 
+      class="radius" 
+      :style="{ borderRadius: borderRadiusSmall }"
+    ></div>
+  </el-col>
+  <el-col :span="6" :xs="{span: 12}">
+    <div class="title">大圆角</div>
+    <div class="value">border-radius: {{borderRadiusBase}}</div>
+    <div 
+      class="radius"
+      :style="{ borderRadius: borderRadiusBase }"
+    ></div>
+  </el-col>
+  <el-col :span="6" :xs="{span: 12}">
+    <div class="title">圆形圆角</div>
+    <div class="value">border-radius: 30px</div>
+    <div class="radius radius-30"></div>
+  </el-col>
+</el-row>
+
+### 投影
+
+我们提供了一下几种投影样式,以供选择。
+
+<div 
+class="demo-shadow"
+:style="{ boxShadow: boxShadowBase }"
+></div>
+<span class="demo-shadow-text">基础投影 box-shadow: {{boxShadowBase}}</span>
+
+<div 
+class="demo-shadow"
+:style="{ boxShadow: boxShadowLight }"
+></div>
+<span class="demo-shadow-text">浅色投影 box-shadow: {{boxShadowLight}}</span>

+ 244 - 52
examples/docs/zh-CN/color.md

@@ -1,9 +1,101 @@
+<script>
+  import bus from '../../bus';
+  import { tintColor } from '../../color.js';
+  const varMap = {
+    'primary': '$--color-primary',
+    'success': '$--color-success',
+    'warning': '$--color-warning',
+    'danger': '$--color-danger',
+    'info': '$--color-info',
+    'white': '$--color-white',
+    'black': '$--color-black',
+    'textPrimary': '$--color-text-primary',
+    'textRegular': '$--color-text-regular',
+    'textSecondary': '$--color-text-secondary',
+    'textPlaceholder': '$--color-text-placeholder',
+    'borderBase': '$--border-color-base',
+    'borderLight': '$--border-color-light',
+    'borderLighter': '$--border-color-lighter',
+    'borderExtraLight': '$--border-color-extra-light'
+  };
+  const original = {
+    primary: '#409EFF',
+    success: '#67C23A',
+    warning: '#E6A23C',
+    danger: '#F56C6C',
+    info: '#909399',
+    white: '#FFFFFF',
+    black: '#000000',
+    textPrimary: '#303133',
+    textRegular: '#606266',
+    textSecondary: '#909399',
+    textPlaceholder: '#C0C4CC',
+    borderBase: '#DCDFE6',
+    borderLight: '#E4E7ED',
+    borderLighter: '#EBEEF5',
+    borderExtraLight: '#F2F6FC'
+  }
+  export default {
+    created() {
+      bus.$on('user-theme-config-update', this.setGlobal);
+    },
+    mounted() {
+      this.setGlobal();
+    },
+    methods: {
+      tintColor(color, tint) {
+        return tintColor(color, tint);
+      },
+      setGlobal() {
+        if (window.userThemeConfig) {
+          this.global = window.userThemeConfig.global;
+        }
+      }
+    },
+    data() {
+      return {
+        global: {},
+        primary: '',
+        success: '',
+        warning: '',
+        danger: '',
+        info: '',
+        white: '',
+        black: '',
+        textPrimary: '',
+        textRegular: '',
+        textSecondary: '',
+        textPlaceholder: '',
+        borderBase: '',
+        borderLight: '',
+        borderLighter: '',
+        borderExtraLight: ''
+      }
+    },
+    watch: {
+      global: {
+        immediate: true,
+        handler(value) {
+          Object.keys(original).forEach((o) => {
+            if (value[varMap[o]]) {
+              this[o] = value[varMap[o]]
+            } else {
+              this[o] = original[o]
+            }
+          });
+        }
+      }
+    },
+  }
+</script>
+
 <style>
 <style>
   .demo-color-box {
   .demo-color-box {
+    position: relative;
     border-radius: 4px;
     border-radius: 4px;
     padding: 20px;
     padding: 20px;
     margin: 5px 0;
     margin: 5px 0;
-    height: 74px;
+    height: 114px;
     box-sizing: border-box;
     box-sizing: border-box;
     color: #fff;
     color: #fff;
     font-size: 14px;
     font-size: 14px;
@@ -14,6 +106,12 @@
       line-height: 24px;
       line-height: 24px;
     }
     }
   }
   }
+  .demo-color-box-other {
+    height: 74px;
+    margin: 10px 0!important;
+    border-radius: 4px 4px 4px 4px!important;
+    padding: 15px 20px;
+  }
   .demo-color-box-group {
   .demo-color-box-group {
     .demo-color-box {
     .demo-color-box {
       border-radius: 0;
       border-radius: 0;
@@ -26,50 +124,42 @@
       border-radius: 0 0 4px 4px;
       border-radius: 0 0 4px 4px;
     }
     }
   }
   }
-  .bg-blue {
-    background-color: #409EFF;
-  }
-
-  .bg-success {
-    background-color: #67C23A;
-  }
-  .bg-warning {
-    background-color: #E6A23C;
-  }
-  .bg-danger {
-    background-color: #F56C6C;
-  }
-  .bg-info {
-    background-color: #909399;
-  }
-
-  .bg-text-primary {
-    background-color: #303133;
-  }
-  .bg-text-regular {
-    background-color: #606266;
+  .bg-color-sub {
+    width: 100%;
+    height: 40px;
+    left: 0;
+    bottom: 0;
+    position: absolute;
+    border-radius: 0 0 4px 4px;
   }
   }
-  .bg-text-secondary {
-    background-color: #909399;
+  .bg-blue-sub-item {
+    width: 11.1111111%;
+    height: 100%;
+    display: inline-block;
   }
   }
-  .bg-text-placeholder {
-    background-color: #c0c4cc;
+  .bg-blue-sub-item:first-child {
+    border-radius: 0 0 0 4px;
   }
   }
-
-  .bg-border-base {
-    background-color: #dcdfe6;
+  .bg-success-sub-item {
+    width: 50%;
+    height: 100%;
+    display: inline-block;
   }
   }
-  .bg-border-light {
-    background-color: #e4e7ed;
+  .bg-success-sub-item:first-child {
+    border-radius: 0 0 0 4px;
   }
   }
-  .bg-border-lighter {
-    background-color: #ebeef5;
+  .bg-success-sub-item:last-child {
+    border-radius: 0 0 4px 0;
   }
   }
-  .bg-border-extra-light {
-    background-color: #f2f6fc;
+  .bg-transparent {
+    border: 1px solid #FCC3C3;
+    color: #303133;
+    background: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' version='1.1' preserveAspectRatio='none' viewBox='0 0 100 100'><path d='M0 98 L100 0 L100 1 L1 98' fill='%23FCC3C3' /></svg>");
+    background-repeat:no-repeat;
+    background-position:center center;
+    background-size: 100% 100%, auto;
   }
   }
-
-  [class*=" bg-border-"] {
+  .demo-color-box-lite {
     color: #303133;
     color: #303133;
   }
   }
 </style>
 </style>
@@ -83,8 +173,24 @@ Element 为了避免视觉传达差异,使用一套特定的调色板来规定
 Element 主要品牌颜色是鲜艳、友好的蓝色。
 Element 主要品牌颜色是鲜艳、友好的蓝色。
 
 
 <el-row :gutter="12">
 <el-row :gutter="12">
-  <el-col :span="6" :xs="{span: 12}">
-    <div class="demo-color-box bg-blue">Blue<div class="value">#409EFF</div></div>
+  <el-col :span="10" :xs="{span: 12}">
+    <div 
+      class="demo-color-box"
+      :style="{ background: primary }"
+    >
+      Brand Color<div class="value">#409EFF</div>
+    <div 
+      class="bg-color-sub"
+      :style="{ background: tintColor(primary, 0.9) }"
+    >
+    <div 
+      class="bg-blue-sub-item" 
+      v-for="(item, key) in Array(8)"
+      :key="key"
+      :style="{ background: tintColor(primary, (key + 1) / 10) }"
+        >
+    </div>
+    </div>
   </el-col>
   </el-col>
 </el-row>
 </el-row>
 
 
@@ -94,16 +200,72 @@ Element 主要品牌颜色是鲜艳、友好的蓝色。
 
 
 <el-row :gutter="12">
 <el-row :gutter="12">
   <el-col :span="6" :xs="{span: 12}">
   <el-col :span="6" :xs="{span: 12}">
-    <div class="demo-color-box bg-success">Success<div class="value">#67C23A</div></div>
+    <div class="demo-color-box"
+    :style="{ background: success }"
+    >Success<div class="value">#67C23A</div>
+      <div 
+        class="bg-color-sub"
+      >
+        <div 
+          class="bg-success-sub-item" 
+          v-for="(item, key) in Array(2)"
+          :key="key"
+          :style="{ background: tintColor(success, (key + 8) / 10) }"
+            >
+        </div>
+      </div>
+    </div>
   </el-col>
   </el-col>
   <el-col :span="6" :xs="{span: 12}">
   <el-col :span="6" :xs="{span: 12}">
-    <div class="demo-color-box bg-warning">Warning<div class="value">#E6A23C</div></div>
+    <div class="demo-color-box"
+    :style="{ background: warning }"
+    >Warning<div class="value">#E6A23C</div>
+      <div 
+          class="bg-color-sub"
+        >
+        <div 
+          class="bg-success-sub-item" 
+          v-for="(item, key) in Array(2)"
+          :key="key"
+          :style="{ background: tintColor(warning, (key + 8) / 10) }"
+            >
+        </div>
+      </div>
+    </div>
   </el-col>
   </el-col>
   <el-col :span="6" :xs="{span: 12}">
   <el-col :span="6" :xs="{span: 12}">
-    <div class="demo-color-box bg-danger">Danger<div class="value">#F56C6C</div></div>
+    <div class="demo-color-box"
+    :style="{ background: danger }"
+    >Danger<div class="value">#F56C6C</div>
+      <div 
+          class="bg-color-sub"
+        >
+        <div 
+          class="bg-success-sub-item" 
+          v-for="(item, key) in Array(2)"
+          :key="key"
+          :style="{ background: tintColor(danger, (key + 8) / 10) }"
+            >
+        </div>
+      </div>
+    </div>
   </el-col>
   </el-col>
   <el-col :span="6" :xs="{span: 12}">
   <el-col :span="6" :xs="{span: 12}">
-    <div class="demo-color-box bg-info">Info<div class="value">#909399</div></div>
+    <div class="demo-color-box"
+    :style="{ background: info }"
+    >Info<div class="value">#909399</div>
+      <div 
+          class="bg-color-sub"
+        >
+        <div 
+          class="bg-success-sub-item" 
+          v-for="(item, key) in Array(2)"
+          :key="key"
+          :style="{ background: tintColor(info, (key + 8) / 10) }"
+            >
+        </div>
+      </div>
+    </div>
   </el-col>
   </el-col>
 </el-row>
 </el-row>
 
 
@@ -114,18 +276,48 @@ Element 主要品牌颜色是鲜艳、友好的蓝色。
 <el-row :gutter="12">
 <el-row :gutter="12">
   <el-col :span="6" :xs="{span: 12}">
   <el-col :span="6" :xs="{span: 12}">
     <div class="demo-color-box-group">
     <div class="demo-color-box-group">
-      <div class="demo-color-box bg-text-primary">主要文字<div class="value">#303133</div></div>
-      <div class="demo-color-box bg-text-regular">常规文字<div class="value">#606266</div></div>
-      <div class="demo-color-box bg-text-secondary">次要文字<div class="value">#909399</div></div>
-      <div class="demo-color-box bg-text-placeholder">占位文字<div class="value">#C0C4CC</div></div>
+      <div class="demo-color-box demo-color-box-other"
+      :style="{ background: textPrimary }"
+      >主要文字<div class="value">{{textPrimary}}</div></div>
+      <div class="demo-color-box demo-color-box-other"
+      :style="{ background: textRegular }"
+      >
+      常规文字<div class="value">{{textRegular}}</div></div>
+      <div class="demo-color-box demo-color-box-other"
+      :style="{ background: textSecondary }"
+      >次要文字<div class="value">{{textSecondary}}</div></div>
+      <div class="demo-color-box demo-color-box-other"
+      :style="{ background: textPlaceholder }"
+      >占位文字<div class="value">{{textPlaceholder}}</div></div>
+    </div>
+  </el-col>
+  <el-col :span="6" :xs="{span: 12}">
+    <div class="demo-color-box-group">
+      <div class="demo-color-box demo-color-box-other demo-color-box-lite"
+      :style="{ background: borderBase }"
+      >一级边框<div class="value">{{borderBase}}</div></div>
+      <div class="demo-color-box demo-color-box-other demo-color-box-lite"
+      :style="{ background: borderLight }"
+      >二级边框<div class="value">{{borderLight}}</div></div>
+      <div class="demo-color-box demo-color-box-other demo-color-box-lite"
+      :style="{ background: borderLighter }"
+      >三级边框<div class="value">{{borderLighter}}</div></div>
+      <div class="demo-color-box demo-color-box-other demo-color-box-lite"
+      :style="{ background: borderExtraLight }"
+      >四级边框<div class="value">{{borderExtraLight}}</div></div>
     </div>
     </div>
   </el-col>
   </el-col>
   <el-col :span="6" :xs="{span: 12}">
   <el-col :span="6" :xs="{span: 12}">
     <div class="demo-color-box-group">
     <div class="demo-color-box-group">
-      <div class="demo-color-box bg-border-base">一级边框<div class="value">#DCDFE6</div></div>
-      <div class="demo-color-box bg-border-light">二级边框<div class="value">#E4E7ED</div></div>
-      <div class="demo-color-box bg-border-lighter">三级边框<div class="value">#EBEEF5</div></div>
-      <div class="demo-color-box bg-border-extra-light">四级边框<div class="value">#F2F6FC</div></div>
+      <div 
+      class="demo-color-box demo-color-box-other"
+      :style="{ background: black }"
+      >基础黑色<div class="value">{{black}}</div></div>
+      <div
+      class="demo-color-box demo-color-box-other"
+      :style="{ background: white, color: '#303133', border: '1px solid #eee' }"
+      >基础白色<div class="value">{{white}}</div></div>
+      <div class="demo-color-box demo-color-box-other bg-transparent">透明<div class="value">Transparent</div>
     </div>
     </div>
   </el-col>
   </el-col>
 </el-row>
 </el-row>

+ 152 - 120
examples/docs/zh-CN/typography.md

@@ -1,74 +1,96 @@
-<style>
-  .demo-typo-box {
-    height: 200px;
-    width: 200px;
-    position: relative;
-    border: 1px solid #eaeefb;
-    font-size: 40px;
-    color: #1f2d3d;
-    text-align: center;
-    line-height: 162px;
-    padding-bottom: 36px;
-    box-sizing: border-box;
-    display: inline-block;
-    margin-right: 17px;
-    border-radius: 4px;
-
-    .name {
-      position: absolute;
-      bottom: 0;
-      width: 100%;
-      height: 35px;
-      border-top: 1px solid #eaeefb;
-      font-size: 14px;
-      color: #8492a6;
-      line-height: 35px;
-      text-align: left;
-      text-indent: 10px;
-      font-family: 'Helvetica Neue';
-    }
+<script>
+  import bus from '../../bus';
+  const varMap = [
+    '$--font-size-extra-large',
+    '$--font-size-large',
+    '$--font-size-medium',
+    '$--font-size-base',
+    '$--font-size-small',
+    '$--font-size-extra-small'
+  ];
+  const original = {
+    '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'
+  }
+  export default {
+    created() {
+      bus.$on('user-theme-config-update', this.setGlobal);
+    },
+    mounted() {
+      this.setGlobal();
+    },
+    methods: {
+      tintColor(color, tint) {
+        return tintColor(color, tint);
+      },
+      setGlobal() {
+        if (window.userThemeConfig) {
+          this.global = window.userThemeConfig.global;
+        }
+      }
+    },
+    data() {
+      return {
+        global: {},
+        'font_size_extra_large': '',
+        'font_size_large': '',
+        'font_size_medium': '',
+        'font_size_base': '',
+        'font_size_small': '',
+        'font_size_extra_small': ''
+      }
+    },
+    watch: {
+      global: {
+        immediate: true,
+        handler(value) {
+          varMap.forEach((v) => {
+            const key = v.replace('$--', '').replace(/-/g, '_')
+            if (value[v]) {
+              this[key] = value[v]
+            } else {
+              this[key] = original[key]
+            }
+          });
+        }
+      }
+    },
   }
   }
+</script>
+<style>
   .demo-typo-size {
   .demo-typo-size {
-    .h1 {
-      font-size: 20px;
-    }
-    .h2 {
-      font-size: 18px;
-    }
-    .h3 {
-      font-size: 16px;
-    }
-    .text-regular {
-      font-size: 14px;
-    }
-    .text-small {
-      font-size: 13px;
-    }
-    .text-smaller {
-      font-size: 12px;
-    }
     .color-dark-light {
     .color-dark-light {
       color: #99a9bf;
       color: #99a9bf;
     }
     }
   }
   }
-  .typo-PingFang {
-    font-family: 'PingFang SC';
-  }
-  .typo-Hiragino {
-    font-family: 'Hiragino Sans GB';
+  .demo-term-box img{
+    width: 24%;
+    margin: 0 4% 20px 0;
   }
   }
-  .typo-Microsoft {
-    font-family: 'Microsoft YaHei';
+
+  .lineH-left {
+    display: inline-block;
+    height: 80px
   }
   }
-  /* 英文 */
-  .typo-Helvetica-Neue {
-    font-family: 'Helvetica Neue';
+  .lineH-right {
+    display: inline-block;
+    list-style: none;
+    padding: 0 0 0 90px;
+    margin: 0;
+    vertical-align: top;
   }
   }
-  .typo-Helvetica {
-    font-family: 'Helvetica';
+  .lineH-right li{
+    font-size: 13px;
+    color: #666;
+    height: 20px;
+    line-height: 20px;
   }
   }
-  .typo-Arial {
-    font-family: 'Arial';
+  .lineH-right li span{
+    padding-left: 40px;
   }
   }
 </style>
 </style>
 
 
@@ -76,75 +98,85 @@
 
 
 我们对字体进行统一规范,力求在各个操作系统下都有最佳展示效果。
 我们对字体进行统一规范,力求在各个操作系统下都有最佳展示效果。
 
 
-### 中文字体
-
-<div class="demo-typo-box typo-PingFang">
-  和畅惠风
-  <div class="name">PingFang SC</div>
-</div>
-<div class="demo-typo-box typo-Hiragino">
-  和畅惠风
-  <div class="name">Hiragino Sans GB</div>
-</div>
-<div class="demo-typo-box typo-Microsoft">
-  和畅惠风
-  <div class="name">Microsoft YaHei</div>
-</div>
-
-### 英文/数字字体
-
-<div class="demo-typo-box typo-Helvetica-neue">
-  RGag
-  <div class="name">Helvetica Neue</div>
-</div>
-<div class="demo-typo-box typo-Helvetica">
-  RGag
-  <div class="name">Helvetica</div>
+### 字体
+<div class="demo-term-box">
+<img src="../../assets/images/term-pingfang.png" alt="">
+<img src="../../assets/images/term-hiragino.png" alt="">
+<img src="../../assets/images/term-microsoft.png" alt="">
+<img src="../../assets/images/term-sf.png" alt="">
+<img src="../../assets/images/term-helvetica.png" alt="">
+<img src="../../assets/images/term-arial.png" alt="">
 </div>
 </div>
-<div class="demo-typo-box typo-Arial">
-  RGag
-  <div class="name">Arial</div>
-</div>
-
-### Font-family 代码
-
-```css
-font-family: "Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","微软雅黑",Arial,sans-serif;
-```
 
 
-### 字体使用规范
+### 字号
 
 
 <table class="demo-typo-size">
 <table class="demo-typo-size">
   <tbody>
   <tbody>
-    <tr>
-      <td class="h1">主标题</td>
-      <td class="h1">用 Element 快速搭建页面</td>
-      <td class="color-dark-light">20px  Extra large</td>
+  <tr
+    >
+      <td>层级</td>
+      <td>字体大小</td>
+      <td class="color-dark-light">举例</td>
     </tr>
     </tr>
-    <tr>
-      <td class="h2">标题</td>
-      <td class="h2">用 Element 快速搭建页面</td>
-      <td class="color-dark-light">18px large</td>
+    <tr
+    :style="{ fontSize: font_size_extra_small }"
+    >
+      <td>辅助文字</td>
+      <td class="color-dark-light">{{font_size_extra_small}} Extra Small</td>
+      <td>用 Element 快速搭建页面</td>
     </tr>
     </tr>
-    <tr>
-      <td class="h3">小标题</td>
-      <td class="h3">用 Element 快速搭建页面</td>
-      <td class="color-dark-light">16px Medium</td>
+    <tr
+    :style="{ fontSize: font_size_small }"
+    >
+      <td>正文(小)</td>
+      <td class="color-dark-light">{{font_size_small}} Small</td>
+      <td>用 Element 快速搭建页面</td>
     </tr>
     </tr>
-    <tr>
-      <td class="text-regular">正文</td>
-      <td class="text-regular">用 Element 快速搭建页面</td>
-      <td class="color-dark-light">14px Small</td>
+    <tr
+    :style="{ fontSize: font_size_base }"
+    >
+      <td>正文</td>
+      <td class="color-dark-light">{{font_size_base}} Base</td>
+      <td>用 Element 快速搭建页面</td>
     </tr>
     </tr>
-    <tr>
-      <td class="text-small">正文(小)</td>
-      <td class="text-small">用 Element 快速搭建页面</td>
-      <td class="color-dark-light">13px Extra Small</td>
+    <tr
+    :style="{ fontSize: font_size_medium }"
+    >
+      <td>小标题</td>
+      <td class="color-dark-light">{{font_size_medium}} Medium</td>
+      <td>用 Element 快速搭建页面</td>
     </tr>
     </tr>
-    <tr>
-      <td class="text-smaller">辅助文字</td>
-      <td class="text-smaller">用 Element 快速搭建页面</td>
-      <td class="color-dark-light">12px Extra Extra Small</td>
+    <tr
+    :style="{ fontSize: font_size_large }"
+    >
+      <td>标题</td>
+      <td class="color-dark-light">{{font_size_large}} large</td>
+      <td>用 Element 快速搭建页面</td>
+    </tr>
+    <tr
+    :style="{ fontSize: font_size_extra_large }"
+    >
+      <td>主标题</td>
+      <td class="color-dark-light">{{font_size_extra_large}} Extra large</td>
+      <td>用 Element 快速搭建页面</td>
     </tr>
     </tr>
   </tbody>
   </tbody>
 </table>
 </table>
+
+### 行高
+
+<div>
+<img class="lineH-left" src="~examples/assets/images/typography.png" />
+<ul class="lineH-right">
+<li>line-height:1 <span>无行高</span></li>
+<li>line-height:1.3 <span>紧凑</span></li>
+<li>line-height:1.5 <span>常规</span></li>
+<li>line-height:1.7 <span>宽松</span></li>
+</ul>
+</div>
+
+### Font-family 代码
+
+```css
+font-family: "Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","微软雅黑",Arial,sans-serif;
+```

+ 75 - 0
examples/i18n/theme-editor.json

@@ -0,0 +1,75 @@
+[
+  {
+    "lang": "zh-CN",
+    "display-name": {
+      "border-color": "边框颜色",
+      "font-color": "文字颜色",
+      "background-color": "背景颜色",
+      "font-weight": "文字粗细",
+      "font-size": "文字大小",
+      "font-line-height": "文字行高",
+      "border-radius": "边框圆角",
+      "color": "颜色"
+    },
+    "action": {
+      "theme-editor": "主题编辑器",
+      "no-config": "暂不可编辑,敬请期待",
+      "reset-theme": "重置",
+      "download-theme": "下载"
+    },
+    "category": {
+      "BrandColor": "品牌颜色",
+      "SecondaryColor": "辅助颜色",
+      "FontColor": "文字颜色",
+      "BorderColor": "边框颜色",
+      "BackgroundColor": "背景颜色",
+      "Other": "其他",
+      "Color": "颜色",
+      "Border": "边框",
+      "Font": "文字",
+      "Radius": "边框圆角",
+      "Shadow": "阴影",
+      "FontSize": "文字大小",
+      "FontWeight": "文字粗细",
+      "LineHeight": "文字行高"
+    }
+  },
+  {
+    "lang": "en-US",
+    "display-name": {
+      "border-color": "border color",
+      "font-color": "font color",
+      "background-color": "background color",
+      "font-weight": "font weight",
+      "font-size": "font size",
+      "font-line-height": "font line height",
+      "border-radius": "border radius"
+    },
+    "action": {
+      "theme-editor": "Theme Editor",
+      "no-config": "Please stay tuned",
+      "reset-theme": "Reset",
+      "download-theme": "Download"
+    },
+    "category": {
+      "BrandColor": "Brand Color",
+      "SecondaryColor": "Secondary Color",
+      "FontColor": "Font Color",
+      "BorderColor": "Border Color",
+      "BackgroundColor": "Background Color",
+      "FontSize": "Font Size",
+      "FontWeight": "Font Weight",
+      "LineHeight": "Line Height"
+    }
+  },
+  {
+    "lang": "es",
+    "display-name": {
+    }
+  },
+  {
+    "lang": "fr-FR",
+    "display-name": {
+    }
+  }
+]

+ 16 - 0
examples/nav.config.json

@@ -59,6 +59,10 @@
               "path": "/typography",
               "path": "/typography",
               "title": "Typography 字体"
               "title": "Typography 字体"
             },
             },
+            {
+              "path": "/border",
+              "title": "Border 边框"
+            },
             {
             {
               "path": "/icon",
               "path": "/icon",
               "title": "Icon 图标"
               "title": "Icon 图标"
@@ -313,6 +317,10 @@
               "path": "/typography",
               "path": "/typography",
               "title": "Typography"
               "title": "Typography"
             },
             },
+            {
+              "path": "/border",
+              "title": "Border"
+            },
             {
             {
               "path": "/icon",
               "path": "/icon",
               "title": "Icon"
               "title": "Icon"
@@ -567,6 +575,10 @@
               "path": "/typography",
               "path": "/typography",
               "title": "Typography"
               "title": "Typography"
             },
             },
+            {
+              "path": "/border",
+              "title": "Border"
+            },
             {
             {
               "path": "/icon",
               "path": "/icon",
               "title": "Icon"
               "title": "Icon"
@@ -821,6 +833,10 @@
               "path": "/typography",
               "path": "/typography",
               "title": "Typography"
               "title": "Typography"
             },
             },
+            {
+              "path": "/border",
+              "title": "Border"
+            },
             {
             {
               "path": "/icon",
               "path": "/icon",
               "title": "Icon"
               "title": "Icon"

+ 41 - 3
examples/pages/template/component.tpl

@@ -133,6 +133,37 @@
     }
     }
   }
   }
 
 
+  @media (min-width: 1140px) {
+    .page-component__content {
+      transition:padding-right 0.3s ease;
+      &.theme-config {
+        padding-right: 26%;  
+      }
+    }
+    .page-container.page-component {
+      transition:width 0.3s ease;
+      &.theme-config {
+        width: 98%;
+      }
+      .page-component__nav {
+        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) {
   @media (max-width: 768px) {
     .page-component {
     .page-component {
       .page-component__nav {
       .page-component__nav {
@@ -163,11 +194,11 @@
 </style>
 </style>
 <template>
 <template>
   <el-scrollbar class="page-component__scroll" ref="componentScrollBar">
   <el-scrollbar class="page-component__scroll" ref="componentScrollBar">
-  <div class="page-container page-component">
+  <div class="page-container page-component" :class="{'theme-config': isThemeConfigVisible}">
     <el-scrollbar class="page-component__nav">
     <el-scrollbar class="page-component__nav">
       <side-nav :data="navsData[lang]" :base="`/${ lang }/component`"></side-nav>
       <side-nav :data="navsData[lang]" :base="`/${ lang }/component`"></side-nav>
     </el-scrollbar>
     </el-scrollbar>
-    <div class="page-component__content">
+    <div class="page-component__content" :class="{'theme-config': isThemeConfigVisible}">
       <router-view class="content"></router-view>
       <router-view class="content"></router-view>
       <footer-nav></footer-nav>
       <footer-nav></footer-nav>
     </div>
     </div>
@@ -200,7 +231,8 @@
         scrollTop: 0,
         scrollTop: 0,
         showHeader: true,
         showHeader: true,
         componentScrollBar: null,
         componentScrollBar: null,
-        componentScrollBoxElement: null
+        componentScrollBoxElement: null,
+        isThemeConfigVisible: false
       };
       };
     },
     },
     watch: {
     watch: {
@@ -261,6 +293,9 @@
       bus.$on('navFade', val => {
       bus.$on('navFade', val => {
         this.navFaded = val;
         this.navFaded = val;
       });
       });
+      bus.$on('user-theme-config-visible', val => {
+        this.isThemeConfigVisible = val;
+      });
       window.addEventListener('hashchange', () => {
       window.addEventListener('hashchange', () => {
         if (location.href.match(/#/g).length < 2) {
         if (location.href.match(/#/g).length < 2) {
           document.documentElement.scrollTop = document.body.scrollTop = 0;
           document.documentElement.scrollTop = document.body.scrollTop = 0;
@@ -271,6 +306,9 @@
       });
       });
     },
     },
     mounted() {
     mounted() {
+      if (window.userThemeConfigVisible) {
+        this.isThemeConfigVisible = window.userThemeConfigVisible;
+      }
       this.componentScrollBar = this.$refs.componentScrollBar;
       this.componentScrollBar = this.$refs.componentScrollBar;
       this.componentScrollBox = this.componentScrollBar.$el.querySelector('.el-scrollbar__wrap');
       this.componentScrollBox = this.componentScrollBar.$el.querySelector('.el-scrollbar__wrap');
       this.throttledScrollHandler = throttle(300, this.handleScroll);
       this.throttledScrollHandler = throttle(300, this.handleScroll);

+ 16 - 3
package.json

@@ -27,9 +27,22 @@
     "test": "npm run lint && npm run build:theme && cross-env CI_ENV=/dev/ BABEL_ENV=test karma start test/unit/karma.conf.js --single-run",
     "test": "npm run lint && npm run build:theme && cross-env CI_ENV=/dev/ BABEL_ENV=test karma start test/unit/karma.conf.js --single-run",
     "test:watch": "npm run build:theme && cross-env BABEL_ENV=test karma start test/unit/karma.conf.js"
     "test:watch": "npm run build:theme && cross-env BABEL_ENV=test karma start test/unit/karma.conf.js"
   },
   },
-  "faas": {
-    "domain": "element",
-    "public": "temp_web/element"
+  "faas": [
+    {
+      "domain": "element",
+      "public": "temp_web/element"
+    },
+    {
+      "domain": "element-theme",
+      "public": "examples/element-ui",
+      "build": [
+        "yarn",
+        "npm run deploy:build"
+      ]
+    }
+  ],
+  "engines": {
+    "node": "8"
   },
   },
   "repository": {
   "repository": {
     "type": "git",
     "type": "git",

+ 13 - 13
packages/theme-chalk/src/button.scss

@@ -9,10 +9,10 @@
   line-height: 1;
   line-height: 1;
   white-space: nowrap;
   white-space: nowrap;
   cursor: pointer;
   cursor: pointer;
-  background: $--button-default-fill;
+  background: $--button-default-background-color;
   border: $--border-base;
   border: $--border-base;
-  border-color: $--button-default-border;
-  color: $--button-default-color;
+  border-color: $--button-default-border-color;
+  color: $--button-default-font-color;
   -webkit-appearance: none;
   -webkit-appearance: none;
   text-align: center;
   text-align: center;
   box-sizing: border-box;
   box-sizing: border-box;
@@ -75,11 +75,11 @@
     &,
     &,
     &:hover,
     &:hover,
     &:focus {
     &:focus {
-      color: $--button-disabled-color;
+      color: $--button-disabled-font-color;
       cursor: not-allowed;
       cursor: not-allowed;
       background-image: none;
       background-image: none;
-      background-color: $--button-disabled-fill;
-      border-color: $--button-disabled-border;
+      background-color: $--button-disabled-background-color;
+      border-color: $--button-disabled-border-color;
     }
     }
 
 
     &.el-button--text {
     &.el-button--text {
@@ -91,8 +91,8 @@
       &:hover,
       &:hover,
       &:focus {
       &:focus {
         background-color: $--color-white;
         background-color: $--color-white;
-        border-color: $--button-disabled-border;
-        color: $--button-disabled-color;
+        border-color: $--button-disabled-border-color;
+        color: $--button-disabled-font-color;
       }
       }
     }
     }
   }
   }
@@ -122,19 +122,19 @@
     padding: $--button-padding-vertical;
     padding: $--button-padding-vertical;
   }
   }
   @include m(primary) {
   @include m(primary) {
-    @include button-variant($--button-primary-color, $--button-primary-fill, $--button-primary-border);
+    @include button-variant($--button-primary-font-color, $--button-primary-background-color, $--button-primary-border-color);
   }
   }
   @include m(success) {
   @include m(success) {
-    @include button-variant($--button-success-color, $--button-success-fill, $--button-success-border);
+    @include button-variant($--button-success-font-color, $--button-success-background-color, $--button-success-border-color);
   }
   }
   @include m(warning) {
   @include m(warning) {
-    @include button-variant($--button-warning-color, $--button-warning-fill, $--button-warning-border);
+    @include button-variant($--button-warning-font-color, $--button-warning-background-color, $--button-warning-border-color);
   }
   }
   @include m(danger) {
   @include m(danger) {
-    @include button-variant($--button-danger-color, $--button-danger-fill, $--button-danger-border);
+    @include button-variant($--button-danger-font-color, $--button-danger-background-color, $--button-danger-border-color);
   }
   }
   @include m(info) {
   @include m(info) {
-    @include button-variant($--button-info-color, $--button-info-fill, $--button-info-border);
+    @include button-variant($--button-info-font-color, $--button-info-background-color, $--button-info-border-color);
   }
   }
   @include m(medium) {
   @include m(medium) {
     @include button-size($--button-medium-padding-vertical, $--button-medium-padding-horizontal, $--button-medium-font-size, $--button-medium-border-radius);
     @include button-size($--button-medium-padding-vertical, $--button-medium-padding-horizontal, $--button-medium-font-size, $--button-medium-border-radius);

+ 6 - 6
packages/theme-chalk/src/checkbox.scss

@@ -256,10 +256,10 @@
     white-space: nowrap;
     white-space: nowrap;
     vertical-align: middle;
     vertical-align: middle;
     cursor: pointer;
     cursor: pointer;
-    background: $--button-default-fill;
+    background: $--button-default-background-color;
     border: $--border-base;
     border: $--border-base;
     border-left: 0;
     border-left: 0;
-    color: $--button-default-color;
+    color: $--button-default-font-color;
     -webkit-appearance: none;
     -webkit-appearance: none;
     text-align: center;
     text-align: center;
     box-sizing: border-box;
     box-sizing: border-box;
@@ -306,15 +306,15 @@
 
 
   &.is-disabled {
   &.is-disabled {
     & .el-checkbox-button__inner {
     & .el-checkbox-button__inner {
-      color: $--button-disabled-color;
+      color: $--button-disabled-font-color;
       cursor: not-allowed;
       cursor: not-allowed;
       background-image: none;
       background-image: none;
-      background-color: $--button-disabled-fill;
-      border-color: $--button-disabled-border;
+      background-color: $--button-disabled-background-color;
+      border-color: $--button-disabled-border-color;
       box-shadow: none;
       box-shadow: none;
     }
     }
     &:first-child .el-checkbox-button__inner {
     &:first-child .el-checkbox-button__inner {
-      border-left-color: $--button-disabled-border;
+      border-left-color: $--button-disabled-border-color;
     }
     }
   }
   }
 
 

+ 134 - 61
packages/theme-chalk/src/common/var.scss

@@ -1,5 +1,8 @@
 /* Element Chalk Variables */
 /* Element Chalk Variables */
 
 
+// Special comment for theme configurator
+// type|[Chinese Name, English Name, Spanish Name, French Name]|Category|Order
+
 /* Transition
 /* Transition
 -------------------------- */
 -------------------------- */
 $--all-transition: all .3s cubic-bezier(.645,.045,.355,1) !default;
 $--all-transition: all .3s cubic-bezier(.645,.045,.355,1) !default;
@@ -9,12 +12,14 @@ $--md-fade-transition: transform 300ms cubic-bezier(0.23, 1, 0.32, 1), opacity 3
 $--border-transition-base: border-color .2s cubic-bezier(.645,.045,.355,1) !default;
 $--border-transition-base: border-color .2s cubic-bezier(.645,.045,.355,1) !default;
 $--color-transition-base: color .2s cubic-bezier(.645,.045,.355,1) !default;
 $--color-transition-base: color .2s cubic-bezier(.645,.045,.355,1) !default;
 
 
-/* Colors
+/* Color
 -------------------------- */
 -------------------------- */
-$--color-white: #fff !default;
-$--color-black: #000 !default;
-
+/// color|[主题色,primary color,color primario]|BrandColor|0
 $--color-primary: #409EFF !default;
 $--color-primary: #409EFF !default;
+/// color|[基础白色,basic white,basic white]|BackgroundColor|4
+$--color-white: #FFFFFF !default;
+/// color|[基础黑色,basic black,basic black]|BackgroundColor|4
+$--color-black: #000000 !default;
 $--color-primary-light-1: mix($--color-white, $--color-primary, 10%) !default; /* 53a8ff */
 $--color-primary-light-1: mix($--color-white, $--color-primary, 10%) !default; /* 53a8ff */
 $--color-primary-light-2: mix($--color-white, $--color-primary, 20%) !default; /* 66b1ff */
 $--color-primary-light-2: mix($--color-white, $--color-primary, 20%) !default; /* 66b1ff */
 $--color-primary-light-3: mix($--color-white, $--color-primary, 30%) !default; /* 79bbff */
 $--color-primary-light-3: mix($--color-white, $--color-primary, 30%) !default; /* 79bbff */
@@ -24,10 +29,13 @@ $--color-primary-light-6: mix($--color-white, $--color-primary, 60%) !default; /
 $--color-primary-light-7: mix($--color-white, $--color-primary, 70%) !default; /* c6e2ff */
 $--color-primary-light-7: mix($--color-white, $--color-primary, 70%) !default; /* c6e2ff */
 $--color-primary-light-8: mix($--color-white, $--color-primary, 80%) !default; /* d9ecff */
 $--color-primary-light-8: mix($--color-white, $--color-primary, 80%) !default; /* d9ecff */
 $--color-primary-light-9: mix($--color-white, $--color-primary, 90%) !default; /* ecf5ff */
 $--color-primary-light-9: mix($--color-white, $--color-primary, 90%) !default; /* ecf5ff */
-
-$--color-success: #67c23a !default;
-$--color-warning: #e6a23c !default;
-$--color-danger: #f56c6c !default;
+/// color|[成功颜色,success color,success color]|SecondaryColor|1
+$--color-success: #67C23A !default;
+/// color|[警告颜色,warning color,warning color]|SecondaryColor|1
+$--color-warning: #E6A23C !default;
+/// color|[危险颜色,danger color,danger color]|SecondaryColor|1
+$--color-danger: #F56C6C !default;
+/// color|[信息颜色,info color,info color]|SecondaryColor|1
 $--color-info: #909399 !default;
 $--color-info: #909399 !default;
 
 
 $--color-success-light: mix($--color-white, $--color-success, 80%) !default;
 $--color-success-light: mix($--color-white, $--color-success, 80%) !default;
@@ -39,55 +47,81 @@ $--color-success-lighter: mix($--color-white, $--color-success, 90%) !default;
 $--color-warning-lighter: mix($--color-white, $--color-warning, 90%) !default;
 $--color-warning-lighter: mix($--color-white, $--color-warning, 90%) !default;
 $--color-danger-lighter: mix($--color-white, $--color-danger, 90%) !default;
 $--color-danger-lighter: mix($--color-white, $--color-danger, 90%) !default;
 $--color-info-lighter: mix($--color-white, $--color-info, 90%) !default;
 $--color-info-lighter: mix($--color-white, $--color-info, 90%) !default;
-
+/// color|[主要文字颜色,primary text color,primary text color]|FontColor|2
 $--color-text-primary: #303133 !default;
 $--color-text-primary: #303133 !default;
+/// color|[常规文字颜色,regular text color,regular text color]|FontColor|2
 $--color-text-regular: #606266 !default;
 $--color-text-regular: #606266 !default;
+/// color|[次要文字颜色,secondary text color,secondary text color]|FontColor|2
 $--color-text-secondary: #909399 !default;
 $--color-text-secondary: #909399 !default;
-$--color-text-placeholder: #c0c4cc !default;
+/// color|[占位文字颜色,placeholder text color,placeholder text color]|FontColor|2
+$--color-text-placeholder: #C0C4CC !default;
+/// color|[一级边框颜色,border color,border color]|BorderColor|3
+$--border-color-base: #DCDFE6 !default;
+/// color|[二级边框颜色,border color light,border color light]|BorderColor|3
+$--border-color-light: #E4E7ED !default;
+/// color|[三级边框颜色,border color lighter,border color lighter]|BorderColor|3
+$--border-color-lighter: #EBEEF5 !default;
+/// color|[四级边框颜色,border color extra light,border color extra light]|BorderColor|3
+$--border-color-extra-light: #F2F6FC !default;
+
+// Background
+/// color|[基础背景色,base background color,base background color]|BackgroundColor|4
+$--background-color-base: #f5f7fa !default;
 
 
 /* Link
 /* Link
 -------------------------- */
 -------------------------- */
 $--link-color: $--color-primary-light-2 !default;
 $--link-color: $--color-primary-light-2 !default;
 $--link-hover-color: $--color-primary !default;
 $--link-hover-color: $--color-primary !default;
 
 
-/* Background
--------------------------- */
-$--background-color-base: #f5f7fa !default;
-
 /* Border
 /* Border
 -------------------------- */
 -------------------------- */
 $--border-width-base: 1px !default;
 $--border-width-base: 1px !default;
 $--border-style-base: solid !default;
 $--border-style-base: solid !default;
-$--border-color-base: #dcdfe6 !default;
-$--border-color-light: #e4e7ed !default;
-$--border-color-lighter: #ebeef5 !default;
-$--border-color-extra-light: #f2f6fc !default;
 $--border-color-hover: $--color-text-placeholder !default;
 $--border-color-hover: $--color-text-placeholder !default;
 $--border-base: $--border-width-base $--border-style-base $--border-color-base !default;
 $--border-base: $--border-width-base $--border-style-base $--border-color-base !default;
+/// borderRadius|[大圆角,border radius base,border radius base]|Radius|0
 $--border-radius-base: 4px !default;
 $--border-radius-base: 4px !default;
+/// borderRadius|[小圆角,border radius small,border radius small]|Radius|0
 $--border-radius-small: 2px !default;
 $--border-radius-small: 2px !default;
+/// borderRadius|[圆形圆角,border radius circle,border radius circle]|Radius|0
 $--border-radius-circle: 100% !default;
 $--border-radius-circle: 100% !default;
 
 
-/* Box-shadow
--------------------------- */
+// Box-shadow
+/// boxShadow|[基础投影,box shadow base,box shadow base]|Shadow|1
 $--box-shadow-base: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04) !default;
 $--box-shadow-base: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04) !default;
+// boxShadow|[深色投影,box shadow,box shadow]|Shadow|1
 $--box-shadow-dark: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .12) !default;
 $--box-shadow-dark: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .12) !default;
+/// boxShadow|[浅色投影,box shadow,box shadow]|Shadow|1
 $--box-shadow-light: 0 2px 12px 0 rgba(0, 0, 0, 0.1) !default;
 $--box-shadow-light: 0 2px 12px 0 rgba(0, 0, 0, 0.1) !default;
 
 
 /* Fill
 /* Fill
 -------------------------- */
 -------------------------- */
 $--fill-base: $--color-white !default;
 $--fill-base: $--color-white !default;
 
 
-/* Font
+/* Typography
 -------------------------- */
 -------------------------- */
 $--font-path: 'fonts' !default;
 $--font-path: 'fonts' !default;
+/// fontSize|[主标题文字大小,Extra large font size,Extra large font size]|FontSize|0
+$--font-size-extra-large: 20px !default;
+/// fontSize|[标题文字大小,large font size,large font size]|FontSize|0
+$--font-size-large: 18px !default;
+/// fontSize|[小标题文字大小,Medium font size,Medium font size]|FontSize|0
+$--font-size-medium: 16px !default;
+/// fontSize|[正文文字大小,base font size,base font size]|FontSize|0
 $--font-size-base: 14px !default;
 $--font-size-base: 14px !default;
+/// fontSize|[正文(小)文字大小,small font size,small font size]|FontSize|0
 $--font-size-small: 13px !default;
 $--font-size-small: 13px !default;
-$--font-size-large: 18px !default;
-$--font-color-disabled-base: #bbb !default;
+/// fontSize|[辅助文字大小,Extra small font size,Extra small font size]|FontSize|0
+$--font-size-extra-small: 12px !default;
+/// fontWeight|[主要文字粗细,primary font weight,primary font weight]|FontWeight|1
 $--font-weight-primary: 500 !default;
 $--font-weight-primary: 500 !default;
+/// fontWeight|[次要文字粗细,secondary font weight,secondary font weight]|FontWeight|1
+$--font-weight-secondary: 100 !default;
+/// fontLineHeight|[主要文字行高,primary font line height,primary font line height]|LineHeight|2
 $--font-line-height-primary: 24px !default;
 $--font-line-height-primary: 24px !default;
-
+/// fontLineHeight|[次要文字行高,secondary font line height,secondary font line height]|LineHeight|2
+$--font-line-height-secondary: 16px !default;
+$--font-color-disabled-base: #bbb !default;
 /* Size
 /* Size
 -------------------------- */
 -------------------------- */
 $--size-base: 14px !default;
 $--size-base: 14px !default;
@@ -161,15 +195,22 @@ $--checkbox-button-checked-border-color: $--color-primary !default;
 
 
 /* Radio
 /* Radio
 -------------------------- */
 -------------------------- */
-$--radio-font-size: 14px !default;
+/// fontSize|[]|Font|1
+$--radio-font-size: $--font-size-base !default;
+/// fontWeight|[]|Font|1
 $--radio-font-weight: $--font-weight-primary !default;
 $--radio-font-weight: $--font-weight-primary !default;
-$--radio-color: $--color-text-regular !default;
+/// color|[]|Color|0
+$--radio-font-color: $--color-text-regular !default;
 $--radio-input-height: 14px !default;
 $--radio-input-height: 14px !default;
 $--radio-input-width: 14px !default;
 $--radio-input-width: 14px !default;
+/// borderRadius|[]|Border|2
 $--radio-input-border-radius: $--border-radius-circle !default;
 $--radio-input-border-radius: $--border-radius-circle !default;
-$--radio-input-fill: $--color-white !default;
+/// color|[]|Color|0
+$--radio-input-background-color: $--color-white !default;
 $--radio-input-border: $--border-base !default;
 $--radio-input-border: $--border-base !default;
+/// color|[]|Color|0
 $--radio-input-border-color: $--border-color-base !default;
 $--radio-input-border-color: $--border-color-base !default;
+/// color|[]|Color|0
 $--radio-icon-color: $--color-white !default;
 $--radio-icon-color: $--color-white !default;
 
 
 $--radio-disabled-input-border-color: $--disabled-border-base !default;
 $--radio-disabled-input-border-color: $--disabled-border-base !default;
@@ -180,9 +221,13 @@ $--radio-disabled-checked-input-border-color: $--disabled-border-base !default;
 $--radio-disabled-checked-input-fill: $--disabled-fill-base !default;
 $--radio-disabled-checked-input-fill: $--disabled-fill-base !default;
 $--radio-disabled-checked-icon-color: $--color-text-placeholder !default;
 $--radio-disabled-checked-icon-color: $--color-text-placeholder !default;
 
 
-$--radio-checked-text-color: $--color-primary !default;
+/// color|[]|Color|0
+$--radio-checked-font-color: $--color-primary !default;
+/// color|[]|Color|0
 $--radio-checked-input-border-color: $--color-primary !default;
 $--radio-checked-input-border-color: $--color-primary !default;
-$--radio-checked-input-fill: $--color-white !default;
+/// color|[]|Color|0
+$--radio-checked-input-background-color: $--color-white !default;
+/// color|[]|Color|0
 $--radio-checked-icon-color: $--color-primary !default;
 $--radio-checked-icon-color: $--color-primary !default;
 
 
 $--radio-input-border-color-hover: $--color-primary !default;
 $--radio-input-border-color-hover: $--color-primary !default;
@@ -202,9 +247,13 @@ $--radio-bordered-mini-input-height: 12px !default;
 $--radio-bordered-mini-input-width: 12px !default;
 $--radio-bordered-mini-input-width: 12px !default;
 $--radio-bordered-mini-height: 28px !default;
 $--radio-bordered-mini-height: 28px !default;
 
 
+/// fontSize|[]|Font|1
 $--radio-button-font-size: $--font-size-base !default;
 $--radio-button-font-size: $--font-size-base !default;
-$--radio-button-checked-fill: $--color-primary !default;
-$--radio-button-checked-color: $--color-white !default;
+/// color|[]|Color|0
+$--radio-button-checked-background-color: $--color-primary !default;
+/// color|[]|Color|0
+$--radio-button-checked-font-color: $--color-white !default;
+/// color|[]|Color|0
 $--radio-button-checked-border-color: $--color-primary !default;
 $--radio-button-checked-border-color: $--color-primary !default;
 $--radio-button-disabled-checked-fill: $--border-color-extra-light !default;
 $--radio-button-disabled-checked-fill: $--border-color-extra-light !default;
 
 
@@ -393,17 +442,23 @@ $--tab-vertical-header-count-fill: $--color-text-secondary !default;
 
 
 /* Button
 /* Button
 -------------------------- */
 -------------------------- */
-$--button-font-size: 14px !default;
+/// fontSize|[]|Font|1
+$--button-font-size: $--font-size-base !default;
+/// fontWeight|[]|Font|1
 $--button-font-weight: $--font-weight-primary !default;
 $--button-font-weight: $--font-weight-primary !default;
+/// borderRadius|[]|Border|2
 $--button-border-radius: $--border-radius-base !default;
 $--button-border-radius: $--border-radius-base !default;
 $--button-padding-vertical: 12px !default;
 $--button-padding-vertical: 12px !default;
 $--button-padding-horizontal: 20px !default;
 $--button-padding-horizontal: 20px !default;
 
 
-$--button-medium-font-size: 14px !default;
+/// fontSize|[]|Font|1
+$--button-medium-font-size: $--font-size-base !default;
+/// borderRadius|[]|Border|2
 $--button-medium-border-radius: $--border-radius-base !default;
 $--button-medium-border-radius: $--border-radius-base !default;
 $--button-medium-padding-vertical: 10px !default;
 $--button-medium-padding-vertical: 10px !default;
 $--button-medium-padding-horizontal: 20px !default;
 $--button-medium-padding-horizontal: 20px !default;
 
 
+/// fontSize|[]|Font|1
 $--button-small-font-size: 12px !default;
 $--button-small-font-size: 12px !default;
 $--button-small-border-radius: #{$--border-radius-base - 1} !default;
 $--button-small-border-radius: #{$--border-radius-base - 1} !default;
 $--button-small-padding-vertical: 9px !default;
 $--button-small-padding-vertical: 9px !default;
@@ -414,33 +469,50 @@ $--button-mini-border-radius: #{$--border-radius-base - 1} !default;
 $--button-mini-padding-vertical: 7px !default;
 $--button-mini-padding-vertical: 7px !default;
 $--button-mini-padding-horizontal: 15px !default;
 $--button-mini-padding-horizontal: 15px !default;
 
 
-$--button-default-color: $--color-text-regular !default;
-$--button-default-fill: $--color-white !default;
-$--button-default-border: $--border-color-base !default;
-
-$--button-disabled-color: $--color-text-placeholder !default;
-$--button-disabled-fill: $--color-white !default;
-$--button-disabled-border: $--border-color-lighter !default;
-
-$--button-primary-border: $--color-primary !default;
-$--button-primary-color: $--color-white !default;
-$--button-primary-fill: $--color-primary !default;
-
-$--button-success-border: $--color-success !default;
-$--button-success-color: $--color-white !default;
-$--button-success-fill: $--color-success !default;
-
-$--button-warning-border: $--color-warning !default;
-$--button-warning-color: $--color-white !default;
-$--button-warning-fill: $--color-warning !default;
-
-$--button-danger-border: $--color-danger !default;
-$--button-danger-color: $--color-white !default;
-$--button-danger-fill: $--color-danger !default;
-
-$--button-info-border: $--color-info !default;
-$--button-info-color: $--color-white !default;
-$--button-info-fill: $--color-info !default;
+/// color|[]|Color|0
+$--button-default-font-color: $--color-text-regular !default;
+/// color|[]|Color|0
+$--button-default-background-color: $--color-white !default;
+/// color|[]|Color|0
+$--button-default-border-color: $--border-color-base !default;
+
+/// color|[]|Color|0
+$--button-disabled-font-color: $--color-text-placeholder !default;
+/// color|[]|Color|0
+$--button-disabled-background-color: $--color-white !default;
+/// color|[]|Color|0
+$--button-disabled-border-color: $--border-color-lighter !default;
+
+/// color|[]|Color|0
+$--button-primary-border-color: $--color-primary !default;
+/// color|[]|Color|0
+$--button-primary-font-color: $--color-white !default;
+/// color|[]|Color|0
+$--button-primary-background-color: $--color-primary !default;
+/// color|[]|Color|0
+$--button-success-border-color: $--color-success !default;
+/// color|[]|Color|0
+$--button-success-font-color: $--color-white !default;
+/// color|[]|Color|0
+$--button-success-background-color: $--color-success !default;
+/// color|[]|Color|0
+$--button-warning-border-color: $--color-warning !default;
+/// color|[]|Color|0
+$--button-warning-font-color: $--color-white !default;
+/// color|[]|Color|0
+$--button-warning-background-color: $--color-warning !default;
+/// color|[]|Color|0
+$--button-danger-border-color: $--color-danger !default;
+/// color|[]|Color|0
+$--button-danger-font-color: $--color-white !default;
+/// color|[]|Color|0
+$--button-danger-background-color: $--color-danger !default;
+/// color|[]|Color|0
+$--button-info-border-color: $--color-info !default;
+/// color|[]|Color|0
+$--button-info-font-color: $--color-white !default;
+/// color|[]|Color|0
+$--button-info-background-color: $--color-info !default;
 
 
 $--button-hover-tint-percent: 20% !default;
 $--button-hover-tint-percent: 20% !default;
 $--button-active-shade-percent: 10% !default;
 $--button-active-shade-percent: 10% !default;
@@ -470,7 +542,8 @@ $--dialog-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3) !default;
 $--dialog-close-hover-color: $--color-primary !default;
 $--dialog-close-hover-color: $--color-primary !default;
 $--dialog-title-font-size: $--font-size-large !default;
 $--dialog-title-font-size: $--font-size-large !default;
 $--dialog-font-size: 14px !default;
 $--dialog-font-size: 14px !default;
-$--dialog-line-height: $--font-line-height-primary !default;
+/// fontLineHeight|[]
+$--dialog-font-line-height: $--font-line-height-primary !default;
 $--dialog-padding-primary: 20px !default;
 $--dialog-padding-primary: 20px !default;
 
 
 /* Table
 /* Table

+ 1 - 1
packages/theme-chalk/src/dialog.scss

@@ -58,7 +58,7 @@
   }
   }
 
 
   @include e(title) {
   @include e(title) {
-    line-height: $--dialog-line-height;
+    line-height: $--dialog-font-line-height;
     font-size: $--dialog-title-font-size;
     font-size: $--dialog-title-font-size;
     color: $--color-text-primary;
     color: $--color-text-primary;
   }
   }

+ 7 - 7
packages/theme-chalk/src/radio-button.scss

@@ -12,11 +12,11 @@
     line-height: 1;
     line-height: 1;
     white-space: nowrap;
     white-space: nowrap;
     vertical-align: middle;
     vertical-align: middle;
-    background: $--button-default-fill;
+    background: $--button-default-background-color;
     border: $--border-base;
     border: $--border-base;
     font-weight: $--button-font-weight;
     font-weight: $--button-font-weight;
     border-left: 0;
     border-left: 0;
-    color: $--button-default-color;
+    color: $--button-default-font-color;
     -webkit-appearance: none;
     -webkit-appearance: none;
     text-align: center;
     text-align: center;
     box-sizing: border-box;
     box-sizing: border-box;
@@ -57,8 +57,8 @@
 
 
     &:checked {
     &:checked {
       & + .el-radio-button__inner {
       & + .el-radio-button__inner {
-        color: $--radio-button-checked-color;
-        background-color: $--radio-button-checked-fill;
+        color: $--radio-button-checked-font-color;
+        background-color: $--radio-button-checked-background-color;
         border-color: $--radio-button-checked-border-color;
         border-color: $--radio-button-checked-border-color;
         box-shadow: -1px 0 0 0 $--radio-button-checked-border-color;
         box-shadow: -1px 0 0 0 $--radio-button-checked-border-color;
       }
       }
@@ -66,11 +66,11 @@
 
 
     &:disabled {
     &:disabled {
       & + .el-radio-button__inner {
       & + .el-radio-button__inner {
-        color: $--button-disabled-color;
+        color: $--button-disabled-font-color;
         cursor: not-allowed;
         cursor: not-allowed;
         background-image: none;
         background-image: none;
-        background-color: $--button-disabled-fill;
-        border-color: $--button-disabled-border;
+        background-color: $--button-disabled-background-color;
+        border-color: $--button-disabled-border-color;
         box-shadow: none;
         box-shadow: none;
       }
       }
       &:checked + .el-radio-button__inner {
       &:checked + .el-radio-button__inner {

+ 3 - 3
packages/theme-chalk/src/radio.scss

@@ -4,7 +4,7 @@
 @import "common/var";
 @import "common/var";
 
 
 @include b(radio) {
 @include b(radio) {
-  color: $--radio-color;
+  color: $--radio-font-color;
   font-weight: $--radio-font-weight;
   font-weight: $--radio-font-weight;
   line-height: 1;
   line-height: 1;
   position: relative;
   position: relative;
@@ -135,7 +135,7 @@
       }
       }
 
 
       & + .el-radio__label {
       & + .el-radio__label {
-        color: $--radio-checked-text-color;
+        color: $--radio-checked-font-color;
       }
       }
     }
     }
 
 
@@ -150,7 +150,7 @@
     border-radius: $--radio-input-border-radius;
     border-radius: $--radio-input-border-radius;
     width: $--radio-input-width;
     width: $--radio-input-width;
     height: $--radio-input-height;
     height: $--radio-input-height;
-    background-color: $--radio-input-fill;
+    background-color: $--radio-input-background-color;
     position: relative;
     position: relative;
     cursor: pointer;
     cursor: pointer;
     display: inline-block;
     display: inline-block;