upd personlist
This commit is contained in:
parent
883d267328
commit
6fcc58b88a
|
|
@ -1 +1 @@
|
|||
1.1.87
|
||||
1.1.89
|
||||
|
|
@ -16,15 +16,35 @@
|
|||
const subTypeLabels: Record<PersonSubType, string> = {
|
||||
contact: 'Kontakt',
|
||||
employee: 'Mitarbeiter',
|
||||
colleague: 'Kollege'
|
||||
colleague: 'Kollege',
|
||||
family: 'Familie',
|
||||
acquaintance: 'Bekannte/r'
|
||||
};
|
||||
|
||||
const subTypeColors: Record<PersonSubType, string> = {
|
||||
contact: 'bg-[#555] text-[#ccc]',
|
||||
employee: 'bg-accent/30 text-accent',
|
||||
colleague: 'bg-[#00b894]/30 text-[#00b894]'
|
||||
colleague: 'bg-[#00b894]/30 text-[#00b894]',
|
||||
family: 'bg-pink-900/40 text-pink-300',
|
||||
acquaintance: 'bg-purple-900/40 text-purple-300'
|
||||
};
|
||||
|
||||
function formatDate(iso: string): string {
|
||||
const [y, m, d] = iso.split('-');
|
||||
return `${d}.${m}.${y}`;
|
||||
}
|
||||
|
||||
function tenure(joinDate: string): string {
|
||||
const start = new Date(joinDate);
|
||||
const now = new Date();
|
||||
let years = now.getFullYear() - start.getFullYear();
|
||||
let months = now.getMonth() - start.getMonth();
|
||||
if (months < 0) { years--; months += 12; }
|
||||
if (years > 0 && months > 0) return `${years} J. ${months} Mo.`;
|
||||
if (years > 0) return `${years} J.`;
|
||||
return `${months} Mo.`;
|
||||
}
|
||||
|
||||
let confirmDeleteId = $state<string | null>(null);
|
||||
let confirmDeleteName = $state('');
|
||||
|
||||
|
|
@ -42,7 +62,10 @@
|
|||
{#if persons.length > 0}
|
||||
<div class="flex flex-col gap-2">
|
||||
{#each persons as ctx, i (ctx.id)}
|
||||
{@const subType = ((ctx.meta as PersonMeta | null)?.personSubType ?? 'contact') as PersonSubType}
|
||||
{@const meta = ctx.meta as PersonMeta | null}
|
||||
{@const subType = (meta?.personSubType ?? 'contact') as PersonSubType}
|
||||
{@const showBirthday = subType === 'family' || subType === 'employee' || subType === 'colleague'}
|
||||
{@const showTenure = subType === 'employee' && !!meta?.joinDate}
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="flex flex-col">
|
||||
<button class="text-[#555] hover:text-[#aaa] disabled:opacity-20 leading-none px-1" onclick={() => reorderContext(ctx.id, 'up')} disabled={i === 0} title="Nach oben">▲</button>
|
||||
|
|
@ -58,7 +81,15 @@
|
|||
onclick={() => goto(`/context/${ctx.id}`)}
|
||||
>
|
||||
<span class="font-bold text-white">{displayName(ctx.name)}</span>
|
||||
<span class="rounded px-2 py-0.5 text-xs {subTypeColors[subType]}">{subTypeLabels[subType]}</span>
|
||||
<span class="flex items-center gap-2">
|
||||
{#if showBirthday && meta?.birthday}
|
||||
<span class="text-xs text-muted">🎂 {formatDate(meta.birthday)}</span>
|
||||
{/if}
|
||||
{#if showTenure && meta?.joinDate}
|
||||
<span class="text-xs text-muted" title="seit {formatDate(meta.joinDate)}">⏱ {tenure(meta.joinDate)}</span>
|
||||
{/if}
|
||||
<span class="rounded px-2 py-0.5 text-xs {subTypeColors[subType]}">{subTypeLabels[subType]}</span>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
class="rounded border border-[#444] bg-sidebar px-2.5 py-2.5 text-[#888] transition-colors hover:border-red-900 hover:text-red-400"
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
import { upsertContext, contextNameExists } from '$lib/db/repositories';
|
||||
import { newId } from '$lib/db/helpers';
|
||||
import PersonList from '$lib/components/PersonList.svelte';
|
||||
import type { PersonMeta, PersonSubType } from '@ka-note/shared';
|
||||
|
||||
const allPersons = liveQuery(() =>
|
||||
db.contexts.filter(c => !c.deletedAt && c.type === 'person').sortBy('sortOrder')
|
||||
|
|
@ -12,6 +13,25 @@
|
|||
|
||||
const persons = $derived($allPersons ?? []);
|
||||
|
||||
type Tab = 'all' | PersonSubType;
|
||||
|
||||
const tabs: { key: Tab; label: string }[] = [
|
||||
{ key: 'all', label: 'Alle' },
|
||||
{ key: 'family', label: 'Familie' },
|
||||
{ key: 'colleague', label: 'Kollegen' },
|
||||
{ key: 'employee', label: 'Mitarbeiter' },
|
||||
{ key: 'contact', label: 'Kontakte' },
|
||||
{ key: 'acquaintance', label: 'Bekannte' }
|
||||
];
|
||||
|
||||
let activeTab = $state<Tab>('all');
|
||||
|
||||
const filtered = $derived(
|
||||
activeTab === 'all'
|
||||
? persons
|
||||
: persons.filter(c => ((c.meta as PersonMeta | null)?.personSubType ?? 'contact') === activeTab)
|
||||
);
|
||||
|
||||
let creating = $state(false);
|
||||
let newName = $state('');
|
||||
let createError = $state('');
|
||||
|
|
@ -39,7 +59,7 @@
|
|||
</script>
|
||||
|
||||
<div class="mx-auto max-w-3xl p-6">
|
||||
<div class="mb-6 flex items-center gap-3">
|
||||
<div class="mb-4 flex items-center gap-3">
|
||||
<h1 class="flex-1 text-2xl font-bold text-white">Alle Personen</h1>
|
||||
<button class="rounded bg-accent px-3 py-1.5 text-sm font-medium text-white hover:bg-accent/80" onclick={() => creating = true}>+ Neu</button>
|
||||
</div>
|
||||
|
|
@ -57,5 +77,20 @@
|
|||
{#if createError}<p class="mb-3 -mt-2 text-xs text-red-400">{createError}</p>{/if}
|
||||
{/if}
|
||||
|
||||
<PersonList {persons} />
|
||||
<div class="mb-4 flex flex-wrap gap-1 border-b border-[#333] pb-2">
|
||||
{#each tabs as tab}
|
||||
{@const count = tab.key === 'all' ? persons.length : persons.filter(c => ((c.meta as PersonMeta | null)?.personSubType ?? 'contact') === tab.key).length}
|
||||
{#if count > 0 || tab.key === 'all'}
|
||||
<button
|
||||
class="rounded px-3 py-1 text-sm transition-colors {activeTab === tab.key ? 'bg-accent text-white' : 'text-muted hover:text-white'}"
|
||||
onclick={() => activeTab = tab.key}
|
||||
>
|
||||
{tab.label}
|
||||
<span class="ml-1 opacity-60">{count}</span>
|
||||
</button>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<PersonList persons={filtered} />
|
||||
</div>
|
||||
|
|
|
|||
Binary file not shown.
Loading…
Reference in New Issue