Skip to content

Commit

Permalink
Merge pull request #6 from nivedin/feat/alignable-tab-buttons
Browse files Browse the repository at this point in the history
feat: add ability to tab which helps to align tabs to right end
  • Loading branch information
anwarulislam authored Feb 22, 2024
2 parents 405e420 + 6222472 commit 4c2ea5b
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 42 deletions.
5 changes: 4 additions & 1 deletion src/components/smart/Tab.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<div v-if="shouldRender" v-show="active" class="flex flex-col flex-1">
<div v-if="shouldRender" v-show="active" class="flex flex-1 flex-col">
<slot></slot>
</div>
</template>
Expand All @@ -24,12 +24,14 @@ const props = withDefaults(
info?: string | null
indicator?: boolean
disabled?: boolean
alignLast?: boolean
}>(),
{
icon: null,
indicator: false,
info: null,
disabled: false,
alignLast: false,
},
)
Expand All @@ -44,6 +46,7 @@ const tabMeta = computed<TabMeta>(() => ({
info: props.info,
label: props.label,
disabled: props.disabled,
alignLast: props.alignLast,
}))
const {
Expand Down
103 changes: 62 additions & 41 deletions src/components/smart/Tabs.vue
Original file line number Diff line number Diff line change
@@ -1,65 +1,78 @@
<template>
<div
class="flex flex-1 h-full flex-nowrap"
class="flex h-full flex-1 flex-nowrap"
:class="{ '!h-auto !flex-col': !vertical }"
>
<div
class="relative tabs border-dividerLight"
class="tabs relative border-dividerLight"
:class="[vertical ? 'border-r' : 'border-b', styles]"
>
<div class="flex flex-1">
<div
class="flex justify-between flex-1"
class="flex flex-1 justify-between"
:class="{ 'flex-col': vertical }"
>
<div class="flex" :class="{ 'flex-col space-y-2 p-2': vertical }">
<button
v-for="([tabID, tabMeta], index) in tabEntries"
:key="`tab-${index}`"
v-tippy="{
theme: 'tooltip',
placement: 'left',
content: vertical ? tabMeta.label : null,
<template
v-for="(tabGroup, alignment) in alignedTabs"
:key="alignment"
>
<div
class="flex flex-1"
:class="{
'flex-col space-y-2 p-2': vertical,
'justify-end': alignment === 'right',
}"
class="tab"
:class="[
{ active: modelValue === tabID },
{ vertical: vertical },
{ '!cursor-not-allowed opacity-75': tabMeta.disabled },
]"
:aria-label="tabMeta.label || ''"
:disabled="tabMeta.disabled"
role="button"
@keyup.enter="selectTab(tabID)"
@click="selectTab(tabID)"
>
<component
:is="tabMeta.icon"
v-if="tabMeta.icon"
class="svg-icons"
:class="{ 'mr-2': tabMeta.label && !vertical }"
/>
<span v-if="tabMeta.label && !vertical">{{ tabMeta.label }}</span>
<span
v-if="tabMeta.info && tabMeta.info !== 'null'"
class="tab-info"
<button
v-for="([tabID, tabMeta], index) in tabGroup"
:key="`tab-${index}`"
v-tippy="{
theme: 'tooltip',
placement: 'left',
content: vertical ? tabMeta.label : null,
}"
class="tab"
:class="[
{ active: modelValue === tabID },
{ vertical: vertical },
{ '!cursor-not-allowed opacity-75': tabMeta.disabled },
]"
:aria-label="tabMeta.label || ''"
:disabled="tabMeta.disabled"
role="button"
@keyup.enter="selectTab(tabID)"
@click="selectTab(tabID)"
>
{{ tabMeta.info }}
</span>
<span
v-if="tabMeta.indicator"
class="w-1 h-1 ml-2 rounded-full bg-accentLight"
></span>
</button>
</div>
<component
:is="tabMeta.icon"
v-if="tabMeta.icon"
class="svg-icons"
:class="{ 'mr-2': tabMeta.label && !vertical }"
/>
<span v-if="tabMeta.label && !vertical">{{
tabMeta.label
}}</span>
<span
v-if="tabMeta.info && tabMeta.info !== 'null'"
class="tab-info"
>
{{ tabMeta.info }}
</span>
<span
v-if="tabMeta.indicator"
class="ml-2 h-1 w-1 rounded-full bg-accentLight"
></span>
</button>
</div>
</template>
<div class="flex items-center justify-center">
<slot name="actions"></slot>
</div>
</div>
</div>
</div>
<div
class="w-full h-full contents"
class="contents h-full w-full"
:class="[
{
'!flex flex-1 flex-col overflow-y-auto': vertical,
Expand All @@ -86,6 +99,7 @@ export type TabMeta = {
indicator: boolean
info: string | null
disabled: boolean
alignLast: boolean
}
export type TabProvider = {
Expand Down Expand Up @@ -131,6 +145,13 @@ const throwError = (message: string): never => {
const tabEntries = ref<Array<[string, TabMeta]>>([])
// Tab related logic
const alignedTabs = computed(() => {
const leftTabs = tabEntries.value.filter(([_, tabMeta]) => !tabMeta.alignLast)
const rightTabs = tabEntries.value.filter(([_, tabMeta]) => tabMeta.alignLast)
return { left: leftTabs, right: rightTabs }
})
const addTabEntry = (tabID: string, meta: TabMeta) => {
tabEntries.value = pipe(
tabEntries.value,
Expand Down

0 comments on commit 4c2ea5b

Please sign in to comment.