Compare commits
7 Commits
0bd7a70c96
...
f8d888a5be
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f8d888a5be | ||
|
|
29f0ec8a05 | ||
|
|
5db17880f9 | ||
|
|
ce02c1bf39 | ||
|
|
e1c09ddc7f | ||
|
|
93408c5825 | ||
|
|
2a2ce240e1 |
@@ -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" />
|
||||
|
||||
@@ -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}
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user