fix(conversations): keep swap button in DOM to prevent grid column width shift
All checks were successful
CI / Unit & Component Tests (push) Successful in 1m56s
CI / Backend Unit Tests (push) Successful in 1m53s
CI / E2E Tests (push) Successful in 16m37s
CI / Unit & Component Tests (pull_request) Successful in 2m2s
CI / Backend Unit Tests (pull_request) Successful in 2m2s
CI / E2E Tests (pull_request) Successful in 16m55s

The swap button was conditionally removed from the DOM with {#if}, which
caused the receiver input to collapse into the narrow auto column of the
grid-cols-[1fr_auto_1fr] layout on desktop when no persons were selected.

The button is now always rendered. On desktop it becomes invisible
(visibility:hidden) when no persons are selected, preserving the middle
column width so both 1fr columns stay equal. On mobile it remains hidden
(display:none) via the hidden class so no empty gap appears between the
stacked inputs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit was merged in pull request #43.
This commit is contained in:
Marcel
2026-03-20 18:32:37 +01:00
parent 0f8b582813
commit 513a7290b0
2 changed files with 32 additions and 28 deletions

View File

@@ -91,13 +91,17 @@ const enrichedDocuments = $derived(
/> />
</div> </div>
<!-- Swap button — icon-only on desktop, full-width with text on mobile --> <!-- Swap button — always rendered to hold grid column width on desktop.
{#if senderId && receiverId} On mobile: hidden (display:none) when no persons selected so no gap appears.
<div class="flex items-end"> On desktop: invisible (visibility:hidden) when no persons so both 1fr columns stay equal. -->
<div class="{senderId && receiverId ? 'flex' : 'hidden md:flex'} items-end">
<button <button
data-testid="conv-swap-btn" data-testid="conv-swap-btn"
onclick={swapPersons} onclick={swapPersons}
class="flex w-full items-center justify-center gap-2 border border-brand-sand px-3 py-2.5 text-xs font-bold tracking-widest text-brand-navy uppercase transition-colors hover:bg-brand-navy hover:text-white md:w-auto" class="flex w-full items-center justify-center gap-2 border border-brand-sand px-3 py-2.5 text-xs font-bold tracking-widest text-brand-navy uppercase transition-colors hover:bg-brand-navy hover:text-white md:w-auto {senderId &&
receiverId
? ''
: 'invisible'}"
title={m.conv_swap_btn()} title={m.conv_swap_btn()}
> >
<svg <svg
@@ -116,7 +120,6 @@ const enrichedDocuments = $derived(
<span class="md:hidden">{m.conv_swap_btn()}</span> <span class="md:hidden">{m.conv_swap_btn()}</span>
</button> </button>
</div> </div>
{/if}
<!-- Receiver --> <!-- Receiver -->
<div <div

View File

@@ -51,9 +51,10 @@ describe('Conversations page empty state', () => {
await expect.element(page.getByText(/Wählen Sie zwei Personen aus/i)).toBeInTheDocument(); await expect.element(page.getByText(/Wählen Sie zwei Personen aus/i)).toBeInTheDocument();
}); });
it('does not show the swap button when no persons are selected', async () => { it('hides the swap button when no persons are selected', async () => {
render(Page, { data: baseData }); render(Page, { data: baseData });
await expect.element(page.getByTestId('conv-swap-btn')).not.toBeInTheDocument(); // Button is always in the DOM (holds grid column width on desktop) but made invisible
await expect.element(page.getByTestId('conv-swap-btn')).toHaveClass('invisible');
}); });
it('does not show the new document link when no persons are selected', async () => { it('does not show the new document link when no persons are selected', async () => {
@@ -76,7 +77,7 @@ describe('Conversations page no results', () => {
describe('Conversations page swap button', () => { describe('Conversations page swap button', () => {
it('shows the swap button when both persons are selected', async () => { it('shows the swap button when both persons are selected', async () => {
render(Page, { data: withPersons }); render(Page, { data: withPersons });
await expect.element(page.getByTestId('conv-swap-btn')).toBeInTheDocument(); await expect.element(page.getByTestId('conv-swap-btn')).not.toHaveClass('invisible');
}); });
it('calls goto with swapped sender and receiver when clicked', async () => { it('calls goto with swapped sender and receiver when clicked', async () => {