Create tabs

This commit is contained in:
Marcos Moura 2016-09-12 02:34:07 -03:00
parent f92aaa0487
commit 36d4c26dd1
11 changed files with 465 additions and 0 deletions

View file

@ -17,6 +17,7 @@
"dependencies": {
"autosize": "^3.0.17",
"element.scrollintoviewifneeded-polyfill": "^1.0.1",
"highlightjs": "^8.7.0",
"scopedQuerySelectorShim": "github:lazd/scopedQuerySelectorShim"
},
"devDependencies": {

View file

@ -0,0 +1,10 @@
import mdTabs from './mdTabs.vue';
import mdTab from './mdTab.vue';
import mdTabsTheme from './mdTabs.theme';
export default function install(Vue) {
Vue.component('md-tabs', Vue.extend(mdTabs));
Vue.component('md-tab', Vue.extend(mdTab));
window.VueMaterial.styles.push(mdTabsTheme);
}

View file

@ -0,0 +1,29 @@
<template>
<div class="md-tab" ref="tab">
<slot></slot>
</div>
</template>
<script>
export default {
props: {
mdLabel: String,
mdIcon: String,
mdActive: Boolean
},
mounted() {
if (!this.$parent.$el.classList.contains('md-tabs')) {
this.$destroy();
throw new Error('You should wrap the md-tab in a md-tabs');
}
this.$parent.registerTab({
label: this.mdLabel,
icon: this.mdIcon,
active: this.mdActive,
ref: this.$refs.tab
});
}
};
</script>

View file

@ -0,0 +1,112 @@
@import '../../core/stylesheets/variables.scss';
$tab-width: 72px;
$tab-max-width: 264px;
.md-tabs {
width: 100%;
position: relative;
&.md-has-icon.md-has-label {
.md-tabs-navigation {
height: 72px;
.md-icon {
margin-bottom: 10px;
}
}
}
&.md-centered {
.md-tabs-navigation {
justify-content: center;
}
}
&.md-fixed {
.md-tab-header {
flex: 1;
}
}
.md-tabs-navigation {
height: 48px;
position: relative;
z-index: 1;
display: flex;
transition: $swift-ease-out;
}
.md-tab-header {
min-width: $tab-width;
max-width: $tab-max-width;
margin: 0;
padding: 0 12px;
display: inline-block;
position: relative;
display: flex;
flex-flow: column;
justify-content: center;
align-items: center;
cursor: pointer;
border: 0;
background: none;
transition: $swift-ease-out;
color: rgba(#fff, .7);
font-size: inherit;
font-family: inherit;
font-weight: 500;
text-transform: uppercase;
&.md-active,
&:hover {
color: #fff;
}
.md-icon {
margin: 0;
}
}
.md-tab-indicator {
height: 2px;
position: absolute;
bottom: 0;
left: 0;
transform: translate3D(0, 0, 0);
transition: left ($swift-ease-in-out-duration * .8) $swift-ease-out-timing-function,
right ($swift-ease-out-duration * .8) $swift-ease-out-timing-function;
}
.md-tabs-content {
width: 100%;
height: 0;
position: relative;
overflow: hidden;
transition: height ($swift-ease-in-out-duration * .8) $swift-ease-out-timing-function;
}
.md-tabs-wrapper {
width: 999em;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
transform: translate3d(0, 0, 0);
transition: left ($swift-ease-in-out-duration * .8) $swift-ease-out-timing-function;
}
.md-tab {
padding: 16px;
position: absolute;
top: 0;
left: 0;
right: 0;
pointer-events: none;
&.md-active {
pointer-events: auto;
}
}
}

View file

@ -0,0 +1,42 @@
.THEME_NAME {
.md-tabs,
&.md-tabs {
.md-tabs-navigation {
background-color: #{'PRIMARY-COLOR'};
}
.md-tab-indicator {
background-color: #{'ACCENT-COLOR'};
}
&.md-accent {
.md-tabs-navigation {
background-color: #{'ACCENT-COLOR'};
}
.md-tab-indicator {
background-color: #{'BACKGROUND-COLOR'};
}
}
&.md-warn {
.md-tabs-navigation {
background-color: #{'WARN-COLOR'};
}
.md-tab-indicator {
background-color: #{'BACKGROUND-COLOR'};
}
}
&.md-transparent {
.md-tabs-navigation {
background-color: transparent;
}
.md-tab-indicator {
background-color: #{'BACKGROUND-COLOR'};
}
}
}
}

View file

@ -0,0 +1,110 @@
<template>
<div class="md-tabs" :class="tabClasses">
<div class="md-tabs-navigation">
<button
v-for="(header, index) in tabs"
type="button"
class="md-tab-header"
:class="{ 'md-active': activeTab === index }"
@click="changeTab(index)"
v-md-ink-ripple
ref="tabHeader">
<md-icon v-if="header.icon">{{ header.icon }}</md-icon>
<span v-if="header.label">{{ header.label }}</span>
</button>
<span class="md-tab-indicator" ref="indicator"></span>
</div>
<div class="md-tabs-content" ref="tabContent">
<div class="md-tabs-wrapper" ref="tabWrapper">
<slot></slot>
</div>
</div>
</div>
</template>
<style lang="scss" src="./mdTabs.scss"></style>
<script>
import Vue from 'vue';
export default {
props: {
mdFixed: Boolean,
mdCentered: Boolean
},
data() {
return {
hasIcons: false,
hasLabel: false,
activeTab: 0,
tabs: []
};
},
computed: {
tabClasses() {
return {
'md-fixed': this.mdFixed,
'md-centered': this.mdCentered || this.mdFixed,
'md-has-icon': this.hasIcons,
'md-has-label': this.hasLabel
};
}
},
methods: {
calculateIndicatorPos() {
let indicator = this.$refs.indicator;
let tabsWidth = this.$el.offsetWidth;
Vue.nextTick(() => {
let activeTab = this.$refs.tabHeader[this.activeTab];
let left = activeTab.offsetLeft;
let right = tabsWidth - left - activeTab.offsetWidth;
indicator.style.left = left + 'px';
indicator.style.right = right + 'px';
});
},
calculateTabPos(ref, index) {
this.$refs.tabWrapper.style.left = -this.$refs.tabContent.offsetWidth * this.activeTab + 'px';
ref.style.width = this.$refs.tabContent.offsetWidth + 'px';
ref.style.left = this.$refs.tabContent.offsetWidth * index + 'px';
},
setVisibleTab(ref) {
Vue.nextTick(() => {
this.$refs.tabContent.style.height = ref.offsetHeight + 'px';
ref.classList.add('md-active');
});
},
changeTab(index) {
this.tabs[this.activeTab].ref.classList.remove('md-active');
this.activeTab = index;
this.calculateIndicatorPos();
this.calculateTabPos(this.tabs[this.activeTab].ref, this.activeTab);
this.setVisibleTab(this.tabs[index].ref);
},
registerTab(options) {
this.tabs.push(options);
if (options.icon) {
this.hasIcons = true;
}
if (options.label) {
this.hasLabel = true;
}
if (options.active) {
this.changeTab(this.tabs.length - 1);
}
this.calculateTabPos(this.tabs[this.tabs.length - 1].ref, this.tabs.length - 1);
}
},
mounted() {
if (this.activeTab === 0) {
this.changeTab(0);
}
}
};
</script>

View file

@ -66,6 +66,10 @@
<router-link to="/switch">Switch</router-link>
</md-list-item>
<md-list-item>
<router-link to="/tabs">Tabs</router-link>
</md-list-item>
<md-list-item>
<router-link to="/theme">Theme</router-link>
</md-list-item>

View file

@ -68,6 +68,12 @@
</div>
</template>
<style lang="scss" scoped>
.md-whiteframe-1dp {
margin-bottom: 16px;
}
</style>
<script>
export default {
mounted() {

143
src/docs/pages/Tabs.vue Normal file
View file

@ -0,0 +1,143 @@
<template>
<div class="page-content">
<md-whiteframe md-elevation="2">
<md-toolbar class="md-dense">
<md-button>Examples</md-button>
<md-button>Code</md-button>
<md-button>API</md-button>
</md-toolbar>
</md-whiteframe>
<div class="main-content">
<md-whiteframe class="cell-phone">
<md-toolbar v-md-theme="'grey'">
<h2 class="md-title">Default</h2>
</md-toolbar>
<section>
<md-tabs>
<md-tab md-label="Movies">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt dolorum quas amet cum vitae, omnis! Illum quas voluptatem, expedita iste, dicta ipsum ea veniam dolore in, quod saepe reiciendis nihil.</p>
</md-tab>
<md-tab md-label="Music">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt dolorum quas amet cum vitae, omnis! Illum quas voluptatem, expedita iste, dicta ipsum ea veniam dolore in, quod saepe reiciendis nihil.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt dolorum quas amet cum vitae, omnis! Illum quas voluptatem, expedita iste, dicta ipsum ea veniam dolore in, quod saepe reiciendis nihil.</p>
</md-tab>
<md-tab md-label="Books">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt dolorum quas.</p>
</md-tab>
<md-tab md-label="Pictures">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt dolorum quas.</p>
</md-tab>
</md-tabs>
</section>
</md-whiteframe>
<md-whiteframe class="cell-phone">
<md-toolbar v-md-theme="'grey'">
<h2 class="md-title">Fixed</h2>
</md-toolbar>
<section>
<md-tabs md-fixed class="md-accent">
<md-tab md-label="Movies">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt dolorum quas amet cum vitae, omnis! Illum quas voluptatem, expedita iste, dicta ipsum ea veniam dolore in, quod saepe reiciendis nihil.</p>
</md-tab>
<md-tab md-label="Music">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt dolorum quas amet cum vitae, omnis! Illum quas voluptatem, expedita iste, dicta ipsum ea veniam dolore in, quod saepe reiciendis nihil.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt dolorum quas amet cum vitae, omnis! Illum quas voluptatem, expedita iste, dicta ipsum ea veniam dolore in, quod saepe reiciendis nihil.</p>
</md-tab>
<md-tab md-label="Books">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt dolorum quas.</p>
</md-tab>
<md-tab md-label="Pictures">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt dolorum quas.</p>
</md-tab>
</md-tabs>
</section>
</md-whiteframe>
<md-whiteframe class="cell-phone">
<md-toolbar v-md-theme="'grey'">
<h2 class="md-title">With icons and text</h2>
</md-toolbar>
<section>
<md-tabs md-fixed v-md-theme="'teal'">
<md-tab md-label="Movies" md-icon="ondemand_video">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt dolorum quas amet cum vitae, omnis! Illum quas voluptatem, expedita iste, dicta ipsum ea veniam dolore in, quod saepe reiciendis nihil.</p>
</md-tab>
<md-tab md-label="Music" md-icon="music_note">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt dolorum quas amet cum vitae, omnis! Illum quas voluptatem, expedita iste, dicta ipsum ea veniam dolore in, quod saepe reiciendis nihil.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt dolorum quas amet cum vitae, omnis! Illum quas voluptatem, expedita iste, dicta ipsum ea veniam dolore in, quod saepe reiciendis nihil.</p>
</md-tab>
<md-tab md-label="Books" md-icon="books">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt dolorum quas.</p>
</md-tab>
<md-tab md-label="Pictures" md-icon="photo">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt dolorum quas.</p>
</md-tab>
</md-tabs>
</section>
</md-whiteframe>
<md-whiteframe class="cell-phone">
<md-toolbar v-md-theme="'grey'">
<h2 class="md-title">Centered with only icon</h2>
</md-toolbar>
<section>
<md-tabs md-centered v-md-theme="'green'">
<md-tab md-icon="phone">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt dolorum quas amet cum vitae, omnis! Illum quas voluptatem, expedita iste, dicta ipsum ea veniam dolore in, quod saepe reiciendis nihil.</p>
</md-tab>
<md-tab md-icon="favorite">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt dolorum quas amet cum vitae, omnis! Illum quas voluptatem, expedita iste, dicta ipsum ea veniam dolore in, quod saepe reiciendis nihil.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt dolorum quas amet cum vitae, omnis! Illum quas voluptatem, expedita iste, dicta ipsum ea veniam dolore in, quod saepe reiciendis nihil.</p>
</md-tab>
<md-tab md-icon="near_me">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt dolorum quas.</p>
</md-tab>
</md-tabs>
</section>
</md-whiteframe>
</div>
</div>
</template>
<style lang="scss" scoped>
.cell-phone {
width: 100%;
height: 732px;
max-width: 412px;
margin-right: 16px;
display: inline-block;
position: relative;
overflow: hidden;
border: none;
background-color: #fafafa;
}
.md-whiteframe-1dp {
margin-bottom: 16px;
}
</style>
<script>
export default {
mounted() {
this.$root.pageTitle = 'Tabs';
}
};
</script>

View file

@ -15,6 +15,7 @@ import Select from './pages/Select';
import Sidenav from './pages/Sidenav';
import Subheader from './pages/Subheader';
import Switch from './pages/Switch';
import Tabs from './pages/Tabs';
import Theme from './pages/Theme';
import Toolbar from './pages/Toolbar';
import Tooltip from './pages/Tooltip';
@ -101,6 +102,11 @@ const routes = [
name: 'subheader',
component: Subheader
},
{
path: '/tabs',
name: 'tabs',
component: Tabs
},
{
path: '/theme',
name: 'theme',

View file

@ -14,6 +14,7 @@ import MdSelect from './components/mdSelect';
import MdSidenav from './components/mdSidenav';
import MdSubheader from './components/mdSubheader';
import mdSwitch from './components/mdSwitch';
import mdTabs from './components/mdTabs';
import MdToolbar from './components/mdToolbar';
import MdTooltip from './components/mdTooltip';
import MdWhiteframe from './components/mdWhiteframe';
@ -35,6 +36,7 @@ let options = {
MdSidenav,
MdSubheader,
mdSwitch,
mdTabs,
MdToolbar,
MdTooltip,
MdWhiteframe,