feat(dashboard): Classic Split — 2-col layout, remove DashboardMentions widget
Some checks failed
CI / Unit & Component Tests (pull_request) Has been cancelled
CI / Backend Unit Tests (pull_request) Has been cancelled
CI / E2E Tests (pull_request) Has been cancelled
CI / Unit & Component Tests (push) Has been cancelled
CI / Backend Unit Tests (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled

Restructures the dashboard to a lg:grid-cols-[1fr_300px] split:
- Left column: DashboardRecentDocuments (with stats footnote)
- Right column: DropZone (canWrite) + DashboardNeedsMetadata (flex-1)

Adds showRightColumn guard (canWrite || incompleteDocs.length > 0) so
read-only users with a complete archive never see an empty 300px ghost
column. DashboardMentions is removed from the page; the file is kept.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-03-31 19:36:36 +02:00
parent f618364632
commit 92e7aa127c
2 changed files with 62 additions and 14 deletions

View File

@@ -6,7 +6,6 @@ import SearchFilterBar from './SearchFilterBar.svelte';
import DropZone from './DropZone.svelte';
import DocumentList from './DocumentList.svelte';
import DashboardResumeStrip from '$lib/components/DashboardResumeStrip.svelte';
import DashboardMentions from '$lib/components/DashboardMentions.svelte';
import DashboardNeedsMetadata from '$lib/components/DashboardNeedsMetadata.svelte';
import DashboardRecentDocuments from '$lib/components/DashboardRecentDocuments.svelte';
import { m } from '$lib/paraglide/messages.js';
@@ -69,6 +68,11 @@ $effect(() => {
tagNames = data.filters?.tags || [];
if (hasAdvancedFilters(data.filters)) showAdvanced = true;
});
// Right column is only rendered when there is something to show.
// Omitting it prevents an empty 300px ghost column for read-only users
// with a complete archive.
const showRightColumn = $derived(data.canWrite || (data.incompleteDocs?.length ?? 0) > 0);
</script>
<svelte:head>
@@ -94,20 +98,24 @@ $effect(() => {
{#if data.isDashboard}
<DashboardResumeStrip />
{#if data.canWrite}
<div class="mt-4">
<DropZone />
</div>
{/if}
<!-- Classic Split: left column (recent docs) + right column (upload + metadata queue) -->
<!-- No items-start — CSS Grid stretch default makes both columns equal height -->
<div class="mt-4 grid grid-cols-1 gap-4 {showRightColumn ? 'lg:grid-cols-[1fr_300px]' : ''}">
<DashboardRecentDocuments recentDocs={data.recentDocs ?? []} stats={data.stats} />
<div
class="mt-6 grid gap-4 {(data.mentions?.length ?? 0) > 0 && (data.incompleteDocs?.length ?? 0) > 0 ? 'lg:grid-cols-2' : ''}"
>
<DashboardMentions mentions={data.mentions ?? []} />
<DashboardNeedsMetadata incompleteDocs={data.incompleteDocs ?? []} />
</div>
<div class="mt-4">
<DashboardRecentDocuments recentDocs={data.recentDocs ?? []} />
{#if showRightColumn}
<div data-testid="dashboard-right-column" class="flex h-full flex-col gap-4">
{#if data.canWrite}
<DropZone />
{/if}
<!-- flex-1 + min-h-0 fills remaining height after DropZone.
min-h-0 overrides the default min-height:auto that prevents flex
children from shrinking below their content size. -->
<div class="flex min-h-0 flex-1 flex-col">
<DashboardNeedsMetadata incompleteDocs={data.incompleteDocs ?? []} />
</div>
</div>
{/if}
</div>
{:else}
<DocumentList documents={data.documents ?? []} canWrite={data.canWrite} error={data.error} />

View File

@@ -21,8 +21,12 @@ const emptyData = {
user: undefined,
canWrite: true,
canAnnotate: false,
isDashboard: false,
filters: { q: '', from: '', to: '', senderId: '', receiverId: '', tags: [] },
documents: [],
incompleteDocs: [],
recentDocs: [],
stats: null,
incompleteCount: 0,
initialValues: { senderName: '', receiverName: '' },
error: null
@@ -189,6 +193,42 @@ describe('Home page search input keystroke preservation', () => {
});
});
// ─── Dashboard mode ───────────────────────────────────────────────────────────
describe('Home page dashboard mode', () => {
const dashboardData = {
...emptyData,
isDashboard: true,
canWrite: false,
incompleteDocs: [],
recentDocs: []
};
it('hides the right column when canWrite is false and incompleteDocs is empty', async () => {
render(Page, { data: dashboardData });
const rightCol = page.getByTestId('dashboard-right-column');
await expect.element(rightCol).not.toBeInTheDocument();
});
it('shows the right column when canWrite is true', async () => {
render(Page, { data: { ...dashboardData, canWrite: true } });
const rightCol = page.getByTestId('dashboard-right-column');
await expect.element(rightCol).toBeInTheDocument();
});
it('shows the right column when incompleteDocs is non-empty', async () => {
render(Page, {
data: {
...dashboardData,
canWrite: false,
incompleteDocs: [{ id: 'd1', title: 'Taufschein' }]
}
});
const rightCol = page.getByTestId('dashboard-right-column');
await expect.element(rightCol).toBeInTheDocument();
});
});
// ─── Error state ──────────────────────────────────────────────────────────────
describe('Home page error state', () => {