feat(ui): show read-only transcription header without an edit tab (#697)
TranscriptionPanelHeader gains a canEdit prop (default true). Editors keep the Lesen/Bearbeiten segmented toggle; read-only users get a plain "Transkription" heading instead of a lone single-option pill, while the "N Abschnitte" status line stays visible. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -8,11 +8,20 @@ type Props = {
|
||||
hasBlocks: boolean;
|
||||
blockCount: number;
|
||||
lastEditedAt: string | null;
|
||||
canEdit?: boolean;
|
||||
onModeChange: (mode: 'read' | 'edit') => void;
|
||||
onClose: () => void;
|
||||
};
|
||||
|
||||
let { mode, hasBlocks, blockCount, lastEditedAt, onModeChange, onClose }: Props = $props();
|
||||
let {
|
||||
mode,
|
||||
hasBlocks,
|
||||
blockCount,
|
||||
lastEditedAt,
|
||||
canEdit = true,
|
||||
onModeChange,
|
||||
onClose
|
||||
}: Props = $props();
|
||||
|
||||
const formattedDate = $derived(
|
||||
lastEditedAt
|
||||
@@ -34,37 +43,41 @@ function handleReadClick() {
|
||||
<div
|
||||
class="flex h-[44px] items-center justify-between border-b border-line bg-surface px-3 font-sans"
|
||||
>
|
||||
<!-- Segmented toggle + help chip -->
|
||||
<div class="flex items-center gap-1.5">
|
||||
<div class="flex h-9 items-center rounded-full border border-line bg-muted p-0.5 md:h-7">
|
||||
<button
|
||||
type="button"
|
||||
data-testid="mode-read"
|
||||
aria-disabled={!hasBlocks}
|
||||
onclick={handleReadClick}
|
||||
class="h-full rounded-full px-3 text-xs font-semibold transition-colors {mode === 'read'
|
||||
? 'bg-primary text-primary-fg'
|
||||
: 'text-ink-2 hover:text-ink'}"
|
||||
style:opacity={!hasBlocks ? '0.35' : undefined}
|
||||
>
|
||||
{m.mode_read()}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
data-testid="mode-edit"
|
||||
onclick={() => onModeChange('edit')}
|
||||
class="h-full rounded-full px-3 text-xs font-semibold transition-colors {mode === 'edit'
|
||||
? 'bg-primary text-primary-fg'
|
||||
: 'text-ink-2 hover:text-ink'}"
|
||||
>
|
||||
<span class="md:hidden">{m.mode_edit_short()}</span>
|
||||
<span class="hidden md:inline">{m.mode_edit()}</span>
|
||||
</button>
|
||||
<!-- Segmented toggle + help chip for editors; plain title for read-only users -->
|
||||
{#if canEdit}
|
||||
<div class="flex items-center gap-1.5">
|
||||
<div class="flex h-9 items-center rounded-full border border-line bg-muted p-0.5 md:h-7">
|
||||
<button
|
||||
type="button"
|
||||
data-testid="mode-read"
|
||||
aria-disabled={!hasBlocks}
|
||||
onclick={handleReadClick}
|
||||
class="h-full rounded-full px-3 text-xs font-semibold transition-colors {mode === 'read'
|
||||
? 'bg-primary text-primary-fg'
|
||||
: 'text-ink-2 hover:text-ink'}"
|
||||
style:opacity={!hasBlocks ? '0.35' : undefined}
|
||||
>
|
||||
{m.mode_read()}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
data-testid="mode-edit"
|
||||
onclick={() => onModeChange('edit')}
|
||||
class="h-full rounded-full px-3 text-xs font-semibold transition-colors {mode === 'edit'
|
||||
? 'bg-primary text-primary-fg'
|
||||
: 'text-ink-2 hover:text-ink'}"
|
||||
>
|
||||
<span class="md:hidden">{m.mode_edit_short()}</span>
|
||||
<span class="hidden md:inline">{m.mode_edit()}</span>
|
||||
</button>
|
||||
</div>
|
||||
<HelpPopover label={m.transcription_mode_help_label()}>
|
||||
<p class="text-xs leading-relaxed">{m.transcription_mode_help_body()}</p>
|
||||
</HelpPopover>
|
||||
</div>
|
||||
<HelpPopover label={m.transcription_mode_help_label()}>
|
||||
<p class="text-xs leading-relaxed">{m.transcription_mode_help_body()}</p>
|
||||
</HelpPopover>
|
||||
</div>
|
||||
{:else}
|
||||
<h2 class="text-[16px] font-semibold text-ink">{m.transcription_panel_title()}</h2>
|
||||
{/if}
|
||||
|
||||
<!-- Status line (hidden on mobile to save space) -->
|
||||
<p class="hidden text-xs text-ink-2 md:block">
|
||||
|
||||
@@ -22,6 +22,27 @@ describe('TranscriptionPanelHeader', () => {
|
||||
await expect.element(page.getByRole('button', { name: /bearbeiten/i })).toBeVisible();
|
||||
});
|
||||
|
||||
it('renders both tabs when canEdit is true', async () => {
|
||||
render(TranscriptionPanelHeader, { ...baseProps, canEdit: true });
|
||||
|
||||
await expect.element(page.getByTestId('mode-read')).toBeInTheDocument();
|
||||
await expect.element(page.getByTestId('mode-edit')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('hides the edit tab and shows a plain title when canEdit is false', async () => {
|
||||
render(TranscriptionPanelHeader, { ...baseProps, canEdit: false });
|
||||
|
||||
await expect.element(page.getByTestId('mode-edit')).not.toBeInTheDocument();
|
||||
await expect.element(page.getByTestId('mode-read')).not.toBeInTheDocument();
|
||||
await expect.element(page.getByRole('heading', { name: /^transkription$/i })).toBeVisible();
|
||||
});
|
||||
|
||||
it('keeps the section status line visible for readers (canEdit false)', async () => {
|
||||
render(TranscriptionPanelHeader, { ...baseProps, canEdit: false, blockCount: 3 });
|
||||
|
||||
await expect.element(page.getByText('3 Abschnitte')).toBeVisible();
|
||||
});
|
||||
|
||||
it('marks the Lesen button as aria-disabled when hasBlocks is false', async () => {
|
||||
render(TranscriptionPanelHeader, {
|
||||
...baseProps,
|
||||
|
||||
Reference in New Issue
Block a user