From ea2852dcb0a0f00318a2c8067405630bcff4eee6 Mon Sep 17 00:00:00 2001 From: Paul Nothaft Date: Thu, 25 Jun 2026 18:06:08 +0200 Subject: [PATCH] fix(admin): stack publish-gallery dialog CTAs so the German label fits (#670) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reporter @the-luap hit the German `Veröffentlichen & Kunden benachrichtigen` button overflowing the modal footer in the publish dialog. Two failure modes chained: 1. The footer was a `flex` row with two `flex-1` buttons inside a `max-w-md` (448 px) modal. Default `min-width: auto` on flex children meant the primary button kept its content width (~340 px including the paper-airplane icon + padding) and pushed the row past the modal frame. 2. Adding `min-w-0 whitespace-normal` doesn't help — the base `.btn` class has `@apply ... whitespace-nowrap` (`index.css:149`) which wins over a utility className via the Tailwind CSS cascade order. So the text won't wrap, the button silently extends past the modal frame, no overflow indicator. Verified with `getComputedStyle().whiteSpace = 'normal'` and the button still rendering as one ~340 px wide line at ~224 px allocated space. Fix: stack both buttons vertically (`flex flex-col-reverse gap-3`). Primary appears on top visually (col-reverse), cancel below — standard confirmation-dialog pattern (Material, Headless UI, Radix all do this for single-action dialogs). Works in every locale and viewport regardless of label length. No side-by-side row to overflow. Tried two prior shapes that didn't hold: - `flex-col-reverse sm:flex-row` with `sm:flex-1 min-w-0 whitespace-normal` on the primary: still overflowed silently because of the whitespace-nowrap cascade above. - `flex-col-reverse sm:flex-row sm:justify-end` with content-width buttons: `justify-end` doesn't constrain a row whose content sum exceeds the container; row just pushes left of the modal. Bumping the modal to `max-w-lg` (or wider) was also considered and rejected: matching modal width is asymmetric (every other admin dialog stays at `max-w-md`), and any locale longer than German would re-hit the wall. Stack-always is the only shape that handles every locale + every viewport without per-language tuning. Verified end-to-end against a dockerised dev backend: - DE + EN × desktop (1280px) + mobile (375px) — all four show primary on top, cancel below, both inside the modal frame, no overflow. Lint + tsc + full vitest suite (84/84) clean. Closes #670. --- .../src/components/admin/PublishGalleryDialog.tsx | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/frontend/src/components/admin/PublishGalleryDialog.tsx b/frontend/src/components/admin/PublishGalleryDialog.tsx index d0421602..aec06aa7 100644 --- a/frontend/src/components/admin/PublishGalleryDialog.tsx +++ b/frontend/src/components/admin/PublishGalleryDialog.tsx @@ -110,12 +110,21 @@ export const PublishGalleryDialog: React.FC = ({ )} -
+ {/* Stack both buttons vertically (always). The German primary label + "Veröffentlichen & Kunden benachrichtigen" is ~40 chars including + the icon — at max-w-md, no side-by-side row layout fits it on one + line, and the base .btn class has @apply whitespace-nowrap (see + index.css:149) which overrides a whitespace-normal className via + CSS cascade order, so the text won't wrap either. Side-by-side + would silently push the button past the modal frame (#670). + col-reverse keeps the DOM order semantically secondary-then-primary + while putting the primary action visually on top — standard + confirmation-dialog pattern. */} +
@@ -125,7 +134,6 @@ export const PublishGalleryDialog: React.FC = ({ disabled={isPublishing} isLoading={isPublishing} leftIcon={} - className="flex-1" > {t('events.publishAndNotify')}