diff options
Diffstat (limited to 'core/src/components/AppMenuEntry.vue')
-rw-r--r-- | core/src/components/AppMenuEntry.vue | 52 |
1 files changed, 34 insertions, 18 deletions
diff --git a/core/src/components/AppMenuEntry.vue b/core/src/components/AppMenuEntry.vue index cef6d413dcd..1bf160f0695 100644 --- a/core/src/components/AppMenuEntry.vue +++ b/core/src/components/AppMenuEntry.vue @@ -4,9 +4,11 @@ --> <template> - <li class="app-menu-entry" + <li ref="containerElement" + class="app-menu-entry" :class="{ 'app-menu-entry--active': app.active, + 'app-menu-entry--truncated': needsSpace, }"> <a class="app-menu-entry__link" :href="app.href" @@ -15,7 +17,7 @@ :target="app.target ? '_blank' : undefined" :rel="app.target ? 'noopener noreferrer' : undefined"> <AppMenuIcon class="app-menu-entry__icon" :app="app" /> - <span class="app-menu-entry__label"> + <span ref="labelElement" class="app-menu-entry__label"> {{ app.name }} </span> </a> @@ -24,11 +26,26 @@ <script setup lang="ts"> import type { INavigationEntry } from '../types/navigation' +import { onMounted, ref, watch } from 'vue' import AppMenuIcon from './AppMenuIcon.vue' -defineProps<{ +const props = defineProps<{ app: INavigationEntry }>() + +const containerElement = ref<HTMLLIElement>() +const labelElement = ref<HTMLSpanElement>() +const needsSpace = ref(false) + +/** Update the space requirements of the app label */ +function calculateSize() { + const maxWidth = containerElement.value!.clientWidth + // Also keep the 0.5px letter spacing in mind + needsSpace.value = (maxWidth - props.app.name.length * 0.5) < (labelElement.value!.scrollWidth) +} +// Update size on mounted and when the app name changes +onMounted(calculateSize) +watch(() => props.app.name, calculateSize) </script> <style scoped lang="scss"> @@ -37,8 +54,6 @@ defineProps<{ width: var(--header-height); height: var(--header-height); position: relative; - // Needed to prevent jumping when hover an entry (keep in sync with :hover styles) - transition: width var(--animation-quick) ease-in-out; &__link { position: relative; @@ -65,9 +80,8 @@ defineProps<{ left: 50%; top: 50%; display: block; - min-width: 100%; transform: translateX(-50%); - width: 100%; + max-width: 100%; text-overflow: ellipsis; overflow: hidden; letter-spacing: -0.5px; @@ -115,25 +129,27 @@ defineProps<{ // Adjust the width when an entry is focussed // The focussed / hovered entry should grow, while both neighbors need to shrink - &:hover, - &:focus-within { - width: calc(var(--header-height) + var(--app-menu-entry-growth)); + &--truncated:hover, + &--truncated:focus-within { + .app-menu-entry__label { + max-width: calc(var(--header-height) + var(--app-menu-entry-growth)); + } // The next entry needs to shrink half the growth + .app-menu-entry { - width: calc(var(--header-height) - (var(--app-menu-entry-growth) / 2)); - .app-menu-entry__icon { - margin-inline-end: calc(var(--app-menu-entry-growth) / 2); + .app-menu-entry__label { + font-weight: normal; + max-width: calc(var(--header-height) - var(--app-menu-entry-growth)); } } } // The previous entry needs to shrink half the growth - &:has(+ .app-menu-entry:hover), - &:has(+ .app-menu-entry:focus-within) { - width: calc(var(--header-height) - (var(--app-menu-entry-growth) / 2)); - .app-menu-entry__icon { - margin-inline-start: calc(var(--app-menu-entry-growth) / 2); + &:has(+ .app-menu-entry--truncated:hover), + &:has(+ .app-menu-entry--truncated:focus-within) { + .app-menu-entry__label { + font-weight: normal; + max-width: calc(var(--header-height) - var(--app-menu-entry-growth)); } } } |