Merge pull request #47236 from nextcloud/backport/47203/stable30

[stable30] fix(AppMenu): Prevent menu entries from jumping on hover
pull/47190/head
John Molakvoæ 2024-08-14 16:27:51 +07:00 committed by GitHub
commit f68065c4e1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 37 additions and 31 deletions

@ -123,16 +123,6 @@ export default defineComponent({
display: flex;
flex-wrap: nowrap;
margin-inline: calc(var(--app-menu-entry-growth) / 2);
transition: margin-inline var(--animation-quick) ease-in-out;
// Remove padding if the first child is focussed
&:has(.app-menu-entry:hover:first-child, .app-menu-entry:focus-within:first-child) {
margin-inline: 0 calc(var(--app-menu-entry-growth) / 2);
}
// Remove padding if the last child is focussed
&:has(.app-menu-entry:hover:last-child, .app-menu-entry:focus-within:last-child) {
margin-inline: calc(var(--app-menu-entry-growth) / 2) 0;
}
}
&__overflow {

@ -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));
}
}
}

4
dist/core-main.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long