feat: service layout done

This commit is contained in:
hrsonion 2019-06-06 16:44:10 +08:00
parent 732d880c02
commit 1d36ad7a44
20 changed files with 473 additions and 75 deletions

View File

@ -78,10 +78,6 @@ export default {
</script>
<style scoped>
.body {
min-width: 1280px;
background: #1a2033;
}
.nav-container {
position: absolute;
top: 0;

View File

@ -1,7 +1,46 @@
<template>
<div>
<div class="service-container">
<nv-service-layout />
<nv-service-layout>
<nv-with-padding
:padding-left="48"
:padding-right="48"
>
<nv-table>
<template v-slot:header>
<nv-tr>
<nv-th>ID</nv-th>
<nv-th>Cluster</nv-th>
<nv-th>Cluster Type</nv-th>
<nv-th>Tags</nv-th>
<nv-th>Network Type</nv-th>
<nv-th>Cluster Status</nv-th>
<nv-th>Nodes</nv-th>
<nv-th>Location</nv-th>
<nv-th>Version</nv-th>
<nv-th>Actions</nv-th>
</nv-tr>
</template>
<template v-slot:body>
<nv-tr
v-for="i in [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]"
:key="i"
>
<nv-td>1</nv-td>
<nv-td>Name1</nv-td>
<nv-td>Type1</nv-td>
<nv-td>bla</nv-td>
<nv-td>blablabla</nv-td>
<nv-td>Running</nv-td>
<nv-td>6</nv-td>
<nv-td>Beijing</nv-td>
<nv-td>1.12.6-aliyun.1</nv-td>
<nv-td>Manage | View Logs | Dashboard | Scale Out | More</nv-td>
</nv-tr>
</template>
</nv-table>
</nv-with-padding>
</nv-service-layout>
</div>
<div class="nav-container">
<nv-navbar />
@ -17,11 +56,12 @@ export default {
<style>
.nav-container {
position: fixed;
position: absolute;
top: 0;
left: 0;
right: 0;
width: 100%;
height: 50px;
min-width: 1280px;
background-color: #1f263e;
}
.service-container {
@ -30,6 +70,9 @@ export default {
left: 0;
right: 0;
bottom: 0;
width: 100%;
min-width: 1280px;
background-color: #171D33;
overflow: scroll;
}
</style>

View File

@ -8,7 +8,9 @@ import Loader from 'packages/common/Loader'
import GradientHeader from 'packages/common/GradientHeader'
import ColumnGroup from 'packages/common/ColumnGroup'
import WithPadding from 'packages/common/WithPadding'
import WithMargin from 'packages/common/WithMargin'
import MasonryGroup from 'packages/common/MasonryGroup'
import Table from 'packages/common/Table'
import ServiceCard from 'packages/nimbus/ServiceCard'
import HomeLayout from 'packages/nimbus/HomeLayout'
@ -31,6 +33,8 @@ ColumnGroup.install(Vue)
WithPadding.install(Vue)
ServiceCard.install(Vue)
MasonryGroup.install(Vue)
Table.install(Vue)
WithMargin.install(Vue)
const routes = [
{ path: '/sidemenu', component: sideMenuDemo },

View File

@ -3,6 +3,7 @@
<head>
<meta charset="utf-8">
<title>2s design</title>
<style></style>
</head>
<body>
<div id="app">

View File

@ -0,0 +1,7 @@
import NvTh from './src/main.vue'
NvTh.install = function (Vue) {
Vue.component(NvTh.name, NvTh)
}
export default NvTh

View File

@ -0,0 +1,19 @@
<template>
<td>
<slot>
default th content
</slot>
</td>
</template>
<script>
export default {
name: 'NvTd',
props: {
}
}
</script>
<style lang="scss" scoped>
</style>

View File

@ -0,0 +1,7 @@
import NvTh from './src/main.vue'
NvTh.install = function (Vue) {
Vue.component(NvTh.name, NvTh)
}
export default NvTh

View File

@ -0,0 +1,17 @@
<template>
<th>
<slot>
default th content
</slot>
</th>
</template>
<script>
export default {
name: 'NvTh'
}
</script>
<style lang="scss" scoped>
</style>

View File

@ -0,0 +1,7 @@
import NvTr from './src/main.vue'
NvTr.install = function (Vue) {
Vue.component(NvTr.name, NvTr)
}
export default NvTr

View File

@ -0,0 +1,15 @@
<template>
<tr>
<slot />
</tr>
</template>
<script>
export default {
name: 'NvTr'
}
</script>
<style lang="scss" scoped>
</style>

View File

@ -0,0 +1,13 @@
import NvTable from './src/main.vue'
import NvTh from './Th/src/main.vue'
import NvTr from './Tr/src/main.vue'
import NvTd from './Td/src/main.vue'
NvTable.install = function (Vue) {
Vue.component(NvTable.name, NvTable)
Vue.component(NvTh.name, NvTh)
Vue.component(NvTr.name, NvTr)
Vue.component(NvTd.name, NvTd)
}
export default NvTable

View File

@ -0,0 +1,26 @@
<template>
<div class="nv-table">
<table>
<thead>
<slot name="header">
<tr><th>header</th></tr>
</slot>
</thead>
<tbody>
<slot name="body">
<tr><td>body</td></tr>
</slot>
</tbody>
</table>
</div>
</template>
<script>
export default {
name: 'NvTable'
}
</script>
<style lang="scss" scoped>
</style>

View File

@ -0,0 +1,7 @@
import WithMargin from './src/main.vue'
WithMargin.install = function (Vue) {
Vue.component(WithMargin.name, WithMargin)
}
export default WithMargin

View File

@ -0,0 +1,42 @@
<template>
<div
class="nv-with-margin"
:style="style"
>
<slot />
</div>
</template>
<script>
export default {
name: 'NvWithMargin',
props: {
marginTop: {
type: Number,
default: 0
},
marginRight: {
type: Number,
default: 0
},
marginBottom: {
type: Number,
default: 0
},
marginLeft: {
type: Number,
default: 0
}
},
computed: {
style () {
const marginStyle = {}
if (this.marginTop) marginStyle.marginTop = this.marginTop + 'px'
if (this.marginRight) marginStyle.marginRight = this.marginRight + 'px'
if (this.marginBottom) marginStyle.marginBottom = this.marginBottom + 'px'
if (this.marginLeft) marginStyle.marginLeft = this.marginLeft + 'px'
return marginStyle
}
}
}
</script>

View File

@ -2,38 +2,74 @@
<div class="layout">
<div
class="body"
:class="{ collapse: collapse, active: !collapse }"
:class="{ 'is-collapsed': isCollapsed, active: !isCollapsed }"
>
<div class="header">
<span class="content">
Service Management
</span>
</div>
<nv-loader />
<slot />
</div>
<div
class="menu"
:class="{ collapse: collapse, active: !collapse }"
:class="{ 'is-collapsed': isCollapsed, active: !isCollapsed }"
>
<div class="header">
<div class="content">
<div class="icon">
<nv-icon
type="md-settings"
:size="22"
/>
<div class="item-wrapper">
<div class="header">
<div class="content">
<div class="icon">
<nv-icon
type="md-settings"
:size="22"
/>
</div>
Administration
</div>
</div>
<div
v-for="item in items"
:key="item.name"
>
<div
v-if="!item.childItems"
class="item"
:class="{ active: activeItemName === item.name }"
@click="makeActive(item.name)"
>
<span>{{ item.name }}</span>
</div>
<div
v-else
>
<div
class="item is-group-header"
:class="{
'group-item-is-choosed': !!(1 + item.childItems.findIndex(item => item.name === activeItemName)),
'is-collapsed': item.isCollapsed
}"
@click="toggleGroupHeaderCollapse(item.name)"
>
<span>{{ item.name }}</span>
</div>
<div
class="group-items"
:class="{
'is-collapsed': item.isCollapsed
}"
>
<div
v-for="childItem in item.childItems"
:key="childItem.name"
class="item is-group-item"
:class="{ active: activeItemName === childItem.name }"
@click="makeActive(childItem.name)"
>
<span>{{ childItem.name }}</span>
</div>
</div>
</div>
Administration
</div>
</div>
<div
v-for="item in items"
:key="item.name"
class="item"
:class="{ active: activeItemName === item.name }"
@click="setActive(item.name)"
>
<span>{{ item.name }}</span>
</div>
<div
class="toggle-button"
@ -51,14 +87,32 @@ export default {
props: {},
data () {
return {
collapse: false,
isCollapsed: false,
activeItemName: 'Service Management',
items: [
{
name: 'Service Management'
},
{
name: 'Service Type Management'
name: 'Service Type Management',
isCollapsed: false,
childItems: [
{
name: 'Clusters'
},
{
name: 'Notes'
},
{
name: 'Volume'
},
{
name: 'Namespaces'
},
{
name: 'Authorization'
}
]
},
{
name: 'User Management'
@ -68,10 +122,16 @@ export default {
},
methods: {
toggle () {
this.collapse = !this.collapse
this.isCollapsed = !this.isCollapsed
},
setActive (itemName) {
makeActive (itemName) {
this.activeItemName = itemName
},
toggleGroupHeaderCollapse (headerName) {
const headerIndex = this.items.findIndex(item => item.name === headerName && item.childItems)
if (headerIndex + 1) {
this.items[headerIndex].isCollapsed = !this.items[headerIndex].isCollapsed
}
}
}
}
@ -95,11 +155,12 @@ export default {
top: 0;
bottom: 0;
transition: left .3s cubic-bezier(0.4, 0.0, 0.2, 1);
overflow: scroll;
}
&.active {
left: 272px;
}
&.collapse {
&.is-collapsed {
left: 48px;
}
.header {
@ -140,24 +201,31 @@ export default {
transform: translateX(50%) translateY(-50%) rotate(0deg);
}
}
&.collapse {
&.is-collapsed {
transform: translateX(-224px);
transition: transform .3s cubic-bezier(0.4, 0.0, 0.2, 1);
.toggle-button {
transition: transform .3s cubic-bezier(0.4, 0.0, 0.2, 1);
transform: translateX(50%) translateY(-50%) rotate(180deg);
}
.item.active {
span {
opacity: .4;
.item-wrapper {
.item.active {
span {
opacity: .4;
}
&::before {
content: "";
opacity: 0;
}
&:hover::before {
content: "";
opacity: 0;
}
}
&::before {
content: "";
opacity: 0;
}
&:hover::before {
content: "";
opacity: 0;
.item.is-group-header {
&::after {
opacity: 0;
}
}
}
}
@ -187,39 +255,104 @@ export default {
top: 50%;
right: 0;
}
.item {
cursor: pointer;
position: relative;
padding-top: 16px;
padding-bottom: 16px;
padding-left: 48px;
font-size: 14px;
color: #fff;
span {
transition: opacity 0.3s cubic-bezier(0.4, 0.0, 0.2, 1);
opacity: .4;
.item-wrapper {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
overflow: scroll;
.item {
cursor: pointer;
position: relative;
padding-top: 16px;
padding-bottom: 16px;
padding-left: 48px;
font-size: 14px;
color: #fff;
span {
transition: opacity 0.3s cubic-bezier(0.4, 0.0, 0.2, 1);
opacity: .4;
}
&.active span{
opacity: .9;
}
&:hover span {
opacity: .9;
}
&::before {
content: "";
background-image:linear-gradient(47deg,rgba(232,232,235,.4) 0%,rgba(31,38,62,.4) 100%);
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: -1;
transition: opacity 0.3s cubic-bezier(0.4, 0.0, 0.2, 1);
opacity: 0;
}
&.active::before {
opacity: .9;
}
&.is-group-header {
&::after {
content: '';
height: 6px;
width: 6px;
border-left: 2px solid #63E2B7;
border-top: 2px solid #63E2B7;
position: absolute;
right: 24px;
top: 50%;
transform: rotate(45deg) translateY(-3px);
transform-origin: 25% 25%;
opacity: 1;
transition: transform 0.3s cubic-bezier(0.4, 0.0, 0.2, 1), opacity 0.3s cubic-bezier(0.4, 0.0, 0.2, 1);
}
&.is-collapsed::after {
transform: rotate(225deg) translateY(0px);
opacity: 1;
}
&:hover span {
transition: opacity 0.3s cubic-bezier(0.4, 0.0, 0.2, 1), color 0.3s cubic-bezier(0.4, 0.0, 0.2, 1);
background-clip: text;
-webkit-background-clip: text;
transform-origin: 50% 50%;
color: transparent;
opacity: 1;
}
span {
transition: opacity 0.3s cubic-bezier(0.4, 0.0, 0.2, 1), color 0.3s cubic-bezier(.6, 0.2, 0.4, 1);
background: linear-gradient(14deg, rgba(120,205,104,1) 0%, rgba(20,166,165,1) 100%);
background-clip: text;
-webkit-background-clip: text;
color: #fff;
opacity: 0.4;
}
}
&.is-group-item {
padding-left: 64px;
}
&.is-group-header.group-item-is-choosed {
span {
transition: opacity 0.3s cubic-bezier(0.4, 0.0, 0.2, 1), color 0.3s cubic-bezier(0.4, 0.0, 0.2, 1);
background-clip: text;
-webkit-background-clip: text;
color: transparent;
opacity: 1;
}
}
}
&.active span{
opacity: .9;
}
&:hover span {
opacity: .9;
}
&::before {
content: "";
background-image:linear-gradient(47deg,rgba(232,232,235,.4) 0%,rgba(31,38,62,.4) 100%);
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: -1;
transition: opacity 0.3s cubic-bezier(0.4, 0.0, 0.2, 1);
opacity: 0;
}
&.active::before {
opacity: .9;
.group-items {
overflow: hidden;
max-height: 600px;
transition: max-height .45s cubic-bezier(0.4, 0.0, 0.2, 1);
&.is-collapsed {
max-height: 0;
}
}
}
}
</style>

51
styles/Table.scss Normal file
View File

@ -0,0 +1,51 @@
@import './mixins/mixins.scss';
@include b(table) {
width: 100%;
border-radius: 12px;
font-size: 12px;
overflow: hidden;
box-shadow: 0 3px 20px 6px rgba(0, 0, 0, .2);
padding-bottom: 8px;
background-color: #1f263e;
table {
border-collapse: collapse;
width: 100%;
thead {
background-color: rgb(43,49,71);
color: #fff;
tr {
th {
padding: 16px 6px 16px 6px;
text-align: left;
border: none;
}
th:nth-child(1) {
padding-left: 32px;
border-radius: 12px 0 0 0;
}
th:nth-last-child(1) {
padding-left: 32px;
border-radius: 0 12px 0 0;
}
}
}
tbody {
background-color: #1f263e;
color: #fff;
tr {
td {
padding: 16px 6px 12px 6px;
text-align: left;
border: none;
}
td:nth-child(1) {
padding-left: 32px;
}
td:nth-last-child(1) {
padding-left: 32px;
}
}
}
}
}

5
styles/WithMargin.scss Normal file
View File

@ -0,0 +1,5 @@
@import './mixins/mixins.scss';
@include b(with-padding) {
width: 100%;
}

View File

@ -1,5 +1,6 @@
@import './mixins/mixins.scss';
@include b(with-padding) {
box-sizing: border-box;
width: 100%;
}

View File

@ -3,4 +3,6 @@
body {
margin: 0;
font-family: 'Open Sans';
min-width: 1280px;
background: #1a2033;
}

View File

@ -5,4 +5,6 @@
@import './GradientHeader.scss';
@import './ColumnGroup.scss';
@import './WithPadding.scss';
@import './ServiceCard.scss';
@import './ServiceCard.scss';
@import './Table.scss';
@import './WithMargin.scss';