dashboard: fix styling and enhancements (#8)

Refactoring, visual enhancements and extend readme.

Signed-off-by: Rohit Yadav <rohit.yadav@shapeblue.com>
This commit is contained in:
M. Weber 2019-08-08 17:28:03 +02:00 committed by Rohit Yadav
parent f8f0a99e26
commit 33df072505
26 changed files with 286 additions and 141 deletions

View File

@ -12,6 +12,8 @@ Install tools and dependencies:
Build and run:
npm start
or
npm run serve
Production Build:

View File

@ -152,3 +152,30 @@ export default {
}
}
</script>
<style lang="less">
// Todo try to get this rules scoped
.ant-drawer.drawer-sider {
.sider {
box-shadow: none;
}
&.dark {
.ant-drawer-content {
background-color: rgb(0, 21, 41);
}
}
&.light {
box-shadow: none;
.ant-drawer-content {
background-color: #fff;
}
}
.ant-drawer-body {
padding: 0
}
}
</style>

View File

@ -48,9 +48,10 @@ export default {
</script>
<style lang="less" scoped>
.header-notice{
.header-notice {
display: inline-block;
transition: all 0.3s;
span {
vertical-align: initial;
}

View File

@ -42,6 +42,10 @@ export default {
}
</script>
<style scoped>
<style lang="less" scoped>
.breadcrumb {
.mobile & {
display: none;
}
}
</style>

View File

@ -5,7 +5,7 @@
placement="bottomRight"
:autoAdjustOverflow="true"
:arrowPointAtCenter="true"
overlayClassName="header-notice-wrapper"
overlayClassName="ant-pro-header-notice__popover"
:overlayStyle="{ width: '300px', top: '50px' }">
<template slot="content">
<a-spin :spinning="loadding">
@ -38,9 +38,9 @@
</a-tabs>
</a-spin>
</template>
<span @click="fetchNotice" class="header-notice">
<span @click="fetchNotice" class="ant-pro-header-notice__opener">
<a-badge count="12">
<a-icon style="font-size: 16px; padding: 4px" type="bell" />
<a-icon class="ant-pro-header-notice__icon" type="bell" />
</a-badge>
</span>
</a-popover>
@ -71,13 +71,8 @@ export default {
}
</script>
<style lang="css">
.header-notice-wrapper {
top: 50px !important;
}
</style>
<style lang="less" scoped>
.header-notice{
.header-notice {
display: inline-block;
transition: all 0.3s;
@ -85,4 +80,25 @@ export default {
vertical-align: initial;
}
}
.ant-pro-header-notice {
&__popover {
top: 50px !important;
}
&__opener {
display: inline-block;
transition: all 0.3s;
span {
vertical-align: initial;
}
}
&__icon {
font-size: 18px;
padding: 4px;
}
}
</style>

View File

@ -1,7 +1,7 @@
<template>
<a-dropdown>
<span class="action ant-dropdown-link">
<span class="action ant-dropdown-link ant-pro-translation-menu">
<a-icon type="global"></a-icon>
</span>
<a-menu slot="overlay" @click="onClick">

View File

@ -76,3 +76,27 @@ export default {
}
}
</script>
<style lang="less" scoped>
.user-dropdown-menu {
span {
user-select: none;
}
}
.user-dropdown-menu-wrapper.ant-dropdown-menu {
padding: 4px 0;
.ant-dropdown-menu-item {
width: 160px;
}
.ant-dropdown-menu-item > .anticon:first-child,
.ant-dropdown-menu-item > a > .anticon:first-child,
.ant-dropdown-menu-submenu-title > .anticon:first-child .ant-dropdown-menu-submenu-title > a > .anticon:first-child {
min-width: 12px;
margin-right: 8px;
}
}
</style>

View File

@ -87,9 +87,10 @@ const updateTheme = primaryColor => {
}
}
const updateColorWeak = colorWeak => {
// document.body.className = colorWeak ? 'colorWeak' : '';
colorWeak ? document.body.classList.add('colorWeak') : document.body.classList.remove('colorWeak')
const updateInvertedMode = invertedMode => {
invertedMode = true;
console.log(invertedMode);
invertedMode ? document.body.classList.add('layout-inverted-mode') : document.body.classList.remove('layout-inverted-mode')
}
export { updateTheme, colorList, updateColorWeak }
export { updateTheme, colorList, updateInvertedMode }

View File

@ -6,7 +6,7 @@ export default {
fixedHeader: true, // sticky header
fixSiderbar: true, // sticky siderbar
autoHideHeader: false, // auto hide header
colorWeak: false,
invertedMode: true,
multiTab: false, // enable to have tab/route history stuff
// CloudStack options
apiBase: '/client/api',

View File

@ -6,7 +6,7 @@ import {
DEFAULT_COLOR,
DEFAULT_THEME,
DEFAULT_LAYOUT_MODE,
DEFAULT_COLOR_WEAK,
DEFAULT_COLOR_INVERTED,
SIDEBAR_TYPE,
DEFAULT_FIXED_HEADER,
DEFAULT_FIXED_HEADER_HIDDEN,
@ -24,7 +24,7 @@ export default function Initializer () {
store.commit('TOGGLE_FIXED_SIDERBAR', Vue.ls.get(DEFAULT_FIXED_SIDEMENU, config.fixSiderbar))
store.commit('TOGGLE_CONTENT_WIDTH', Vue.ls.get(DEFAULT_CONTENT_WIDTH_TYPE, config.contentWidth))
store.commit('TOGGLE_FIXED_HEADER_HIDDEN', Vue.ls.get(DEFAULT_FIXED_HEADER_HIDDEN, config.autoHideHeader))
store.commit('TOGGLE_WEAK', Vue.ls.get(DEFAULT_COLOR_WEAK, config.colorWeak))
store.commit('TOGGLE_INVERTED', Vue.ls.get(DEFAULT_COLOR_INVERTED, config.invertedMode))
store.commit('TOGGLE_COLOR', Vue.ls.get(DEFAULT_COLOR, config.primaryColor))
store.commit('TOGGLE_MULTI_TAB', Vue.ls.get(DEFAULT_MULTI_TAB, config.multiTab))
store.commit('SET_TOKEN', Vue.ls.get(ACCESS_TOKEN))

View File

@ -4,7 +4,7 @@ import {
DEFAULT_THEME,
DEFAULT_LAYOUT_MODE,
DEFAULT_COLOR,
DEFAULT_COLOR_WEAK,
DEFAULT_COLOR_INVERTED,
DEFAULT_FIXED_HEADER,
DEFAULT_FIXED_SIDEMENU,
DEFAULT_FIXED_HEADER_HIDDEN,
@ -23,7 +23,7 @@ const app = {
fixSiderbar: false,
autoHideHeader: false,
color: null,
weak: false,
inverted: true,
multiTab: true
},
mutations: {
@ -67,9 +67,9 @@ const app = {
Vue.ls.set(DEFAULT_COLOR, color)
state.color = color
},
TOGGLE_WEAK: (state, flag) => {
Vue.ls.set(DEFAULT_COLOR_WEAK, flag)
state.weak = flag
TOGGLE_INVERTED: (state, flag) => {
Vue.ls.set(DEFAULT_COLOR_INVERTED, flag)
state.inverted = flag
},
TOGGLE_MULTI_TAB: (state, bool) => {
Vue.ls.set(DEFAULT_MULTI_TAB, bool)
@ -110,8 +110,8 @@ const app = {
ToggleColor ({ commit }, color) {
commit('TOGGLE_COLOR', color)
},
ToggleWeak ({ commit }, weakFlag) {
commit('TOGGLE_WEAK', weakFlag)
ToggleInverted ({ commit }, invertedFlag) {
commit('TOGGLE_INVERTED', invertedFlag)
},
ToggleMultiTab ({ commit }, bool) {
commit('TOGGLE_MULTI_TAB', bool)

View File

@ -4,7 +4,7 @@ export const SIDEBAR_TYPE = 'SIDEBAR_TYPE'
export const DEFAULT_THEME = 'DEFAULT_THEME'
export const DEFAULT_LAYOUT_MODE = 'DEFAULT_LAYOUT_MODE'
export const DEFAULT_COLOR = 'DEFAULT_COLOR'
export const DEFAULT_COLOR_WEAK = 'DEFAULT_COLOR_WEAK'
export const DEFAULT_COLOR_INVERTED = 'DEFAULT_COLOR_INVERTED'
export const DEFAULT_FIXED_HEADER = 'DEFAULT_FIXED_HEADER'
export const DEFAULT_FIXED_SIDEMENU = 'DEFAULT_FIXED_SIDEMENU'
export const DEFAULT_FIXED_HEADER_HIDDEN = 'DEFAULT_FIXED_HEADER_HIDDEN'

View File

@ -24,13 +24,16 @@
2. common
- include all rules that reset styles, define global stuffs without classes at all
- e.g. body {} p, ul, li {} h1, h2, h3 {}
3. frame
3. ant-overwrite
- any styles that overwrites the existin ant rules by any reason
- e.g. classes like .ant-layout-header .anticon {}
4. frame
- everything that belongs to the frame
- e.g. header, footer, nav, sider, content (just the actual content frame, not every component in it)
4. layout
5. layout
- rules that modify the page at all if new layout class is set.
- e.g. #html class="layout-ant-black"#
5. objects
- repeatly used elements like buttons, inputs,
6. components
6. objects
- repeatly used elements like buttons, inputs
7. components
- complex elements like dropdown, forms, table, search (usualy include this to components/FooterToolbar/ folder)

View File

@ -0,0 +1,33 @@
.ant-layout-header {
.anticon-menu-fold {
font-size: 18px;
line-height: 1;
}
.ant-breadcrumb .anticon {
margin-top: -3px;
margin-left: 12px;
}
.anticon-home {
font-size: 18px;
}
.anticon {
vertical-align: middle;
}
}
.ant-menu {
.ant-menu-item .anticon,
.ant-menu-submenu-title .anticon {
font-size: 18px!important; // overwrite ant-menu collaped defaults
margin-right: 12px;
vertical-align: sub;
}
}
.ant-badge-count {
top: -15px;
}

View File

@ -0,0 +1,4 @@
.ant-progress-circle .ant-progress-text {
font-size: 16px;
transform: translateY(-67%); // position text centered to down cut off progress circle
}

View File

@ -1,7 +1,3 @@
body {
overflow-y: scroll;
&.colorWeak {
filter: invert(80%);
}
}

View File

@ -1,22 +0,0 @@
.ant-drawer.drawer-sider {
.sider {
box-shadow: none;
}
&.dark {
.ant-drawer-content {
background-color: rgb(0, 21, 41);
}
}
&.light {
box-shadow: none;
.ant-drawer-content {
background-color: #fff;
}
}
.ant-drawer-body {
padding: 0
}
}

View File

@ -0,0 +1,36 @@
.ant-pro-capacity-dashboard {
&__wrapper {
display: flex;
margin-bottom: 24px;
flex-wrap: nowrap;
.mobile & {
flex-wrap: wrap;
}
}
&__select {
width: 100%;
padding: 0 12px;
.mobile & {
margin-bottom: 12px;
}
}
&__button {
width: auto;
padding: 0 12px;
}
&__tile-wrapper:after {
content: "";
clear: both;
display: table;
}
&__alert-wrapper {
clear: both;
padding: 0 12px;
}
}

View File

@ -0,0 +1,4 @@
.ant-pro-translation-menu {
font-size: 18px;
line-height: 1;
}

View File

@ -1,21 +0,0 @@
.user-dropdown-menu {
span {
user-select: none;
}
}
.user-dropdown-menu-wrapper.ant-dropdown-menu {
padding: 4px 0;
.ant-dropdown-menu-item {
width: 160px;
}
.ant-dropdown-menu-item > .anticon:first-child,
.ant-dropdown-menu-item > a > .anticon:first-child,
.ant-dropdown-menu-submenu-title > .anticon:first-child .ant-dropdown-menu-submenu-title > a > .anticon:first-child {
min-width: 12px;
margin-right: 8px;
}
}

View File

@ -3,18 +3,21 @@
@import "~ant-design-vue/lib/style/core/index";
//* import all ## custom ## variables, mixins and styles
@import "variables/prefixes";
@import "common/common";
@import "component/ant-drawer";
@import "layout/ant";
@import "layout/inverted-mode";
@import "ant-overwrite/ant-layout-header";
@import "ant-overwrite/ant-progress";
@import "frame/header/translation-menu";
@import "frame/content";
@import "frame/search";
@import "frame/sider";
@import "frame/top-menu";
@import "frame/user-dropdown";
@import "layout/ant";
@import "objects/table";

View File

@ -126,8 +126,10 @@
.action {
cursor: pointer;
padding: 0 12px;
display: inline-block;
padding: 0 10px;
display: flex;
align-items: center;
float: left;
transition: all .3s;
height: 100%;
color: rgba(0, 0, 0, 0.65);
@ -311,4 +313,4 @@
padding: 0 12px 0 0;
}
}
}

View File

@ -0,0 +1,3 @@
body.layout-inverted-mode {
filter: invert(80%);
}

View File

@ -11,7 +11,7 @@ const mixin = {
layoutMode: state => state.app.layout,
navTheme: state => state.app.theme,
primaryColor: state => state.app.color,
colorWeak: state => state.app.weak,
invertedMode: state => state.app.inverted,
fixedHeader: state => state.app.fixedHeader,
fixSiderbar: state => state.app.fixSiderbar,
fixSidebar: state => state.app.fixSiderbar,

View File

@ -1,61 +1,73 @@
<template>
<div class="page-header-index-wide">
<a-row :gutter="24" :style="{ marginTop: '24px' }">
<a-col :sm="24" :md="6" :xl="18" :style="{ marginBottom: '24px' }">
<a-col :sm="24" :md="6" :xl="20" :style="{ marginBottom: '24px' }">
<a-select
showSearch
optionFilterProp="children"
:defaultValue="zoneSelected.name"
:value="zoneSelected.name"
@change="changeZone"
style="width: 100%" >
<a-select-option v-for="(zone, index) in zones" :key="index">
{{ zone.name }}
</a-select-option>
</a-select>
</a-col>
<a-col :sm="24" :md="6" :xl="4" :style="{ marginBottom: '24px' }">
<a-button
type="primary"
@click="listCapacity(zoneSelected, true)">Fetch Latest Statistics</a-button>
</a-col>
<a-col
:sm="12"
:md="12"
:xl="6"
:style="{ marginBottom: '28px' }"
v-for="stat in stats"
:key="stat.type">
<chart-card :loading="loading" style="padding-top: 40px">
<div style="text-align: center">
<h4>{{ stat.name }}</h4>
<a-progress type="dashboard" :percent="parseFloat(stat.percentused, 10)" :width="100" />
</div>
<template slot="footer"><span>{{ stat.capacityused }} / {{ stat.capacitytotal }}</span></template>
</chart-card>
</a-col>
<a-col :sm="24" :md="24" :xl="18" :style="{ marginBottom: '24px' }">
<div class="ant-pro-capacity-dashboard__wrapper">
<div class="ant-pro-capacity-dashboard__select">
<a-select
showSearch
optionFilterProp="children"
:defaultValue="zoneSelected.name"
:value="zoneSelected.name"
@change="changeZone"
style="width: 100%" >
<a-select-option v-for="(zone, index) in zones" :key="index">
{{ zone.name }}
</a-select-option>
</a-select>
</div>
<div class="ant-pro-capacity-dashboard__button">
<a-button
type="primary"
@click="listCapacity(zoneSelected, true)">Fetch Latest Statistics</a-button>
</div>
</div>
<div class="ant-pro-capacity-dashboard__tile-wrapper">
<a-col
:xs="12"
:sm="12"
:md="8"
:xl="6"
:style="{ marginBottom: '28px' }"
v-for="stat in stats"
:key="stat.type">
<chart-card :loading="loading" style="padding-top: 40px">
<div style="text-align: center">
<h4>{{ stat.name }}</h4>
<a-progress type="dashboard" :percent="Number(parseFloat(stat.percentused, 10).toFixed(2))" :width="100" />
</div>
<template slot="footer"><span>{{ stat.capacityused }} / {{ stat.capacitytotal }}</span></template>
</chart-card>
</a-col>
</div>
</a-col>
<a-col :xl="6">
<chart-card style="margin-bottom: 24px">
<div style="text-align: center">
<h4>Alerts</h4>
<p>Some event data here...</p>
</div>
</chart-card>
<chart-card style="margin-bottom: 24px">
<div style="text-align: center">
<h4>Host Alerts</h4>
<p>Some event data here...</p>
</div>
</chart-card>
<chart-card style="margin-bottom: 24px">
<div style="text-align: center">
<h4>Events</h4>
<p>Some event data here...</p>
</div>
</chart-card>
<a-row class="ant-pro-capacity-dashboard__alert-wrapper" :gutter="24">
<a-col :md="8" :xl="24">
<chart-card style="margin-bottom: 24px">
<div style="text-align: center">
<h4>Alerts</h4>
<p>Some event data here...</p>
</div>
</chart-card>
</a-col>
<a-col :md="8" :xl="24">
<chart-card style="margin-bottom: 24px">
<div style="text-align: center">
<h4>Host Alerts</h4>
<p>Some event data here...</p>
</div>
</chart-card>
</a-col>
<a-col :md="8" :xl="24">
<chart-card style="margin-bottom: 24px">
<div style="text-align: center">
<h4>Events</h4>
<p>Some event data here...</p>
</div>
</chart-card>
</a-col>
</a-row>
</a-col>
</a-row>
</div>
@ -159,4 +171,21 @@ export default {
}
}
}
.ant-pro-capacity-dashboard {
&__wrapper {
display: flex;
margin-bottom: 24px;
}
&__select {
width: 100%;
padding: 0 12px;
}
&__button {
width: auto;
padding: 0 12px;
}
}
</style>