main.vue 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. <template>
  2. <el-color-picker
  3. v-model="theme"
  4. :predefine="[
  5. '#409EFF',
  6. '#1890ff',
  7. '#304156',
  8. '#212121',
  9. '#11a983',
  10. '#13c2c2',
  11. '#6959CD',
  12. '#f5222d'
  13. ]"
  14. class="theme-picker"
  15. popper-class="theme-picker-dropdown"
  16. />
  17. </template>
  18. <script>
  19. const version = require('element-ui/package.json').version // element-ui version from node_modules
  20. const ORIGINAL_THEME = '#409EFF' // default color
  21. export default {
  22. data() {
  23. return {
  24. chalk: '', // content of theme-chalk css
  25. theme: ''
  26. }
  27. },
  28. computed: {
  29. defaultTheme() {
  30. return this.$store.state.settings.theme
  31. }
  32. },
  33. watch: {
  34. defaultTheme: {
  35. handler: function(val, oldVal) {
  36. this.theme = val
  37. },
  38. immediate: true
  39. },
  40. async theme(val) {
  41. const oldVal = this.chalk ? this.theme : ORIGINAL_THEME
  42. if (typeof val !== 'string') return
  43. const themeCluster = this.getThemeCluster(val.replace('#', ''))
  44. const originalCluster = this.getThemeCluster(oldVal.replace('#', ''))
  45. console.log(themeCluster, originalCluster)
  46. const $message = this.$message({
  47. message: ' Compiling the theme',
  48. customClass: 'theme-message',
  49. type: 'success',
  50. duration: 0,
  51. iconClass: 'el-icon-loading'
  52. })
  53. const getHandler = (variable, id) => {
  54. return () => {
  55. const originalCluster = this.getThemeCluster(
  56. ORIGINAL_THEME.replace('#', '')
  57. )
  58. const newStyle = this.updateStyle(
  59. this[variable],
  60. originalCluster,
  61. themeCluster
  62. )
  63. let styleTag = document.getElementById(id)
  64. if (!styleTag) {
  65. styleTag = document.createElement('style')
  66. styleTag.setAttribute('id', id)
  67. document.head.appendChild(styleTag)
  68. }
  69. styleTag.innerText = newStyle
  70. }
  71. }
  72. if (!this.chalk) {
  73. const url = `https://unpkg.com/element-ui@${version}/lib/theme-chalk/index.css`
  74. await this.getCSSString(url, 'chalk')
  75. }
  76. const chalkHandler = getHandler('chalk', 'chalk-style')
  77. chalkHandler()
  78. const styles = [].slice
  79. .call(document.querySelectorAll('style'))
  80. .filter(style => {
  81. const text = style.innerText
  82. return (
  83. new RegExp(oldVal, 'i').test(text) && !/Chalk Variables/.test(text)
  84. )
  85. })
  86. styles.forEach(style => {
  87. const { innerText } = style
  88. if (typeof innerText !== 'string') return
  89. style.innerText = this.updateStyle(
  90. innerText,
  91. originalCluster,
  92. themeCluster
  93. )
  94. })
  95. this.$emit('change', val)
  96. $message.close()
  97. }
  98. },
  99. methods: {
  100. updateStyle(style, oldCluster, newCluster) {
  101. let newStyle = style
  102. oldCluster.forEach((color, index) => {
  103. newStyle = newStyle.replace(new RegExp(color, 'ig'), newCluster[index])
  104. })
  105. return newStyle
  106. },
  107. getCSSString(url, variable) {
  108. return new Promise(resolve => {
  109. const xhr = new XMLHttpRequest()
  110. xhr.onreadystatechange = () => {
  111. if (xhr.readyState === 4 && xhr.status === 200) {
  112. this[variable] = xhr.responseText.replace(/@font-face{[^}]+}/, '')
  113. resolve()
  114. }
  115. }
  116. xhr.open('GET', url)
  117. xhr.send()
  118. })
  119. },
  120. getThemeCluster(theme) {
  121. const tintColor = (color, tint) => {
  122. let red = parseInt(color.slice(0, 2), 16)
  123. let green = parseInt(color.slice(2, 4), 16)
  124. let blue = parseInt(color.slice(4, 6), 16)
  125. if (tint === 0) {
  126. // when primary color is in its rgb space
  127. return [red, green, blue].join(',')
  128. } else {
  129. red += Math.round(tint * (255 - red))
  130. green += Math.round(tint * (255 - green))
  131. blue += Math.round(tint * (255 - blue))
  132. red = red.toString(16)
  133. green = green.toString(16)
  134. blue = blue.toString(16)
  135. return `#${red}${green}${blue}`
  136. }
  137. }
  138. const shadeColor = (color, shade) => {
  139. let red = parseInt(color.slice(0, 2), 16)
  140. let green = parseInt(color.slice(2, 4), 16)
  141. let blue = parseInt(color.slice(4, 6), 16)
  142. red = Math.round((1 - shade) * red)
  143. green = Math.round((1 - shade) * green)
  144. blue = Math.round((1 - shade) * blue)
  145. red = red.toString(16)
  146. green = green.toString(16)
  147. blue = blue.toString(16)
  148. return `#${red}${green}${blue}`
  149. }
  150. const clusters = [theme]
  151. for (let i = 0; i <= 9; i++) {
  152. clusters.push(tintColor(theme, Number((i / 10).toFixed(2))))
  153. }
  154. clusters.push(shadeColor(theme, 0.1))
  155. return clusters
  156. }
  157. }
  158. }
  159. </script>
  160. <style>
  161. .theme-message,
  162. .theme-picker-dropdown {
  163. z-index: 99999 !important;
  164. }
  165. .theme-picker .el-color-picker__trigger {
  166. height: 26px !important;
  167. width: 26px !important;
  168. padding: 2px;
  169. }
  170. .theme-picker-dropdown .el-color-dropdown__link-btn {
  171. display: none;
  172. }
  173. </style>