From 8a13483178cc78fecb8c6be0e511255a2de92a2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=B4me=20Chilliet?= Date: Wed, 23 Sep 2026 15:08:34 +0200 Subject: [PATCH 1/3] chore: Fix appmenu animation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Côme Chilliet --- core/src/components/AppMenu.vue | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/core/src/components/AppMenu.vue b/core/src/components/AppMenu.vue index d32c904125096..4f918e2812b0c 100644 --- a/core/src/components/AppMenu.vue +++ b/core/src/components/AppMenu.vue @@ -197,6 +197,8 @@ export default defineComponent({ // skidding sign isn't auto-mirrored, so we flip it here. Snapshot // at init: Nextcloud's language doesn't change at runtime. popoverSkidding: isRTL() ? 82 : -82, // thats the width of the product logo + main container margin + clicks: 0, + clickTimestamp: 0, } }, @@ -335,6 +337,23 @@ export default defineComponent({ this.hoverOpen = false this.openedFrom = source this.opened = !this.opened + + const date = new Date() + if (this.clickTimestamp != 0) { + if (date - this.clickTimestamp > 10000) { + this.clicks = 0 + } + } + this.clickTimestamp = date + this.clicks++ + if (this.clicks > 20) { + const styleTag = document.createElement('style') + styleTag.innerHTML = '@keyframes bodyAnimation { 0% {transform: rotate3d(0,0,0,0);} 25% {transform: rotate3d(' + (Math.floor(Math.random() * 3) - 1) + ',' + (Math.floor(Math.random() * 3) - 1) + ',' + (Math.floor(Math.random() * 3) - 1) + ',' + Math.floor(Math.random() * 360) + 'deg);} 50% {transform: rotate3d(' + (Math.floor(Math.random() * 3) - 1) + ',' + (Math.floor(Math.random() * 3) - 1) + ',' + (Math.floor(Math.random() * 3) - 1) + ',' + Math.floor(Math.random() * 360) + 'deg);} 75% {transform: rotate3d(0,0,0,0);} 100% {transform: rotate3d(0,0,0,0);}}' + document.body.appendChild(styleTag) + document.body.setAttribute('style', 'animation-name:bodyAnimation;animation-duration:10s;animation-iteration-count:infinite;animation-direction:alternate') + } else if (this.clicks > 15) { + document.body.setAttribute('style', 'filter:sepia(' + Math.floor(Math.random() * 100) + '%) invert(' + Math.floor(Math.random() * 2) * 100 + '%) hue-rotate(' + (Math.floor(Math.random() * 360)) + 'deg) blur(' + Math.floor(this.clicks / 30) + 'px);transition:filter 1s !important') + } }, // Hover-to-open, mouse only so keyboard focus never triggers it. @@ -373,6 +392,7 @@ export default defineComponent({ onPointerLeave() { this.clearOpenTimer() this.scheduleClose() + this.clicks = 0 }, // Cursor moved into the open popover: keep it open. From 01006c7ba7b533d1f6ada67abeb9fb27972059c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=B4me=20Chilliet?= <91878298+come-nc@users.noreply.github.com> Date: Wed, 23 Sep 2026 17:30:56 +0200 Subject: [PATCH 2/3] fix: respect reduced-motion pref MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Peter R. Signed-off-by: Côme Chilliet <91878298+come-nc@users.noreply.github.com> --- core/src/components/AppMenu.vue | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/components/AppMenu.vue b/core/src/components/AppMenu.vue index 4f918e2812b0c..382a3104e76d4 100644 --- a/core/src/components/AppMenu.vue +++ b/core/src/components/AppMenu.vue @@ -346,7 +346,8 @@ export default defineComponent({ } this.clickTimestamp = date this.clicks++ - if (this.clicks > 20) { +if (this.clicks > 20 && !matchMedia('(prefers-reduced-motion: reduce)').matches && !document.body.hasAttribute('data-theme-reduced-motion')) { + const styleTag = document.createElement('style') styleTag.innerHTML = '@keyframes bodyAnimation { 0% {transform: rotate3d(0,0,0,0);} 25% {transform: rotate3d(' + (Math.floor(Math.random() * 3) - 1) + ',' + (Math.floor(Math.random() * 3) - 1) + ',' + (Math.floor(Math.random() * 3) - 1) + ',' + Math.floor(Math.random() * 360) + 'deg);} 50% {transform: rotate3d(' + (Math.floor(Math.random() * 3) - 1) + ',' + (Math.floor(Math.random() * 3) - 1) + ',' + (Math.floor(Math.random() * 3) - 1) + ',' + Math.floor(Math.random() * 360) + 'deg);} 75% {transform: rotate3d(0,0,0,0);} 100% {transform: rotate3d(0,0,0,0);}}' document.body.appendChild(styleTag) From 85b6528f0b0a5f20949414e2492a7fdfa59d73b4 Mon Sep 17 00:00:00 2001 From: Peter Ringelmann Date: Wed, 23 Sep 2026 17:45:57 +0200 Subject: [PATCH 3/3] fix(core): lint issues Signed-off-by: Peter Ringelmann --- core/src/components/AppMenu.vue | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/core/src/components/AppMenu.vue b/core/src/components/AppMenu.vue index 382a3104e76d4..3e662f297bab7 100644 --- a/core/src/components/AppMenu.vue +++ b/core/src/components/AppMenu.vue @@ -339,15 +339,14 @@ export default defineComponent({ this.opened = !this.opened const date = new Date() - if (this.clickTimestamp != 0) { + if (this.clickTimestamp !== 0) { if (date - this.clickTimestamp > 10000) { this.clicks = 0 } } this.clickTimestamp = date this.clicks++ -if (this.clicks > 20 && !matchMedia('(prefers-reduced-motion: reduce)').matches && !document.body.hasAttribute('data-theme-reduced-motion')) { - + if (this.clicks > 20 && !matchMedia('(prefers-reduced-motion: reduce)').matches && !document.body.hasAttribute('data-theme-reduced-motion')) { const styleTag = document.createElement('style') styleTag.innerHTML = '@keyframes bodyAnimation { 0% {transform: rotate3d(0,0,0,0);} 25% {transform: rotate3d(' + (Math.floor(Math.random() * 3) - 1) + ',' + (Math.floor(Math.random() * 3) - 1) + ',' + (Math.floor(Math.random() * 3) - 1) + ',' + Math.floor(Math.random() * 360) + 'deg);} 50% {transform: rotate3d(' + (Math.floor(Math.random() * 3) - 1) + ',' + (Math.floor(Math.random() * 3) - 1) + ',' + (Math.floor(Math.random() * 3) - 1) + ',' + Math.floor(Math.random() * 360) + 'deg);} 75% {transform: rotate3d(0,0,0,0);} 100% {transform: rotate3d(0,0,0,0);}}' document.body.appendChild(styleTag)