mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 20:21:09 +02:00
✨ feat(auth): add centralized user settings synced across all apps
- Add settings module to mana-core-auth with REST API endpoints - Create user_settings table with globalSettings and appOverrides (JSONB) - Add createUserSettingsStore() factory in shared-theme package - Integrate user settings in all app layouts (calendar, chat, contacts, etc.) - Support for nav position, theme, locale settings with per-app overrides - Optimistic updates with localStorage caching for offline support - Add comprehensive documentation in docs/USER_SETTINGS.md API Endpoints: - GET /api/v1/settings - Get all user settings - PATCH /api/v1/settings/global - Update global settings - PATCH /api/v1/settings/app/:appId - Set app override - DELETE /api/v1/settings/app/:appId - Remove app override 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
0f2aae631d
commit
0e5d923faf
30 changed files with 1624 additions and 7 deletions
|
|
@ -0,0 +1,19 @@
|
|||
/**
|
||||
* User Settings Store for Calendar
|
||||
*
|
||||
* This store syncs settings with mana-core-auth and provides:
|
||||
* - Global settings that apply to all apps
|
||||
* - Per-app overrides for customization
|
||||
* - localStorage caching for offline support
|
||||
*/
|
||||
|
||||
import { createUserSettingsStore } from '@manacore/shared-theme';
|
||||
import { authStore } from './auth.svelte';
|
||||
|
||||
const MANA_AUTH_URL = 'http://localhost:3001';
|
||||
|
||||
export const userSettings = createUserSettingsStore({
|
||||
appId: 'calendar',
|
||||
authUrl: MANA_AUTH_URL,
|
||||
getAccessToken: () => authStore.getAccessToken(),
|
||||
});
|
||||
|
|
@ -7,6 +7,7 @@
|
|||
import type { PillNavItem, PillDropdownItem } from '@manacore/shared-ui';
|
||||
import { theme } from '$lib/stores/theme';
|
||||
import { authStore } from '$lib/stores/auth.svelte';
|
||||
import { userSettings } from '$lib/stores/user-settings.svelte';
|
||||
import { viewStore } from '$lib/stores/view.svelte';
|
||||
import { calendarsStore } from '$lib/stores/calendars.svelte';
|
||||
import { settingsStore } from '$lib/stores/settings.svelte';
|
||||
|
|
@ -144,9 +145,10 @@
|
|||
// Initialize auth
|
||||
await authStore.initialize();
|
||||
|
||||
// Load calendars if authenticated
|
||||
// Load calendars and user settings if authenticated
|
||||
if (authStore.isAuthenticated) {
|
||||
await calendarsStore.fetchCalendars();
|
||||
await userSettings.load();
|
||||
}
|
||||
|
||||
// Initialize sidebar mode from localStorage
|
||||
|
|
@ -196,6 +198,7 @@
|
|||
onModeChange={handleModeChange}
|
||||
{isCollapsed}
|
||||
onCollapsedChange={handleCollapsedChange}
|
||||
desktopPosition={userSettings.nav.desktopPosition}
|
||||
showThemeToggle={true}
|
||||
showThemeVariants={true}
|
||||
{themeVariantItems}
|
||||
|
|
|
|||
19
apps/chat/apps/web/src/lib/stores/user-settings.svelte.ts
Normal file
19
apps/chat/apps/web/src/lib/stores/user-settings.svelte.ts
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
/**
|
||||
* User Settings Store for Chat
|
||||
*
|
||||
* This store syncs settings with mana-core-auth and provides:
|
||||
* - Global settings that apply to all apps
|
||||
* - Per-app overrides for customization
|
||||
* - localStorage caching for offline support
|
||||
*/
|
||||
|
||||
import { createUserSettingsStore } from '@manacore/shared-theme';
|
||||
import { authStore } from './auth.svelte';
|
||||
|
||||
const MANA_AUTH_URL = 'http://localhost:3001';
|
||||
|
||||
export const userSettings = createUserSettingsStore({
|
||||
appId: 'chat',
|
||||
authUrl: MANA_AUTH_URL,
|
||||
getAccessToken: () => authStore.getAccessToken(),
|
||||
});
|
||||
|
|
@ -4,6 +4,7 @@
|
|||
import { page } from '$app/stores';
|
||||
import { locale } from 'svelte-i18n';
|
||||
import { authStore } from '$lib/stores/auth.svelte';
|
||||
import { userSettings } from '$lib/stores/user-settings.svelte';
|
||||
import { theme } from '$lib/stores/theme';
|
||||
import { THEME_DEFINITIONS } from '@manacore/shared-theme';
|
||||
import {
|
||||
|
|
@ -156,6 +157,9 @@
|
|||
return;
|
||||
}
|
||||
|
||||
// Load user settings
|
||||
await userSettings.load();
|
||||
|
||||
isChecking = false;
|
||||
});
|
||||
</script>
|
||||
|
|
@ -187,6 +191,7 @@
|
|||
onModeChange={handleModeChange}
|
||||
{isCollapsed}
|
||||
onCollapsedChange={handleCollapsedChange}
|
||||
desktopPosition={userSettings.nav.desktopPosition}
|
||||
showThemeToggle={true}
|
||||
showThemeVariants={true}
|
||||
{themeVariantItems}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
/**
|
||||
* User Settings Store for Contacts
|
||||
*
|
||||
* This store syncs settings with mana-core-auth and provides:
|
||||
* - Global settings that apply to all apps
|
||||
* - Per-app overrides for customization
|
||||
* - localStorage caching for offline support
|
||||
*/
|
||||
|
||||
import { createUserSettingsStore } from '@manacore/shared-theme';
|
||||
import { authStore } from './auth.svelte';
|
||||
|
||||
const MANA_AUTH_URL = 'http://localhost:3001';
|
||||
|
||||
export const userSettings = createUserSettingsStore({
|
||||
appId: 'contacts',
|
||||
authUrl: MANA_AUTH_URL,
|
||||
getAccessToken: () => authStore.getAccessToken(),
|
||||
});
|
||||
|
|
@ -7,6 +7,7 @@
|
|||
import type { PillNavItem, PillDropdownItem } from '@manacore/shared-ui';
|
||||
import { theme } from '$lib/stores/theme';
|
||||
import { authStore } from '$lib/stores/auth.svelte';
|
||||
import { userSettings } from '$lib/stores/user-settings.svelte';
|
||||
import { THEME_DEFINITIONS } from '@manacore/shared-theme';
|
||||
import {
|
||||
isSidebarMode as sidebarModeStore,
|
||||
|
|
@ -137,6 +138,9 @@
|
|||
return;
|
||||
}
|
||||
|
||||
// Load user settings
|
||||
await userSettings.load();
|
||||
|
||||
// Initialize sidebar mode from localStorage
|
||||
const savedSidebar = localStorage.getItem('contacts-nav-sidebar');
|
||||
if (savedSidebar === 'true') {
|
||||
|
|
@ -169,6 +173,7 @@
|
|||
onModeChange={handleModeChange}
|
||||
{isCollapsed}
|
||||
onCollapsedChange={handleCollapsedChange}
|
||||
desktopPosition={userSettings.nav.desktopPosition}
|
||||
showThemeToggle={true}
|
||||
showThemeVariants={true}
|
||||
{themeVariantItems}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
/**
|
||||
* User Settings Store for ManaCore
|
||||
*
|
||||
* This store syncs settings with mana-core-auth and provides:
|
||||
* - Global settings that apply to all apps
|
||||
* - Per-app overrides for customization
|
||||
* - localStorage caching for offline support
|
||||
*/
|
||||
|
||||
import { createUserSettingsStore } from '@manacore/shared-theme';
|
||||
import { authStore } from './authStore.svelte';
|
||||
|
||||
// TODO: Use PUBLIC_MANA_CORE_AUTH_URL from env when available
|
||||
const MANA_AUTH_URL = 'http://localhost:3001';
|
||||
|
||||
export const userSettings = createUserSettingsStore({
|
||||
appId: 'manacore',
|
||||
authUrl: MANA_AUTH_URL,
|
||||
getAccessToken: () => authStore.getAccessToken(),
|
||||
});
|
||||
|
|
@ -11,6 +11,7 @@
|
|||
import { setLocale, supportedLocales } from '$lib/i18n';
|
||||
import { theme } from '$lib/stores/theme';
|
||||
import { authStore } from '$lib/stores/authStore.svelte';
|
||||
import { userSettings } from '$lib/stores/user-settings.svelte';
|
||||
import {
|
||||
isSidebarMode as sidebarModeStore,
|
||||
isNavCollapsed as collapsedStore,
|
||||
|
|
@ -129,7 +130,7 @@
|
|||
}
|
||||
});
|
||||
|
||||
onMount(() => {
|
||||
onMount(async () => {
|
||||
// Initialize sidebar mode from localStorage
|
||||
const savedSidebar = localStorage.getItem('manacore-nav-sidebar');
|
||||
if (savedSidebar === 'true') {
|
||||
|
|
@ -144,6 +145,11 @@
|
|||
collapsedStore.set(true);
|
||||
}
|
||||
|
||||
// Load user settings from server
|
||||
if (authStore.isAuthenticated) {
|
||||
await userSettings.load();
|
||||
}
|
||||
|
||||
loading = false;
|
||||
});
|
||||
</script>
|
||||
|
|
@ -174,6 +180,7 @@
|
|||
onModeChange={handleModeChange}
|
||||
{isCollapsed}
|
||||
onCollapsedChange={handleCollapsedChange}
|
||||
desktopPosition={userSettings.nav.desktopPosition}
|
||||
showThemeToggle={true}
|
||||
showThemeVariants={true}
|
||||
{themeVariantItems}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
import { Button, Input, Card, PageHeader } from '@manacore/shared-ui';
|
||||
import { authStore } from '$lib/stores/authStore.svelte';
|
||||
import { creditsService, type CreditBalance } from '$lib/api/credits';
|
||||
import { userSettings } from '$lib/stores/user-settings.svelte';
|
||||
import type { NavPosition, ThemeMode } from '@manacore/shared-theme';
|
||||
|
||||
let loading = $state(true);
|
||||
let savingProfile = $state(false);
|
||||
|
|
@ -20,13 +22,40 @@
|
|||
if (authStore.isAuthenticated) {
|
||||
try {
|
||||
creditBalance = await creditsService.getBalance();
|
||||
// Load user settings from server
|
||||
await userSettings.load();
|
||||
} catch (e) {
|
||||
console.error('Failed to load credits:', e);
|
||||
console.error('Failed to load data:', e);
|
||||
}
|
||||
}
|
||||
loading = false;
|
||||
});
|
||||
|
||||
// Navigation position handler
|
||||
async function handleNavPositionChange(position: NavPosition) {
|
||||
await userSettings.updateGlobal({ nav: { ...userSettings.globalSettings.nav, desktopPosition: position } });
|
||||
}
|
||||
|
||||
// Sidebar collapsed handler
|
||||
async function handleSidebarChange(collapsed: boolean) {
|
||||
await userSettings.updateGlobal({ nav: { ...userSettings.globalSettings.nav, sidebarCollapsed: collapsed } });
|
||||
}
|
||||
|
||||
// Theme mode handler
|
||||
async function handleThemeModeChange(mode: ThemeMode) {
|
||||
await userSettings.updateGlobal({ theme: { ...userSettings.globalSettings.theme, mode } });
|
||||
}
|
||||
|
||||
// Color scheme handler
|
||||
async function handleColorSchemeChange(colorScheme: string) {
|
||||
await userSettings.updateGlobal({ theme: { ...userSettings.globalSettings.theme, colorScheme } });
|
||||
}
|
||||
|
||||
// Locale handler
|
||||
async function handleLocaleChange(locale: string) {
|
||||
await userSettings.updateGlobal({ locale });
|
||||
}
|
||||
|
||||
function formatCredits(amount: number): string {
|
||||
return amount.toLocaleString('de-DE');
|
||||
}
|
||||
|
|
@ -133,6 +162,193 @@
|
|||
</div>
|
||||
</Card>
|
||||
|
||||
<!-- Default App Settings Section -->
|
||||
<Card>
|
||||
<div class="p-6">
|
||||
<div class="flex items-center gap-3 mb-6">
|
||||
<div
|
||||
class="flex h-10 w-10 items-center justify-center rounded-full bg-purple-100 dark:bg-purple-900/20 text-purple-600 dark:text-purple-400"
|
||||
>
|
||||
<svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"
|
||||
/>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="text-lg font-semibold">Standard App-Einstellungen</h2>
|
||||
<p class="text-sm text-muted-foreground">
|
||||
Diese Einstellungen gelten für alle Mana Apps
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="space-y-6">
|
||||
<!-- Navigation Settings -->
|
||||
<div class="space-y-4">
|
||||
<h3 class="text-sm font-medium text-muted-foreground uppercase tracking-wide">
|
||||
Navigation
|
||||
</h3>
|
||||
|
||||
<div class="flex items-center justify-between py-3 border-b border-border">
|
||||
<div>
|
||||
<p class="font-medium">Position (Desktop)</p>
|
||||
<p class="text-sm text-muted-foreground">Position der Navigation auf großen Bildschirmen</p>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<button
|
||||
class="px-4 py-2 text-sm font-medium rounded-lg transition-colors {userSettings.globalSettings.nav.desktopPosition === 'top'
|
||||
? 'bg-primary text-primary-foreground'
|
||||
: 'bg-surface-hover hover:bg-surface-hover/80'}"
|
||||
onclick={() => handleNavPositionChange('top')}
|
||||
>
|
||||
Oben
|
||||
</button>
|
||||
<button
|
||||
class="px-4 py-2 text-sm font-medium rounded-lg transition-colors {userSettings.globalSettings.nav.desktopPosition === 'bottom'
|
||||
? 'bg-primary text-primary-foreground'
|
||||
: 'bg-surface-hover hover:bg-surface-hover/80'}"
|
||||
onclick={() => handleNavPositionChange('bottom')}
|
||||
>
|
||||
Unten
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between py-3">
|
||||
<div>
|
||||
<p class="font-medium">Sidebar eingeklappt</p>
|
||||
<p class="text-sm text-muted-foreground">Standard-Zustand der Sidebar</p>
|
||||
</div>
|
||||
<button
|
||||
class="relative inline-flex h-6 w-11 items-center rounded-full transition-colors {userSettings.globalSettings.nav.sidebarCollapsed
|
||||
? 'bg-primary'
|
||||
: 'bg-gray-200 dark:bg-gray-700'}"
|
||||
onclick={() => handleSidebarChange(!userSettings.globalSettings.nav.sidebarCollapsed)}
|
||||
>
|
||||
<span
|
||||
class="inline-block h-4 w-4 transform rounded-full bg-white transition-transform {userSettings.globalSettings.nav.sidebarCollapsed
|
||||
? 'translate-x-6'
|
||||
: 'translate-x-1'}"
|
||||
></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Theme Settings -->
|
||||
<div class="space-y-4">
|
||||
<h3 class="text-sm font-medium text-muted-foreground uppercase tracking-wide">
|
||||
Erscheinungsbild
|
||||
</h3>
|
||||
|
||||
<div class="flex items-center justify-between py-3 border-b border-border">
|
||||
<div>
|
||||
<p class="font-medium">Farbmodus</p>
|
||||
<p class="text-sm text-muted-foreground">Hell, Dunkel oder automatisch</p>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<button
|
||||
class="px-3 py-2 text-sm font-medium rounded-lg transition-colors {userSettings.globalSettings.theme.mode === 'light'
|
||||
? 'bg-primary text-primary-foreground'
|
||||
: 'bg-surface-hover hover:bg-surface-hover/80'}"
|
||||
onclick={() => handleThemeModeChange('light')}
|
||||
>
|
||||
Hell
|
||||
</button>
|
||||
<button
|
||||
class="px-3 py-2 text-sm font-medium rounded-lg transition-colors {userSettings.globalSettings.theme.mode === 'dark'
|
||||
? 'bg-primary text-primary-foreground'
|
||||
: 'bg-surface-hover hover:bg-surface-hover/80'}"
|
||||
onclick={() => handleThemeModeChange('dark')}
|
||||
>
|
||||
Dunkel
|
||||
</button>
|
||||
<button
|
||||
class="px-3 py-2 text-sm font-medium rounded-lg transition-colors {userSettings.globalSettings.theme.mode === 'system'
|
||||
? 'bg-primary text-primary-foreground'
|
||||
: 'bg-surface-hover hover:bg-surface-hover/80'}"
|
||||
onclick={() => handleThemeModeChange('system')}
|
||||
>
|
||||
System
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between py-3">
|
||||
<div>
|
||||
<p class="font-medium">Farbschema</p>
|
||||
<p class="text-sm text-muted-foreground">Akzentfarbe der Benutzeroberfläche</p>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
{#each [
|
||||
{ id: 'ocean', label: 'Ozean', color: 'bg-blue-500' },
|
||||
{ id: 'forest', label: 'Wald', color: 'bg-green-500' },
|
||||
{ id: 'sunset', label: 'Sonnenuntergang', color: 'bg-orange-500' },
|
||||
{ id: 'lavender', label: 'Lavendel', color: 'bg-purple-500' }
|
||||
] as scheme}
|
||||
<button
|
||||
class="w-8 h-8 rounded-full transition-all {scheme.color} {userSettings.globalSettings.theme.colorScheme === scheme.id
|
||||
? 'ring-2 ring-offset-2 ring-primary'
|
||||
: 'hover:scale-110'}"
|
||||
onclick={() => handleColorSchemeChange(scheme.id)}
|
||||
title={scheme.label}
|
||||
></button>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Language Settings -->
|
||||
<div class="space-y-4">
|
||||
<h3 class="text-sm font-medium text-muted-foreground uppercase tracking-wide">
|
||||
Sprache
|
||||
</h3>
|
||||
|
||||
<div class="flex items-center justify-between py-3">
|
||||
<div>
|
||||
<p class="font-medium">Anzeigesprache</p>
|
||||
<p class="text-sm text-muted-foreground">Sprache der Benutzeroberfläche</p>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
{#each [
|
||||
{ id: 'de', label: 'DE' },
|
||||
{ id: 'en', label: 'EN' },
|
||||
{ id: 'fr', label: 'FR' },
|
||||
{ id: 'es', label: 'ES' },
|
||||
{ id: 'it', label: 'IT' }
|
||||
] as lang}
|
||||
<button
|
||||
class="px-3 py-2 text-sm font-medium rounded-lg transition-colors {userSettings.globalSettings.locale === lang.id
|
||||
? 'bg-primary text-primary-foreground'
|
||||
: 'bg-surface-hover hover:bg-surface-hover/80'}"
|
||||
onclick={() => handleLocaleChange(lang.id)}
|
||||
>
|
||||
{lang.label}
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if userSettings.syncing}
|
||||
<div class="mt-4 flex items-center gap-2 text-sm text-muted-foreground">
|
||||
<div class="h-4 w-4 animate-spin rounded-full border-2 border-primary border-t-transparent"></div>
|
||||
<span>Einstellungen werden synchronisiert...</span>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
<!-- Credits Section -->
|
||||
<Card>
|
||||
<div class="p-6">
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
/**
|
||||
* User Settings Store for ManaDeck
|
||||
*
|
||||
* This store syncs settings with mana-core-auth and provides:
|
||||
* - Global settings that apply to all apps
|
||||
* - Per-app overrides for customization
|
||||
* - localStorage caching for offline support
|
||||
*/
|
||||
|
||||
import { createUserSettingsStore } from '@manacore/shared-theme';
|
||||
import { authStore } from './authStore.svelte';
|
||||
|
||||
const MANA_AUTH_URL = 'http://localhost:3001';
|
||||
|
||||
export const userSettings = createUserSettingsStore({
|
||||
appId: 'manadeck',
|
||||
authUrl: MANA_AUTH_URL,
|
||||
getAccessToken: () => authStore.getAccessToken(),
|
||||
});
|
||||
|
|
@ -4,6 +4,7 @@
|
|||
import { onMount } from 'svelte';
|
||||
import { locale } from 'svelte-i18n';
|
||||
import { authStore } from '$lib/stores/authStore.svelte';
|
||||
import { userSettings } from '$lib/stores/user-settings.svelte';
|
||||
import { theme } from '$lib/stores/theme';
|
||||
import {
|
||||
isSidebarMode as sidebarModeStore,
|
||||
|
|
@ -135,6 +136,9 @@
|
|||
return;
|
||||
}
|
||||
|
||||
// Load user settings
|
||||
await userSettings.load();
|
||||
|
||||
// Initialize sidebar mode from localStorage
|
||||
const savedSidebar = localStorage.getItem('manadeck-nav-sidebar');
|
||||
if (savedSidebar === 'true') {
|
||||
|
|
@ -177,6 +181,7 @@
|
|||
onModeChange={handleModeChange}
|
||||
{isCollapsed}
|
||||
onCollapsedChange={handleCollapsedChange}
|
||||
desktopPosition={userSettings.nav.desktopPosition}
|
||||
showThemeToggle={true}
|
||||
showThemeVariants={true}
|
||||
{themeVariantItems}
|
||||
|
|
|
|||
19
apps/picture/apps/web/src/lib/stores/user-settings.svelte.ts
Normal file
19
apps/picture/apps/web/src/lib/stores/user-settings.svelte.ts
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
/**
|
||||
* User Settings Store for Picture
|
||||
*
|
||||
* This store syncs settings with mana-core-auth and provides:
|
||||
* - Global settings that apply to all apps
|
||||
* - Per-app overrides for customization
|
||||
* - localStorage caching for offline support
|
||||
*/
|
||||
|
||||
import { createUserSettingsStore } from '@manacore/shared-theme';
|
||||
import { authStore } from './auth.svelte';
|
||||
|
||||
const MANA_AUTH_URL = 'http://localhost:3001';
|
||||
|
||||
export const userSettings = createUserSettingsStore({
|
||||
appId: 'picture',
|
||||
authUrl: MANA_AUTH_URL,
|
||||
getAccessToken: () => authStore.getAccessToken(),
|
||||
});
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
<script lang="ts">
|
||||
import { authStore } from '$lib/stores/auth.svelte';
|
||||
import { userSettings } from '$lib/stores/user-settings.svelte';
|
||||
import { goto } from '$app/navigation';
|
||||
import { page } from '$app/stores';
|
||||
import { locale } from 'svelte-i18n';
|
||||
|
|
@ -64,6 +65,13 @@
|
|||
}
|
||||
});
|
||||
|
||||
// Load user settings when authenticated
|
||||
$effect(() => {
|
||||
if (authStore.initialized && authStore.user) {
|
||||
userSettings.load();
|
||||
}
|
||||
});
|
||||
|
||||
// Navigation items (Mana is in user dropdown via manaHref)
|
||||
const navItems: PillNavItem[] = [
|
||||
{ href: '/app/gallery', label: 'Galerie', icon: 'home' },
|
||||
|
|
@ -222,6 +230,7 @@
|
|||
onModeChange={handleModeChange}
|
||||
{isCollapsed}
|
||||
onCollapsedChange={handleCollapsedChange}
|
||||
desktopPosition={userSettings.nav.desktopPosition}
|
||||
showThemeToggle={true}
|
||||
showThemeVariants={true}
|
||||
{themeVariantItems}
|
||||
|
|
|
|||
19
apps/presi/apps/web/src/lib/stores/user-settings.svelte.ts
Normal file
19
apps/presi/apps/web/src/lib/stores/user-settings.svelte.ts
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
/**
|
||||
* User Settings Store for Presi
|
||||
*
|
||||
* This store syncs settings with mana-core-auth and provides:
|
||||
* - Global settings that apply to all apps
|
||||
* - Per-app overrides for customization
|
||||
* - localStorage caching for offline support
|
||||
*/
|
||||
|
||||
import { createUserSettingsStore } from '@manacore/shared-theme';
|
||||
import { authStore } from './auth.svelte';
|
||||
|
||||
const MANA_AUTH_URL = 'http://localhost:3001';
|
||||
|
||||
export const userSettings = createUserSettingsStore({
|
||||
appId: 'presi',
|
||||
authUrl: MANA_AUTH_URL,
|
||||
getAccessToken: () => authStore.getAccessToken(),
|
||||
});
|
||||
|
|
@ -6,6 +6,7 @@
|
|||
import { PillNavigation } from '@manacore/shared-ui';
|
||||
import type { PillNavItem, PillDropdownItem } from '@manacore/shared-ui';
|
||||
import { auth } from '$lib/stores/auth.svelte';
|
||||
import { userSettings } from '$lib/stores/user-settings.svelte';
|
||||
import { theme } from '$lib/stores/theme';
|
||||
import { THEME_DEFINITIONS } from '@manacore/shared-theme';
|
||||
import {
|
||||
|
|
@ -128,10 +129,13 @@
|
|||
}
|
||||
});
|
||||
|
||||
onMount(() => {
|
||||
onMount(async () => {
|
||||
// Initialize auth
|
||||
auth.init();
|
||||
|
||||
// Load user settings
|
||||
await userSettings.load();
|
||||
|
||||
// Initialize theme
|
||||
const cleanup = theme.initialize();
|
||||
|
||||
|
|
@ -186,6 +190,7 @@
|
|||
onModeChange={handleModeChange}
|
||||
{isCollapsed}
|
||||
onCollapsedChange={handleCollapsedChange}
|
||||
desktopPosition={userSettings.nav.desktopPosition}
|
||||
showThemeToggle={true}
|
||||
showThemeVariants={true}
|
||||
{themeVariantItems}
|
||||
|
|
|
|||
19
apps/storage/apps/web/src/lib/stores/user-settings.svelte.ts
Normal file
19
apps/storage/apps/web/src/lib/stores/user-settings.svelte.ts
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
/**
|
||||
* User Settings Store for Storage
|
||||
*
|
||||
* This store syncs settings with mana-core-auth and provides:
|
||||
* - Global settings that apply to all apps
|
||||
* - Per-app overrides for customization
|
||||
* - localStorage caching for offline support
|
||||
*/
|
||||
|
||||
import { createUserSettingsStore } from '@manacore/shared-theme';
|
||||
import { authStore } from './auth.svelte';
|
||||
|
||||
const MANA_AUTH_URL = 'http://localhost:3001';
|
||||
|
||||
export const userSettings = createUserSettingsStore({
|
||||
appId: 'storage',
|
||||
authUrl: MANA_AUTH_URL,
|
||||
getAccessToken: () => authStore.getAccessToken(),
|
||||
});
|
||||
|
|
@ -7,6 +7,7 @@
|
|||
import type { PillNavItem, PillDropdownItem } from '@manacore/shared-ui';
|
||||
import { theme } from '$lib/stores/theme.svelte';
|
||||
import { authStore } from '$lib/stores/auth.svelte';
|
||||
import { userSettings } from '$lib/stores/user-settings.svelte';
|
||||
import { THEME_DEFINITIONS } from '@manacore/shared-theme';
|
||||
import {
|
||||
isSidebarMode as sidebarModeStore,
|
||||
|
|
@ -146,6 +147,9 @@
|
|||
// Initialize auth
|
||||
await authStore.initialize();
|
||||
|
||||
// Load user settings
|
||||
await userSettings.load();
|
||||
|
||||
// Initialize sidebar mode from localStorage
|
||||
const savedSidebar = localStorage.getItem('storage-nav-sidebar');
|
||||
if (savedSidebar === 'true') {
|
||||
|
|
@ -194,6 +198,7 @@
|
|||
onModeChange={handleModeChange}
|
||||
{isCollapsed}
|
||||
onCollapsedChange={handleCollapsedChange}
|
||||
desktopPosition={userSettings.nav.desktopPosition}
|
||||
showThemeToggle={true}
|
||||
showThemeVariants={true}
|
||||
{themeVariantItems}
|
||||
|
|
|
|||
19
apps/zitare/apps/web/src/lib/stores/user-settings.svelte.ts
Normal file
19
apps/zitare/apps/web/src/lib/stores/user-settings.svelte.ts
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
/**
|
||||
* User Settings Store for Zitare
|
||||
*
|
||||
* This store syncs settings with mana-core-auth and provides:
|
||||
* - Global settings that apply to all apps
|
||||
* - Per-app overrides for customization
|
||||
* - localStorage caching for offline support
|
||||
*/
|
||||
|
||||
import { createUserSettingsStore } from '@manacore/shared-theme';
|
||||
import { authStore } from './auth.svelte';
|
||||
|
||||
const MANA_AUTH_URL = 'http://localhost:3001';
|
||||
|
||||
export const userSettings = createUserSettingsStore({
|
||||
appId: 'zitare',
|
||||
authUrl: MANA_AUTH_URL,
|
||||
getAccessToken: () => authStore.getAccessToken(),
|
||||
});
|
||||
|
|
@ -7,6 +7,7 @@
|
|||
import type { PillNavItem, PillDropdownItem } from '@manacore/shared-ui';
|
||||
import { theme } from '$lib/stores/theme';
|
||||
import { authStore } from '$lib/stores/auth.svelte';
|
||||
import { userSettings } from '$lib/stores/user-settings.svelte';
|
||||
import { THEME_DEFINITIONS } from '@manacore/shared-theme';
|
||||
import {
|
||||
isSidebarMode as sidebarModeStore,
|
||||
|
|
@ -141,6 +142,11 @@
|
|||
// Initialize auth
|
||||
await authStore.initialize();
|
||||
|
||||
// Load user settings if authenticated
|
||||
if (authStore.isAuthenticated) {
|
||||
await userSettings.load();
|
||||
}
|
||||
|
||||
// Initialize sidebar mode from localStorage
|
||||
const savedSidebar = localStorage.getItem('zitare-nav-sidebar');
|
||||
if (savedSidebar === 'true') {
|
||||
|
|
@ -187,6 +193,7 @@
|
|||
onModeChange={handleModeChange}
|
||||
{isCollapsed}
|
||||
onCollapsedChange={handleCollapsedChange}
|
||||
desktopPosition={userSettings.nav.desktopPosition}
|
||||
showThemeToggle={true}
|
||||
showThemeVariants={true}
|
||||
{themeVariantItems}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue