mirror of
https://github.com/nextcloud/server.git
synced 2026-06-08 08:16:43 -04:00
Merge pull request #47236 from nextcloud/backport/47203/stable30
[stable30] fix(AppMenu): Prevent menu entries from jumping on hover
This commit is contained in:
commit
f68065c4e1
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
4
dist/core-main.js
vendored
File diff suppressed because one or more lines are too long
2
dist/core-main.js.map
vendored
2
dist/core-main.js.map
vendored
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue