From 3e940dc9ab104c12888cd920898b5412d8bb8aa2 Mon Sep 17 00:00:00 2001 From: kolaente Date: Thu, 11 Jun 2026 22:31:30 +0200 Subject: [PATCH] fix(frontend): restore quick actions menu styling and height limit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The quick actions menu (cmd+k) rendered without any background and grew beyond the viewport: - Its card visuals came from the global Bulma .card styles, which were dropped when Card.vue got its own scoped copy — QuickActions is the only place using a bare class="card" div, so it lost background, border and shadow. Give it its own card styles. - Its height limit came from Bulma's .modal-content max-height, lost when the Bulma modal import was dropped in the native-dialog refactor. The :deep(.modal-content) position override in QuickActions never matched (.modal-content is an ancestor of the scoped selector, not a descendant). Replace both with a proper `top` modal variant that anchors the content 3rem below the top edge and caps its height, resolving the FIXME asking for exactly that option. - The dark scrim never showed: Chromium intermittently stops painting a styled ::backdrop (after subtree re-renders, or while display is transitioned) even though getComputedStyle reports the color. Move the scrim onto the viewport-filling dialog element itself — same as the old div-based .modal-mask — and drop the display/allow-discrete transitions, which the JS-timed close fade never needed. --- frontend/src/components/misc/Modal.vue | 55 ++++++++++++++----- .../components/quick-actions/QuickActions.vue | 14 +++-- 2 files changed, 48 insertions(+), 21 deletions(-) diff --git a/frontend/src/components/misc/Modal.vue b/frontend/src/components/misc/Modal.vue index 5a3fedc98..b654e0268 100644 --- a/frontend/src/components/misc/Modal.vue +++ b/frontend/src/components/misc/Modal.vue @@ -68,7 +68,7 @@ const props = withDefaults(defineProps<{ enabled?: boolean, overflow?: boolean, wide?: boolean, - variant?: 'default' | 'hint-modal' | 'scrolling', + variant?: 'default' | 'hint-modal' | 'scrolling' | 'top', }>(), { enabled: true, overflow: false, @@ -211,7 +211,13 @@ $modal-width: 1024px; // Reset UA dialog styles padding: 0; border: none; - background: transparent; + // The scrim lives on the dialog element, not on ::backdrop: Chromium + // intermittently stops painting a styled ::backdrop (e.g. after the + // dialog's subtree re-renders, or while display is transitioned) even + // though getComputedStyle still reports the color. The dialog fills the + // viewport anyway, and its opacity transition fades the scrim with it — + // same as the old div-based .modal-mask. + background: rgba(0, 0, 0, .8); color: #ffffff; // Fill viewport position: fixed; @@ -221,10 +227,12 @@ $modal-width: 1024px; max-inline-size: 100%; max-block-size: 100%; - // Transitions + // Transitions. No display/allow-discrete transition needed: the close + // fade runs while the dialog is still [open] (data-closing + timer in + // closeDialog), and transitioning display triggers the Chromium paint + // bug above. opacity: 0; - transition: opacity 150ms ease, - display 150ms ease allow-discrete; + transition: opacity 150ms ease; &[open]:not([data-closing]) { opacity: 1; @@ -236,16 +244,11 @@ $modal-width: 1024px; &::backdrop { background-color: rgba(0, 0, 0, 0); - transition: background-color 150ms ease, - display 150ms ease allow-discrete; } - &[open]:not([data-closing])::backdrop { - background-color: rgba(0, 0, 0, .8); - - @starting-style { - background-color: rgba(0, 0, 0, 0); - } + // in quick-add mode the Electron window itself is the overlay — no scrim + &:has(.is-quick-add-mode) { + background: transparent; } } @@ -261,7 +264,8 @@ $modal-width: 1024px; } .default .modal-content, -.hint-modal .modal-content { +.hint-modal .modal-content, +.top .modal-content { text-align: center; position: absolute; // fine to use top/left since we're only using this to position it centered @@ -289,11 +293,31 @@ $modal-width: 1024px; } } +// anchored below the top edge instead of centered, used for QuickActions +.top .modal-content { + inset-block-start: 3rem; + transform: translate(-50%, 0); + max-block-size: calc(100dvh - 6rem); + overflow: auto; + + [dir="rtl"] & { + transform: translate(50%, 0); + } + + // the fullscreen mobile layout flows and scrolls in .modal-container + @media screen and (max-width: $tablet) { + transform: none; + max-block-size: none; + overflow: visible; + } +} + // Default width for centered modals. Scoped with :not(.is-wide) so the // `wide` prop can still expand the modal (the .is-wide rule below would // otherwise be outranked by .default .modal-content's specificity). .default .modal-content:not(.is-wide), -.hint-modal .modal-content:not(.is-wide) { +.hint-modal .modal-content:not(.is-wide), +.top .modal-content:not(.is-wide) { inline-size: calc(100% - 2rem); max-inline-size: 640px; @@ -403,6 +427,7 @@ $modal-width: 1024px; block-size: auto; max-inline-size: none; max-block-size: none; + background: transparent; &::backdrop { display: none; diff --git a/frontend/src/components/quick-actions/QuickActions.vue b/frontend/src/components/quick-actions/QuickActions.vue index 13605fe4f..3656d5e89 100644 --- a/frontend/src/components/quick-actions/QuickActions.vue +++ b/frontend/src/components/quick-actions/QuickActions.vue @@ -2,6 +2,7 @@
.quick-actions { + // global Bulma .card styles are gone (ported into Card.vue, scoped), + // so this bare .card div needs its own card visuals + background-color: var(--white); + border-radius: $radius; + border: 1px solid var(--card-border-color); + box-shadow: var(--shadow-sm); + color: var(--text); overflow: hidden; justify-content: flex-start !important; - // FIXME: changed position should be an option of the modal - :deep(.modal-content) { - inset-block-start: 3rem; - transform: translate(-50%, 0); - } - &.is-quick-add-mode { padding: 0; margin: 0;