فهرست منبع

主题模式添加

wxb 5 سال پیش
والد
کامیت
8e3bc5a938

+ 1 - 0
package.json

@@ -62,6 +62,7 @@
     "normalize.css": "8.0.1",
     "nprogress": "0.2.0",
     "path-to-regexp": "6.1.0",
+    "sass-resources-loader": "^2.0.3",
     "screenfull": "5.0.2",
     "showdown": "^1.9.1",
     "solarlunar": "^2.0.7",

+ 39 - 0
src/assets/dark.svg

@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="52px" height="45px" viewBox="0 0 52 45" version="1.1" 
+    xmlns="http://www.w3.org/2000/svg" 
+    xmlns:xlink="http://www.w3.org/1999/xlink">
+    <defs>
+        <filter x="-9.4%" y="-6.2%" width="118.8%" height="122.5%" filterUnits="objectBoundingBox" id="filter-1">
+            <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
+            <feColorMatrix values="0 0 0 0 0   0 0 0 0 0   0 0 0 0 0  0 0 0 0.15 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
+            <feMerge>
+                <feMergeNode in="shadowMatrixOuter1"></feMergeNode>
+                <feMergeNode in="SourceGraphic"></feMergeNode>
+            </feMerge>
+        </filter>
+        <rect id="path-2" x="0" y="0" width="48" height="40" rx="4"></rect>
+        <filter x="-4.2%" y="-2.5%" width="108.3%" height="110.0%" filterUnits="objectBoundingBox" id="filter-4">
+            <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feGaussianBlur stdDeviation="0.5" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
+            <feColorMatrix values="0 0 0 0 0   0 0 0 0 0   0 0 0 0 0  0 0 0 0.1 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
+        </filter>
+    </defs>
+    <g id="配置面板" width="48" height="40" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="setting-copy-2" width="48" height="40" transform="translate(-1190.000000, -136.000000)">
+            <g id="Group-8" width="48" height="40" transform="translate(1167.000000, 0.000000)">
+                <g id="Group-5-Copy-5" filter="url(#filter-1)" transform="translate(25.000000, 137.000000)">
+                    <mask id="mask-3" fill="white">
+                        <use xlink:href="#path-2"></use>
+                    </mask>
+                    <g id="Rectangle-18">
+                        <use fill="black" fill-opacity="1" filter="url(#filter-4)" xlink:href="#path-2"></use>
+                        <use fill="#F0F2F5" fill-rule="evenodd" xlink:href="#path-2"></use>
+                    </g>
+                    <rect id="Rectangle-11" fill="#FFFFFF" mask="url(#mask-3)" x="0" y="0" width="48" height="10"></rect>
+                    <rect id="Rectangle-18" fill="#303648" mask="url(#mask-3)" x="0" y="0" width="16" height="40"></rect>
+                </g>
+            </g>
+        </g>
+    </g>
+</svg>

+ 39 - 0
src/assets/light.svg

@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="52px" height="45px" viewBox="0 0 52 45" version="1.1" 
+    xmlns="http://www.w3.org/2000/svg" 
+    xmlns:xlink="http://www.w3.org/1999/xlink">
+    <defs>
+        <filter x="-9.4%" y="-6.2%" width="118.8%" height="122.5%" filterUnits="objectBoundingBox" id="filter-1">
+            <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
+            <feColorMatrix values="0 0 0 0 0   0 0 0 0 0   0 0 0 0 0  0 0 0 0.15 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
+            <feMerge>
+                <feMergeNode in="shadowMatrixOuter1"></feMergeNode>
+                <feMergeNode in="SourceGraphic"></feMergeNode>
+            </feMerge>
+        </filter>
+        <rect id="path-2" x="0" y="0" width="48" height="40" rx="4"></rect>
+        <filter x="-4.2%" y="-2.5%" width="108.3%" height="110.0%" filterUnits="objectBoundingBox" id="filter-4">
+            <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feGaussianBlur stdDeviation="0.5" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
+            <feColorMatrix values="0 0 0 0 0   0 0 0 0 0   0 0 0 0 0  0 0 0 0.1 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
+        </filter>
+    </defs>
+    <g id="配置面板" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="setting-copy-2" transform="translate(-1254.000000, -136.000000)">
+            <g id="Group-8" transform="translate(1167.000000, 0.000000)">
+                <g id="Group-5" filter="url(#filter-1)" transform="translate(89.000000, 137.000000)">
+                    <mask id="mask-3" fill="white">
+                        <use xlink:href="#path-2"></use>
+                    </mask>
+                    <g id="Rectangle-18">
+                        <use fill="black" fill-opacity="1" filter="url(#filter-4)" xlink:href="#path-2"></use>
+                        <use fill="#F0F2F5" fill-rule="evenodd" xlink:href="#path-2"></use>
+                    </g>
+                    <rect id="Rectangle-18" fill="#FFFFFF" mask="url(#mask-3)" x="0" y="0" width="16" height="40"></rect>
+                    <rect id="Rectangle-11" fill="#FFFFFF" mask="url(#mask-3)" x="0" y="0" width="48" height="10"></rect>
+                </g>
+            </g>
+        </g>
+    </g>
+</svg>

+ 2 - 5
src/components/ThemePicker/index.vue

@@ -9,7 +9,7 @@
 
 <script>
 const version = require('element-ui/package.json').version // element-ui version from node_modules
-const ORIGINAL_THEME = '#409EFF' // default color
+const ORIGINAL_THEME = '#1890FF' // default color
 
 export default {
   data() {
@@ -35,10 +35,9 @@ export default {
       if (typeof val !== 'string') return
       const themeCluster = this.getThemeCluster(val.replace('#', ''))
       const originalCluster = this.getThemeCluster(oldVal.replace('#', ''))
-      console.log(themeCluster, originalCluster)
 
       const $message = this.$message({
-        message: '  Compiling the theme',
+        message: '编译主题中',
         customClass: 'theme-message',
         type: 'success',
         duration: 0,
@@ -79,9 +78,7 @@ export default {
         if (typeof innerText !== 'string') return
         style.innerText = this.updateStyle(innerText, originalCluster, themeCluster)
       })
-
       this.$emit('change', val)
-
       $message.close()
     }
   },

+ 98 - 17
src/layout/components/Settings/index.vue

@@ -1,28 +1,61 @@
 <template>
   <div class="drawer-container">
     <div>
-      <h3 class="drawer-title">页面设置</h3>
-
-      <div class="drawer-item">
-        <span>主题颜色</span>
-        <theme-picker style="float: right;height: 26px;margin: -3px 8px 0 0;" @change="themeChange" />
+      <div class="setting-drawer-content">
+        <div class="setting-drawer-title">
+          页面设置
+        </div>
+        <div class="setting-drawer-block-checbox">
+          <div class="setting-drawer-block-checbox-item" @click="handleTheme('light')">
+            <img src="@/assets/light.svg" alt="light">
+            <div v-if="themeStyle === 'light'" class="setting-drawer-block-checbox-selectIcon" style="display: block;">
+              <i aria-label="图标: check" class="anticon anticon-check">
+                <svg viewBox="64 64 896 896" data-icon="check" width="1em" height="1em" :fill="theme" aria-hidden="true" focusable="false" class=""><path d="M912 190h-69.9c-9.8 0-19.1 4.5-25.1 12.2L404.7 724.5 207 474a32 32 0 0 0-25.1-12.2H112c-6.7 0-10.4 7.7-6.3 12.9l273.9 347c12.8 16.2 37.4 16.2 50.3 0l488.4-618.9c4.1-5.1.4-12.8-6.3-12.8z" />
+                </svg>
+              </i>
+            </div>
+          </div>
+          <div class="setting-drawer-block-checbox-item" @click="handleTheme('dark')">
+            <img src="@/assets/dark.svg" alt="dark">
+            <div v-if="themeStyle === 'dark'" class="setting-drawer-block-checbox-selectIcon" style="display: block;">
+              <i aria-label="图标: check" class="anticon anticon-check">
+                <svg viewBox="64 64 896 896" data-icon="check" width="1em" height="1em" :fill="theme" aria-hidden="true" focusable="false" class=""><path d="M912 190h-69.9c-9.8 0-19.1 4.5-25.1 12.2L404.7 724.5 207 474a32 32 0 0 0-25.1-12.2H112c-6.7 0-10.4 7.7-6.3 12.9l273.9 347c12.8 16.2 37.4 16.2 50.3 0l488.4-618.9c4.1-5.1.4-12.8-6.3-12.8z" />
+                </svg>
+              </i>
+            </div>
+          </div>
+        </div>
       </div>
-
-      <div class="drawer-item">
-        <span>开启任务栏</span>
-        <el-switch v-model="tagsView" class="drawer-switch" />
+      <el-divider />
+      <div class="setting-drawer-content">
+        <div class="setting-drawer-title">
+          主题设置
+        </div>
+        <div class="drawer-item">
+          <span>主题颜色</span>
+          <theme-picker style="float: right;height: 26px;margin: -3px 8px 0 0;" @change="themeChange" />
+        </div>
       </div>
+      <el-divider />
+      <div class="setting-drawer-content">
+        <div class="setting-drawer-title">
+          布局设置
+        </div>
+        <div class="drawer-item">
+          <span>开启任务栏</span>
+          <el-switch v-model="tagsView" class="drawer-switch" />
+        </div>
 
-      <div class="drawer-item">
-        <span>Header 固定</span>
-        <el-switch v-model="fixedHeader" class="drawer-switch" />
-      </div>
+        <div class="drawer-item">
+          <span>Header 固定</span>
+          <el-switch v-model="fixedHeader" class="drawer-switch" />
+        </div>
 
-      <div class="drawer-item">
-        <span>侧边栏Logo</span>
-        <el-switch v-model="sidebarLogo" class="drawer-switch" />
+        <div class="drawer-item">
+          <span>侧边栏Logo</span>
+          <el-switch v-model="sidebarLogo" class="drawer-switch" />
+        </div>
       </div>
-
     </div>
   </div>
 </template>
@@ -36,6 +69,12 @@ export default {
     return {}
   },
   computed: {
+    theme() {
+      return this.$store.state.settings.theme
+    },
+    themeStyle() {
+      return this.$store.state.settings.themeStyle
+    },
     fixedHeader: {
       get() {
         return this.$store.state.settings.fixedHeader
@@ -76,6 +115,12 @@ export default {
         key: 'theme',
         value: val
       })
+    },
+    handleTheme(val) {
+      this.$store.dispatch('settings/changeSetting', {
+        key: 'themeStyle',
+        value: val
+      })
     }
   }
 }
@@ -105,4 +150,40 @@ export default {
     float: right
   }
 }
+.setting-drawer-content{
+  .setting-drawer-title{
+    margin-bottom: 12px;
+    color: rgba(0,0,0,.85);
+    font-size: 14px;
+    line-height: 22px;
+    font-weight: bold;
+  }
+  .setting-drawer-block-checbox{
+    display: flex;
+    justify-content: flex-start;
+    align-items: center;
+    .setting-drawer-block-checbox-item {
+        position: relative;
+        margin-right: 16px;
+        border-radius: 2px;
+        cursor: pointer;
+        img{
+          width: 48px;
+          height: 48px;
+        }
+        .setting-drawer-block-checbox-selectIcon{
+            position: absolute;
+            top: 0;
+            right: 0;
+            width: 100%;
+            height: 100%;
+            padding-top: 15px;
+            padding-left: 24px;
+            color: #1890ff;
+            font-weight: 700;
+            font-size: 14px;
+        }
+    }
+  }
+}
 </style>

+ 8 - 4
src/layout/components/Sidebar/Logo.vue

@@ -1,13 +1,13 @@
 <template>
-  <div class="sidebar-logo-container" :class="{'collapse':collapse}">
+  <div class="sidebar-logo-container" :class="{'collapse':collapse}" :style="{ backgroundColor: $store.state.settings.themeStyle === 'dark' ? variables.menuBg : variables.menuLightBg }">
     <transition name="sidebarLogoFade">
       <router-link v-if="collapse" key="collapse" class="sidebar-logo-link" to="/">
         <img v-if="appInfo.logo" :src="appInfo.logo" class="sidebar-logo">
-        <h1 v-else class="sidebar-title">{{ appInfo.name }} </h1>
+        <h1 v-else class="sidebar-title" :style="{ color: $store.state.settings.themeStyle === 'dark' ? variables.sidebarTitle : variables.sidebarLightTitle }">{{ appInfo.name }} </h1>
       </router-link>
       <router-link v-else key="expand" class="sidebar-logo-link" to="/">
         <img v-if="appInfo.logo" :src="appInfo.logo" class="sidebar-logo">
-        <h1 class="sidebar-title">{{ appInfo.name }} </h1>
+        <h1 class="sidebar-title" :style="{ color: $store.state.settings.themeStyle === 'dark' ? variables.sidebarTitle : variables.sidebarLightTitle }">{{ appInfo.name }} </h1>
       </router-link>
     </transition>
   </div>
@@ -15,6 +15,7 @@
 
 <script>
 
+import variables from '@/styles/variables.scss'
 import { mapGetters } from 'vuex'
 
 export default {
@@ -28,7 +29,10 @@ export default {
   computed: {
     ...mapGetters([
       'appInfo'
-    ])
+    ]),
+    variables() {
+      return variables
+    }
   }
 }
 </script>

+ 1 - 1
src/layout/components/Sidebar/SidebarItem.vue

@@ -8,7 +8,7 @@
       </app-link>
     </template>
 
-    <el-submenu v-else ref="subMenu" :index="resolvePath(item.path)" popper-append-to-body>
+    <el-submenu v-else ref="subMenu" :index="resolvePath(item.path)" popper-append-to-body :style="{ backgroundColor: '#000c17' }">
       <template slot="title">
         <item v-if="item.meta" :icon="item.meta && item.meta.icon" :title="item.meta.title" />
       </template>

+ 3 - 2
src/layout/components/Sidebar/index.vue

@@ -5,8 +5,9 @@
       <el-menu
         :default-active="activeMenu"
         :collapse="isCollapse"
-        :background-color="variables.menuBg"
-        :text-color="variables.menuText"
+        :background-color=" $store.state.settings.themeStyle === 'light' ? variables.menuLightBg : variables.menuBg"
+        :text-color="$store.state.settings.themeStyle === 'light' ? 'rgba(0,0,0,.65)' : '#fff'"
+        :active-text-color="$store.state.settings.theme"
         :unique-opened="true"
         :collapse-transition="true"
         mode="vertical"

+ 6 - 2
src/layout/index.vue

@@ -1,7 +1,7 @@
 <template>
-  <div :class="classObj" class="app-wrapper">
+  <div :class="classObj" class="app-wrapper" :style="{'--current-color': $store.state.settings.theme}">
     <div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside" />
-    <sidebar class="sidebar-container" />
+    <sidebar class="sidebar-container" :style="{ backgroundColor: $store.state.settings.themeStyle === 'dark' ? variables.menuBg : variables.menuLightBg }" />
     <div :class="{hasTagsView:needTagsView}" class="main-container">
       <div :class="{'fixed-header':fixedHeader}">
         <navbar />
@@ -20,6 +20,7 @@ import RightPanel from '@/components/RightPanel'
 import { AppMain, Navbar, Settings, Sidebar, TagsView } from './components'
 import ResizeMixin from './mixin/ResizeHandler'
 import { mapState } from 'vuex'
+import variables from '@/styles/variables.scss'
 
 export default {
   name: 'Layout',
@@ -47,6 +48,9 @@ export default {
         withoutAnimation: this.sidebar.withoutAnimation,
         mobile: this.device === 'mobile'
       }
+    },
+    variables() {
+      return variables
     }
   },
   methods: {

+ 3 - 1
src/settings.js

@@ -31,5 +31,7 @@ module.exports = {
    * The default is only used in the production env
    * If you want to also use it in dev, you can pass ['production', 'development']
    */
-  errorLog: 'production'
+  errorLog: 'production',
+
+  themeStyle: 'dark'
 }

+ 4 - 2
src/store/modules/settings.js

@@ -1,14 +1,15 @@
 import variables from '@/styles/element-variables.scss'
 import defaultSettings from '@/settings'
 
-const { showSettings, tagsView, fixedHeader, sidebarLogo } = defaultSettings
+const { showSettings, tagsView, fixedHeader, sidebarLogo, themeStyle } = defaultSettings
 
 const state = {
   theme: variables.theme,
   showSettings: showSettings,
   tagsView: tagsView,
   fixedHeader: fixedHeader,
-  sidebarLogo: sidebarLogo
+  sidebarLogo: sidebarLogo,
+  themeStyle: themeStyle
 }
 
 const mutations = {
@@ -22,6 +23,7 @@ const mutations = {
 
 const actions = {
   changeSetting({ commit }, data) {
+    console.log(data)
     commit('CHANGE_SETTING', data)
   }
 }

+ 21 - 13
src/styles/sidebar.scss

@@ -68,25 +68,41 @@
     .submenu-title-noDropdown,
     .el-submenu__title {
       &:hover {
-        background-color: $menuHover !important;
+        background-color: rgba(0,0,0,0.06)!important;
+        // background-color: transparent!important;
       }
     }
 
     .is-active>.el-submenu__title {
-      color: $subMenuActiveText !important;
+      // color: $subMenuActiveText !important;
     }
 
     & .nest-menu .el-submenu>.el-submenu__title,
     & .el-submenu .el-menu-item {
       min-width: $sideBarWidth !important;
-      background-color: $subMenuBg !important;
+      // background-color: $subMenuBg !important;
+      position: relative;
 
-      &:hover {
-        background-color: $subMenuHover !important;
+     &:hover {
+        background-color: rgba(0,0,0,0.06)!important;
+        // &::before{
+        //   content: "";
+        //   position: absolute;
+        //   top: 0;
+        //   bottom: 0;
+        //   width: 2px;
+        //   background-color: $menuActiveText;
+        //   height: 100%;
+        //   right: 0;
+        // }
       }
     }
   }
 
+  .el-submenu{
+    background-color: transparent!important;
+  }
+
   .hideSidebar {
     .sidebar-container {
       width: 54px !important;
@@ -181,14 +197,6 @@
     }
   }
 
-  .nest-menu .el-submenu>.el-submenu__title,
-  .el-menu-item {
-    &:hover {
-      // you can use $subMenuHover
-      background-color: $menuHover !important;
-    }
-  }
-
   // the scroll bar appears when the subMenu is too long
   >.el-menu--popup {
     max-height: 100vh;

+ 8 - 5
src/styles/variables.css

@@ -1,10 +1,13 @@
 :export {
-  menuText: #bfcbd9;
   menuActiveText: #409EFF;
   subMenuActiveText: #f4f4f5;
-  menuBg: #304156;
-  menuHover: #263445;
-  subMenuBg: #1f2d3d;
+  menuBg: #001529;
+  menuHover: #000c17;
+  menuLightBg: #ffffff;
+  menuLightHover: #f0f1f5;
+  subMenuBg: #000c17;
   subMenuHover: #001528;
-  sideBarWidth: 253px;
+  sideBarWidth: 256px;
+  sidebarTitle: #ffffff;
+  sidebarLightTitle: #001529;
 }

+ 1 - 1
src/styles/variables.min.css

@@ -1 +1 @@
-:export{menuText:#bfcbd9;menuActiveText:#409EFF;subMenuActiveText:#f4f4f5;menuBg:#304156;menuHover:#263445;subMenuBg:#1f2d3d;subMenuHover:#001528;sideBarWidth:253px}
+:export{menuActiveText:#409EFF;subMenuActiveText:#f4f4f5;menuBg:#001529;menuHover:#000c17;menuLightBg:#fff;menuLightHover:#f0f1f5;subMenuBg:#000c17;subMenuHover:#001528;sideBarWidth:256px;sidebarTitle:#fff;sidebarLightTitle:#001529}

+ 10 - 2
src/styles/variables.scss

@@ -9,13 +9,17 @@ $yellow:#FEC171;
 $panGreen: #30B08F;
 
 // sidebar
-$menuText:#bfcbd9;
+// $menuText:#bfcbd9;
 $menuActiveText:#409EFF;
 $subMenuActiveText:#f4f4f5; // https://github.com/ElemeFE/element/issues/12951
 
 $menuBg:#001529;
 $menuHover:#000c17;
+$sidebarTitle: #ffffff;
 
+$menuLightBg:#ffffff;
+$menuLightHover:#f0f1f5;
+$sidebarLightTitle: #001529;
 
 $subMenuBg:#000c17;
 $subMenuHover:#001528;
@@ -25,12 +29,16 @@ $sideBarWidth: 256px;
 // the :export directive is the magic sauce for webpack
 // https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
 :export {
-  menuText: $menuText;
+  // menuText: $menuText;
   menuActiveText: $menuActiveText;
   subMenuActiveText: $subMenuActiveText;
   menuBg: $menuBg;
   menuHover: $menuHover;
+  menuLightBg: $menuLightBg;
+  menuLightHover: $menuLightHover;
   subMenuBg: $subMenuBg;
   subMenuHover: $subMenuHover;
   sideBarWidth: $sideBarWidth;
+  sidebarTitle: $sidebarTitle;
+  sidebarLightTitle: $sidebarLightTitle
 }

+ 15 - 0
vue.config.js

@@ -125,5 +125,20 @@ module.exports = {
           config.optimization.runtimeChunk('single')
         }
       )
+  },
+  css: {
+    loaderOptions: {
+      less: {
+        modifyVars: {
+          // less vars,customize ant design theme
+
+          // 'primary-color': '#F5222D',
+          // 'link-color': '#F5222D',
+          'border-radius-base': '2px'
+        },
+        // DO NOT REMOVE THIS LINE
+        javascriptEnabled: true
+      }
+    }
   }
 }