feat(settings): inline sync, my-data, and vault — delete all sub-routes

The three Settings sub-routes (/settings/sync, /settings/security,
/settings/my-data) were standalone pages with their own PageHeaders
that felt disconnected from the workbench settings app. Inline them
as section components so everything lives in one scrollable view:

- SyncSection.svelte (from /settings/sync) → embedded in Data tab
- MyDataSection.svelte (from /settings/my-data) → embedded in Data tab
- VaultSection.svelte (from /settings/security) → embedded in Security tab

Each component is the route content minus PageHeader/Breadcrumbs/
svelte:head. Toasts stay self-contained in each section.

- Delete all three route files + empty /settings/ directory tree
- Add 'vault' anchor to searchIndex (search "Verschlüsselung")
- Update external links: sync-status dropdown, sync billing banner,
  EncryptionIntroBanner → /?app=settings#cloud-sync / #vault

The routes/(app)/settings/ directory is now completely gone.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Till JS 2026-04-16 13:30:33 +02:00
parent 56171ff13b
commit 827b252090
9 changed files with 33 additions and 75 deletions

View file

@ -111,7 +111,7 @@
Notizen, Chats, Tagebuch und Kontaktdetails liegen nur als verschlüsselter Blob auf diesem
Gerät. Ohne deinen Schlüssel kann sie niemand lesen — nicht mal Mana.
</p>
<a href="/settings/security" class="learn-more">Mehr erfahren →</a>
<a href="/?app=settings#vault" class="learn-more">Mehr erfahren →</a>
</div>
<button type="button" class="dismiss" onclick={dismiss} aria-label="Hinweis ausblenden">
<X size={18} />

View file

@ -46,7 +46,7 @@ export function useSyncStatusItems() {
id: 'sync-inactive',
label: 'Sync aktivieren',
icon: 'cloud',
onClick: () => goto('/settings/sync'),
onClick: () => goto('/?app=settings#cloud-sync'),
});
result.push({
id: 'sync-info',
@ -61,7 +61,7 @@ export function useSyncStatusItems() {
id: 'sync-settings',
label: 'Sync-Einstellungen',
icon: 'settings',
onClick: () => goto('/settings/sync'),
onClick: () => goto('/?app=settings#cloud-sync'),
});
return result;

View file

@ -35,9 +35,9 @@ export const categories: Category[] = [
{
id: 'security',
label: 'Sicherheit',
description: 'Passkeys, 2FA & Sitzungen',
description: 'Passkeys, 2FA, Verschlüsselung & Sitzungen',
icon: ShieldCheck,
anchors: ['passkeys', 'sessions', 'two-factor', 'security-log'],
anchors: ['passkeys', 'sessions', 'two-factor', 'vault', 'security-log'],
},
{
id: 'credits',
@ -130,6 +130,12 @@ export const searchIndex: SearchEntry[] = [
category: 'security',
anchor: 'two-factor',
},
{
label: 'Verschlüsselung',
keywords: ['vault', 'encryption', 'aes', 'schlüssel', 'zero-knowledge'],
category: 'security',
anchor: 'vault',
},
{
label: 'Sicherheits-Log',
keywords: ['audit', 'history', 'verlauf'],

View file

@ -1,7 +1,9 @@
<script lang="ts">
import { Cloud, FileText, CaretRight } from '@mana/shared-icons';
import { Cloud, FileText } from '@mana/shared-icons';
import SettingsPanel from '../SettingsPanel.svelte';
import SettingsSectionHeader from '../SettingsSectionHeader.svelte';
import SyncSection from './SyncSection.svelte';
import MyDataSection from './MyDataSection.svelte';
</script>
<SettingsPanel id="cloud-sync">
@ -10,11 +12,8 @@
title="Cloud Sync"
description="Synchronisiere deine Daten über alle Geräte"
tone="blue"
>
{#snippet action()}
<a href="/settings/sync" class="text-sm text-primary hover:underline">Einstellungen</a>
{/snippet}
</SettingsSectionHeader>
/>
<SyncSection />
</SettingsPanel>
<SettingsPanel id="my-data">
@ -24,41 +23,5 @@
description="Datenschutz und Datenexport"
tone="purple"
/>
<div class="space-y-4">
<div class="flex items-center justify-between border-b border-border py-3">
<div>
<p class="font-medium">Daten ansehen & exportieren</p>
<p class="text-sm text-muted-foreground">
Sieh alle deine gespeicherten Daten ein und exportiere sie als JSON
</p>
</div>
<a
href="/settings/my-data"
class="inline-flex items-center gap-2 rounded-lg bg-primary px-4 py-2 text-sm font-medium text-primary-foreground transition-colors hover:bg-primary/90"
>
Meine Daten
<CaretRight size={16} />
</a>
</div>
<div
class="rounded-lg border border-red-200 bg-red-50 p-4 dark:border-red-800 dark:bg-red-900/10"
>
<div class="flex items-center justify-between">
<div>
<p class="font-medium text-red-600 dark:text-red-400">Konto löschen</p>
<p class="text-sm text-muted-foreground">
Das Löschen deines Kontos kann nicht rückgängig gemacht werden.
</p>
</div>
<a
href="/settings/my-data"
class="inline-flex items-center gap-2 rounded-lg bg-red-600 px-4 py-2 text-sm font-medium text-white transition-colors hover:bg-red-700"
>
Verwalten
</a>
</div>
</div>
</div>
<MyDataSection />
</SettingsPanel>

View file

@ -1,7 +1,7 @@
<script lang="ts">
import { onMount } from 'svelte';
import { goto } from '$app/navigation';
import { Card, PageHeader } from '@mana/shared-ui';
import { Card } from '@mana/shared-ui';
import {
QrCode,
DownloadSimple,
@ -13,7 +13,6 @@
CheckCircle,
WarningCircle,
} from '@mana/shared-icons';
import Breadcrumbs from '$lib/components/Breadcrumbs.svelte';
import StatCard from '$lib/components/admin/StatCard.svelte';
import ProjectDataCard from '$lib/components/admin/ProjectDataCard.svelte';
import DeleteConfirmationModal from '$lib/components/my-data/DeleteConfirmationModal.svelte';
@ -177,20 +176,13 @@
});
</script>
<svelte:head>
<title>Meine Daten - Einstellungen</title>
</svelte:head>
<div class="space-y-6">
<!-- Header -->
<div class="flex items-center justify-between gap-4">
<div>
<Breadcrumbs
items={[{ label: 'Einstellungen', href: '/?app=settings' }, { label: 'Meine Daten' }]}
/>
<h1 class="text-2xl font-bold">Meine Daten</h1>
<p class="text-muted-foreground">
Ubersicht uber alle deine gespeicherten Daten (GDPR/DSGVO)
<h2 class="text-lg font-bold">Meine Daten</h2>
<p class="text-sm text-muted-foreground">
Übersicht über alle deine gespeicherten Daten (GDPR/DSGVO)
</p>
</div>
{#if userData}

View file

@ -5,6 +5,7 @@
import { authStore } from '$lib/stores/auth.svelte';
import SettingsPanel from '../SettingsPanel.svelte';
import SettingsSectionHeader from '../SettingsSectionHeader.svelte';
import VaultSection from './VaultSection.svelte';
let passkeys = $state<any[]>([]);
let sessions = $state<any[]>([]);
@ -34,7 +35,7 @@
<SettingsSectionHeader
icon={ShieldCheck}
title="Sicherheit"
description="Passkeys, 2FA & Sitzungen"
description="Passkeys, 2FA, Verschlüsselung & Sitzungen"
tone="blue"
/>
</SettingsPanel>
@ -77,6 +78,10 @@
/>
</SettingsPanel>
<SettingsPanel id="vault">
<VaultSection />
</SettingsPanel>
<SettingsPanel id="security-log">
<AuditLog
events={securityEvents}

View file

@ -1,5 +1,5 @@
<script lang="ts">
import { Card, PageHeader } from '@mana/shared-ui';
import { Card } from '@mana/shared-ui';
import { syncBilling } from '$lib/stores/sync-billing.svelte';
import { creditsService, type CreditBalance } from '$lib/api/credits';
import type { BillingInterval } from '$lib/api/sync';
@ -106,8 +106,6 @@
</script>
<div>
<PageHeader title="Cloud Sync" backHref="/?app=settings" sticky size="lg" />
{#if syncBilling.loading}
<div class="flex items-center justify-center py-12">
<div
@ -267,11 +265,6 @@
</div>
</Card>
</div>
<!-- Back link -->
<div class="mt-6">
<a href="/?app=settings" class="text-sm text-primary hover:underline"> ← Zurück </a>
</div>
{/if}
</div>

View file

@ -291,13 +291,9 @@
const badge = $derived(statusBadge(vaultState));
</script>
<svelte:head>
<title>Sicherheit · Einstellungen · Mana</title>
</svelte:head>
<div class="security-page">
<header>
<h1>Sicherheit</h1>
<h2>Verschlüsselung</h2>
<p class="subtitle">
Verschlüsselung deiner Inhalte auf diesem Gerät. Sensitive Felder werden mit AES-GCM-256
verschlüsselt, bevor sie in die lokale Datenbank geschrieben werden.

View file

@ -821,7 +821,10 @@
>
Credits aufladen
</a>
<a href="/settings/sync" class="font-medium underline hover:no-underline">
<a
href="/?app=settings#cloud-sync"
class="font-medium underline hover:no-underline"
>
Sync-Einstellungen
</a>
</div>