## New Features ### Network Graph Visualization (Contacts, Calendar, Todo) - D3.js force simulation for physics-based layout - Zoom & pan with mouse/touchpad - Keyboard shortcuts: +/- zoom, 0 reset, Esc deselect, / search, F focus - Filtering by tags, company/location/project, connection strength - Shared components in @manacore/shared-ui ### Central Tags API (mana-core-auth) - CRUD endpoints for tags - Schema: tags table with userId, name, color, app - Shared tag components in @manacore/shared-ui ### Custom Themes System - Theme editor with live preview and color picker - Community theme gallery - Theme sharing (public, unlisted, private) - Backend API in mana-core-auth ### Todo App Extensions - Glass-pill design for task input and items - Settings page with 20+ preferences - Task edit modal with inline editing - Statistics page with visualizations - PWA support with offline capabilities - Multiple kanban boards ### Contacts App Features - Duplicate detection - Photo upload - Batch operations - Enhanced favorites page with multiple view modes - Alphabet view improvements - Search modal ### Help System - @manacore/shared-help-content - @manacore/shared-help-ui - @manacore/shared-help-types ### Other Features - Themes page for all apps - Referral system frontend - CommandBar (global search) - Skeleton loaders - Settings page improvements ## Bug Fixes - Network graph simulation initialization - Database schema TEXT for user_id columns (Better Auth compatibility) - Various styling fixes ## Documentation - Daily report for 2025-12-10 - CI/CD deployment guide 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
13 KiB
Central Theming System
Das zentrale Theming-System ermöglicht einheitliches Aussehen und Benutzereinstellungen über alle Manacore-Apps hinweg. Es besteht aus mehreren Schichten: Theme-Varianten, Light/Dark-Modus, Accessibility-Einstellungen und Custom Themes.
Architektur
┌─────────────────────────────────────────────────────────────┐
│ mana-core-auth │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ user_settings (JSON-Feld) │ │
│ │ - theme: { mode, colorScheme, pinnedThemes } │ │
│ │ - nav: { desktopPosition, sidebarCollapsed } │ │
│ │ - locale: "de" │ │
│ │ - general: { startPages, sounds, etc. } │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ custom_themes Tabelle (Community Themes) │ │
│ │ - lightColors, darkColors, author, downloads, etc. │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
┌────────────────────┼────────────────────┐
│ │ │
┌────▼────┐ ┌─────▼────┐ ┌─────▼────┐
│ Todo │ │ Calendar │ │ Contacts │
│ │ │ │ │ │
│ shared- │ │ shared- │ │ shared- │
│ theme │ │ theme │ │ theme │
└─────────┘ └──────────┘ └──────────┘
Packages
| Package | Beschreibung |
|---|---|
@manacore/shared-theme |
Theme Store, Types, Utilities, Konstanten |
@manacore/shared-theme-ui |
Svelte UI-Komponenten (ThemeSelector, ThemePage, etc.) |
Theme-Varianten
Es gibt 8 vordefinierte Theme-Varianten:
Standard-Varianten (PillNav)
| Name | Farbe | Icon | Hue |
|---|---|---|---|
lume |
Gold ✨ | sparkle | 47 |
nature |
Grün 🌿 | leaf | 122 |
stone |
Blau-Grau 🪨 | hexagon | 200 |
ocean |
Blau 🌊 | waves | 199 |
Erweiterte Varianten (Themes-Seite)
| Name | Farbe | Icon | Hue |
|---|---|---|---|
sunset |
Coral/Orange 🌅 | sun | 15 |
midnight |
Violett 🌙 | moon | 260 |
rose |
Pink 🌹 | flower | 340 |
lavender |
Lavendel 💜 | sparkle | 270 |
Theme-Modus
type ThemeMode = 'light' | 'dark' | 'system';
- light: Heller Modus
- dark: Dunkler Modus
- system: Folgt der System-Einstellung
Color Tokens
Jede Theme-Variante definiert diese HSL-Farbwerte für Light und Dark:
interface ThemeColors {
primary: string; // Hauptfarbe
primaryForeground: string; // Text auf Primary
secondary: string; // Sekundärfarbe
secondaryForeground: string;
background: string; // Seitenhintergrund
foreground: string; // Haupttext
surface: string; // Karten-Hintergrund
surfaceHover: string; // Hover-Zustand
surfaceElevated: string; // Modals, Dropdowns
muted: string; // Deaktivierte Elemente
mutedForeground: string;
border: string; // Rahmen
borderStrong: string; // Starke Rahmen
error: string; // Fehler-Rot
success: string; // Erfolg-Grün
warning: string; // Warnung-Orange
input: string; // Input-Hintergrund
ring: string; // Focus-Ring
}
HSL-Format
Farben werden als HSL-Strings ohne hsl() Wrapper gespeichert:
// Format: "H S% L%"
const gold = '47 95% 58%';
const darkBlue = '199 100% 18%';
// CSS-Verwendung
--color-primary: 47 95% 58%;
background-color: hsl(var(--color-primary));
Store-Nutzung
Theme Store
import { createThemeStore } from '@manacore/shared-theme';
// Store erstellen
export const theme = createThemeStore({
appId: 'calendar',
defaultMode: 'system',
defaultVariant: 'ocean',
});
// In Komponente initialisieren
onMount(() => {
const cleanup = theme.initialize();
return cleanup;
});
// Zugriff auf State
theme.mode // 'light' | 'dark' | 'system'
theme.variant // 'ocean' | 'nature' | ...
theme.effectiveMode // 'light' | 'dark' (aufgelöst)
theme.isDark // boolean
// Aktionen
theme.setMode('dark');
theme.setVariant('nature');
theme.toggleMode(); // Light ↔ Dark
theme.cycleMode(); // Light → Dark → System → Light
App-spezifische Primary Color
export const theme = createThemeStore({
appId: 'memoro',
primaryColor: {
light: '47 95% 58%', // Gold
dark: '47 95% 58%',
},
});
User Settings Store (Server-Sync)
import { createUserSettingsStore } from '@manacore/shared-theme';
export const userSettings = createUserSettingsStore({
appId: 'calendar',
authUrl: 'http://localhost:3001',
getAccessToken: () => authStore.getAccessToken(),
});
// Laden
await userSettings.load();
// Zugriff
userSettings.theme.mode // Theme-Modus
userSettings.theme.colorScheme // Variante
userSettings.nav.desktopPosition // 'top' | 'bottom'
userSettings.locale // 'de'
userSettings.general.soundsEnabled
// Aktualisieren (speichert auf Server)
await userSettings.updateGlobal({
theme: { mode: 'dark' }
});
// App-spezifische Überschreibung
await userSettings.updateAppOverride({
theme: { colorScheme: 'nature' }
});
Accessibility (A11y)
A11y Store
import { createA11yStore } from '@manacore/shared-theme';
export const a11y = createA11yStore({ appId: 'calendar' });
// State
a11y.contrast // 'normal' | 'high'
a11y.colorblind // 'none' | 'deuteranopia' | 'protanopia' | 'monochrome'
a11y.reduceMotion // boolean
// Aktionen
a11y.setContrast('high');
a11y.setColorblind('deuteranopia');
a11y.setReduceMotion(true);
a11y.resetAll();
A11y-Optionen
Kontrast:
normal: Standard (WCAG AA 4.5:1)high: Erhöhter Kontrast (WCAG AAA 7:1)
Farbenblindheit:
none: Keine Anpassungdeuteranopia: Grün-Blindheit (~6% der Männer)protanopia: Rot-Blindheit (~1% der Männer)monochrome: Graustufen
Reduzierte Bewegung:
- Respektiert
prefers-reduced-motion - Kann manuell überschrieben werden
Custom Themes
Custom Themes Store
import { createCustomThemesStore } from '@manacore/shared-theme';
export const customThemes = createCustomThemesStore({
authUrl: 'http://localhost:3001',
getAccessToken: () => authStore.getAccessToken(),
});
// Eigene Themes laden
await customThemes.loadCustomThemes();
// Theme erstellen
const newTheme = await customThemes.createTheme({
name: 'Mein Theme',
emoji: '🎨',
lightColors: { primary: '200 80% 50%', ... },
darkColors: { primary: '200 70% 60%', ... },
});
// Community Themes durchsuchen
await customThemes.browseCommunity({
sort: 'popular',
search: 'dark',
});
// Theme herunterladen
await customThemes.downloadTheme(themeId);
// Theme anwenden
customThemes.applyCustomTheme(theme);
Theme Editor
Der Theme Editor erlaubt das visuelle Erstellen von Themes:
Hauptfarben (immer sichtbar):
- Primary, Background, Surface, Foreground
- Error, Success, Warning
Erweiterte Farben (zugeklappt):
- PrimaryForeground, Secondary, SecondaryForeground
- SurfaceHover, SurfaceElevated, Muted, MutedForeground
- Border, BorderStrong, Input, Ring
UI-Komponenten
ThemePage
Vollständige Themes-Seite mit allen Optionen:
<script>
import { ThemePage } from '@manacore/shared-theme-ui';
import { theme, a11y } from '$lib/stores';
</script>
<ThemePage
themeStore={theme}
a11yStore={a11y}
showAccessibility={true}
showPinnedThemes={true}
/>
ThemeSelector
Dropdown zur Theme-Auswahl:
<script>
import { ThemeSelector } from '@manacore/shared-theme-ui';
import { theme } from '$lib/stores';
</script>
<ThemeSelector themeStore={theme} />
ThemeModeSelector
Umschalter für Light/Dark/System:
<script>
import { ThemeModeSelector } from '@manacore/shared-theme-ui';
import { theme } from '$lib/stores';
</script>
<ThemeModeSelector themeStore={theme} />
ThemeToggle
Einfacher Dark/Light Toggle:
<script>
import { ThemeToggle } from '@manacore/shared-theme-ui';
import { theme } from '$lib/stores';
</script>
<ThemeToggle themeStore={theme} />
A11ySettings
Vollständige Accessibility-Einstellungen:
<script>
import { A11ySettings } from '@manacore/shared-theme-ui';
import { a11y } from '$lib/stores';
</script>
<A11ySettings store={a11y} />
CSS-Integration
Tailwind CSS
Die Themes werden als CSS-Variablen angewendet:
:root {
--color-primary: 199 98% 45%;
--color-background: 199 100% 97%;
--color-foreground: 199 100% 18%;
/* ... weitere Tokens */
}
.dark {
--color-primary: 199 98% 48%;
--color-background: 200 25% 7%;
--color-foreground: 0 0% 100%;
}
In Tailwind:
<div class="bg-background text-foreground">
<button class="bg-primary text-primary-foreground">
Klick mich
</button>
</div>
tailwind.config.js
theme: {
extend: {
colors: {
background: 'hsl(var(--color-background))',
foreground: 'hsl(var(--color-foreground))',
primary: {
DEFAULT: 'hsl(var(--color-primary))',
foreground: 'hsl(var(--color-primary-foreground))',
},
// ... weitere
}
}
}
Dateien
@manacore/shared-theme
| Datei | Beschreibung |
|---|---|
src/types.ts |
Alle TypeScript Interfaces |
src/constants.ts |
Theme-Definitionen (8 Varianten) |
src/store.svelte.ts |
Theme Store Factory |
src/a11y-store.svelte.ts |
Accessibility Store |
src/a11y-constants.ts |
A11y Konstanten |
src/a11y-utils.ts |
A11y Helper |
src/user-settings-store.svelte.ts |
Server-Sync Store |
src/custom-themes-store.svelte.ts |
Custom Themes Store |
src/utils.ts |
Theme Utilities |
src/app-routes.ts |
Start-Page Konfiguration |
@manacore/shared-theme-ui
| Datei | Beschreibung |
|---|---|
src/ThemeSelector.svelte |
Theme-Dropdown |
src/ThemeModeSelector.svelte |
Light/Dark/System Selector |
src/ThemeToggle.svelte |
Einfacher Toggle |
src/components/ThemeCard.svelte |
Theme-Vorschau Karte |
src/components/ThemeGrid.svelte |
Grid von Theme-Karten |
src/components/A11ySettings.svelte |
A11y Einstellungen |
src/components/editor/ |
Theme Editor Komponenten |
src/components/community/ |
Community Themes Komponenten |
src/pages/ThemePage.svelte |
Vollständige Themes-Seite |
src/pages/ThemeEditorPage.svelte |
Theme Editor Seite |
src/pages/CommunityThemesPage.svelte |
Community Themes |
Integration in eine App
1. Dependencies installieren
{
"dependencies": {
"@manacore/shared-theme": "workspace:*",
"@manacore/shared-theme-ui": "workspace:*"
}
}
2. Store erstellen
// src/lib/stores/theme.ts
import { createThemeStore, createA11yStore } from '@manacore/shared-theme';
export const theme = createThemeStore({
appId: 'myapp',
defaultVariant: 'ocean',
});
export const a11y = createA11yStore({
appId: 'myapp',
});
3. Im Root-Layout initialisieren
<!-- src/routes/+layout.svelte -->
<script>
import { onMount } from 'svelte';
import { theme, a11y } from '$lib/stores/theme';
onMount(() => {
const cleanupTheme = theme.initialize();
const cleanupA11y = a11y.initialize();
return () => {
cleanupTheme();
cleanupA11y();
};
});
</script>
<slot />
4. Themes-Seite hinzufügen
<!-- src/routes/(app)/themes/+page.svelte -->
<script>
import { ThemePage } from '@manacore/shared-theme-ui';
import { theme, a11y } from '$lib/stores/theme';
</script>
<ThemePage themeStore={theme} a11yStore={a11y} />
Vorteile
- Konsistenz: Alle Apps sehen einheitlich aus
- User Experience: Theme-Einstellungen werden gespeichert
- Accessibility: Barrierefreiheit ist eingebaut
- Anpassbarkeit: Nutzer können eigene Themes erstellen
- Community: Themes können geteilt werden