Skip to content

Commit e97cd55

Browse files
committed
feat(sidebar-tabs): Redesign active tab as rounded filled pill
The active sidebar tab now renders as a fully-rounded filled pill with an inset, rounded blue indicator that grows into place when selected, replacing the previous full-width bottom border and bold label treatment. Tabs keep a small gap between each other to eliminate the hover radius artifact, and the tab icon slot now receives the active state so consumers can render filled/outlined icon variants. Signed-off-by: nfebe <fenn25.fn@gmail.com>
1 parent ea71fe9 commit e97cd55

4 files changed

Lines changed: 40 additions & 23 deletions

File tree

src/components/NcAppSidebar/NcAppSidebar.vue

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,10 @@ Using `v-show` directly will result in usability issues due to internal focus tr
4141
Search tab content
4242
</NcAppSidebarTab>
4343
<NcAppSidebarTab name="Settings" id="settings-tab">
44-
<template #icon>
45-
<IconCogOutline :size="20" />
44+
<!-- The `selected` slot prop lets you swap to a filled icon variant for the active tab. -->
45+
<template #icon="{ selected }">
46+
<IconCog v-if="selected" :size="20" />
47+
<IconCogOutline v-else :size="20" />
4648
</template>
4749
Settings tab content
4850
</NcAppSidebarTab>
@@ -58,12 +60,14 @@ Using `v-show` directly will result in usability issues due to internal focus tr
5860

5961
<script>
6062
import IconMagnify from 'vue-material-design-icons/Magnify.vue'
63+
import IconCog from 'vue-material-design-icons/Cog.vue'
6164
import IconCogOutline from 'vue-material-design-icons/CogOutline.vue'
6265
import IconShareVariantOutline from 'vue-material-design-icons/ShareVariantOutline.vue'
6366

6467
export default {
6568
components: {
6669
IconMagnify,
70+
IconCog,
6771
IconCogOutline,
6872
IconShareVariantOutline,
6973
},

src/components/NcAppSidebar/NcAppSidebarTabs.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ export default {
253253
&__nav {
254254
display: flex;
255255
justify-content: stretch;
256+
gap: var(--default-grid-baseline);
256257
margin: 10px 8px 0 8px;
257258
border-bottom: 1px solid var(--color-border);
258259
}

src/components/NcAppSidebar/NcAppSidebarTabsButton.vue

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ defineProps<{
2929
:tabindex="selected ? 0 : -1"
3030
@click="selected = true">
3131
<span :class="$style.sidebarTabsButton__icon">
32-
<NcVNodes :vnodes="tab.renderIcon()">
32+
<NcVNodes :vnodes="tab.renderIcon(selected)">
3333
<span :class="[$style.sidebarTabsButton__legacyIcon, tab.icon]" />
3434
</NcVNodes>
3535
</span>
@@ -41,9 +41,9 @@ defineProps<{
4141

4242
<style module lang="scss">
4343
.sidebarTabsButton {
44+
position: relative;
4445
border: none;
45-
border-bottom: var(--default-grid-baseline) solid transparent !important;
46-
border-radius: var(--border-radius-small);
46+
border-radius: var(--border-radius-element);
4747
background-color: var(--color-main-background);
4848
color: var(--color-main-text);
4949
font-size: var(--default-font-size);
@@ -52,18 +52,31 @@ defineProps<{
5252
flex-direction: column;
5353
gap: var(--default-grid-baseline);
5454
padding: var(--border-radius-small);
55-
transition:
56-
background-color var(--animation-quick),
57-
border-bottom-color var(--animation-quick);
55+
padding-block-end: calc(var(--border-radius-small) + var(--default-grid-baseline));
56+
transition: background-color var(--animation-quick);
5857
min-width: var(--default-clickable-area);
5958
59+
&::after {
60+
content: '';
61+
position: absolute;
62+
bottom: 2px;
63+
left: 50%;
64+
width: 0;
65+
height: 4px;
66+
border-radius: 999px;
67+
background-color: var(--color-primary-element);
68+
opacity: 0;
69+
transform: translateX(-50%);
70+
transition: width var(--animation-quick), opacity var(--animation-quick);
71+
}
72+
6073
&:hover {
61-
background-color: var(--color-background-hover) !important;
74+
background-color: var(--color-background-hover);
6275
}
6376
64-
&:active,
65-
&:focus {
66-
background-color: var(--color-main-background) !important;
77+
&:focus-visible {
78+
outline: 2px solid var(--color-main-text);
79+
outline-offset: 2px;
6780
}
6881
6982
* {
@@ -72,14 +85,16 @@ defineProps<{
7285
}
7386
7487
.sidebarTabsButton_selected {
75-
border-bottom-color: var(--color-primary-element) !important;
76-
border-bottom-left-radius: 0px;
77-
border-bottom-right-radius: 0px;
88+
background-color: var(--color-background-hover);
7889
cursor: default;
7990
91+
&::after {
92+
width: 80%;
93+
opacity: 1;
94+
}
95+
8096
&:hover {
81-
background-color: var(--color-primary-element-light-hover) !important;
82-
color: var(--color-primary-element-light-text) !important;
97+
background-color: var(--color-background-dark);
8398
}
8499
85100
* {
@@ -94,10 +109,6 @@ defineProps<{
94109
text-wrap: nowrap;
95110
}
96111
97-
.sidebarTabsButton_selected .sidebarTabsButton__name {
98-
font-weight: bold;
99-
}
100-
101112
.sidebarTabsButton__icon {
102113
display: inline-flex;
103114
align-items: center;

src/components/NcAppSidebarTab/NcAppSidebarTab.vue

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,11 @@ export default {
114114
/**
115115
* Render tab's icon slot if any
116116
*
117+
* @param {boolean} selected Whether the tab is the active one
117118
* @return {import('vue').VNode[]}
118119
*/
119-
renderIcon() {
120-
return this.$slots.icon?.()
120+
renderIcon(selected = false) {
121+
return this.$slots.icon?.({ selected })
121122
},
122123
},
123124
}

0 commit comments

Comments
 (0)