Compare commits

...

7 Commits

Author SHA1 Message Date
Marcel
f8d888a5be fix(#103): move language switcher from header into mobile nav drawer
Some checks failed
CI / Unit & Component Tests (push) Has been cancelled
CI / Backend Unit Tests (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
On mobile the header is now cleaner — language buttons move to the
bottom of the hamburger panel. Desktop header is unchanged (sm:flex).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 16:41:51 +01:00
Marcel
29f0ec8a05 fix(#102): replace native file input in edit form with styled upload zone
Matches the FileSectionNew design: upload arrow icon, hidden <input>,
styled label as the click target, shows selected filename on pick.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 16:40:23 +01:00
Marcel
5db17880f9 fix(#101): stop bottom panel from overlapping document viewer
Replaced position:fixed on the bottom panel with shrink-0 flex child,
so the viewer (flex-1) naturally stops at the panel top instead of
extending behind it.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 16:38:47 +01:00
Marcel
ce02c1bf39 fix(#100): hide action button labels on mobile to prevent toolbar overflow
At 320px, showing "Annotieren" + "Bearbeiten" + download pushed the
toolbar past its bounds. Icon-only at mobile, labels revealed at sm:.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 16:36:15 +01:00
Marcel
e1c09ddc7f fix(#99): make document detail tab bar scrollable on narrow screens
Wrap tabs in overflow-x-auto container with hidden scrollbar so all 4
German labels ("Transkription" etc.) are reachable at 320px. Close
button stays pinned outside the scroll area, always visible.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 16:33:47 +01:00
Marcel
93408c5825 fix(#98): make drop zone border and card borders visible in dark mode
- DropZone: raise border opacity from /20 to /30 for dashed drop zone
- layout.css: bump dark mode --c-line from #2e2e2e to #3d3d3d (was
  ~1.3:1 contrast on #1a1a1a surface, effectively invisible)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 16:31:00 +01:00
Marcel
2a2ce240e1 fix(#97): add px-4 base padding to person directory on mobile
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 16:28:31 +01:00
8 changed files with 102 additions and 54 deletions

View File

@@ -107,7 +107,7 @@ function handleCountChange(count: number) {
</script>
<div
class="fixed right-0 bottom-0 left-0 z-30 flex flex-col border-t border-line bg-surface shadow-[0_-4px_16px_rgba(0,0,0,0.08)]"
class="z-30 flex shrink-0 flex-col border-t border-line bg-surface shadow-[0_-4px_16px_rgba(0,0,0,0.08)]"
style="height: {panelHeight}px"
data-testid="bottom-panel"
>
@@ -127,35 +127,37 @@ function handleCountChange(count: number) {
</div>
<!-- Tab bar -->
<div class="flex shrink-0 items-center border-b border-line bg-surface px-4">
{#each tabs as tab (tab.id)}
<button
onclick={() => openTab(tab.id)}
class="mr-1 px-3 py-2.5 font-sans text-xs font-medium transition-colors {activeTab === tab.id && open
? 'border-b-2 border-primary text-ink'
: 'text-ink-3 hover:text-ink'}"
aria-pressed={activeTab === tab.id && open}
>
{tab.label()}
{#if tab.id === 'discussion'}
<span
data-testid="discussion-count-badge"
class="ml-1.5 inline-flex h-4 min-w-4 items-center justify-center rounded-full bg-primary px-1 font-sans text-[10px] font-bold text-primary-fg"
>{discussionCount}</span
>
{/if}
</button>
{/each}
<!-- spacer -->
<div class="flex-1"></div>
<div class="flex shrink-0 items-center border-b border-line bg-surface">
<!-- Scrollable tabs area — hides scrollbar visually -->
<div
class="flex flex-1 items-center overflow-x-auto px-2 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden"
>
{#each tabs as tab (tab.id)}
<button
onclick={() => openTab(tab.id)}
class="mr-1 shrink-0 px-3 py-2.5 font-sans text-xs font-medium transition-colors {activeTab === tab.id && open
? 'border-b-2 border-primary text-ink'
: 'text-ink-3 hover:text-ink'}"
aria-pressed={activeTab === tab.id && open}
>
{tab.label()}
{#if tab.id === 'discussion'}
<span
data-testid="discussion-count-badge"
class="ml-1.5 inline-flex h-4 min-w-4 items-center justify-center rounded-full bg-primary px-1 font-sans text-[10px] font-bold text-primary-fg"
>{discussionCount}</span
>
{/if}
</button>
{/each}
</div>
{#if open}
<button
onclick={closePanel}
data-testid="panel-close-btn"
aria-label="Panel schließen"
class="rounded p-1.5 text-ink-3 transition-colors hover:bg-muted hover:text-ink"
class="mr-2 shrink-0 rounded p-1.5 text-ink-3 transition-colors hover:bg-muted hover:text-ink"
>
<svg class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />

View File

@@ -58,7 +58,7 @@ const compactMeta = $derived.by(() => {
</script>
<div
class="z-20 flex shrink-0 items-center justify-between border-b border-line bg-surface px-6 py-3 shadow-sm"
class="z-20 flex shrink-0 items-center justify-between border-b border-line bg-surface px-3 py-3 shadow-sm sm:px-6"
data-topbar
>
<!-- Left: back + title -->
@@ -111,13 +111,16 @@ const compactMeta = $derived.by(() => {
aria-hidden="true"
class="h-4 w-4 {annotateMode ? 'invert' : ''}"
/>
{annotateMode ? m.doc_panel_annotate_stop() : m.doc_panel_annotate()}
<span class="hidden sm:inline"
>{annotateMode ? m.doc_panel_annotate_stop() : m.doc_panel_annotate()}</span
>
</button>
{/if}
{#if canWrite}
<a
href="/documents/{doc.id}/edit"
aria-label={m.btn_edit()}
class="flex items-center gap-2 rounded border border-primary bg-transparent px-3 py-1.5 text-xs font-medium text-ink transition hover:bg-primary hover:text-primary-fg"
>
<img
@@ -126,7 +129,7 @@ const compactMeta = $derived.by(() => {
aria-hidden="true"
class="h-4 w-4"
/>
{m.btn_edit()}
<span class="hidden sm:inline">{m.btn_edit()}</span>
</a>
{/if}

View File

@@ -46,8 +46,8 @@ const userInitials = $derived.by(() => {
<!-- Right Side -->
<div class="flex items-center gap-3">
<!-- Language selector -->
<div class="flex items-center gap-1 border-r border-line pr-3">
<!-- Language selector (desktop only — mobile lives in nav drawer) -->
<div class="hidden items-center gap-1 border-r border-line pr-3 sm:flex">
{#each locales as locale (locale)}
<button
type="button"

View File

@@ -2,9 +2,14 @@
import { page } from '$app/state';
import { untrack } from 'svelte';
import { m } from '$lib/paraglide/messages.js';
import { setLocale, getLocale } from '$lib/paraglide/runtime';
let { isAdmin = false }: { isAdmin?: boolean } = $props();
const locales = ['DE', 'EN', 'ES'] as const;
const localeMap = { DE: 'de', EN: 'en', ES: 'es' } as const;
const activeLocale = $derived(getLocale().toUpperCase());
let mobileNavOpen = $state(false);
$effect(() => {
@@ -180,6 +185,22 @@ function handleOverlayKeydown(event: KeyboardEvent) {
{m.nav_admin()}
</a>
{/if}
<!-- Language switcher -->
<div class="flex items-center gap-2 border-t border-line px-4 py-3">
{#each locales as locale (locale)}
<button
type="button"
onclick={() => setLocale(localeMap[locale])}
class="min-h-[44px] px-3 font-sans text-sm tracking-widest transition-colors
{activeLocale === locale
? 'font-bold text-ink'
: 'font-normal text-ink-3 hover:text-ink'}"
>
{locale}
</button>
{/each}
</div>
</nav>
</div>
</div>

View File

@@ -146,7 +146,7 @@ $effect(() => {
? 'border-primary bg-accent-bg py-10 text-primary'
: windowDragging
? 'border-primary/60 bg-accent-bg/50 py-10 text-primary/80'
: 'border-ink/20 py-6 text-ink-3 hover:border-primary hover:text-primary'}"
: 'border-ink/30 py-6 text-ink-3 hover:border-primary hover:text-primary'}"
ondragover={handleDragOver}
ondragleave={handleDragLeave}
ondrop={handleDrop}

View File

@@ -2,14 +2,24 @@
import { m } from '$lib/paraglide/messages.js';
let { originalFilename }: { originalFilename: string } = $props();
let selectedFilename = $state<string | null>(null);
function handleFileChange(e: Event) {
const file = (e.target as HTMLInputElement).files?.[0];
selectedFilename = file?.name ?? null;
}
</script>
<div class="rounded-sm border border-line bg-surface p-6 shadow-sm">
<h2 class="mb-5 text-xs font-bold tracking-widest text-ink-3 uppercase">
{m.doc_section_file()}
</h2>
<div class="rounded-sm border border-line bg-surface shadow-sm">
<div class="border-b border-line px-6 py-4">
<h2 class="text-xs font-bold tracking-widest text-ink-3 uppercase">
{m.doc_section_file()}
</h2>
</div>
<div class="mb-4 flex items-center gap-3 rounded bg-muted px-3 py-2 text-sm text-ink-2">
<!-- Current file -->
<div class="flex items-center gap-3 border-b border-line px-6 py-3 text-sm text-ink-2">
<img
src="/degruyter-icons/Simple/Medium-24px/SVG/Action/PDF-Document-MD.svg"
alt=""
@@ -22,19 +32,31 @@ let { originalFilename }: { originalFilename: string } = $props();
>
</div>
<label for="file-upload" class="mb-1 block text-sm font-medium text-ink-2">
{m.doc_file_replace_label()}
<span class="font-normal text-ink-3">({m.doc_file_replace_note()})</span>
<!-- Replace file upload zone -->
<label
for="file-upload"
class="flex cursor-pointer flex-col items-center gap-3 px-6 py-8 transition-colors hover:bg-muted/40"
>
<svg
class="h-8 w-8 text-ink-3"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
aria-hidden="true"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="1.5"
d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12"
/>
</svg>
{#if selectedFilename}
<span class="text-sm font-medium text-ink">{selectedFilename}</span>
{:else}
<span class="text-sm font-medium text-ink-2">{m.doc_file_replace_label()}</span>
<span class="text-xs text-ink-3">{m.doc_file_replace_note()}</span>
{/if}
</label>
<input
id="file-upload"
type="file"
name="file"
class="block w-full cursor-pointer text-sm
text-ink-2 file:mr-4 file:rounded
file:border-0 file:bg-muted
file:px-4 file:py-2
file:text-sm file:font-semibold
file:text-ink hover:file:bg-muted"
/>
<input id="file-upload" type="file" name="file" onchange={handleFileChange} class="sr-only" />
</div>

View File

@@ -96,8 +96,8 @@
--c-overlay: #242424;
--c-muted: #252525;
--c-line: #2e2e2e;
--c-line-2: #222222;
--c-line: #3d3d3d;
--c-line-2: #2e2e2e;
--c-ink: #f0efe9;
--c-ink-2: #9ca3af; /* gray-400 — 7.5:1 on dark surface — WCAG AAA ✓ */
@@ -124,8 +124,8 @@
--c-overlay: #242424;
--c-muted: #252525;
--c-line: #2e2e2e;
--c-line-2: #222222;
--c-line: #3d3d3d;
--c-line-2: #2e2e2e;
--c-ink: #f0efe9;
--c-ink-2: #9ca3af;

View File

@@ -23,7 +23,7 @@ function handleSearch() {
}
</script>
<div class="mx-auto max-w-7xl py-12 sm:px-6 lg:px-8">
<div class="mx-auto max-w-7xl px-4 py-12 sm:px-6 lg:px-8">
<!-- Header Area -->
<div
class="mb-10 flex flex-col justify-between gap-6 border-b border-ink/10 pb-6 md:flex-row md:items-end"