Tabs redesigned, update url and can show counter.
Tabs have been redesigned and can now display a counter. This counter
can be set by emiting a "counter" event from the child.
Tabs read and set a ?tab={slug} query parameter when changing tab, when
loaded we check for this parameter to automatically select the correct
tab.
This commit is contained in:
@@ -1,51 +1,80 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="tab-container">
|
<nav class="tab-container">
|
||||||
<div
|
<a
|
||||||
class="tab"
|
class="tab"
|
||||||
v-for="(tab, index) in tabs"
|
v-for="(tab, index) in tabs"
|
||||||
:key="index"
|
:key="index"
|
||||||
@click="changeTab(index)"
|
@click="changeTab(index)"
|
||||||
|
@keydown.enter="changeTab(index)"
|
||||||
|
tabindex="0"
|
||||||
:class="chosenTab == index ? 'active' : null"
|
:class="chosenTab == index ? 'active' : null"
|
||||||
>{{ tab.name }}</div>
|
>
|
||||||
</div>
|
{{ tab.name }}
|
||||||
|
|
||||||
|
<span v-if="tab.counter" class="counter">{{ tab.counter }}</span>
|
||||||
|
</a>
|
||||||
|
</nav>
|
||||||
|
|
||||||
<div class="tab-elements">
|
<div class="tab-elements">
|
||||||
<component :is="tabs[chosenTab].component" />
|
<component :is="tabs[chosenTab].component" @counter="updateCounter" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import eventBus from "@/mixins/EventBus";
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
tabs: {
|
tabs: {
|
||||||
type: Array
|
type: Array
|
||||||
},
|
|
||||||
active: {
|
|
||||||
type: Number,
|
|
||||||
default: 0
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
beforeMount() {
|
beforeMount() {
|
||||||
this.chosenTab = this.active;
|
const url = location.href;
|
||||||
|
|
||||||
|
if (url.includes("tab=")) {
|
||||||
|
const tabParameter = url.split("tab=")[1];
|
||||||
|
const matchingSlug = this.tabs.findIndex(tab => tab.slug == tabParameter);
|
||||||
|
console.log("matchingSlug:", matchingSlug);
|
||||||
|
this.chosenTab = matchingSlug;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
chosenTab: 0
|
chosenTab: 0
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
activeTab() {
|
||||||
|
return this.tabs[this.chosenTab];
|
||||||
|
}
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
changeTab: function(num) {
|
changeTab(num) {
|
||||||
this.chosenTab = num;
|
this.chosenTab = num;
|
||||||
this.$emit("tabChange", num);
|
|
||||||
eventBus.$emit("tab-change");
|
let url = location.href;
|
||||||
|
const tabParameterIndex = url.indexOf("tab=");
|
||||||
|
|
||||||
|
if (tabParameterIndex > 0) {
|
||||||
|
url = url.split("tab=")[0] + `tab=${this.activeTab.slug}`;
|
||||||
|
} else {
|
||||||
|
url = url + `?tab=${this.activeTab.slug}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.history.pushState({}, "", url);
|
||||||
|
},
|
||||||
|
updateCounter(val) {
|
||||||
|
this.activeTab.counter = val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@import "@/styles/variables.scss";
|
||||||
|
@import "@/styles/media-queries.scss";
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
@@ -54,28 +83,50 @@ h1 {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
margin-top: 25px;
|
// margin-top: 25px;
|
||||||
border-bottom: 1px solid #333333;
|
border-bottom: 1px solid var(--underlinenav-text);
|
||||||
|
|
||||||
|
margin-top: 2rem;
|
||||||
|
|
||||||
|
@include mobile {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab {
|
.tab {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-size: 1.2rem;
|
font-size: 1.1rem;
|
||||||
display: flex;
|
padding: 8px 16px;
|
||||||
justify-content: center;
|
border-bottom: 2px solid transparent;
|
||||||
align-items: center;
|
color: rgba($matte-text-color, 0.9);
|
||||||
padding: 20px;
|
|
||||||
margin: 0 15px;
|
|
||||||
border: 1px solid #333333;
|
|
||||||
border-top-left-radius: 5px;
|
|
||||||
border-top-right-radius: 5px;
|
|
||||||
background: #00000008;
|
|
||||||
border-bottom: 1px solid #333333;
|
|
||||||
margin-bottom: -1px;
|
|
||||||
|
|
||||||
&.active {
|
&.active {
|
||||||
border-bottom: 1px solid white;
|
color: $matte-text-color;
|
||||||
|
border-color: var(--underlinenav-text-active) !important;
|
||||||
background: white;
|
background: white;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus {
|
||||||
|
border-color: var(--underlinenav-text-hover);
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .counter {
|
||||||
|
margin-left: 4px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
display: inline-block;
|
||||||
|
min-width: 20px;
|
||||||
|
padding: 0 6px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 18px;
|
||||||
|
text-align: center;
|
||||||
|
background-color: rgba(209, 213, 218, 0.5);
|
||||||
|
border: 1px solid transparent;
|
||||||
|
border-radius: 2em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user