diff --git a/apps/manacore/apps/web/src/lib/modules/contacts/components/pages/ContactPage.svelte b/apps/manacore/apps/web/src/lib/modules/contacts/components/pages/ContactPage.svelte
index e5fe3f8bf..bdf87d523 100644
--- a/apps/manacore/apps/web/src/lib/modules/contacts/components/pages/ContactPage.svelte
+++ b/apps/manacore/apps/web/src/lib/modules/contacts/components/pages/ContactPage.svelte
@@ -145,11 +145,16 @@
let meta = $derived(PAGE_META[pageId]);
+ let selfContact = $derived(allContacts.find((c) => c.id === SELF_CONTACT_ID && !c.isArchived));
+
let filtered = $derived.by(() => {
const active = allContacts.filter((c) => !c.isArchived);
const byPage = active.filter(meta.filterFn);
const searched = searchContacts(byPage, searchQuery);
+ // My-profile: just show the self contact
+ if (pageId === 'my-profile') return searched;
+
// Birthday-soon: sort by upcoming birthday
if (pageId === 'birthday-soon') {
const today = startOfDay(new Date());
@@ -167,7 +172,14 @@
);
}
- return sortContacts(searched, 'firstName');
+ // Default: sort alphabetically, pin self-contact to top
+ const sorted = sortContacts(searched, 'firstName');
+ const selfIdx = sorted.findIndex((c) => c.id === SELF_CONTACT_ID);
+ if (selfIdx > 0) {
+ const [self] = sorted.splice(selfIdx, 1);
+ sorted.unshift(self);
+ }
+ return sorted;
});
let groups = $derived(
@@ -215,7 +227,10 @@
{/snippet}
- {#if filtered.length === 0}
+ {#if pageId === 'my-profile' && selfContact}
+
+ {@render profileCard(selfContact)}
+ {:else if filtered.length === 0}
Keine Kontakte
@@ -239,6 +254,51 @@
+{#snippet profileCard(contact: Contact)}
+
+
onOpenContact?.(contact)}>
+
+ {#if contact.photoUrl}
+

+ {:else}
+ {getInitials(contact)}
+ {/if}
+
+
{getDisplayName(contact)}
+ {#if contact.email}
+
+
+ {contact.email}
+
+ {/if}
+ {#if contact.phone || contact.mobile}
+
+
+
{contact.mobile || contact.phone}
+
+ {/if}
+ {#if contact.company}
+
+
+ {[contact.jobTitle, contact.company].filter(Boolean).join(' @ ')}
+
+ {/if}
+ {#if contact.city}
+
+
+ {[contact.street, contact.postalCode, contact.city].filter(Boolean).join(', ')}
+
+ {/if}
+ {#if contact.birthday}
+
+
+ {contact.birthday}
+
+ {/if}
+
Tippe zum Bearbeiten
+
+{/snippet}
+
{#snippet contactRow(contact: Contact)}
{getDisplayName(contact)}
+ {#if contact.id === SELF_CONTACT_ID}
+ Du
+ {/if}
{#if contact.isFavorite}
{/if}
@@ -445,4 +508,76 @@
.contact-row:hover .row-actions {
opacity: 1;
}
+
+ /* Self badge */
+ .self-badge {
+ font-size: 0.5625rem;
+ font-weight: 600;
+ padding: 0.0625rem 0.375rem;
+ border-radius: 9999px;
+ background: color-mix(in srgb, var(--color-primary, #8b5cf6) 12%, transparent);
+ color: var(--color-primary, #8b5cf6);
+ flex-shrink: 0;
+ }
+
+ /* Profile card */
+ .profile-card {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ padding: 1.5rem 1rem;
+ cursor: pointer;
+ border-radius: 0.375rem;
+ transition: background 0.15s;
+ }
+ .profile-card:hover {
+ background: rgba(0, 0, 0, 0.02);
+ }
+ :global(.dark) .profile-card:hover {
+ background: rgba(255, 255, 255, 0.03);
+ }
+ .profile-avatar {
+ width: 4.5rem;
+ height: 4.5rem;
+ border-radius: 9999px;
+ background: color-mix(in srgb, var(--color-primary, #8b5cf6) 12%, transparent);
+ color: var(--color-primary, #8b5cf6);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 1.25rem;
+ font-weight: 600;
+ overflow: hidden;
+ margin-bottom: 0.75rem;
+ }
+ .profile-avatar-img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ }
+ .profile-name {
+ font-size: 1.125rem;
+ font-weight: 700;
+ color: #374151;
+ margin-bottom: 0.75rem;
+ }
+ :global(.dark) .profile-name {
+ color: #f3f4f6;
+ }
+ .profile-detail {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ font-size: 0.8125rem;
+ color: #6b7280;
+ padding: 0.25rem 0;
+ }
+ :global(.dark) .profile-detail {
+ color: #9ca3af;
+ }
+ .profile-hint {
+ margin-top: 1rem;
+ font-size: 0.6875rem;
+ color: #9ca3af;
+ }
diff --git a/apps/manacore/apps/web/src/lib/modules/contacts/components/pages/ContactPagePicker.svelte b/apps/manacore/apps/web/src/lib/modules/contacts/components/pages/ContactPagePicker.svelte
index cb44cd045..a0a069e0c 100644
--- a/apps/manacore/apps/web/src/lib/modules/contacts/components/pages/ContactPagePicker.svelte
+++ b/apps/manacore/apps/web/src/lib/modules/contacts/components/pages/ContactPagePicker.svelte
@@ -2,6 +2,7 @@
import { _ } from 'svelte-i18n';
import {
Users,
+ User,
Star,
Cake,
Envelope,
@@ -21,6 +22,13 @@
let { onSelect, onClose, activePageIds = [] }: Props = $props();
const PAGE_OPTIONS = [
+ {
+ id: 'my-profile',
+ title: 'Mein Profil',
+ description: 'Deine eigene Kontaktkarte',
+ icon: User,
+ color: '#8B5CF6',
+ },
{
id: 'all',
title: 'Alle Kontakte',
diff --git a/apps/manacore/apps/web/src/routes/(app)/contacts/+page.svelte b/apps/manacore/apps/web/src/routes/(app)/contacts/+page.svelte
index f4d6a3985..be42c20f5 100644
--- a/apps/manacore/apps/web/src/routes/(app)/contacts/+page.svelte
+++ b/apps/manacore/apps/web/src/routes/(app)/contacts/+page.svelte
@@ -72,6 +72,7 @@
]);
const PAGE_META: Record = {
+ 'my-profile': { title: 'Mein Profil', color: '#8B5CF6' },
all: { title: 'Alle Kontakte', color: '#3B82F6' },
favorites: { title: 'Favoriten', color: '#F59E0B' },
'birthday-soon': { title: 'Bald Geburtstag', color: '#EC4899' },