diff --git a/frontend/src/lib/document/DocumentTopBarActions.svelte b/frontend/src/lib/document/DocumentTopBarActions.svelte
new file mode 100644
index 00000000..6e34eada
--- /dev/null
+++ b/frontend/src/lib/document/DocumentTopBarActions.svelte
@@ -0,0 +1,103 @@
+
+
+{#if canWrite && isPdf && !transcribeMode}
+
+{/if}
+
+{#if transcribeMode}
+
+{/if}
+
+{#if canWrite && !transcribeMode}
+
+
+ {m.btn_edit()}
+
+{/if}
+
+{#if filePath && !transcribeMode}
+
+
+
+{/if}
diff --git a/frontend/src/lib/document/DocumentTopBarActions.svelte.test.ts b/frontend/src/lib/document/DocumentTopBarActions.svelte.test.ts
new file mode 100644
index 00000000..280a3245
--- /dev/null
+++ b/frontend/src/lib/document/DocumentTopBarActions.svelte.test.ts
@@ -0,0 +1,94 @@
+import { describe, it, expect, afterEach } from 'vitest';
+import { cleanup, render } from 'vitest-browser-svelte';
+import { page } from 'vitest/browser';
+import DocumentTopBarActions from './DocumentTopBarActions.svelte';
+
+afterEach(cleanup);
+
+const baseProps = {
+ documentId: 'd1',
+ canWrite: false,
+ isPdf: false,
+ transcribeMode: false,
+ filePath: null as string | null,
+ originalFilename: 'brief.pdf' as string | null,
+ fileUrl: ''
+};
+
+describe('DocumentTopBarActions', () => {
+ it('renders nothing visible when canWrite is false and no file is present', async () => {
+ render(DocumentTopBarActions, { props: baseProps });
+
+ await expect
+ .element(page.getByRole('button', { name: /transkribieren/i }))
+ .not.toBeInTheDocument();
+ await expect.element(page.getByRole('link', { name: /bearbeiten/i })).not.toBeInTheDocument();
+ await expect.element(page.getByTitle('Herunterladen')).not.toBeInTheDocument();
+ });
+
+ it('renders the transcribe button when canWrite, isPdf, and not transcribing', async () => {
+ render(DocumentTopBarActions, {
+ props: { ...baseProps, canWrite: true, isPdf: true, filePath: 'docs/x.pdf' }
+ });
+
+ await expect.element(page.getByRole('button', { name: /transkribieren/i })).toBeVisible();
+ });
+
+ it('omits the transcribe button when not a PDF', async () => {
+ render(DocumentTopBarActions, {
+ props: { ...baseProps, canWrite: true, isPdf: false, filePath: 'docs/x.jpg' }
+ });
+
+ await expect
+ .element(page.getByRole('button', { name: /transkribieren/i }))
+ .not.toBeInTheDocument();
+ });
+
+ it('renders the stop-transcribe button when transcribeMode is true', async () => {
+ render(DocumentTopBarActions, {
+ props: {
+ ...baseProps,
+ canWrite: true,
+ isPdf: true,
+ transcribeMode: true,
+ filePath: 'docs/x.pdf'
+ }
+ });
+
+ await expect.element(page.getByRole('button', { name: /fertig/i })).toBeVisible();
+ });
+
+ it('renders the edit link to the document edit route when canWrite and not transcribing', async () => {
+ render(DocumentTopBarActions, {
+ props: { ...baseProps, canWrite: true, documentId: 'doc-42' }
+ });
+
+ await expect
+ .element(page.getByRole('link', { name: /bearbeiten/i }))
+ .toHaveAttribute('href', '/documents/doc-42/edit');
+ });
+
+ it('hides the edit link when transcribeMode is true', async () => {
+ render(DocumentTopBarActions, {
+ props: { ...baseProps, canWrite: true, transcribeMode: true }
+ });
+
+ await expect.element(page.getByRole('link', { name: /bearbeiten/i })).not.toBeInTheDocument();
+ });
+
+ it('renders the download link when filePath is set and not in transcribe mode', async () => {
+ render(DocumentTopBarActions, {
+ props: { ...baseProps, filePath: 'docs/x.pdf', fileUrl: '/api/docs/x' }
+ });
+
+ await expect.element(page.getByTitle('Herunterladen')).toBeVisible();
+ });
+
+ it('hides the download link when transcribeMode is true', async () => {
+ render(DocumentTopBarActions, {
+ props: { ...baseProps, filePath: 'docs/x.pdf', fileUrl: '/api/docs/x', transcribeMode: true }
+ });
+
+ await expect.element(page.getByTitle('Herunterladen')).not.toBeInTheDocument();
+ });
+});