Skip to content

feat(core): app menu waffle launcher#60180

Open
pringelmann wants to merge 6 commits intomasterfrom
feat/59888/waffle-menu
Open

feat(core): app menu waffle launcher#60180
pringelmann wants to merge 6 commits intomasterfrom
feat/59888/waffle-menu

Conversation

@pringelmann
Copy link
Copy Markdown
Contributor

@pringelmann pringelmann commented May 6, 2026

Summary

First pass at the waffle launcher behind the apps icon in the header. Opening it shows a 4-wide grid of installed apps in a popover; admins also see a "More apps" tile linking to the app store. The existing current-app button is kept as a second trigger for the same popover.

Preview link

image

What's in:

  • Popover grid replaces the old hamburger overlay
  • Roving tabindex keyboard nav (arrow keys, Home/End, Enter/Space)
  • Focus returns to whichever trigger opened the popover
  • RTL-aware horizontal alignment
  • Admin-only "More apps" tile
  • Unit + Cypress coverage

TODO

Follow-ups for later PRs:

  • Live unread/notification counts on the tiles
  • Drag-and-drop reordering, persisted per user
  • Broaden test coverage (RTL, focus trap edge cases, keyboard variants, viewport breakpoints)

Checklist

  • Code is properly formatted
  • Sign-off message is added to all commits
  • Tests (unit, integration, api and/or acceptance) are included
  • Screenshots before/after for front-end changes (preview link)
  • Documentation (manuals or wiki) has been updated or is not required
  • Backports requested where applicable (ex: critical bugfixes)
  • Labels added where applicable (ex: bug/enhancement, 3. to review, feature component)
  • Milestone added for target branch/version (ex: 32.x for stable32)

- Popover grid replaces the old hamburger overlay
- Roving tabindex keyboard nav (arrow keys, Home/End, Enter/Space)
- Focus returns to whichever trigger opened the popover
- RTL-aware horizontal alignment
- Admin-only "More apps" tile
- Unit + Cypress coverage

Resolves: #59888
Signed-off-by: Peter Ringelmann <peter.ringelmann@nextcloud.com>
-e
Signed-off-by: Peter Ringelmann <peter.ringelmann@nextcloud.com>
@pringelmann pringelmann self-assigned this May 6, 2026
Comment thread core/src/components/AppItem.vue Outdated
</script>

<style scoped lang="scss">
.app-item {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can consider moving this to @nextcloud/vue in future, since this item will be used on dashboard, universal search, etc.

Would like to ship in-place for first iteration.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if planned for nextcloud-vue it would be great to use css modules instead of scoped styles for two-way isolation of styles.

// NcPopover's focus-trap only knows the slot trigger (waffle).
// The current-app button lives outside the slot, so we track the
// source and restore focus manually via setReturnFocus.
openedFrom: null as 'waffle' | 'currentApp' | null,
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UX behaviour relevant question here. Used common sense for first iteration.

return
}

const cols = 4
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

magic number 😬 imo fine for first iteration, but some rework might be needed here.

case ' ': {
// Space's default scrolls the nearest scrollable ancestor (the
// popover); intercept and click programmatically. Enter gets
// the same treatment so we can close the popover uniformly.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consistent with other waffle menus I looked at, but worth flagging as UX question

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

space seems a bit unexpected here rest seems fine (for accessibility)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fwiw APG recommends this behaviour:

https://www.w3.org/WAI/ARIA/apg/patterns/menubar/examples/menubar-navigation/#:~:text=activates%20the%20menu%20item%2C

My reasoning is that arrows, Home and End all trigger focus events (which will auto-scroll), making it possible for users to scroll the list without needing a dedicated key for it.

// which is dark on light themes. The header sits on the theme primary
// background, so override to use the matching plain-text color.
--color-main-text: var(--color-background-plain-text);
color: var(--color-background-plain-text);
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be better to add variants to @nextcloud/vue, but imo fine for first iteration

--app-item-row-height: 64px;
--app-menu-rows-visible: 6;
padding: calc(var(--default-grid-baseline) * 3) calc(var(--default-grid-baseline) * 2);
display: grid;
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can debate whether grid is best/simplest solution here. Happy to iterate on this.

scrollbar-color: var(--color-scrollbar) transparent !important;

&::-webkit-scrollbar {
width: 6px !important;
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quick and dirty scrollbar styling. Happy to iterate on this.

@pringelmann pringelmann added 3. to review Waiting for reviews enhancement design Design, UI, UX, etc. labels May 6, 2026
@pringelmann pringelmann added this to the Nextcloud 34 milestone May 6, 2026
@pringelmann pringelmann marked this pull request as ready for review May 6, 2026 08:33
@pringelmann pringelmann requested a review from a team as a code owner May 6, 2026 08:34
@pringelmann pringelmann requested review from ShGKme, artonge, kra-mo, nfebe, sorbaugh and susnux and removed request for a team May 6, 2026 08:34
-e
Signed-off-by: Peter Ringelmann <peter.ringelmann@nextcloud.com>
-e
Signed-off-by: Peter Ringelmann <peter.ringelmann@nextcloud.com>
-e
Signed-off-by: Peter Ringelmann <peter.ringelmann@nextcloud.com>
Comment thread core/src/components/AppItem.vue Outdated
v-if="currentApp"
class="app-menu__current-app"
type="button"
:aria-label="t('core', 'Open apps menu')"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so both buttons open the waffle menu?
I would expect this button to open the index of the current app instead

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes as per design spec

This also feels like a weird interaction to me, especially since the popup anchor still points to the waffle. Would you mind expanding on what the rationale is here @kra-mo?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agree UX wise this is unexpected

-e
Signed-off-by: Peter Ringelmann <peter.ringelmann@nextcloud.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

3. to review Waiting for reviews design Design, UI, UX, etc. enhancement

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

App navigation: waffle menu and header layout

2 participants