mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 20:01:09 +02:00
i18n(website): wire components + views to namespace — 68 strings cleared
Patches ListView, EditorView, SubmissionsView, BlockInspector,
ImageInspector, GalleryInspector, InsertPalette, PageList,
PublishBar, RollbackDialog, SiteSettingsDialog, DomainsSection,
TemplatePicker. Locale JSONs landed in 9e9f5ce64.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
9e9f5ce641
commit
6d1546975f
14 changed files with 223 additions and 164 deletions
|
|
@ -1,4 +1,5 @@
|
|||
<script lang="ts">
|
||||
import { _ } from 'svelte-i18n';
|
||||
import { formatDate } from '$lib/i18n/format';
|
||||
import { useAllSites } from './queries';
|
||||
|
||||
|
|
@ -8,12 +9,12 @@
|
|||
const now = Date.now();
|
||||
const then = new Date(iso).getTime();
|
||||
const diffMin = Math.floor((now - then) / 60_000);
|
||||
if (diffMin < 1) return 'gerade eben';
|
||||
if (diffMin < 60) return `vor ${diffMin} Min`;
|
||||
if (diffMin < 1) return $_('website.list_view.relative_just_now');
|
||||
if (diffMin < 60) return $_('website.list_view.relative_minutes', { values: { n: diffMin } });
|
||||
const diffH = Math.floor(diffMin / 60);
|
||||
if (diffH < 24) return `vor ${diffH} Std`;
|
||||
if (diffH < 24) return $_('website.list_view.relative_hours', { values: { n: diffH } });
|
||||
const diffD = Math.floor(diffH / 24);
|
||||
if (diffD < 30) return `vor ${diffD} Tg`;
|
||||
if (diffD < 30) return $_('website.list_view.relative_days', { values: { n: diffD } });
|
||||
return formatDate(new Date(iso));
|
||||
}
|
||||
</script>
|
||||
|
|
@ -21,18 +22,18 @@
|
|||
<div class="wb-list">
|
||||
<header class="wb-list__header">
|
||||
<div>
|
||||
<h2>Deine Websites</h2>
|
||||
<h2>{$_('website.list_view.heading')}</h2>
|
||||
<p class="wb-list__hint">
|
||||
Block-Editor, veröffentlichen unter <code>mana.how</code>.
|
||||
{$_('website.list_view.hint_prefix')} <code>mana.how</code>.
|
||||
</p>
|
||||
</div>
|
||||
<a class="wb-list__new" href="/website/new">+ Neue Website</a>
|
||||
<a class="wb-list__new" href="/website/new">{$_('website.list_view.action_new')}</a>
|
||||
</header>
|
||||
|
||||
{#if sites.value.length === 0}
|
||||
<div class="wb-list__empty">
|
||||
<p>Noch keine Website. Wähl ein Template oder starte blank.</p>
|
||||
<a class="wb-list__new" href="/website/new">+ Neue Website</a>
|
||||
<p>{$_('website.list_view.empty_text')}</p>
|
||||
<a class="wb-list__new" href="/website/new">{$_('website.list_view.action_new')}</a>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="wb-list__grid">
|
||||
|
|
@ -48,7 +49,9 @@
|
|||
class:wb-pill--green={site.publishedVersion}
|
||||
class:wb-pill--amber={!site.publishedVersion}
|
||||
>
|
||||
{site.publishedVersion ? 'Veröffentlicht' : 'Entwurf'}
|
||||
{site.publishedVersion
|
||||
? $_('website.list_view.status_published')
|
||||
: $_('website.list_view.status_draft')}
|
||||
</span>
|
||||
<span class="wb-card__time">{formatRelative(site.updatedAt)}</span>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<script lang="ts">
|
||||
import type { Component } from 'svelte';
|
||||
import { _ } from 'svelte-i18n';
|
||||
import { getBlockSpec, type Block, type BlockInspectorProps } from '@mana/website-blocks';
|
||||
import { blocksStore, InvalidBlockPropsError } from '../stores/blocks.svelte';
|
||||
import { getEditorHistoryContext } from '../history.svelte';
|
||||
|
|
@ -57,7 +58,7 @@
|
|||
else await blocksStore.updateBlockProps(block.id, p);
|
||||
} catch (err) {
|
||||
if (err instanceof InvalidBlockPropsError) {
|
||||
lastError = `Validation failed: ${err.message}`;
|
||||
lastError = `${$_('website.block_inspector.err_validation_prefix')} ${err.message}`;
|
||||
} else {
|
||||
lastError = err instanceof Error ? err.message : String(err);
|
||||
}
|
||||
|
|
@ -65,7 +66,7 @@
|
|||
}
|
||||
|
||||
async function onDelete() {
|
||||
if (!confirm('Diesen Block löschen?')) return;
|
||||
if (!confirm($_('website.block_inspector.confirm_delete'))) return;
|
||||
if (history) await history.deleteBlock(block.id);
|
||||
else await blocksStore.deleteBlock(block.id);
|
||||
onDeleted?.();
|
||||
|
|
@ -108,8 +109,8 @@
|
|||
class="wb-inspector__action"
|
||||
onclick={onMoveUp}
|
||||
disabled={!canMoveUp}
|
||||
title="Nach oben verschieben"
|
||||
aria-label="Nach oben verschieben"
|
||||
title={$_('website.block_inspector.action_move_up')}
|
||||
aria-label={$_('website.block_inspector.action_move_up')}
|
||||
>
|
||||
↑
|
||||
</button>
|
||||
|
|
@ -117,16 +118,16 @@
|
|||
class="wb-inspector__action"
|
||||
onclick={onMoveDown}
|
||||
disabled={!canMoveDown}
|
||||
title="Nach unten verschieben"
|
||||
aria-label="Nach unten verschieben"
|
||||
title={$_('website.block_inspector.action_move_down')}
|
||||
aria-label={$_('website.block_inspector.action_move_down')}
|
||||
>
|
||||
↓
|
||||
</button>
|
||||
<button
|
||||
class="wb-inspector__action wb-inspector__action--delete"
|
||||
onclick={onDelete}
|
||||
title="Block löschen"
|
||||
aria-label="Block löschen"
|
||||
title={$_('website.block_inspector.action_delete')}
|
||||
aria-label={$_('website.block_inspector.action_delete')}
|
||||
>
|
||||
×
|
||||
</button>
|
||||
|
|
@ -145,7 +146,9 @@
|
|||
<p class="wb-inspector__error">{lastError}</p>
|
||||
{/if}
|
||||
{:else}
|
||||
<p class="wb-inspector__empty">Unbekannter Block-Typ: {block.type}</p>
|
||||
<p class="wb-inspector__empty">
|
||||
{$_('website.block_inspector.unknown_type', { values: { type: block.type } })}
|
||||
</p>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
<script lang="ts">
|
||||
import { _ } from 'svelte-i18n';
|
||||
import {
|
||||
listDomains,
|
||||
addDomain,
|
||||
|
|
@ -42,7 +43,7 @@
|
|||
async function onAdd() {
|
||||
const host = newHost.trim().toLowerCase();
|
||||
if (!host) {
|
||||
addError = 'Hostname erforderlich';
|
||||
addError = $_('website.domains.err_host_required');
|
||||
return;
|
||||
}
|
||||
adding = true;
|
||||
|
|
@ -70,7 +71,7 @@
|
|||
}
|
||||
|
||||
async function onRemove(domainId: string, hostname: string) {
|
||||
if (!confirm(`Domain "${hostname}" entfernen?`)) return;
|
||||
if (!confirm($_('website.domains.confirm_remove', { values: { host: hostname } }))) return;
|
||||
await removeDomain(siteId, domainId);
|
||||
await load();
|
||||
}
|
||||
|
|
@ -82,10 +83,11 @@
|
|||
|
||||
<section class="wb-domains" aria-labelledby="wb-domains-title">
|
||||
<header>
|
||||
<h3 id="wb-domains-title">Eigene Domain</h3>
|
||||
<h3 id="wb-domains-title">{$_('website.domains.heading')}</h3>
|
||||
<p class="wb-domains__hint">
|
||||
Verbinde einen eigenen Hostnamen (z.B. <code>meineseite.de</code>) mit dieser Website. Nur für
|
||||
Founder-Tier.
|
||||
{$_('website.domains.hint_prefix')} <code>meineseite.de</code>{$_(
|
||||
'website.domains.hint_suffix'
|
||||
)}
|
||||
</p>
|
||||
</header>
|
||||
|
||||
|
|
@ -102,12 +104,12 @@
|
|||
>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="z.B. portfolio.deinedomain.de"
|
||||
placeholder={$_('website.domains.placeholder_new')}
|
||||
value={newHost}
|
||||
oninput={(e) => (newHost = e.currentTarget.value)}
|
||||
/>
|
||||
<button class="wb-btn wb-btn--primary" disabled={adding || !newHost.trim()}>
|
||||
{adding ? 'Füge hinzu…' : '+ Domain'}
|
||||
{adding ? $_('website.domains.action_adding') : $_('website.domains.action_add')}
|
||||
</button>
|
||||
</form>
|
||||
|
||||
|
|
@ -116,9 +118,9 @@
|
|||
{/if}
|
||||
|
||||
{#if domains === null}
|
||||
<p class="wb-domains__empty">Lade…</p>
|
||||
<p class="wb-domains__empty">{$_('website.domains.loading')}</p>
|
||||
{:else if domains.length === 0}
|
||||
<p class="wb-domains__empty">Noch keine eigenen Domains verbunden.</p>
|
||||
<p class="wb-domains__empty">{$_('website.domains.empty')}</p>
|
||||
{:else}
|
||||
<ul class="wb-domains__list">
|
||||
{#each domains as d (d.id)}
|
||||
|
|
@ -135,13 +137,15 @@
|
|||
onclick={() => onVerify(d.id)}
|
||||
disabled={verifyingId === d.id}
|
||||
>
|
||||
{verifyingId === d.id ? 'Prüfe…' : 'Verify'}
|
||||
{verifyingId === d.id
|
||||
? $_('website.domains.action_verifying')
|
||||
: $_('website.domains.action_verify')}
|
||||
</button>
|
||||
{/if}
|
||||
<button
|
||||
class="wb-btn wb-btn--icon wb-btn--danger"
|
||||
onclick={() => onRemove(d.id, d.hostname)}
|
||||
title="Entfernen">×</button
|
||||
title={$_('website.domains.action_remove_title')}>×</button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -152,7 +156,7 @@
|
|||
|
||||
{#if d.status !== 'verified'}
|
||||
<div class="wb-domain__dns">
|
||||
<p class="wb-domain__dns-title">DNS konfigurieren:</p>
|
||||
<p class="wb-domain__dns-title">{$_('website.domains.dns_section_title')}</p>
|
||||
<div class="wb-dns-row">
|
||||
<div>
|
||||
<span class="wb-dns-type">CNAME</span>
|
||||
|
|
@ -160,7 +164,7 @@
|
|||
</div>
|
||||
<button class="wb-dns-val" onclick={() => copyToClipboard(d.dnsTarget)}>
|
||||
{d.dnsTarget}
|
||||
<small>Klick zum Kopieren</small>
|
||||
<small>{$_('website.domains.dns_copy_hint')}</small>
|
||||
</button>
|
||||
</div>
|
||||
<div class="wb-dns-row">
|
||||
|
|
@ -170,12 +174,11 @@
|
|||
</div>
|
||||
<button class="wb-dns-val" onclick={() => copyToClipboard(d.verificationToken)}>
|
||||
{d.verificationToken}
|
||||
<small>Klick zum Kopieren</small>
|
||||
<small>{$_('website.domains.dns_copy_hint')}</small>
|
||||
</button>
|
||||
</div>
|
||||
<p class="wb-domain__dns-note">
|
||||
DNS-Änderungen brauchen meist 5–30 Minuten, bis sie weltweit propagiert sind. Danach
|
||||
"Verify" klicken.
|
||||
{$_('website.domains.dns_note')}
|
||||
</p>
|
||||
</div>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
* App-side gallery inspector with multi-image upload via mana-media.
|
||||
* Overrides the URL-only fallback from @mana/website-blocks.
|
||||
*/
|
||||
import { _ } from 'svelte-i18n';
|
||||
import type { BlockInspectorProps } from '@mana/website-blocks';
|
||||
import type { GalleryProps, GalleryImage } from '@mana/website-blocks';
|
||||
import { uploadImage, UploadError } from '../upload';
|
||||
|
|
@ -61,12 +62,12 @@
|
|||
|
||||
<div class="wb-inspector">
|
||||
<label class="wb-field">
|
||||
<span>Überschrift</span>
|
||||
<span>{$_('website.gallery_inspector.label_title')}</span>
|
||||
<input
|
||||
type="text"
|
||||
value={block.props.title}
|
||||
oninput={(e) => onChange({ title: e.currentTarget.value })}
|
||||
placeholder="Optional"
|
||||
placeholder={$_('website.gallery_inspector.placeholder_title')}
|
||||
/>
|
||||
</label>
|
||||
|
||||
|
|
@ -85,9 +86,9 @@
|
|||
}}
|
||||
>
|
||||
{#if uploading}
|
||||
<span>Lade hoch…</span>
|
||||
<span>{$_('website.gallery_inspector.uploading')}</span>
|
||||
{:else}
|
||||
<span>+ Bilder hinzufügen — ziehen oder klicken (mehrere möglich)</span>
|
||||
<span>{$_('website.gallery_inspector.drop_hint')}</span>
|
||||
{/if}
|
||||
</div>
|
||||
<input
|
||||
|
|
@ -105,17 +106,17 @@
|
|||
|
||||
<div class="wb-row">
|
||||
<label class="wb-field">
|
||||
<span>Layout</span>
|
||||
<span>{$_('website.gallery_inspector.label_layout')}</span>
|
||||
<select
|
||||
value={block.props.layout}
|
||||
onchange={(e) => onChange({ layout: e.currentTarget.value as GalleryProps['layout'] })}
|
||||
>
|
||||
<option value="grid">Grid</option>
|
||||
<option value="masonry">Masonry</option>
|
||||
<option value="grid">{$_('website.gallery_inspector.layout_grid')}</option>
|
||||
<option value="masonry">{$_('website.gallery_inspector.layout_masonry')}</option>
|
||||
</select>
|
||||
</label>
|
||||
<label class="wb-field">
|
||||
<span>Spalten</span>
|
||||
<span>{$_('website.gallery_inspector.label_columns')}</span>
|
||||
<select
|
||||
value={String(block.props.columns)}
|
||||
onchange={(e) =>
|
||||
|
|
@ -130,14 +131,14 @@
|
|||
|
||||
<div class="wb-row">
|
||||
<label class="wb-field">
|
||||
<span>Abstand</span>
|
||||
<span>{$_('website.gallery_inspector.label_gap')}</span>
|
||||
<select
|
||||
value={block.props.gap}
|
||||
onchange={(e) => onChange({ gap: e.currentTarget.value as GalleryProps['gap'] })}
|
||||
>
|
||||
<option value="sm">Klein</option>
|
||||
<option value="md">Mittel</option>
|
||||
<option value="lg">Groß</option>
|
||||
<option value="sm">{$_('website.gallery_inspector.gap_sm')}</option>
|
||||
<option value="md">{$_('website.gallery_inspector.gap_md')}</option>
|
||||
<option value="lg">{$_('website.gallery_inspector.gap_lg')}</option>
|
||||
</select>
|
||||
</label>
|
||||
<label class="wb-checkbox">
|
||||
|
|
@ -146,12 +147,16 @@
|
|||
checked={block.props.lightbox}
|
||||
onchange={(e) => onChange({ lightbox: e.currentTarget.checked })}
|
||||
/>
|
||||
<span>Lightbox (Vollbild)</span>
|
||||
<span>{$_('website.gallery_inspector.label_lightbox')}</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="wb-images">
|
||||
<div class="wb-images__head">Bilder ({block.props.images.length})</div>
|
||||
<div class="wb-images__head">
|
||||
{$_('website.gallery_inspector.images_count', {
|
||||
values: { count: block.props.images.length },
|
||||
})}
|
||||
</div>
|
||||
{#each block.props.images as img, i (i)}
|
||||
<div class="wb-image-row">
|
||||
<img src={img.url} alt={img.altText} class="wb-image-row__thumb" />
|
||||
|
|
@ -160,13 +165,13 @@
|
|||
type="text"
|
||||
value={img.altText}
|
||||
oninput={(e) => updateImage(i, { altText: e.currentTarget.value })}
|
||||
placeholder="Alt-Text"
|
||||
placeholder={$_('website.gallery_inspector.placeholder_alt')}
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
value={img.caption}
|
||||
oninput={(e) => updateImage(i, { caption: e.currentTarget.value })}
|
||||
placeholder="Bildunterschrift"
|
||||
placeholder={$_('website.gallery_inspector.placeholder_caption')}
|
||||
/>
|
||||
</div>
|
||||
<div class="wb-image-row__actions">
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
* the URL-only fallback from @mana/website-blocks via the custom
|
||||
* inspector registry (see inspector-overrides.ts).
|
||||
*/
|
||||
import { _ } from 'svelte-i18n';
|
||||
import type { BlockInspectorProps } from '@mana/website-blocks';
|
||||
import type { ImageProps } from '@mana/website-blocks';
|
||||
import { uploadImage, UploadError } from '../upload';
|
||||
|
|
@ -57,12 +58,12 @@
|
|||
}}
|
||||
>
|
||||
{#if uploading}
|
||||
<span class="wb-dropzone__hint">Lade hoch…</span>
|
||||
<span class="wb-dropzone__hint">{$_('website.image_inspector.uploading')}</span>
|
||||
{:else if block.props.url}
|
||||
<img src={block.props.url} alt={block.props.altText} class="wb-dropzone__preview" />
|
||||
<span class="wb-dropzone__hint">Klicken / ziehen, um zu ersetzen</span>
|
||||
<span class="wb-dropzone__hint">{$_('website.image_inspector.replace_hint')}</span>
|
||||
{:else}
|
||||
<span class="wb-dropzone__hint">Bild hier hinziehen oder klicken</span>
|
||||
<span class="wb-dropzone__hint">{$_('website.image_inspector.drop_hint')}</span>
|
||||
{/if}
|
||||
</div>
|
||||
<input
|
||||
|
|
@ -78,7 +79,7 @@
|
|||
{/if}
|
||||
|
||||
<label class="wb-field">
|
||||
<span>Oder URL einsetzen</span>
|
||||
<span>{$_('website.image_inspector.label_url')}</span>
|
||||
<input
|
||||
type="url"
|
||||
value={block.props.url}
|
||||
|
|
@ -88,17 +89,17 @@
|
|||
</label>
|
||||
|
||||
<label class="wb-field">
|
||||
<span>Alt-Text *</span>
|
||||
<span>{$_('website.image_inspector.label_alt')}</span>
|
||||
<input
|
||||
type="text"
|
||||
value={block.props.altText}
|
||||
oninput={(e) => onChange({ altText: e.currentTarget.value })}
|
||||
placeholder="Beschreibung für Screenreader"
|
||||
placeholder={$_('website.image_inspector.placeholder_alt')}
|
||||
/>
|
||||
</label>
|
||||
|
||||
<label class="wb-field">
|
||||
<span>Bildunterschrift</span>
|
||||
<span>{$_('website.image_inspector.label_caption')}</span>
|
||||
<input
|
||||
type="text"
|
||||
value={block.props.caption}
|
||||
|
|
@ -108,13 +109,13 @@
|
|||
|
||||
<div class="wb-row">
|
||||
<label class="wb-field">
|
||||
<span>Seitenverhältnis</span>
|
||||
<span>{$_('website.image_inspector.label_aspect_ratio')}</span>
|
||||
<select
|
||||
value={block.props.aspectRatio}
|
||||
onchange={(e) =>
|
||||
onChange({ aspectRatio: e.currentTarget.value as ImageProps['aspectRatio'] })}
|
||||
>
|
||||
<option value="auto">Auto</option>
|
||||
<option value="auto">{$_('website.image_inspector.aspect_auto')}</option>
|
||||
<option value="21:9">21:9</option>
|
||||
<option value="16:9">16:9</option>
|
||||
<option value="4:3">4:3</option>
|
||||
|
|
@ -123,26 +124,26 @@
|
|||
</label>
|
||||
|
||||
<label class="wb-field">
|
||||
<span>Breite</span>
|
||||
<span>{$_('website.image_inspector.label_width')}</span>
|
||||
<select
|
||||
value={block.props.width}
|
||||
onchange={(e) => onChange({ width: e.currentTarget.value as ImageProps['width'] })}
|
||||
>
|
||||
<option value="narrow">Schmal</option>
|
||||
<option value="container">Container</option>
|
||||
<option value="full">Vollbreit</option>
|
||||
<option value="narrow">{$_('website.image_inspector.width_narrow')}</option>
|
||||
<option value="container">{$_('website.image_inspector.width_container')}</option>
|
||||
<option value="full">{$_('website.image_inspector.width_full')}</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<label class="wb-field">
|
||||
<span>Füllung</span>
|
||||
<span>{$_('website.image_inspector.label_fit')}</span>
|
||||
<select
|
||||
value={block.props.fit}
|
||||
onchange={(e) => onChange({ fit: e.currentTarget.value as ImageProps['fit'] })}
|
||||
>
|
||||
<option value="cover">Zuschneiden</option>
|
||||
<option value="contain">Einpassen</option>
|
||||
<option value="cover">{$_('website.image_inspector.fit_cover')}</option>
|
||||
<option value="contain">{$_('website.image_inspector.fit_contain')}</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
<script lang="ts">
|
||||
import { _ } from 'svelte-i18n';
|
||||
import { getAllBlockSpecs } from '@mana/website-blocks';
|
||||
|
||||
interface Props {
|
||||
|
|
@ -11,7 +12,7 @@
|
|||
</script>
|
||||
|
||||
<div class="wb-palette">
|
||||
<p class="wb-palette__label">Block einfügen</p>
|
||||
<p class="wb-palette__label">{$_('website.insert_palette.label')}</p>
|
||||
<div class="wb-palette__grid">
|
||||
{#each specs as spec (spec.type)}
|
||||
<button class="wb-palette__btn" onclick={() => onInsert(spec.type)} title={spec.label}>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { _ } from 'svelte-i18n';
|
||||
import { pagesStore, InvalidPathError, DuplicatePathError } from '../stores/pages.svelte';
|
||||
import type { WebsitePage } from '../types';
|
||||
|
||||
|
|
@ -29,7 +30,7 @@
|
|||
const page = await pagesStore.createPage({
|
||||
siteId,
|
||||
path: draftPath,
|
||||
title: draftTitle || 'Ohne Titel',
|
||||
title: draftTitle || $_('website.page_list.default_title'),
|
||||
});
|
||||
showAdd = false;
|
||||
await goto(`/website/${siteId}/edit/${page.id}`);
|
||||
|
|
@ -44,10 +45,10 @@
|
|||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
if (pages.length <= 1) {
|
||||
alert('Mindestens eine Seite muss bestehen bleiben.');
|
||||
alert($_('website.page_list.alert_min_one'));
|
||||
return;
|
||||
}
|
||||
if (!confirm('Seite wirklich löschen?')) return;
|
||||
if (!confirm($_('website.page_list.confirm_delete'))) return;
|
||||
await pagesStore.deletePage(pageId);
|
||||
// If the active page was deleted, navigate to another one.
|
||||
if (pageId === activePageId) {
|
||||
|
|
@ -59,8 +60,10 @@
|
|||
|
||||
<div class="wb-pages">
|
||||
<div class="wb-pages__header">
|
||||
<p class="wb-pages__label">Seiten</p>
|
||||
<button class="wb-pages__add" onclick={startAdd} title="Neue Seite">+</button>
|
||||
<p class="wb-pages__label">{$_('website.page_list.heading')}</p>
|
||||
<button class="wb-pages__add" onclick={startAdd} title={$_('website.page_list.action_add')}
|
||||
>+</button
|
||||
>
|
||||
</div>
|
||||
|
||||
<ul class="wb-pages__list">
|
||||
|
|
@ -78,7 +81,7 @@
|
|||
<button
|
||||
class="wb-pages__delete"
|
||||
onclick={(e) => deletePageById(p.id, e)}
|
||||
title="Seite löschen">×</button
|
||||
title={$_('website.page_list.action_delete')}>×</button
|
||||
>
|
||||
</a>
|
||||
</li>
|
||||
|
|
@ -88,31 +91,35 @@
|
|||
{#if showAdd}
|
||||
<div class="wb-pages__form">
|
||||
<label class="wb-field">
|
||||
<span>Titel</span>
|
||||
<span>{$_('website.page_list.label_title')}</span>
|
||||
<!-- svelte-ignore a11y_autofocus — inline add-page form; modal-style focus is expected -->
|
||||
<input
|
||||
type="text"
|
||||
value={draftTitle}
|
||||
oninput={(e) => (draftTitle = e.currentTarget.value)}
|
||||
placeholder="Über uns"
|
||||
placeholder={$_('website.page_list.placeholder_title')}
|
||||
autofocus
|
||||
/>
|
||||
</label>
|
||||
<label class="wb-field">
|
||||
<span>Pfad</span>
|
||||
<span>{$_('website.page_list.label_path')}</span>
|
||||
<input
|
||||
type="text"
|
||||
value={draftPath}
|
||||
oninput={(e) => (draftPath = e.currentTarget.value.toLowerCase())}
|
||||
placeholder="/ueber-uns"
|
||||
placeholder={$_('website.page_list.placeholder_path')}
|
||||
/>
|
||||
</label>
|
||||
{#if addError}
|
||||
<p class="wb-error">{addError}</p>
|
||||
{/if}
|
||||
<div class="wb-pages__form-actions">
|
||||
<button class="wb-btn wb-btn--ghost" onclick={() => (showAdd = false)}>Abbrechen</button>
|
||||
<button class="wb-btn wb-btn--primary" onclick={submitAdd}>Anlegen</button>
|
||||
<button class="wb-btn wb-btn--ghost" onclick={() => (showAdd = false)}
|
||||
>{$_('website.page_list.action_cancel')}</button
|
||||
>
|
||||
<button class="wb-btn wb-btn--primary" onclick={submitAdd}
|
||||
>{$_('website.page_list.action_create')}</button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
<script lang="ts">
|
||||
import { _ } from 'svelte-i18n';
|
||||
import { sitesStore } from '../stores/sites.svelte';
|
||||
import { PublishError } from '../publish';
|
||||
import RollbackDialog from './RollbackDialog.svelte';
|
||||
|
|
@ -46,7 +47,7 @@
|
|||
}
|
||||
|
||||
async function onUnpublish() {
|
||||
if (!confirm('Website offline nehmen? Besucher sehen dann 404.')) return;
|
||||
if (!confirm($_('website.publish_bar.confirm_unpublish'))) return;
|
||||
unpublishing = true;
|
||||
lastError = null;
|
||||
try {
|
||||
|
|
@ -64,16 +65,16 @@
|
|||
<div class="wb-publishbar">
|
||||
<div class="wb-publishbar__status">
|
||||
{#if site.publishedVersion}
|
||||
<span class="wb-pill wb-pill--green">Live</span>
|
||||
<span class="wb-pill wb-pill--green">{$_('website.publish_bar.badge_live')}</span>
|
||||
<a class="wb-publishbar__link" href={publicUrl} target="_blank" rel="noopener">
|
||||
{publicUrl} ↗
|
||||
</a>
|
||||
{#if hasDraftAhead}
|
||||
<span class="wb-pill wb-pill--amber">Unveröffentlichte Änderungen</span>
|
||||
<span class="wb-pill wb-pill--amber">{$_('website.publish_bar.badge_dirty')}</span>
|
||||
{/if}
|
||||
{:else}
|
||||
<span class="wb-pill wb-pill--gray">Entwurf</span>
|
||||
<span class="wb-publishbar__hint">Noch nicht veröffentlicht</span>
|
||||
<span class="wb-pill wb-pill--gray">{$_('website.publish_bar.badge_draft')}</span>
|
||||
<span class="wb-publishbar__hint">{$_('website.publish_bar.hint_unpublished')}</span>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
|
|
@ -82,27 +83,33 @@
|
|||
<button
|
||||
class="wb-btn wb-btn--ghost"
|
||||
onclick={() => (showHistory = true)}
|
||||
title="Versionen einsehen / wiederherstellen"
|
||||
title={$_('website.publish_bar.action_versions_title')}
|
||||
>
|
||||
Versionen
|
||||
{$_('website.publish_bar.action_versions')}
|
||||
</button>
|
||||
<button
|
||||
class="wb-btn wb-btn--ghost"
|
||||
onclick={onUnpublish}
|
||||
disabled={unpublishing || publishing}
|
||||
>
|
||||
{unpublishing ? 'Offline…' : 'Offline nehmen'}
|
||||
{unpublishing
|
||||
? $_('website.publish_bar.action_unpublishing')
|
||||
: $_('website.publish_bar.action_unpublish')}
|
||||
</button>
|
||||
<button
|
||||
class="wb-btn wb-btn--primary"
|
||||
onclick={onPublish}
|
||||
disabled={publishing || !hasDraftAhead}
|
||||
>
|
||||
{publishing ? 'Veröffentliche…' : 'Änderungen veröffentlichen'}
|
||||
{publishing
|
||||
? $_('website.publish_bar.action_publishing')
|
||||
: $_('website.publish_bar.action_publish_changes')}
|
||||
</button>
|
||||
{:else}
|
||||
<button class="wb-btn wb-btn--primary" onclick={onPublish} disabled={publishing}>
|
||||
{publishing ? 'Veröffentliche…' : 'Veröffentlichen'}
|
||||
{publishing
|
||||
? $_('website.publish_bar.action_publishing')
|
||||
: $_('website.publish_bar.action_publish')}
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
<script lang="ts">
|
||||
import { _ } from 'svelte-i18n';
|
||||
import { locale } from 'svelte-i18n';
|
||||
import { get } from 'svelte/store';
|
||||
import { authStore } from '$lib/stores/auth.svelte';
|
||||
import { sitesStore } from '../stores/sites.svelte';
|
||||
import { fetchSnapshotHistory, PublishError, type SnapshotHistoryEntry } from '../publish';
|
||||
|
|
@ -21,7 +24,7 @@
|
|||
loadError = null;
|
||||
try {
|
||||
const token = await authStore.getValidToken();
|
||||
if (!token) throw new Error('Nicht angemeldet');
|
||||
if (!token) throw new Error($_('website.rollback_dialog.err_unauth'));
|
||||
entries = await fetchSnapshotHistory(siteId, token);
|
||||
} catch (err) {
|
||||
loadError =
|
||||
|
|
@ -42,7 +45,7 @@
|
|||
});
|
||||
|
||||
async function onRollback(snapshotId: string) {
|
||||
if (!confirm('Diese Version als aktuell veröffentlicht setzen?')) return;
|
||||
if (!confirm($_('website.rollback_dialog.confirm_rollback'))) return;
|
||||
rollingBackId = snapshotId;
|
||||
actionError = null;
|
||||
try {
|
||||
|
|
@ -61,7 +64,7 @@
|
|||
}
|
||||
|
||||
function formatDate(iso: string): string {
|
||||
return new Date(iso).toLocaleString('de-DE');
|
||||
return new Date(iso).toLocaleString(get(locale) ?? 'de');
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
@ -71,25 +74,29 @@
|
|||
onkeydown={(e) => e.key === 'Escape' && onClose()}
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
aria-label="Schließen"
|
||||
aria-label={$_('website.rollback_dialog.close_aria')}
|
||||
></div>
|
||||
|
||||
<div class="wb-modal" role="dialog" aria-modal="true" aria-labelledby="wb-rollback-title">
|
||||
<header class="wb-modal__head">
|
||||
<div>
|
||||
<h3 id="wb-rollback-title">Version-History</h3>
|
||||
<p>Wähle eine ältere veröffentlichte Version, um sie wieder live zu stellen.</p>
|
||||
<h3 id="wb-rollback-title">{$_('website.rollback_dialog.heading')}</h3>
|
||||
<p>{$_('website.rollback_dialog.subtitle')}</p>
|
||||
</div>
|
||||
<button class="wb-modal__close" onclick={onClose} aria-label="Schließen">×</button>
|
||||
<button
|
||||
class="wb-modal__close"
|
||||
onclick={onClose}
|
||||
aria-label={$_('website.rollback_dialog.close_aria')}>×</button
|
||||
>
|
||||
</header>
|
||||
|
||||
<div class="wb-modal__body">
|
||||
{#if loadError}
|
||||
<p class="wb-error">{loadError}</p>
|
||||
{:else if entries === null}
|
||||
<p class="wb-empty">Lade…</p>
|
||||
<p class="wb-empty">{$_('website.rollback_dialog.loading')}</p>
|
||||
{:else if entries.length === 0}
|
||||
<p class="wb-empty">Noch keine veröffentlichten Versionen.</p>
|
||||
<p class="wb-empty">{$_('website.rollback_dialog.empty')}</p>
|
||||
{:else}
|
||||
{#if actionError}
|
||||
<p class="wb-error">{actionError}</p>
|
||||
|
|
@ -103,14 +110,18 @@
|
|||
</div>
|
||||
<div class="wb-row__actions">
|
||||
{#if entry.isCurrent}
|
||||
<span class="wb-pill wb-pill--current">Aktuell live</span>
|
||||
<span class="wb-pill wb-pill--current"
|
||||
>{$_('website.rollback_dialog.badge_current')}</span
|
||||
>
|
||||
{:else}
|
||||
<button
|
||||
class="wb-btn wb-btn--primary"
|
||||
onclick={() => onRollback(entry.id)}
|
||||
disabled={rollingBackId === entry.id || loading}
|
||||
>
|
||||
{rollingBackId === entry.id ? 'Stelle wieder her…' : 'Wiederherstellen'}
|
||||
{rollingBackId === entry.id
|
||||
? $_('website.rollback_dialog.action_restoring')
|
||||
: $_('website.rollback_dialog.action_restore')}
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
<script lang="ts">
|
||||
import { _ } from 'svelte-i18n';
|
||||
import { PRESET_LABELS, THEME_PRESETS, type ThemePreset } from '@mana/website-blocks/themes';
|
||||
import { sitesStore } from '../stores/sites.svelte';
|
||||
import DomainsSection from './DomainsSection.svelte';
|
||||
|
|
@ -69,18 +70,22 @@
|
|||
onkeydown={(e) => e.key === 'Escape' && onClose()}
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
aria-label="Schließen"
|
||||
aria-label={$_('website.site_settings.close_aria')}
|
||||
></div>
|
||||
|
||||
<div class="wb-modal" role="dialog" aria-modal="true" aria-labelledby="wb-settings-title">
|
||||
<header class="wb-modal__head">
|
||||
<h3 id="wb-settings-title">Website-Einstellungen</h3>
|
||||
<button class="wb-modal__close" onclick={onClose} aria-label="Schließen">×</button>
|
||||
<h3 id="wb-settings-title">{$_('website.site_settings.heading')}</h3>
|
||||
<button
|
||||
class="wb-modal__close"
|
||||
onclick={onClose}
|
||||
aria-label={$_('website.site_settings.close_aria')}>×</button
|
||||
>
|
||||
</header>
|
||||
|
||||
<div class="wb-modal__body">
|
||||
<section class="wb-section">
|
||||
<h4>Theme</h4>
|
||||
<h4>{$_('website.site_settings.section_theme')}</h4>
|
||||
<div class="wb-presets">
|
||||
{#each presets as preset (preset)}
|
||||
{@const tokens = THEME_PRESETS[preset]}
|
||||
|
|
@ -104,14 +109,14 @@
|
|||
|
||||
<section class="wb-section">
|
||||
<div class="wb-section__head">
|
||||
<h4>Farben überschreiben</h4>
|
||||
<h4>{$_('website.site_settings.section_overrides')}</h4>
|
||||
<button class="wb-btn wb-btn--ghost wb-btn--sm" onclick={resetOverrides}>
|
||||
Auf Preset zurücksetzen
|
||||
{$_('website.site_settings.action_reset_overrides')}
|
||||
</button>
|
||||
</div>
|
||||
<div class="wb-colors">
|
||||
<label class="wb-color">
|
||||
<span>Primär</span>
|
||||
<span>{$_('website.site_settings.label_primary')}</span>
|
||||
<input
|
||||
type="color"
|
||||
value={draftPrimary || previewTokens.primary}
|
||||
|
|
@ -125,7 +130,7 @@
|
|||
/>
|
||||
</label>
|
||||
<label class="wb-color">
|
||||
<span>Hintergrund</span>
|
||||
<span>{$_('website.site_settings.label_background')}</span>
|
||||
<input
|
||||
type="color"
|
||||
value={draftBackground || previewTokens.background}
|
||||
|
|
@ -139,7 +144,7 @@
|
|||
/>
|
||||
</label>
|
||||
<label class="wb-color">
|
||||
<span>Text</span>
|
||||
<span>{$_('website.site_settings.label_foreground')}</span>
|
||||
<input
|
||||
type="color"
|
||||
value={draftForeground || previewTokens.foreground}
|
||||
|
|
@ -156,14 +161,14 @@
|
|||
</section>
|
||||
|
||||
<section class="wb-section">
|
||||
<h4>Footer</h4>
|
||||
<h4>{$_('website.site_settings.section_footer')}</h4>
|
||||
<label class="wb-field">
|
||||
<span>Footer-Text</span>
|
||||
<span>{$_('website.site_settings.label_footer_text')}</span>
|
||||
<input
|
||||
type="text"
|
||||
value={draftFooterText}
|
||||
oninput={(e) => (draftFooterText = e.currentTarget.value)}
|
||||
placeholder="© 2026 — Meine Website"
|
||||
placeholder={$_('website.site_settings.placeholder_footer_text')}
|
||||
/>
|
||||
</label>
|
||||
</section>
|
||||
|
|
@ -174,9 +179,11 @@
|
|||
</div>
|
||||
|
||||
<footer class="wb-modal__foot">
|
||||
<button class="wb-btn wb-btn--ghost" onclick={onClose} disabled={saving}>Abbrechen</button>
|
||||
<button class="wb-btn wb-btn--ghost" onclick={onClose} disabled={saving}
|
||||
>{$_('website.site_settings.action_cancel')}</button
|
||||
>
|
||||
<button class="wb-btn wb-btn--primary" onclick={save} disabled={saving}>
|
||||
{saving ? 'Speichere…' : 'Speichern'}
|
||||
{saving ? $_('website.site_settings.action_saving') : $_('website.site_settings.action_save')}
|
||||
</button>
|
||||
</footer>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { _ } from 'svelte-i18n';
|
||||
import { SITE_TEMPLATES, type SiteTemplate } from '../templates';
|
||||
import {
|
||||
sitesStore,
|
||||
|
|
@ -42,11 +43,11 @@
|
|||
async function submit() {
|
||||
error = null;
|
||||
if (!selected) {
|
||||
error = 'Bitte ein Template auswählen.';
|
||||
error = $_('website.template_picker.err_select_template');
|
||||
return;
|
||||
}
|
||||
if (!draftName.trim() || !isValidSlug(draftSlug)) {
|
||||
error = 'Name und Slug sind erforderlich (2–40 Kleinbuchstaben/Zahlen/Bindestrich).';
|
||||
error = $_('website.template_picker.err_invalid_form');
|
||||
return;
|
||||
}
|
||||
creating = true;
|
||||
|
|
@ -75,13 +76,10 @@
|
|||
<div class="wb-templates">
|
||||
<header class="wb-templates__head">
|
||||
<div>
|
||||
<h2>Neue Website</h2>
|
||||
<p>
|
||||
Such dir einen Startpunkt. Templates enthalten fertige Seiten und Blöcke — du kannst alles
|
||||
später anpassen.
|
||||
</p>
|
||||
<h2>{$_('website.template_picker.heading')}</h2>
|
||||
<p>{$_('website.template_picker.subtitle')}</p>
|
||||
</div>
|
||||
<a class="wb-templates__back" href="/website">← Zurück</a>
|
||||
<a class="wb-templates__back" href="/website">{$_('website.template_picker.action_back')}</a>
|
||||
</header>
|
||||
|
||||
<ul class="wb-templates__grid">
|
||||
|
|
@ -98,7 +96,15 @@
|
|||
<div class="wb-template__body">
|
||||
<h3>{template.name}</h3>
|
||||
<p>{template.description}</p>
|
||||
<small>{template.pages.length} Seite{template.pages.length === 1 ? '' : 'n'}</small>
|
||||
<small
|
||||
>{template.pages.length === 1
|
||||
? $_('website.template_picker.pages_count_singular', {
|
||||
values: { count: template.pages.length },
|
||||
})
|
||||
: $_('website.template_picker.pages_count_plural', {
|
||||
values: { count: template.pages.length },
|
||||
})}</small
|
||||
>
|
||||
</div>
|
||||
</button>
|
||||
</li>
|
||||
|
|
@ -107,19 +113,21 @@
|
|||
|
||||
{#if selected}
|
||||
<section class="wb-templates__config" aria-labelledby="wb-config-title">
|
||||
<h3 id="wb-config-title">Mit "{selected.name}" starten</h3>
|
||||
<h3 id="wb-config-title">
|
||||
{$_('website.template_picker.config_title', { values: { name: selected.name } })}
|
||||
</h3>
|
||||
<div class="wb-row">
|
||||
<label class="wb-field">
|
||||
<span>Name</span>
|
||||
<span>{$_('website.template_picker.label_name')}</span>
|
||||
<input
|
||||
type="text"
|
||||
value={draftName}
|
||||
oninput={(e) => onNameInput(e.currentTarget.value)}
|
||||
placeholder="Meine Website"
|
||||
placeholder={$_('website.template_picker.placeholder_name')}
|
||||
/>
|
||||
</label>
|
||||
<label class="wb-field">
|
||||
<span>Slug (URL)</span>
|
||||
<span>{$_('website.template_picker.label_slug')}</span>
|
||||
<div class="wb-slug">
|
||||
<span class="wb-slug__prefix">/s/</span>
|
||||
<input
|
||||
|
|
@ -137,10 +145,12 @@
|
|||
|
||||
<div class="wb-actions">
|
||||
<button class="wb-btn wb-btn--ghost" onclick={() => (selected = null)} disabled={creating}>
|
||||
Abbrechen
|
||||
{$_('website.template_picker.action_cancel')}
|
||||
</button>
|
||||
<button class="wb-btn wb-btn--primary" onclick={submit} disabled={creating}>
|
||||
{creating ? 'Erstelle…' : `Mit "${selected.name}" starten`}
|
||||
{creating
|
||||
? $_('website.template_picker.action_creating')
|
||||
: $_('website.template_picker.action_create', { values: { name: selected.name } })}
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<script lang="ts">
|
||||
import { untrack } from 'svelte';
|
||||
import { _ } from 'svelte-i18n';
|
||||
import {
|
||||
useAllSites,
|
||||
useAllPages,
|
||||
|
|
@ -115,8 +116,10 @@
|
|||
class="wb-toolbar__btn"
|
||||
onclick={() => history.undo()}
|
||||
disabled={!history.canUndo}
|
||||
title={history.undoLabel ? `Rückgängig: ${history.undoLabel}` : 'Rückgängig (⌘Z)'}
|
||||
aria-label="Rückgängig"
|
||||
title={history.undoLabel
|
||||
? $_('website.editor.undo_with_label', { values: { label: history.undoLabel } })
|
||||
: $_('website.editor.undo_default')}
|
||||
aria-label={$_('website.editor.undo_aria')}
|
||||
>
|
||||
↶
|
||||
</button>
|
||||
|
|
@ -124,8 +127,10 @@
|
|||
class="wb-toolbar__btn"
|
||||
onclick={() => history.redo()}
|
||||
disabled={!history.canRedo}
|
||||
title={history.redoLabel ? `Wiederholen: ${history.redoLabel}` : 'Wiederholen (⌘⇧Z)'}
|
||||
aria-label="Wiederholen"
|
||||
title={history.redoLabel
|
||||
? $_('website.editor.redo_with_label', { values: { label: history.redoLabel } })
|
||||
: $_('website.editor.redo_default')}
|
||||
aria-label={$_('website.editor.redo_aria')}
|
||||
>
|
||||
↷
|
||||
</button>
|
||||
|
|
@ -135,8 +140,12 @@
|
|||
<main class="wb-editor__center">
|
||||
{#if pageBlocks.length === 0}
|
||||
<div class="wb-editor__empty">
|
||||
<h3>Leere Seite</h3>
|
||||
<p>Öffne den Tab <strong>Einfügen</strong> rechts, um den ersten Block zu setzen.</p>
|
||||
<h3>{$_('website.editor.empty_title')}</h3>
|
||||
<p>
|
||||
{$_('website.editor.empty_hint_prefix')}
|
||||
<strong>{$_('website.editor.empty_hint_strong')}</strong>
|
||||
{$_('website.editor.empty_hint_suffix')}
|
||||
</p>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="wb-editor__preview">
|
||||
|
|
@ -151,7 +160,7 @@
|
|||
</main>
|
||||
|
||||
<aside class="wb-editor__sidebar">
|
||||
<div class="wb-tabs" role="tablist" aria-label="Editor-Panels">
|
||||
<div class="wb-tabs" role="tablist" aria-label={$_('website.editor.panels_aria')}>
|
||||
<button
|
||||
class="wb-tab"
|
||||
class:wb-tab--active={activeTab === 'pages'}
|
||||
|
|
@ -159,7 +168,7 @@
|
|||
aria-selected={activeTab === 'pages'}
|
||||
onclick={() => (activeTab = 'pages')}
|
||||
>
|
||||
Seiten
|
||||
{$_('website.editor.tab_pages')}
|
||||
</button>
|
||||
<button
|
||||
class="wb-tab"
|
||||
|
|
@ -168,7 +177,7 @@
|
|||
aria-selected={activeTab === 'insert'}
|
||||
onclick={() => (activeTab = 'insert')}
|
||||
>
|
||||
Einfügen
|
||||
{$_('website.editor.tab_insert')}
|
||||
</button>
|
||||
<button
|
||||
class="wb-tab"
|
||||
|
|
@ -177,7 +186,7 @@
|
|||
aria-selected={activeTab === 'block'}
|
||||
onclick={() => (activeTab = 'block')}
|
||||
>
|
||||
Block
|
||||
{$_('website.editor.tab_block')}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
|
@ -194,7 +203,7 @@
|
|||
<button
|
||||
class="wb-editor__settings-btn"
|
||||
onclick={() => (showSettings = true)}
|
||||
title="Website-Einstellungen"
|
||||
title={$_('website.editor.settings_btn_title')}
|
||||
>
|
||||
⚙
|
||||
</button>
|
||||
|
|
@ -217,7 +226,7 @@
|
|||
/>
|
||||
{:else}
|
||||
<p class="wb-editor__inspector-empty">
|
||||
Wähle einen Block in der Vorschau, um ihn zu bearbeiten.
|
||||
{$_('website.editor.inspector_empty')}
|
||||
</p>
|
||||
{/if}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
<script lang="ts">
|
||||
import { _ } from 'svelte-i18n';
|
||||
import { locale } from 'svelte-i18n';
|
||||
import { get } from 'svelte/store';
|
||||
import { authStore } from '$lib/stores/auth.svelte';
|
||||
import { fetchSubmissions, deleteSubmission, type SubmissionEntry } from '../publish';
|
||||
|
||||
|
|
@ -17,7 +20,7 @@
|
|||
loadError = null;
|
||||
try {
|
||||
const token = await authStore.getValidToken();
|
||||
if (!token) throw new Error('Nicht angemeldet');
|
||||
if (!token) throw new Error($_('website.submissions.err_unauth'));
|
||||
entries = await fetchSubmissions(siteId, token);
|
||||
} catch (err) {
|
||||
loadError = err instanceof Error ? err.message : String(err);
|
||||
|
|
@ -33,7 +36,7 @@
|
|||
});
|
||||
|
||||
async function remove(submissionId: string) {
|
||||
if (!confirm('Submission wirklich löschen?')) return;
|
||||
if (!confirm($_('website.submissions.confirm_delete'))) return;
|
||||
const token = await authStore.getValidToken();
|
||||
if (!token) return;
|
||||
await deleteSubmission(siteId, submissionId, token);
|
||||
|
|
@ -41,29 +44,31 @@
|
|||
}
|
||||
|
||||
function formatDate(iso: string): string {
|
||||
return new Date(iso).toLocaleString('de-DE');
|
||||
return new Date(iso).toLocaleString(get(locale) ?? 'de');
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="wb-submissions">
|
||||
<header class="wb-submissions__head">
|
||||
<div>
|
||||
<h2>Eingegangen</h2>
|
||||
<p>Formular-Einsendungen von deiner Website.</p>
|
||||
<h2>{$_('website.submissions.heading')}</h2>
|
||||
<p>{$_('website.submissions.subtitle')}</p>
|
||||
</div>
|
||||
<button class="wb-btn wb-btn--ghost" onclick={load} disabled={loading}>
|
||||
{loading ? 'Lade…' : 'Aktualisieren'}
|
||||
{loading
|
||||
? $_('website.submissions.action_loading')
|
||||
: $_('website.submissions.action_refresh')}
|
||||
</button>
|
||||
</header>
|
||||
|
||||
{#if loadError}
|
||||
<p class="wb-error">{loadError}</p>
|
||||
{:else if entries === null}
|
||||
<div class="wb-submissions__empty">Lade…</div>
|
||||
<div class="wb-submissions__empty">{$_('website.submissions.loading')}</div>
|
||||
{:else if entries.length === 0}
|
||||
<div class="wb-submissions__empty">
|
||||
<p>Noch keine Einsendungen.</p>
|
||||
<small>Sobald jemand ein Formular auf deiner Website ausfüllt, landet es hier.</small>
|
||||
<p>{$_('website.submissions.empty_title')}</p>
|
||||
<small>{$_('website.submissions.empty_hint')}</small>
|
||||
</div>
|
||||
{:else}
|
||||
<ul class="wb-submissions__list">
|
||||
|
|
|
|||
|
|
@ -213,19 +213,6 @@
|
|||
"apps/mana/apps/web/src/lib/modules/todo/components/SyncIndicator.svelte": 4,
|
||||
"apps/mana/apps/web/src/lib/modules/todo/ListView.svelte": 1,
|
||||
"apps/mana/apps/web/src/lib/modules/todo/views/DetailView.svelte": 8,
|
||||
"apps/mana/apps/web/src/lib/modules/website/components/BlockInspector.svelte": 3,
|
||||
"apps/mana/apps/web/src/lib/modules/website/components/DomainsSection.svelte": 4,
|
||||
"apps/mana/apps/web/src/lib/modules/website/components/GalleryInspector.svelte": 9,
|
||||
"apps/mana/apps/web/src/lib/modules/website/components/ImageInspector.svelte": 13,
|
||||
"apps/mana/apps/web/src/lib/modules/website/components/InsertPalette.svelte": 1,
|
||||
"apps/mana/apps/web/src/lib/modules/website/components/PageList.svelte": 7,
|
||||
"apps/mana/apps/web/src/lib/modules/website/components/PublishBar.svelte": 4,
|
||||
"apps/mana/apps/web/src/lib/modules/website/components/RollbackDialog.svelte": 6,
|
||||
"apps/mana/apps/web/src/lib/modules/website/components/SiteSettingsDialog.svelte": 11,
|
||||
"apps/mana/apps/web/src/lib/modules/website/components/TemplatePicker.svelte": 2,
|
||||
"apps/mana/apps/web/src/lib/modules/website/ListView.svelte": 1,
|
||||
"apps/mana/apps/web/src/lib/modules/website/views/EditorView.svelte": 5,
|
||||
"apps/mana/apps/web/src/lib/modules/website/views/SubmissionsView.svelte": 2,
|
||||
"apps/mana/apps/web/src/lib/modules/wetter/components/CurrentConditions.svelte": 2,
|
||||
"apps/mana/apps/web/src/lib/modules/wetter/components/HourlyForecast.svelte": 1,
|
||||
"apps/mana/apps/web/src/lib/modules/wetter/components/LocationPicker.svelte": 5,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue