44 -->
55
66<template >
7- <li class =" app-menu-entry"
7+ <li ref =" containerElement"
8+ class =" app-menu-entry"
89 :class =" {
910 'app-menu-entry--active': app.active,
11+ 'app-menu-entry--truncated': needsSpace,
1012 }" >
1113 <a class =" app-menu-entry__link"
1214 :href =" app.href"
1517 :target =" app.target ? '_blank' : undefined"
1618 :rel =" app.target ? 'noopener noreferrer' : undefined" >
1719 <AppMenuIcon class =" app-menu-entry__icon" :app =" app" />
18- <span class =" app-menu-entry__label" >
20+ <span ref = " labelElement " class =" app-menu-entry__label" >
1921 {{ app.name }}
2022 </span >
2123 </a >
2426
2527<script setup lang="ts">
2628import type { INavigationEntry } from ' ../types/navigation'
29+ import { onMounted , ref , watch } from ' vue'
2730import AppMenuIcon from ' ./AppMenuIcon.vue'
2831
29- defineProps <{
32+ const props = defineProps <{
3033 app: INavigationEntry
3134}>()
35+
36+ const containerElement = ref <HTMLLIElement >()
37+ const labelElement = ref <HTMLSpanElement >()
38+ const needsSpace = ref (false )
39+
40+ /** Update the space requirements of the app label */
41+ function calculateSize() {
42+ const maxWidth = containerElement .value ! .clientWidth
43+ // Also keep the 0.5px letter spacing in mind
44+ needsSpace .value = (maxWidth - props .app .name .length * 0.5 ) < (labelElement .value ! .scrollWidth )
45+ }
46+ // Update size on mounted and when the app name changes
47+ onMounted (calculateSize )
48+ watch (() => props .app .name , calculateSize )
3249 </script >
3350
3451<style scoped lang="scss">
@@ -37,8 +54,6 @@ defineProps<{
3754 width : var (--header-height );
3855 height : var (--header-height );
3956 position : relative ;
40- // Needed to prevent jumping when hover an entry (keep in sync with :hover styles)
41- transition : width var (--animation-quick ) ease-in-out ;
4257
4358 & __link {
4459 position : relative ;
@@ -65,9 +80,8 @@ defineProps<{
6580 left : 50% ;
6681 top : 50% ;
6782 display : block ;
68- min-width : 100% ;
6983 transform : translateX (-50% );
70- width : 100% ;
84+ max- width : 100% ;
7185 text-overflow : ellipsis ;
7286 overflow : hidden ;
7387 letter-spacing : -0.5px ;
@@ -115,25 +129,27 @@ defineProps<{
115129
116130 // Adjust the width when an entry is focussed
117131 // The focussed / hovered entry should grow, while both neighbors need to shrink
118- & :hover ,
119- & :focus-within {
120- width : calc (var (--header-height ) + var (--app-menu-entry-growth ));
132+ & --truncated :hover ,
133+ & --truncated :focus-within {
134+ .app-menu-entry__label {
135+ max-width : calc (var (--header-height ) + var (--app-menu-entry-growth ));
136+ }
121137
122138 // The next entry needs to shrink half the growth
123139 + .app-menu-entry {
124- width : calc ( var ( --header-height ) - ( var ( -- app-menu-entry-growth ) / 2 ));
125- .app-menu-entry__icon {
126- margin-inline-end : calc (var (--app-menu-entry-growth ) / 2 );
140+ . app-menu-entry__label {
141+ font-weight : normal ;
142+ max-width : calc (var (--header-height ) - var ( -- app-menu-entry-growth ));
127143 }
128144 }
129145 }
130146
131147 // The previous entry needs to shrink half the growth
132- & :has (+ .app-menu-entry :hover ),
133- & :has (+ .app-menu-entry :focus-within ) {
134- width : calc ( var ( --header-height ) - ( var ( -- app-menu-entry-growth ) / 2 ));
135- .app-menu-entry__icon {
136- margin-inline-start : calc (var (--app-menu-entry-growth ) / 2 );
148+ & :has (+ .app-menu-entry--truncated :hover ),
149+ & :has (+ .app-menu-entry--truncated :focus-within ) {
150+ . app-menu-entry__label {
151+ font-weight : normal ;
152+ max-width : calc (var (--header-height ) - var ( -- app-menu-entry-growth ));
137153 }
138154 }
139155}
0 commit comments