Skip to content

Commit 4417f0f

Browse files
Merge pull request #47031 from nextcloud/fix/app-menu
fix: Ensure app overflow menu is rendered centered
2 parents 609fa7d + de5ae56 commit 4417f0f

File tree

4 files changed

+49
-46
lines changed

4 files changed

+49
-46
lines changed

core/src/components/AppMenu.vue

Lines changed: 39 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
-->
55

66
<template>
7-
<nav class="app-menu"
7+
<nav ref="appMenu"
8+
class="app-menu"
89
:aria-label="t('core', 'Applications menu')">
910
<ul class="app-menu__list">
1011
<AppMenuEntry v-for="app in mainAppList"
@@ -29,7 +30,8 @@ import type { INavigationEntry } from '../types/navigation'
2930
import { subscribe, unsubscribe } from '@nextcloud/event-bus'
3031
import { loadState } from '@nextcloud/initial-state'
3132
import { n, t } from '@nextcloud/l10n'
32-
import { defineComponent } from 'vue'
33+
import { useElementSize } from '@vueuse/core'
34+
import { defineComponent, ref } from 'vue'
3335
3436
import AppMenuEntry from './AppMenuEntry.vue'
3537
import NcActions from '@nextcloud/vue/dist/Components/NcActions.js'
@@ -46,40 +48,47 @@ export default defineComponent({
4648
},
4749
4850
setup() {
51+
const appMenu = ref()
52+
const { width: appMenuWidth } = useElementSize(appMenu)
4953
return {
5054
t,
5155
n,
56+
appMenu,
57+
appMenuWidth,
5258
}
5359
},
5460
5561
data() {
5662
const appList = loadState<INavigationEntry[]>('core', 'apps', [])
57-
5863
return {
5964
appList,
60-
appLimit: 0,
61-
observer: null as ResizeObserver | null,
6265
}
6366
},
6467
6568
computed: {
69+
appLimit() {
70+
const maxApps = Math.floor(this.appMenuWidth / 50)
71+
if (maxApps < this.appList.length) {
72+
// Ensure there is space for the overflow menu
73+
return Math.max(maxApps - 1, 0)
74+
}
75+
return maxApps
76+
},
77+
6678
mainAppList() {
6779
return this.appList.slice(0, this.appLimit)
6880
},
81+
6982
popoverAppList() {
7083
return this.appList.slice(this.appLimit)
7184
},
7285
},
7386
7487
mounted() {
75-
this.observer = new ResizeObserver(this.resize)
76-
this.observer.observe(this.$el)
77-
this.resize()
7888
subscribe('nextcloud:app-menu.refresh', this.setApps)
7989
},
8090
8191
beforeDestroy() {
82-
this.observer!.disconnect()
8392
unsubscribe('nextcloud:app-menu.refresh', this.setApps)
8493
},
8594
@@ -96,54 +105,44 @@ export default defineComponent({
96105
setApps({ apps }: { apps: INavigationEntry[]}) {
97106
this.appList = apps
98107
},
99-
100-
resize() {
101-
const availableWidth = (this.$el as HTMLElement).offsetWidth
102-
let appCount = Math.floor(availableWidth / 50) - 1
103-
const popoverAppCount = this.appList.length - appCount
104-
if (popoverAppCount === 1) {
105-
appCount--
106-
}
107-
if (appCount < 1) {
108-
appCount = 0
109-
}
110-
this.appLimit = appCount
111-
},
112108
},
113109
})
114110
</script>
115111

116112
<style scoped lang="scss">
117113
.app-menu {
118-
width: 100%;
119114
display: flex;
120-
flex-shrink: 1;
121-
flex-wrap: wrap;
115+
flex: 1 1;
116+
width: 0;
122117
123118
&__list {
124119
display: flex;
125120
flex-wrap: nowrap;
126121
}
127122
128-
// Adjust the overflow NcActions styles as they are directly rendered on the background
129-
&__overflow :deep(.button-vue--vue-tertiary) {
130-
opacity: .7;
131-
margin: 3px;
132-
filter: var(--background-image-invert-if-bright);
123+
&__overflow {
124+
margin-block: auto;
133125
134-
/* Remove all background and align text color if not expanded */
135-
&:not([aria-expanded="true"]) {
136-
color: var(--color-background-plain-text);
126+
// Adjust the overflow NcActions styles as they are directly rendered on the background
127+
:deep(.button-vue--vue-tertiary) {
128+
opacity: .7;
129+
margin: 3px;
130+
filter: var(--background-image-invert-if-bright);
137131
138-
&:hover {
139-
opacity: 1;
140-
background-color: transparent !important;
132+
/* Remove all background and align text color if not expanded */
133+
&:not([aria-expanded="true"]) {
134+
color: var(--color-background-plain-text);
135+
136+
&:hover {
137+
opacity: 1;
138+
background-color: transparent !important;
139+
}
141140
}
142-
}
143141
144-
&:focus-visible {
145-
opacity: 1;
146-
outline: none !important;
142+
&:focus-visible {
143+
opacity: 1;
144+
outline: none !important;
145+
}
147146
}
148147
}
149148

core/src/components/AppMenuEntry.vue

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ defineProps<{
3333

3434
<style scoped lang="scss">
3535
.app-menu-entry {
36+
--app-menu-entry-font-size: 12px;
3637
width: var(--header-height);
3738
height: var(--header-height);
3839
position: relative;
@@ -54,8 +55,7 @@ defineProps<{
5455
&__label {
5556
opacity: 0;
5657
position: absolute;
57-
font-size: 12px;
58-
line-height: 1.25;
58+
font-size: var(--app-menu-entry-font-size);
5959
// this is shown directly on the background
6060
color: var(--color-background-plain-text);
6161
text-align: center;
@@ -71,6 +71,10 @@ defineProps<{
7171
letter-spacing: -0.5px;
7272
}
7373
74+
&__icon {
75+
font-size: var(--app-menu-entry-font-size);
76+
}
77+
7478
&--active {
7579
// When hover or focus, show the label and make it bolder than the other entries
7680
.app-menu-entry__label {
@@ -117,7 +121,7 @@ defineProps<{
117121
.app-menu__list:focus-within {
118122
// Move icon up so that the name does not overflow the icon
119123
.app-menu-entry__icon {
120-
margin-block-end: calc(1.5 * 12px); // font size of label * line height
124+
margin-block-end: 1lh;
121125
}
122126
123127
// Make the label visible

dist/core-main.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/core-main.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)