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> | ||||
|   <div> | ||||
|     <div class="tab-container"> | ||||
|       <div | ||||
|     <nav class="tab-container"> | ||||
|       <a | ||||
|         class="tab" | ||||
|         v-for="(tab, index) in tabs" | ||||
|         :key="index" | ||||
|         @click="changeTab(index)" | ||||
|         @keydown.enter="changeTab(index)" | ||||
|         tabindex="0" | ||||
|         :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"> | ||||
|       <component :is="tabs[chosenTab].component" /> | ||||
|       <component :is="tabs[chosenTab].component" @counter="updateCounter" /> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import eventBus from "@/mixins/EventBus"; | ||||
| export default { | ||||
|   props: { | ||||
|     tabs: { | ||||
|       type: Array | ||||
|     }, | ||||
|     active: { | ||||
|       type: Number, | ||||
|       default: 0 | ||||
|     } | ||||
|   }, | ||||
|   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() { | ||||
|     return { | ||||
|       chosenTab: 0 | ||||
|     }; | ||||
|   }, | ||||
|   computed: { | ||||
|     activeTab() { | ||||
|       return this.tabs[this.chosenTab]; | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     changeTab: function(num) { | ||||
|     changeTab(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> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| @import "@/styles/variables.scss"; | ||||
| @import "@/styles/media-queries.scss"; | ||||
|  | ||||
| h1 { | ||||
|   text-align: center; | ||||
| } | ||||
| @@ -54,28 +83,50 @@ h1 { | ||||
|   display: flex; | ||||
|   flex-direction: row; | ||||
|   justify-content: center; | ||||
|   margin-top: 25px; | ||||
|   border-bottom: 1px solid #333333; | ||||
|   // margin-top: 25px; | ||||
|   border-bottom: 1px solid var(--underlinenav-text); | ||||
|  | ||||
|   margin-top: 2rem; | ||||
|  | ||||
|   @include mobile { | ||||
|     flex-direction: column; | ||||
|   } | ||||
| } | ||||
|  | ||||
| .tab { | ||||
|   cursor: pointer; | ||||
|   font-size: 1.2rem; | ||||
|   display: flex; | ||||
|   justify-content: center; | ||||
|   align-items: center; | ||||
|   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; | ||||
|   font-size: 1.1rem; | ||||
|   padding: 8px 16px; | ||||
|   border-bottom: 2px solid transparent; | ||||
|   color: rgba($matte-text-color, 0.9); | ||||
|  | ||||
|   &.active { | ||||
|     border-bottom: 1px solid white; | ||||
|     color: $matte-text-color; | ||||
|     border-color: var(--underlinenav-text-active) !important; | ||||
|     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> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user