mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-16 20:39:39 +02:00
feat(chat): add shared profile UI package and integrate into navigation
- Create @manacore/shared-profile-ui package with ProfilePage component - Add glassmorphism-styled profile page with user info and actions - Move profile link into user dropdown menu as first item - Move layout toggle control to end of navigation - Fix pill navigation styling in sidebar mode (full-width pills, proper spacing) - Fix segmented control button hover states with proper border-radius - Fix theme mode selector blur styling in dropdown 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
0467ac3891
commit
2dc289c595
11 changed files with 792 additions and 365 deletions
|
|
@ -31,12 +31,15 @@
|
|||
"@manacore/shared-auth": "workspace:*",
|
||||
"@manacore/shared-auth-ui": "workspace:*",
|
||||
"@manacore/shared-branding": "workspace:*",
|
||||
"@manacore/shared-feedback-service": "workspace:*",
|
||||
"@manacore/shared-feedback-ui": "workspace:*",
|
||||
"@manacore/shared-i18n": "workspace:*",
|
||||
"@manacore/shared-icons": "workspace:*",
|
||||
"@manacore/shared-tailwind": "workspace:*",
|
||||
"@manacore/shared-theme": "workspace:*",
|
||||
"@manacore/shared-theme-ui": "workspace:*",
|
||||
"@manacore/shared-subscription-ui": "workspace:*",
|
||||
"@manacore/shared-profile-ui": "workspace:*",
|
||||
"@manacore/shared-ui": "workspace:*",
|
||||
"@manacore/shared-utils": "workspace:*",
|
||||
"marked": "^17.0.0"
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@
|
|||
{ href: '/spaces', label: 'Spaces', icon: 'building' },
|
||||
{ href: '/documents', label: 'Dokumente', icon: 'archive' },
|
||||
{ href: '/archive', label: 'Archiv', icon: 'list' },
|
||||
{ href: '/feedback', label: 'Feedback', icon: 'chat' },
|
||||
];
|
||||
|
||||
// User email for user dropdown
|
||||
|
|
@ -188,6 +189,7 @@
|
|||
{userEmail}
|
||||
settingsHref="/settings"
|
||||
manaHref="/mana"
|
||||
profileHref="/profile"
|
||||
/>
|
||||
|
||||
<!-- Main Content with dynamic padding based on nav mode -->
|
||||
|
|
|
|||
|
|
@ -1,184 +1,76 @@
|
|||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { ProfilePage } from '@manacore/shared-profile-ui';
|
||||
import { authStore } from '$lib/stores/auth.svelte';
|
||||
import { theme } from '$lib/stores/theme';
|
||||
|
||||
function handleSignOut() {
|
||||
authStore.signOut();
|
||||
// Get user from auth store
|
||||
const user = $derived(authStore.user);
|
||||
|
||||
// Map auth user to profile user
|
||||
const profileUser = $derived(() => {
|
||||
if (!user) return null;
|
||||
return {
|
||||
id: user.id,
|
||||
email: user.email,
|
||||
role: user.role,
|
||||
};
|
||||
});
|
||||
|
||||
// Actions
|
||||
function handleEditProfile() {
|
||||
alert('Profil bearbeiten wird noch implementiert.');
|
||||
}
|
||||
|
||||
function handleChangePassword() {
|
||||
alert('Passwort ändern wird noch implementiert.');
|
||||
}
|
||||
|
||||
async function handleLogout() {
|
||||
await authStore.signOut();
|
||||
goto('/login');
|
||||
}
|
||||
|
||||
function toggleTheme() {
|
||||
theme.toggleMode();
|
||||
}
|
||||
|
||||
function formatDate(dateString: string | undefined): string {
|
||||
if (!dateString) return '-';
|
||||
return new Date(dateString).toLocaleDateString('de-DE', {
|
||||
day: '2-digit',
|
||||
month: 'long',
|
||||
year: 'numeric',
|
||||
});
|
||||
function handleDeleteAccount() {
|
||||
if (confirm('Bist du sicher, dass du dein Konto löschen möchtest? Diese Aktion kann nicht rückgängig gemacht werden.')) {
|
||||
alert('Konto löschen wird noch implementiert.');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Profil | ManaChat</title>
|
||||
<title>Profil - ManaChat</title>
|
||||
</svelte:head>
|
||||
|
||||
<div class="min-h-[calc(100vh-4rem)] bg-background py-8">
|
||||
<div class="max-w-2xl mx-auto px-4">
|
||||
<!-- Header -->
|
||||
<div class="mb-8">
|
||||
<h1 class="text-2xl font-bold text-foreground">Profil</h1>
|
||||
<p class="text-sm text-muted-foreground mt-1">
|
||||
Verwalte dein Konto und deine Einstellungen.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Profile Card -->
|
||||
<div
|
||||
class="bg-surface rounded-xl border border-border shadow-sm overflow-hidden mb-6"
|
||||
>
|
||||
<div class="p-6">
|
||||
<div class="flex items-center gap-4 mb-6">
|
||||
<div
|
||||
class="w-16 h-16 rounded-full bg-primary/10 flex items-center justify-center"
|
||||
>
|
||||
<svg
|
||||
class="w-8 h-8 text-primary"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="text-lg font-semibold text-foreground">
|
||||
{authStore.user?.email || 'Benutzer'}
|
||||
</h2>
|
||||
<p class="text-sm text-muted-foreground">
|
||||
Mitglied seit {formatDate(authStore.user?.created_at)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="space-y-4">
|
||||
<div
|
||||
class="flex items-center justify-between py-3 border-b border-border"
|
||||
>
|
||||
<div>
|
||||
<p class="font-medium text-foreground">E-Mail</p>
|
||||
<p class="text-sm text-muted-foreground">{authStore.user?.email || '-'}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="flex items-center justify-between py-3 border-b border-border"
|
||||
>
|
||||
<div>
|
||||
<p class="font-medium text-foreground">Benutzer-ID</p>
|
||||
<p class="text-sm text-muted-foreground font-mono">{authStore.user?.id || '-'}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quick Actions Card -->
|
||||
<div
|
||||
class="bg-surface rounded-xl border border-border shadow-sm overflow-hidden mb-6"
|
||||
>
|
||||
<div class="p-6">
|
||||
<h3 class="text-lg font-semibold text-foreground mb-4">Schnellzugriff</h3>
|
||||
|
||||
<div class="space-y-4">
|
||||
<!-- Settings Link -->
|
||||
<a
|
||||
href="/settings"
|
||||
class="flex items-center justify-between py-3 border-b border-border hover:bg-muted/50 -mx-6 px-6 transition-colors"
|
||||
>
|
||||
<div class="flex items-center gap-3">
|
||||
<svg class="w-5 h-5 text-primary" 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>
|
||||
<p class="font-medium text-foreground">Einstellungen</p>
|
||||
<p class="text-sm text-muted-foreground">Erscheinungsbild, Benachrichtigungen & mehr</p>
|
||||
</div>
|
||||
</div>
|
||||
<svg class="w-5 h-5 text-muted-foreground" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
|
||||
</svg>
|
||||
</a>
|
||||
|
||||
<!-- Theme Toggle -->
|
||||
<div class="flex items-center justify-between py-3">
|
||||
<div class="flex items-center gap-3">
|
||||
<svg class="w-5 h-5 text-primary" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z"
|
||||
/>
|
||||
</svg>
|
||||
<div>
|
||||
<p class="font-medium text-foreground">Dunkler Modus</p>
|
||||
<p class="text-sm text-muted-foreground">Schnell umschalten</p>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
onclick={toggleTheme}
|
||||
class="relative w-12 h-6 rounded-full transition-colors
|
||||
{theme.mode === 'dark' ? 'bg-primary' : 'bg-muted'}"
|
||||
role="switch"
|
||||
aria-checked={theme.mode === 'dark'}
|
||||
aria-label="Dunkler Modus umschalten"
|
||||
>
|
||||
<span
|
||||
class="absolute top-0.5 left-0.5 w-5 h-5 rounded-full bg-white shadow transition-transform
|
||||
{theme.mode === 'dark' ? 'translate-x-6' : 'translate-x-0'}"
|
||||
></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sign Out -->
|
||||
<div
|
||||
class="bg-surface rounded-xl border border-border shadow-sm overflow-hidden"
|
||||
>
|
||||
<div class="p-6">
|
||||
<button
|
||||
onclick={handleSignOut}
|
||||
class="w-full flex items-center justify-center gap-2 px-4 py-3 bg-destructive/10
|
||||
text-destructive rounded-lg font-medium
|
||||
hover:bg-destructive/20 transition-colors"
|
||||
>
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1"
|
||||
/>
|
||||
</svg>
|
||||
Abmelden
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="profile-wrapper">
|
||||
{#if profileUser()}
|
||||
<ProfilePage
|
||||
user={profileUser()!}
|
||||
appName="ManaChat"
|
||||
actions={{
|
||||
onEditProfile: handleEditProfile,
|
||||
onChangePassword: handleChangePassword,
|
||||
onLogout: handleLogout,
|
||||
onDeleteAccount: handleDeleteAccount,
|
||||
}}
|
||||
/>
|
||||
{:else}
|
||||
<div class="loading">Laden...</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.profile-wrapper {
|
||||
min-height: 100%;
|
||||
width: 100%;
|
||||
overflow-x: hidden;
|
||||
background-color: hsl(var(--background));
|
||||
}
|
||||
|
||||
.loading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 100vh;
|
||||
color: hsl(var(--muted-foreground));
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
28
packages/shared-profile-ui/package.json
Normal file
28
packages/shared-profile-ui/package.json
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"name": "@manacore/shared-profile-ui",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"svelte": "./src/index.ts",
|
||||
"main": "./src/index.ts",
|
||||
"types": "./src/index.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"svelte": "./src/index.ts",
|
||||
"types": "./src/index.ts",
|
||||
"default": "./src/index.ts"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"check": "svelte-check --tsconfig ./tsconfig.json"
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"svelte": "^5.0.0",
|
||||
"svelte-check": "^4.0.0",
|
||||
"typescript": "^5.7.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"svelte": "^5.0.0"
|
||||
}
|
||||
}
|
||||
484
packages/shared-profile-ui/src/ProfilePage.svelte
Normal file
484
packages/shared-profile-ui/src/ProfilePage.svelte
Normal file
|
|
@ -0,0 +1,484 @@
|
|||
<script lang="ts">
|
||||
import type { UserProfile, ProfileActions } from './types';
|
||||
|
||||
interface Props {
|
||||
/** User profile data */
|
||||
user: UserProfile;
|
||||
/** App name for the page title */
|
||||
appName: string;
|
||||
/** Profile actions */
|
||||
actions?: ProfileActions;
|
||||
/** Page title */
|
||||
pageTitle?: string;
|
||||
/** Account info section title */
|
||||
accountInfoTitle?: string;
|
||||
/** Account actions section title */
|
||||
actionsTitle?: string;
|
||||
// i18n labels
|
||||
emailLabel?: string;
|
||||
nameLabel?: string;
|
||||
memberSinceLabel?: string;
|
||||
lastLoginLabel?: string;
|
||||
roleLabel?: string;
|
||||
editProfileLabel?: string;
|
||||
changePasswordLabel?: string;
|
||||
logoutLabel?: string;
|
||||
deleteAccountLabel?: string;
|
||||
deleteAccountWarning?: string;
|
||||
}
|
||||
|
||||
let {
|
||||
user,
|
||||
appName,
|
||||
actions,
|
||||
pageTitle = 'Profil',
|
||||
accountInfoTitle = 'Konto-Informationen',
|
||||
actionsTitle = 'Aktionen',
|
||||
emailLabel = 'E-Mail',
|
||||
nameLabel = 'Name',
|
||||
memberSinceLabel = 'Mitglied seit',
|
||||
lastLoginLabel = 'Letzter Login',
|
||||
roleLabel = 'Rolle',
|
||||
editProfileLabel = 'Profil bearbeiten',
|
||||
changePasswordLabel = 'Passwort ändern',
|
||||
logoutLabel = 'Abmelden',
|
||||
deleteAccountLabel = 'Konto löschen',
|
||||
deleteAccountWarning = 'Diese Aktion kann nicht rückgängig gemacht werden.',
|
||||
}: Props = $props();
|
||||
|
||||
// Get display name
|
||||
const displayName = $derived(() => {
|
||||
if (user.displayName) return user.displayName;
|
||||
if (user.firstName && user.lastName) return `${user.firstName} ${user.lastName}`;
|
||||
if (user.firstName) return user.firstName;
|
||||
return null;
|
||||
});
|
||||
|
||||
// Get initials for avatar
|
||||
const initials = $derived(() => {
|
||||
if (user.firstName && user.lastName) {
|
||||
return `${user.firstName[0]}${user.lastName[0]}`.toUpperCase();
|
||||
}
|
||||
if (user.displayName) {
|
||||
const parts = user.displayName.split(' ');
|
||||
if (parts.length >= 2) {
|
||||
return `${parts[0][0]}${parts[1][0]}`.toUpperCase();
|
||||
}
|
||||
return user.displayName.substring(0, 2).toUpperCase();
|
||||
}
|
||||
return user.email.substring(0, 2).toUpperCase();
|
||||
});
|
||||
|
||||
// Format date
|
||||
function formatDate(dateString?: string): string {
|
||||
if (!dateString) return '-';
|
||||
const date = new Date(dateString);
|
||||
return date.toLocaleDateString('de-DE', {
|
||||
day: '2-digit',
|
||||
month: '2-digit',
|
||||
year: 'numeric',
|
||||
});
|
||||
}
|
||||
|
||||
// Format role
|
||||
function formatRole(role?: string): string {
|
||||
if (!role) return '-';
|
||||
const roles: Record<string, string> = {
|
||||
user: 'Benutzer',
|
||||
admin: 'Administrator',
|
||||
moderator: 'Moderator',
|
||||
};
|
||||
return roles[role] || role;
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>{pageTitle} - {appName}</title>
|
||||
</svelte:head>
|
||||
|
||||
<div class="profile-page">
|
||||
<div class="profile-page__content">
|
||||
<div class="profile-page__container">
|
||||
<!-- Header -->
|
||||
<div class="profile-page__header">
|
||||
<!-- Avatar -->
|
||||
<div class="profile-page__avatar">
|
||||
{#if user.avatarUrl}
|
||||
<img src={user.avatarUrl} alt="Avatar" class="profile-page__avatar-image" />
|
||||
{:else}
|
||||
<span class="profile-page__avatar-initials">{initials()}</span>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<h1 class="profile-page__title">{displayName() || user.email}</h1>
|
||||
{#if displayName()}
|
||||
<p class="profile-page__subtitle">{user.email}</p>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<!-- Account Info Section -->
|
||||
<section class="profile-page__section">
|
||||
<h2 class="profile-page__section-title">{accountInfoTitle}</h2>
|
||||
|
||||
<div class="profile-page__card">
|
||||
<div class="profile-page__info-list">
|
||||
<!-- Email -->
|
||||
<div class="profile-page__info-item">
|
||||
<div class="profile-page__info-icon">
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="profile-page__info-content">
|
||||
<span class="profile-page__info-label">{emailLabel}</span>
|
||||
<span class="profile-page__info-value">{user.email}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Name (if available) -->
|
||||
{#if displayName()}
|
||||
<div class="profile-page__info-item">
|
||||
<div class="profile-page__info-icon">
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="profile-page__info-content">
|
||||
<span class="profile-page__info-label">{nameLabel}</span>
|
||||
<span class="profile-page__info-value">{displayName()}</span>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- Role -->
|
||||
{#if user.role}
|
||||
<div class="profile-page__info-item">
|
||||
<div class="profile-page__info-icon">
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="profile-page__info-content">
|
||||
<span class="profile-page__info-label">{roleLabel}</span>
|
||||
<span class="profile-page__info-value">{formatRole(user.role)}</span>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- Member Since -->
|
||||
{#if user.createdAt}
|
||||
<div class="profile-page__info-item">
|
||||
<div class="profile-page__info-icon">
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="profile-page__info-content">
|
||||
<span class="profile-page__info-label">{memberSinceLabel}</span>
|
||||
<span class="profile-page__info-value">{formatDate(user.createdAt)}</span>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- Last Login -->
|
||||
{#if user.lastLoginAt}
|
||||
<div class="profile-page__info-item">
|
||||
<div class="profile-page__info-icon">
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="profile-page__info-content">
|
||||
<span class="profile-page__info-label">{lastLoginLabel}</span>
|
||||
<span class="profile-page__info-value">{formatDate(user.lastLoginAt)}</span>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Actions Section -->
|
||||
{#if actions}
|
||||
<section class="profile-page__section">
|
||||
<h2 class="profile-page__section-title">{actionsTitle}</h2>
|
||||
|
||||
<div class="profile-page__actions">
|
||||
{#if actions.onEditProfile}
|
||||
<button class="profile-page__action-btn" onclick={actions.onEditProfile}>
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
|
||||
</svg>
|
||||
<span>{editProfileLabel}</span>
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
{#if actions.onChangePassword}
|
||||
<button class="profile-page__action-btn" onclick={actions.onChangePassword}>
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z" />
|
||||
</svg>
|
||||
<span>{changePasswordLabel}</span>
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
{#if actions.onLogout}
|
||||
<button class="profile-page__action-btn profile-page__action-btn--secondary" onclick={actions.onLogout}>
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" />
|
||||
</svg>
|
||||
<span>{logoutLabel}</span>
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
{#if actions.onDeleteAccount}
|
||||
<button class="profile-page__action-btn profile-page__action-btn--danger" onclick={actions.onDeleteAccount}>
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
|
||||
</svg>
|
||||
<span>{deleteAccountLabel}</span>
|
||||
</button>
|
||||
<p class="profile-page__warning">{deleteAccountWarning}</p>
|
||||
{/if}
|
||||
</div>
|
||||
</section>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.profile-page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.profile-page__content {
|
||||
flex: 1;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
padding: 1rem;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.profile-page__container {
|
||||
max-width: 40rem;
|
||||
margin: 0 auto;
|
||||
padding-bottom: 3rem;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.profile-page__header {
|
||||
text-align: center;
|
||||
margin-bottom: 2.5rem;
|
||||
}
|
||||
|
||||
.profile-page__avatar {
|
||||
width: 6rem;
|
||||
height: 6rem;
|
||||
margin: 0 auto 1.5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 50%;
|
||||
background: rgba(255, 255, 255, 0.85);
|
||||
backdrop-filter: blur(12px);
|
||||
-webkit-backdrop-filter: blur(12px);
|
||||
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
:global(.dark) .profile-page__avatar {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.profile-page__avatar-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.profile-page__avatar-initials {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 600;
|
||||
color: hsl(var(--primary, 221 83% 53%));
|
||||
}
|
||||
|
||||
.profile-page__title {
|
||||
font-size: 1.875rem;
|
||||
font-weight: 600;
|
||||
color: hsl(var(--foreground));
|
||||
margin: 0 0 0.5rem 0;
|
||||
}
|
||||
|
||||
.profile-page__subtitle {
|
||||
font-size: 1rem;
|
||||
color: hsl(var(--muted-foreground));
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.profile-page__section {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.profile-page__section-title {
|
||||
font-size: 1.125rem;
|
||||
font-weight: 600;
|
||||
color: hsl(var(--foreground));
|
||||
margin: 0 0 1rem 0;
|
||||
}
|
||||
|
||||
.profile-page__card {
|
||||
padding: 1.25rem;
|
||||
border-radius: 1rem;
|
||||
background: rgba(255, 255, 255, 0.85);
|
||||
backdrop-filter: blur(12px);
|
||||
-webkit-backdrop-filter: blur(12px);
|
||||
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
:global(.dark) .profile-page__card {
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
border: 1px solid rgba(255, 255, 255, 0.12);
|
||||
}
|
||||
|
||||
.profile-page__info-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.profile-page__info-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.profile-page__info-icon {
|
||||
width: 2.5rem;
|
||||
height: 2.5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 0.75rem;
|
||||
background: rgba(0, 0, 0, 0.03);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
:global(.dark) .profile-page__info-icon {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
.profile-page__info-icon svg {
|
||||
width: 1.25rem;
|
||||
height: 1.25rem;
|
||||
color: hsl(var(--primary, 221 83% 53%));
|
||||
}
|
||||
|
||||
.profile-page__info-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.125rem;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.profile-page__info-label {
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
color: hsl(var(--muted-foreground));
|
||||
}
|
||||
|
||||
.profile-page__info-value {
|
||||
font-size: 0.9375rem;
|
||||
font-weight: 500;
|
||||
color: hsl(var(--foreground));
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.profile-page__actions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.profile-page__action-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
width: 100%;
|
||||
padding: 1rem 1.25rem;
|
||||
border-radius: 0.75rem;
|
||||
background: rgba(255, 255, 255, 0.85);
|
||||
backdrop-filter: blur(12px);
|
||||
-webkit-backdrop-filter: blur(12px);
|
||||
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||
box-shadow: 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
font-size: 0.9375rem;
|
||||
font-weight: 500;
|
||||
color: hsl(var(--foreground));
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
:global(.dark) .profile-page__action-btn {
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
border: 1px solid rgba(255, 255, 255, 0.12);
|
||||
}
|
||||
|
||||
.profile-page__action-btn:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
:global(.dark) .profile-page__action-btn:hover {
|
||||
background: rgba(255, 255, 255, 0.12);
|
||||
}
|
||||
|
||||
.profile-page__action-btn svg {
|
||||
width: 1.25rem;
|
||||
height: 1.25rem;
|
||||
flex-shrink: 0;
|
||||
color: hsl(var(--primary, 221 83% 53%));
|
||||
}
|
||||
|
||||
.profile-page__action-btn--secondary {
|
||||
background: rgba(0, 0, 0, 0.03);
|
||||
}
|
||||
|
||||
:global(.dark) .profile-page__action-btn--secondary {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
.profile-page__action-btn--secondary svg {
|
||||
color: hsl(var(--muted-foreground));
|
||||
}
|
||||
|
||||
.profile-page__action-btn--danger {
|
||||
color: hsl(0 84% 60%);
|
||||
border-color: hsla(0, 84%, 60%, 0.2);
|
||||
}
|
||||
|
||||
.profile-page__action-btn--danger svg {
|
||||
color: hsl(0 84% 60%);
|
||||
}
|
||||
|
||||
.profile-page__action-btn--danger:hover {
|
||||
background: hsla(0, 84%, 60%, 0.1);
|
||||
border-color: hsla(0, 84%, 60%, 0.3);
|
||||
}
|
||||
|
||||
.profile-page__warning {
|
||||
margin: 0.5rem 0 0 0;
|
||||
font-size: 0.75rem;
|
||||
color: hsl(var(--muted-foreground));
|
||||
padding-left: 0.5rem;
|
||||
}
|
||||
</style>
|
||||
12
packages/shared-profile-ui/src/index.ts
Normal file
12
packages/shared-profile-ui/src/index.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/**
|
||||
* Shared profile UI components for Manacore monorepo
|
||||
*
|
||||
* This package contains Svelte 5 components for displaying
|
||||
* user profile information.
|
||||
*/
|
||||
|
||||
// Pages
|
||||
export { default as ProfilePage } from './ProfilePage.svelte';
|
||||
|
||||
// Types
|
||||
export type { UserProfile, ProfileActions } from './types';
|
||||
37
packages/shared-profile-ui/src/types.ts
Normal file
37
packages/shared-profile-ui/src/types.ts
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/**
|
||||
* User profile data for display in ProfilePage
|
||||
*/
|
||||
export interface UserProfile {
|
||||
/** User ID */
|
||||
id: string;
|
||||
/** User email */
|
||||
email: string;
|
||||
/** Display name (optional) */
|
||||
displayName?: string;
|
||||
/** First name (optional) */
|
||||
firstName?: string;
|
||||
/** Last name (optional) */
|
||||
lastName?: string;
|
||||
/** Avatar URL (optional) */
|
||||
avatarUrl?: string;
|
||||
/** Account creation date */
|
||||
createdAt?: string;
|
||||
/** Last login date */
|
||||
lastLoginAt?: string;
|
||||
/** User role */
|
||||
role?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Profile action handlers
|
||||
*/
|
||||
export interface ProfileActions {
|
||||
/** Called when user wants to edit profile */
|
||||
onEditProfile?: () => void;
|
||||
/** Called when user wants to change password */
|
||||
onChangePassword?: () => void;
|
||||
/** Called when user wants to delete account */
|
||||
onDeleteAccount?: () => void;
|
||||
/** Called when user wants to logout */
|
||||
onLogout?: () => void;
|
||||
}
|
||||
12
packages/shared-profile-ui/tsconfig.json
Normal file
12
packages/shared-profile-ui/tsconfig.json
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "src",
|
||||
"outDir": "dist",
|
||||
"declaration": true,
|
||||
"declarationDir": "dist",
|
||||
"types": ["svelte"]
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
||||
|
|
@ -178,6 +178,11 @@
|
|||
<style>
|
||||
.pill-dropdown {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.pill-dropdown:has(.fan-container) {
|
||||
z-index: 10000;
|
||||
}
|
||||
|
||||
.trigger-button {
|
||||
|
|
@ -338,6 +343,8 @@
|
|||
animation: fanIn 0.15s ease-out forwards;
|
||||
opacity: 0;
|
||||
transform: translateY(10px);
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.fan-up .dropdown-header {
|
||||
|
|
|
|||
|
|
@ -84,6 +84,8 @@
|
|||
settingsHref?: string;
|
||||
/** Mana/subscription page href */
|
||||
manaHref?: string;
|
||||
/** Profile page href */
|
||||
profileHref?: string;
|
||||
}
|
||||
|
||||
let {
|
||||
|
|
@ -116,6 +118,7 @@
|
|||
userEmail,
|
||||
settingsHref = '/settings',
|
||||
manaHref,
|
||||
profileHref,
|
||||
}: Props = $props();
|
||||
|
||||
// Type guards for elements
|
||||
|
|
@ -224,6 +227,7 @@
|
|||
'M4 5a1 1 0 011-1h2a1 1 0 011 1v2a1 1 0 01-1 1H5a1 1 0 01-1-1V5zM10 5a1 1 0 011-1h2a1 1 0 011 1v2a1 1 0 01-1 1h-2a1 1 0 01-1-1V5zM16 5a1 1 0 011-1h2a1 1 0 011 1v2a1 1 0 01-1 1h-2a1 1 0 01-1-1V5zM4 11a1 1 0 011-1h2a1 1 0 011 1v2a1 1 0 01-1 1H5a1 1 0 01-1-1v-2zM10 11a1 1 0 011-1h2a1 1 0 011 1v2a1 1 0 01-1 1h-2a1 1 0 01-1-1v-2zM16 11a1 1 0 011-1h2a1 1 0 011 1v2a1 1 0 01-1 1h-2a1 1 0 01-1-1v-2z',
|
||||
palette:
|
||||
'M7 21a4 4 0 01-4-4V5a2 2 0 012-2h4a2 2 0 012 2v12a4 4 0 01-4 4zm0 0h12a2 2 0 002-2v-4a2 2 0 00-2-2h-2.343M11 7.343l1.657-1.657a2 2 0 012.828 0l2.829 2.829a2 2 0 010 2.828l-8.486 8.485M7 17h.01',
|
||||
chat: 'M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z',
|
||||
};
|
||||
|
||||
function getIconPath(name: string): string {
|
||||
|
|
@ -238,37 +242,6 @@
|
|||
style={primaryColor ? `--pill-primary-color: ${primaryColor}` : ''}
|
||||
>
|
||||
<div class="pill-nav-container" class:sidebar-container={isSidebarMode}>
|
||||
<!-- Control Button (left position in horizontal mode) -->
|
||||
{#if !isSidebarMode}
|
||||
<div class="pill glass-pill segmented-control">
|
||||
<button
|
||||
onclick={toggleSidebarMode}
|
||||
class="segment-btn"
|
||||
title="Switch to sidebar navigation"
|
||||
>
|
||||
<svg class="pill-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d={getIconPath('chevronDown')}
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
<div class="segment-divider"></div>
|
||||
<button onclick={collapseNav} class="segment-btn" title="Collapse navigation">
|
||||
<svg class="pill-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d={getIconPath('chevronLeft')}
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- Logo pill / App Switcher -->
|
||||
{#if showAppSwitcher && appItems.length > 0}
|
||||
<PillDropdown
|
||||
|
|
@ -378,7 +351,7 @@
|
|||
icon="palette"
|
||||
>
|
||||
{#snippet header()}
|
||||
<div class="theme-mode-selector">
|
||||
<div class="theme-mode-selector pill glass-pill">
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => onThemeModeChange?.('light')}
|
||||
|
|
@ -469,6 +442,19 @@
|
|||
{#if userEmail}
|
||||
<PillDropdown
|
||||
items={[
|
||||
...(profileHref
|
||||
? [
|
||||
{
|
||||
id: 'profile',
|
||||
label: 'Profil',
|
||||
icon: 'user',
|
||||
onClick: () => {
|
||||
window.location.href = profileHref;
|
||||
},
|
||||
active: currentPath === profileHref,
|
||||
},
|
||||
]
|
||||
: []),
|
||||
{
|
||||
id: 'settings',
|
||||
label: 'Einstellungen',
|
||||
|
|
@ -505,6 +491,37 @@
|
|||
</button>
|
||||
{/if}
|
||||
|
||||
<!-- Control Button (right position in horizontal mode, bottom in sidebar mode) -->
|
||||
{#if !isSidebarMode}
|
||||
<div class="pill glass-pill segmented-control">
|
||||
<button onclick={collapseNav} class="segment-btn" title="Collapse navigation">
|
||||
<svg class="pill-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d={getIconPath('chevronLeft')}
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
<div class="segment-divider"></div>
|
||||
<button
|
||||
onclick={toggleSidebarMode}
|
||||
class="segment-btn"
|
||||
title="Switch to sidebar navigation"
|
||||
>
|
||||
<svg class="pill-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d={getIconPath('chevronDown')}
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- Control Button (bottom position in sidebar mode) -->
|
||||
{#if isSidebarMode}
|
||||
<div class="sidebar-spacer"></div>
|
||||
|
|
@ -714,7 +731,7 @@
|
|||
gap: 0.5rem;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
padding: 0.5rem 0.75rem;
|
||||
padding: 1rem 1rem;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
|
|
@ -723,6 +740,23 @@
|
|||
width: 100%;
|
||||
}
|
||||
|
||||
.sidebar-container :global(.pill-dropdown) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.sidebar-container :global(.pill-dropdown .trigger-button) {
|
||||
width: 100%;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.sidebar-container .segmented-control {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.sidebar-container .segmented-control .segment-btn {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
/* Transparent pills in sidebar mode */
|
||||
.sidebar-container .glass-pill,
|
||||
.sidebar-container :global(.pill-dropdown .trigger-button) {
|
||||
|
|
@ -820,6 +854,14 @@
|
|||
transition: background 0.2s;
|
||||
}
|
||||
|
||||
.segment-btn:first-child {
|
||||
border-radius: 9999px 0 0 9999px;
|
||||
}
|
||||
|
||||
.segment-btn:last-child {
|
||||
border-radius: 0 9999px 9999px 0;
|
||||
}
|
||||
|
||||
.segment-btn:hover {
|
||||
background: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
|
@ -839,7 +881,7 @@
|
|||
}
|
||||
|
||||
.sidebar-segmented {
|
||||
margin: 0 0.75rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* FAB for collapsed state */
|
||||
|
|
@ -866,28 +908,13 @@
|
|||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
/* Theme mode selector in dropdown header */
|
||||
.theme-mode-selector {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
padding: 0.25rem;
|
||||
background: rgba(255, 255, 255, 0.85);
|
||||
backdrop-filter: blur(12px);
|
||||
-webkit-backdrop-filter: blur(12px);
|
||||
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||
border-radius: 9999px;
|
||||
box-shadow:
|
||||
0 4px 6px -1px rgba(0, 0, 0, 0.1),
|
||||
0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
/* Theme mode selector in dropdown header - extends .pill.glass-pill */
|
||||
:global(.theme-mode-selector) {
|
||||
gap: 0.25rem !important;
|
||||
padding: 0.25rem !important;
|
||||
}
|
||||
|
||||
:global(.dark) .theme-mode-selector {
|
||||
background: rgba(255, 255, 255, 0.12);
|
||||
border: 1px solid rgba(255, 255, 255, 0.15);
|
||||
}
|
||||
|
||||
.mode-btn {
|
||||
:global(.mode-btn) {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
|
|
@ -901,19 +928,19 @@
|
|||
transition: all 0.15s;
|
||||
}
|
||||
|
||||
:global(.dark) .mode-btn {
|
||||
:global(.dark .mode-btn) {
|
||||
color: #f3f4f6;
|
||||
}
|
||||
|
||||
.mode-btn:hover:not(.active) {
|
||||
:global(.mode-btn:hover:not(.active)) {
|
||||
background: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
:global(.dark) .mode-btn:hover:not(.active) {
|
||||
:global(.dark .mode-btn:hover:not(.active)) {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.mode-btn.active {
|
||||
:global(.mode-btn.active) {
|
||||
background: var(--pill-primary-color, var(--color-primary-500, rgba(248, 214, 43, 0.2)));
|
||||
background: color-mix(
|
||||
in srgb,
|
||||
|
|
@ -922,7 +949,7 @@
|
|||
);
|
||||
}
|
||||
|
||||
:global(.dark) .mode-btn.active {
|
||||
:global(.dark .mode-btn.active) {
|
||||
background: color-mix(
|
||||
in srgb,
|
||||
var(--pill-primary-color, var(--color-primary-500, #3b82f6)) 30%,
|
||||
|
|
@ -930,7 +957,7 @@
|
|||
);
|
||||
}
|
||||
|
||||
.mode-icon {
|
||||
:global(.mode-icon) {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
}
|
||||
|
|
|
|||
193
pnpm-lock.yaml
generated
193
pnpm-lock.yaml
generated
|
|
@ -136,14 +136,14 @@ importers:
|
|||
version: link:../../../../packages/shared-landing-ui
|
||||
astro:
|
||||
specifier: ^5.16.0
|
||||
version: 5.16.0(@netlify/blobs@10.4.1)(@types/node@24.10.1)(ioredis@5.8.2)(jiti@1.21.7)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1)
|
||||
version: 5.16.0(@netlify/blobs@10.4.1)(@types/node@24.10.1)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1)
|
||||
typescript:
|
||||
specifier: ^5.0.0
|
||||
version: 5.9.3
|
||||
devDependencies:
|
||||
'@astrojs/tailwind':
|
||||
specifier: ^6.0.0
|
||||
version: 6.0.2(astro@5.16.0(@netlify/blobs@10.4.1)(@types/node@24.10.1)(ioredis@5.8.2)(jiti@1.21.7)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1))(tailwindcss@3.4.18(tsx@4.20.6)(yaml@2.8.1))(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3))
|
||||
version: 6.0.2(astro@5.16.0(@netlify/blobs@10.4.1)(@types/node@24.10.1)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1))(tailwindcss@3.4.18(tsx@4.20.6)(yaml@2.8.1))(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3))
|
||||
'@tailwindcss/typography':
|
||||
specifier: ^0.5.16
|
||||
version: 0.5.19(tailwindcss@3.4.18(tsx@4.20.6)(yaml@2.8.1))
|
||||
|
|
@ -277,12 +277,21 @@ importers:
|
|||
'@manacore/shared-branding':
|
||||
specifier: workspace:*
|
||||
version: link:../../../../packages/shared-branding
|
||||
'@manacore/shared-feedback-service':
|
||||
specifier: workspace:*
|
||||
version: link:../../../../packages/shared-feedback-service
|
||||
'@manacore/shared-feedback-ui':
|
||||
specifier: workspace:*
|
||||
version: link:../../../../packages/shared-feedback-ui
|
||||
'@manacore/shared-i18n':
|
||||
specifier: workspace:*
|
||||
version: link:../../../../packages/shared-i18n
|
||||
'@manacore/shared-icons':
|
||||
specifier: workspace:*
|
||||
version: link:../../../../packages/shared-icons
|
||||
'@manacore/shared-profile-ui':
|
||||
specifier: workspace:*
|
||||
version: link:../../../../packages/shared-profile-ui
|
||||
'@manacore/shared-subscription-ui':
|
||||
specifier: workspace:*
|
||||
version: link:../../../../packages/shared-subscription-ui
|
||||
|
|
@ -2639,6 +2648,41 @@ importers:
|
|||
specifier: ^5.9.3
|
||||
version: 5.9.3
|
||||
|
||||
packages/shared-feedback-service:
|
||||
dependencies:
|
||||
'@manacore/shared-feedback-types':
|
||||
specifier: workspace:*
|
||||
version: link:../shared-feedback-types
|
||||
devDependencies:
|
||||
typescript:
|
||||
specifier: ^5.7.3
|
||||
version: 5.9.3
|
||||
|
||||
packages/shared-feedback-types:
|
||||
devDependencies:
|
||||
typescript:
|
||||
specifier: ^5.7.3
|
||||
version: 5.9.3
|
||||
|
||||
packages/shared-feedback-ui:
|
||||
dependencies:
|
||||
'@manacore/shared-feedback-service':
|
||||
specifier: workspace:*
|
||||
version: link:../shared-feedback-service
|
||||
'@manacore/shared-feedback-types':
|
||||
specifier: workspace:*
|
||||
version: link:../shared-feedback-types
|
||||
devDependencies:
|
||||
svelte:
|
||||
specifier: ^5.0.0
|
||||
version: 5.44.0
|
||||
svelte-check:
|
||||
specifier: ^4.0.0
|
||||
version: 4.3.4(picomatch@4.0.3)(svelte@5.44.0)(typescript@5.9.3)
|
||||
typescript:
|
||||
specifier: ^5.7.3
|
||||
version: 5.9.3
|
||||
|
||||
packages/shared-i18n:
|
||||
devDependencies:
|
||||
svelte:
|
||||
|
|
@ -2680,6 +2724,18 @@ importers:
|
|||
specifier: ^5.0.0
|
||||
version: 5.9.3
|
||||
|
||||
packages/shared-profile-ui:
|
||||
devDependencies:
|
||||
svelte:
|
||||
specifier: ^5.0.0
|
||||
version: 5.44.0
|
||||
svelte-check:
|
||||
specifier: ^4.0.0
|
||||
version: 4.3.4(picomatch@4.0.3)(svelte@5.44.0)(typescript@5.9.3)
|
||||
typescript:
|
||||
specifier: ^5.7.3
|
||||
version: 5.9.3
|
||||
|
||||
packages/shared-subscription-types:
|
||||
devDependencies:
|
||||
typescript:
|
||||
|
|
@ -17136,16 +17192,6 @@ snapshots:
|
|||
transitivePeerDependencies:
|
||||
- ts-node
|
||||
|
||||
'@astrojs/tailwind@6.0.2(astro@5.16.0(@netlify/blobs@10.4.1)(@types/node@24.10.1)(ioredis@5.8.2)(jiti@1.21.7)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1))(tailwindcss@3.4.18(tsx@4.20.6)(yaml@2.8.1))(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3))':
|
||||
dependencies:
|
||||
astro: 5.16.0(@netlify/blobs@10.4.1)(@types/node@24.10.1)(ioredis@5.8.2)(jiti@1.21.7)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1)
|
||||
autoprefixer: 10.4.22(postcss@8.5.6)
|
||||
postcss: 8.5.6
|
||||
postcss-load-config: 4.0.2(postcss@8.5.6)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3))
|
||||
tailwindcss: 3.4.18(tsx@4.20.6)(yaml@2.8.1)
|
||||
transitivePeerDependencies:
|
||||
- ts-node
|
||||
|
||||
'@astrojs/tailwind@6.0.2(astro@5.16.0(@netlify/blobs@10.4.1)(@types/node@24.10.1)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1))(tailwindcss@3.4.18(tsx@4.20.6)(yaml@2.8.1))(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3))':
|
||||
dependencies:
|
||||
astro: 5.16.0(@netlify/blobs@10.4.1)(@types/node@24.10.1)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1)
|
||||
|
|
@ -25049,108 +25095,6 @@ snapshots:
|
|||
- uploadthing
|
||||
- yaml
|
||||
|
||||
astro@5.16.0(@netlify/blobs@10.4.1)(@types/node@24.10.1)(ioredis@5.8.2)(jiti@1.21.7)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1):
|
||||
dependencies:
|
||||
'@astrojs/compiler': 2.13.0
|
||||
'@astrojs/internal-helpers': 0.7.5
|
||||
'@astrojs/markdown-remark': 6.3.9
|
||||
'@astrojs/telemetry': 3.3.0
|
||||
'@capsizecss/unpack': 3.0.1
|
||||
'@oslojs/encoding': 1.1.0
|
||||
'@rollup/pluginutils': 5.3.0(rollup@4.53.3)
|
||||
acorn: 8.15.0
|
||||
aria-query: 5.3.2
|
||||
axobject-query: 4.1.0
|
||||
boxen: 8.0.1
|
||||
ci-info: 4.3.1
|
||||
clsx: 2.1.1
|
||||
common-ancestor-path: 1.0.1
|
||||
cookie: 1.1.0
|
||||
cssesc: 3.0.0
|
||||
debug: 4.4.3
|
||||
deterministic-object-hash: 2.0.2
|
||||
devalue: 5.5.0
|
||||
diff: 5.2.0
|
||||
dlv: 1.1.3
|
||||
dset: 3.1.4
|
||||
es-module-lexer: 1.7.0
|
||||
esbuild: 0.25.12
|
||||
estree-walker: 3.0.3
|
||||
flattie: 1.1.1
|
||||
fontace: 0.3.1
|
||||
github-slugger: 2.0.0
|
||||
html-escaper: 3.0.3
|
||||
http-cache-semantics: 4.2.0
|
||||
import-meta-resolve: 4.2.0
|
||||
js-yaml: 4.1.1
|
||||
magic-string: 0.30.21
|
||||
magicast: 0.5.1
|
||||
mrmime: 2.0.1
|
||||
neotraverse: 0.6.18
|
||||
p-limit: 6.2.0
|
||||
p-queue: 8.1.1
|
||||
package-manager-detector: 1.5.0
|
||||
piccolore: 0.1.3
|
||||
picomatch: 4.0.3
|
||||
prompts: 2.4.2
|
||||
rehype: 13.0.2
|
||||
semver: 7.7.3
|
||||
shiki: 3.15.0
|
||||
smol-toml: 1.5.2
|
||||
svgo: 4.0.0
|
||||
tinyexec: 1.0.2
|
||||
tinyglobby: 0.2.15
|
||||
tsconfck: 3.1.6(typescript@5.9.3)
|
||||
ultrahtml: 1.6.0
|
||||
unifont: 0.6.0
|
||||
unist-util-visit: 5.0.0
|
||||
unstorage: 1.17.3(@netlify/blobs@10.4.1)(ioredis@5.8.2)
|
||||
vfile: 6.0.3
|
||||
vite: 6.4.1(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)
|
||||
vitefu: 1.1.1(vite@6.4.1(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))
|
||||
xxhash-wasm: 1.1.0
|
||||
yargs-parser: 21.1.1
|
||||
yocto-spinner: 0.2.3
|
||||
zod: 3.25.76
|
||||
zod-to-json-schema: 3.25.0(zod@3.25.76)
|
||||
zod-to-ts: 1.2.0(typescript@5.9.3)(zod@3.25.76)
|
||||
optionalDependencies:
|
||||
sharp: 0.34.5
|
||||
transitivePeerDependencies:
|
||||
- '@azure/app-configuration'
|
||||
- '@azure/cosmos'
|
||||
- '@azure/data-tables'
|
||||
- '@azure/identity'
|
||||
- '@azure/keyvault-secrets'
|
||||
- '@azure/storage-blob'
|
||||
- '@capacitor/preferences'
|
||||
- '@deno/kv'
|
||||
- '@netlify/blobs'
|
||||
- '@planetscale/database'
|
||||
- '@types/node'
|
||||
- '@upstash/redis'
|
||||
- '@vercel/blob'
|
||||
- '@vercel/functions'
|
||||
- '@vercel/kv'
|
||||
- aws4fetch
|
||||
- db0
|
||||
- idb-keyval
|
||||
- ioredis
|
||||
- jiti
|
||||
- less
|
||||
- lightningcss
|
||||
- rollup
|
||||
- sass
|
||||
- sass-embedded
|
||||
- stylus
|
||||
- sugarss
|
||||
- supports-color
|
||||
- terser
|
||||
- tsx
|
||||
- typescript
|
||||
- uploadthing
|
||||
- yaml
|
||||
|
||||
astro@5.16.0(@netlify/blobs@10.4.1)(@types/node@24.10.1)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1):
|
||||
dependencies:
|
||||
'@astrojs/compiler': 2.13.0
|
||||
|
|
@ -37234,23 +37178,6 @@ snapshots:
|
|||
tsx: 4.20.6
|
||||
yaml: 2.8.1
|
||||
|
||||
vite@6.4.1(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1):
|
||||
dependencies:
|
||||
esbuild: 0.25.12
|
||||
fdir: 6.5.0(picomatch@4.0.3)
|
||||
picomatch: 4.0.3
|
||||
postcss: 8.5.6
|
||||
rollup: 4.53.3
|
||||
tinyglobby: 0.2.15
|
||||
optionalDependencies:
|
||||
'@types/node': 24.10.1
|
||||
fsevents: 2.3.3
|
||||
jiti: 1.21.7
|
||||
lightningcss: 1.30.2
|
||||
terser: 5.44.1
|
||||
tsx: 4.20.6
|
||||
yaml: 2.8.1
|
||||
|
||||
vite@6.4.1(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1):
|
||||
dependencies:
|
||||
esbuild: 0.25.12
|
||||
|
|
@ -37310,10 +37237,6 @@ snapshots:
|
|||
optionalDependencies:
|
||||
vite: 6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)
|
||||
|
||||
vitefu@1.1.1(vite@6.4.1(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)):
|
||||
optionalDependencies:
|
||||
vite: 6.4.1(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)
|
||||
|
||||
vitefu@1.1.1(vite@6.4.1(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)):
|
||||
optionalDependencies:
|
||||
vite: 6.4.1(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue