opt side panel

This commit is contained in:
beo3000 2026-02-24 19:06:18 +01:00
parent 53b20cf492
commit e5a37bd7ed
4 changed files with 116 additions and 209 deletions

View File

@ -1 +1 @@
1.1.52 1.1.54

View File

@ -14,34 +14,77 @@
<div class="flex flex-wrap gap-2.5 mt-4 pt-4 border-t border-[#444]"> <div class="flex flex-wrap gap-2.5 mt-4 pt-4 border-t border-[#444]">
{#if isDailyLog} {#if isDailyLog}
<button class="flex-1 rounded bg-success px-4 py-2 font-bold text-white text-sm flex items-center justify-center gap-1" onclick={onnote}> <button
class="flex-1 rounded bg-accent px-4 py-2 font-bold text-white text-sm flex items-center justify-center gap-1 hover:brightness-110 transition-all"
onclick={onnote}
>
Notieren Notieren
</button> </button>
<button class="flex-1 rounded bg-accent px-4 py-2 font-bold text-white text-sm flex items-center justify-center gap-1" onclick={ondone}> <div class="flex gap-1.5">
Erledigt <button
</button> class="rounded border border-[#444] bg-transparent px-3 py-2 text-xs text-[#777] hover:border-warning hover:text-warning transition-all flex flex-col items-center gap-0.5 min-w-[4rem]"
<button class="flex-1 rounded bg-warning px-4 py-2 font-bold text-[#222] text-sm flex items-center justify-center gap-1" onclick={onsnooze}> onclick={onsnooze}
Später title="Später"
</button> >
<span class="text-base leading-none"></span>
<span>Später</span>
</button>
<button
class="rounded border border-[#444] bg-transparent px-3 py-2 text-xs text-[#777] hover:border-success hover:text-success transition-all flex flex-col items-center gap-0.5 min-w-[4rem]"
onclick={ondone}
title="Erledigt"
>
<span class="text-base leading-none"></span>
<span>Erledigt</span>
</button>
</div>
{:else if isMeetingMode && !isProcessed} {:else if isMeetingMode && !isProcessed}
<button class="flex-1 rounded bg-success px-4 py-2 font-bold text-white text-sm flex items-center justify-center gap-1" onclick={onnote}> <button
class="flex-1 rounded bg-accent px-4 py-2 font-bold text-white text-sm flex items-center justify-center gap-1 hover:brightness-110 transition-all"
onclick={onnote}
>
Notieren & Offen Notieren & Offen
</button> </button>
<button class="flex-1 rounded bg-warning px-4 py-2 font-bold text-[#222] text-sm flex items-center justify-center gap-1" onclick={onsnooze}> <div class="flex gap-1.5">
Verschieben <button
</button> class="rounded border border-[#444] bg-transparent px-3 py-2 text-xs text-[#777] hover:border-warning hover:text-warning transition-all flex flex-col items-center gap-0.5 min-w-[4rem]"
<button class="flex-1 rounded bg-info px-4 py-2 font-bold text-[#222] text-sm flex items-center justify-center gap-1" onclick={() => onskip?.()}> onclick={onsnooze}
Überspringen title="Verschieben"
</button> >
<button class="flex-1 rounded bg-danger px-4 py-2 font-bold text-white text-sm flex items-center justify-center gap-1" onclick={ondone}> <span class="text-base leading-none"></span>
Erledigt <span>Verschieben</span>
</button> </button>
<button
class="rounded border border-[#444] bg-transparent px-3 py-2 text-xs text-[#777] hover:border-info hover:text-info transition-all flex flex-col items-center gap-0.5 min-w-[4rem]"
onclick={() => onskip?.()}
title="Überspringen"
>
<span class="text-base leading-none"></span>
<span>Überspringen</span>
</button>
<button
class="rounded border border-[#444] bg-transparent px-3 py-2 text-xs text-[#777] hover:border-success hover:text-success transition-all flex flex-col items-center gap-0.5 min-w-[4rem]"
onclick={ondone}
title="Erledigt"
>
<span class="text-base leading-none"></span>
<span>Erledigt</span>
</button>
</div>
{:else} {:else}
<button class="flex-1 rounded bg-success px-4 py-2 font-bold text-white text-sm flex items-center justify-center gap-1" onclick={onnote}> <button
class="flex-1 rounded bg-accent px-4 py-2 font-bold text-white text-sm flex items-center justify-center gap-1 hover:brightness-110 transition-all"
onclick={onnote}
>
Speichern Speichern
</button> </button>
<button class="ml-auto rounded bg-danger px-4 py-2 font-bold text-white text-sm flex items-center justify-center gap-1" onclick={ondone}> <button
Archivieren class="rounded border border-[#444] bg-transparent px-3 py-2 text-xs text-[#777] hover:border-success hover:text-success transition-all flex flex-col items-center gap-0.5 min-w-[4rem]"
onclick={ondone}
title="Erledigt"
>
<span class="text-base leading-none"></span>
<span>Erledigt</span>
</button> </button>
{/if} {/if}
</div> </div>

View File

@ -5,10 +5,8 @@
import { liveQuery } from 'dexie'; import { liveQuery } from 'dexie';
import { db } from '$lib/db/schema'; import { db } from '$lib/db/schema';
import { resetAndReseed } from '$lib/db/seed'; import { resetAndReseed } from '$lib/db/seed';
import { upsertContext } from '$lib/db/repositories'; import type { AgendaContext } from '@ka-note/shared';
import { newId } from '$lib/db/helpers'; import { account, logout } from '$lib/auth/authStore.js';
import type { AgendaContext, ContextType } from '@ka-note/shared';
import { account, logout, login } from '$lib/auth/authStore.js';
import { syncStatus, lastSyncAt, fullSync } from '$lib/sync/syncService'; import { syncStatus, lastSyncAt, fullSync } from '$lib/sync/syncService';
import { deletedItemCount } from '$lib/stores/agenda'; import { deletedItemCount } from '$lib/stores/agenda';
import { favoriteNotebooks } from '$lib/stores/wiki'; import { favoriteNotebooks } from '$lib/stores/wiki';
@ -42,9 +40,6 @@
collapsed[key] = !collapsed[key]; collapsed[key] = !collapsed[key];
} }
let creatingType: ContextType | null = $state(null);
let newName = $state('');
function navigate(id: string) { function navigate(id: string) {
goto(`/context/${id}`); goto(`/context/${id}`);
onnavigate?.(); onnavigate?.();
@ -57,46 +52,17 @@
return ctx.name; return ctx.name;
} }
function startCreating(type: ContextType) { // Active nav item style: subtle left border indicator
creatingType = type; function navItem(active: boolean) {
newName = ''; return active
? 'mb-1 w-full rounded-r px-2.5 py-2 text-left text-sm border-l-2 border-accent bg-white/8 font-semibold text-white'
: 'mb-1 w-full rounded px-2.5 py-2 text-left text-sm border-l-2 border-transparent text-[#aaa] hover:bg-white/5 hover:text-white transition-colors';
} }
function cancelCreating() { // Section header: ▼ toggle (small) + label (navigates to overview)
creatingType = null; const sectionHeader = 'flex items-center gap-2 mt-6 mb-1 pl-1 pr-1';
newName = ''; const sectionToggle = 'text-[10px] text-muted hover:text-white transition-colors flex-shrink-0 px-1 py-1';
} const sectionLabel = 'text-xs uppercase text-muted hover:text-white flex items-center gap-1.5 transition-colors flex-1 text-left font-medium tracking-wide';
async function createNewContext() {
const name = newName.trim();
if (!name || !creatingType) return;
const type = creatingType;
const slug = name.toLowerCase().replace(/\s+/g, '-');
const id = type === 'company' ? `f-${slug}` : type === 'person' ? `u-${slug}` : type === 'project' ? `p-${slug}` : newId();
const fullName = type === 'company' ? `Firma ${name}` : type === 'project' ? `Project ${name}` : type === 'person' ? `Person ${name}` : name;
const existing = ($contexts ?? []).filter((c: AgendaContext) => c.type === type);
const sortOrder = existing.length;
const meta = type === 'person' ? { fullName: '', email: '', phone: '', duSince: '', personSubType: 'contact' as const } : undefined;
await upsertContext({ id, name: fullName, type, sortOrder, ...(meta ? { meta } : {}) });
cancelCreating();
navigate(id);
}
function handleInputKeydown(e: KeyboardEvent) {
if (e.key === 'Enter') {
e.preventDefault();
createNewContext();
} else if (e.key === 'Escape') {
cancelCreating();
}
}
function autofocus(node: HTMLElement) {
node.focus();
}
</script> </script>
{#if !hideLogo} {#if !hideLogo}
@ -108,244 +74,142 @@
{/if} {/if}
<!-- General --> <!-- General -->
<div class="mb-1 mt-6 pl-1 text-xs uppercase text-muted">General</div> <div class="mb-1 mt-6 pl-1 text-xs uppercase text-muted flex items-center gap-1.5 font-medium tracking-wide"><span>🏠</span> General</div>
<ul class="m-0 list-none p-0"> <ul class="m-0 list-none p-0">
{#if dailyLog} {#if dailyLog}
<li> <li>
<button <button class={navItem(currentId === 'daily-log')} onclick={() => navigate('daily-log')}>
class="mb-1 w-full rounded px-2.5 py-2.5 text-left text-sm transition-colors {currentId === 'daily-log' ? 'bg-accent font-bold text-white' : 'text-[#ccc] hover:bg-white/5 hover:text-white'}"
onclick={() => navigate('daily-log')}
>
{dailyLog.name} {dailyLog.name}
</button> </button>
</li> </li>
{/if} {/if}
</ul>
<!-- Archive -->
<ul class="m-0 list-none p-0">
<li> <li>
<button <button
class="mb-1 w-full rounded px-2.5 py-2.5 text-left text-sm transition-colors {page.url.pathname.startsWith('/journal/archive') ? 'bg-accent font-bold text-white' : 'text-[#ccc] hover:bg-white/5 hover:text-white'}" class={navItem(page.url.pathname.startsWith('/journal/archive'))}
onclick={() => { goto('/journal/archive'); onnavigate?.(); }} onclick={() => { goto('/journal/archive'); onnavigate?.(); }}
> >
📅 Archiv Archiv
</button> </button>
</li> </li>
</ul> </ul>
<!-- Jour Fixes --> <!-- Jour Fixes -->
<div class="mb-1 mt-6 flex items-center justify-between pl-1 pr-1"> <div class={sectionHeader}>
<button class="text-xs uppercase text-muted hover:text-white flex items-center gap-1" onclick={() => toggleSection('meetings')}> <button class={sectionToggle} onclick={() => toggleSection('meetings')} title="Auf-/Zuklappen">
<span class="inline-block text-[10px] transition-transform {collapsed['meetings'] ? '-rotate-90' : ''}">{@html '&#9660;'}</span> <span class="inline-block transition-transform {collapsed['meetings'] ? '-rotate-90' : ''}">{@html '&#9660;'}</span>
Jour Fixes </button>
<button class={sectionLabel} onclick={() => { goto('/meetings'); onnavigate?.(); }}>
<span>💬</span> Jour Fixes
</button> </button>
<button class="text-muted hover:text-white text-sm leading-none" onclick={() => startCreating('meeting')}>+</button>
</div> </div>
{#if !collapsed['meetings']} {#if !collapsed['meetings']}
<ul class="m-0 list-none p-0"> <ul class="m-0 list-none p-0">
{#each meetings as ctx} {#each meetings as ctx}
<li> <li>
<button <button class={navItem(currentId === ctx.id)} onclick={() => navigate(ctx.id)}>
class="mb-1 w-full rounded px-2.5 py-2.5 text-left text-sm transition-colors {currentId === ctx.id ? 'bg-accent font-bold text-white' : 'text-[#ccc] hover:bg-white/5 hover:text-white'}"
onclick={() => navigate(ctx.id)}
>
{ctx.name} {ctx.name}
</button> </button>
</li> </li>
{/each} {/each}
{#if creatingType === 'meeting'}
<li>
<input
class="mb-1 w-full rounded bg-white/10 px-2.5 py-2 text-sm text-white outline-none placeholder:text-muted"
placeholder="Name..."
bind:value={newName}
onkeydown={handleInputKeydown}
onblur={cancelCreating}
use:autofocus
/>
</li>
{/if}
<li>
<button
class="mb-1 w-full rounded px-2.5 py-2.5 text-left text-xs text-[#666] transition-colors hover:bg-white/5 hover:text-[#aaa]"
onclick={() => { goto('/meetings'); onnavigate?.(); }}
>
Alle Jour Fixes &rarr;
</button>
</li>
</ul> </ul>
{/if} {/if}
<!-- Projects --> <!-- Projects -->
<div class="mb-1 mt-6 flex items-center justify-between pl-1 pr-1"> <div class={sectionHeader}>
<button class="text-xs uppercase text-muted hover:text-white flex items-center gap-1" onclick={() => toggleSection('projects')}> <button class={sectionToggle} onclick={() => toggleSection('projects')} title="Auf-/Zuklappen">
<span class="inline-block text-[10px] transition-transform {collapsed['projects'] ? '-rotate-90' : ''}">{@html '&#9660;'}</span> <span class="inline-block transition-transform {collapsed['projects'] ? '-rotate-90' : ''}">{@html '&#9660;'}</span>
Projects </button>
<button class={sectionLabel} onclick={() => { goto('/projects'); onnavigate?.(); }}>
<span>📁</span> Projects
</button> </button>
<button class="text-muted hover:text-white text-sm leading-none" onclick={() => startCreating('project')}>+</button>
</div> </div>
{#if !collapsed['projects']} {#if !collapsed['projects']}
<ul class="m-0 list-none p-0"> <ul class="m-0 list-none p-0">
{#each projects as ctx} {#each projects as ctx}
<li> <li>
<button <button class={navItem(currentId === ctx.id)} onclick={() => navigate(ctx.id)}>
class="mb-1 w-full rounded px-2.5 py-2.5 text-left text-sm transition-colors {currentId === ctx.id ? 'bg-accent font-bold text-white' : 'text-[#ccc] hover:bg-white/5 hover:text-white'}"
onclick={() => navigate(ctx.id)}
>
{displayName(ctx)} {displayName(ctx)}
</button> </button>
</li> </li>
{/each} {/each}
{#if creatingType === 'project'}
<li>
<input
class="mb-1 w-full rounded bg-white/10 px-2.5 py-2 text-sm text-white outline-none placeholder:text-muted"
placeholder="Name..."
bind:value={newName}
onkeydown={handleInputKeydown}
onblur={cancelCreating}
use:autofocus
/>
</li>
{/if}
<li>
<button
class="mb-1 w-full rounded px-2.5 py-2.5 text-left text-xs text-[#666] transition-colors hover:bg-white/5 hover:text-[#aaa]"
onclick={() => { goto('/projects'); onnavigate?.(); }}
>
Alle Projekte &rarr;
</button>
</li>
</ul> </ul>
{/if} {/if}
<!-- Companies --> <!-- Companies -->
<div class="mb-1 mt-6 flex items-center justify-between pl-1 pr-1"> <div class={sectionHeader}>
<button class="text-xs uppercase text-muted hover:text-white flex items-center gap-1" onclick={() => toggleSection('companies')}> <button class={sectionToggle} onclick={() => toggleSection('companies')} title="Auf-/Zuklappen">
<span class="inline-block text-[10px] transition-transform {collapsed['companies'] ? '-rotate-90' : ''}">{@html '&#9660;'}</span> <span class="inline-block transition-transform {collapsed['companies'] ? '-rotate-90' : ''}">{@html '&#9660;'}</span>
Firmen </button>
<button class={sectionLabel} onclick={() => { goto('/companies'); onnavigate?.(); }}>
<span>🏢</span> Firmen
</button> </button>
<button class="text-muted hover:text-white text-sm leading-none" onclick={() => startCreating('company')}>+</button>
</div> </div>
{#if !collapsed['companies']} {#if !collapsed['companies']}
<ul class="m-0 list-none p-0"> <ul class="m-0 list-none p-0">
{#each companies as ctx} {#each companies as ctx}
<li> <li>
<button <button class={navItem(currentId === ctx.id)} onclick={() => navigate(ctx.id)}>
class="mb-1 w-full rounded px-2.5 py-2.5 text-left text-sm transition-colors {currentId === ctx.id ? 'bg-accent font-bold text-white' : 'text-[#ccc] hover:bg-white/5 hover:text-white'}"
onclick={() => navigate(ctx.id)}
>
{displayName(ctx)} {displayName(ctx)}
</button> </button>
</li> </li>
{/each} {/each}
{#if creatingType === 'company'}
<li>
<input
class="mb-1 w-full rounded bg-white/10 px-2.5 py-2 text-sm text-white outline-none placeholder:text-muted"
placeholder="Name..."
bind:value={newName}
onkeydown={handleInputKeydown}
onblur={cancelCreating}
use:autofocus
/>
</li>
{/if}
<li>
<button
class="mb-1 w-full rounded px-2.5 py-2.5 text-left text-xs text-[#666] transition-colors hover:bg-white/5 hover:text-[#aaa]"
onclick={() => { goto('/companies'); onnavigate?.(); }}
>
Alle Firmen &rarr;
</button>
</li>
</ul> </ul>
{/if} {/if}
<!-- People --> <!-- People -->
<div class="mb-1 mt-6 flex items-center justify-between pl-1 pr-1"> <div class={sectionHeader}>
<button class="text-xs uppercase text-muted hover:text-white flex items-center gap-1" onclick={() => toggleSection('people')}> <button class={sectionToggle} onclick={() => toggleSection('people')} title="Auf-/Zuklappen">
<span class="inline-block text-[10px] transition-transform {collapsed['people'] ? '-rotate-90' : ''}">{@html '&#9660;'}</span> <span class="inline-block transition-transform {collapsed['people'] ? '-rotate-90' : ''}">{@html '&#9660;'}</span>
People </button>
<button class={sectionLabel} onclick={() => { goto('/persons'); onnavigate?.(); }}>
<span>👤</span> People
</button> </button>
<button class="text-muted hover:text-white text-sm leading-none" onclick={() => startCreating('person')}>+</button>
</div> </div>
{#if !collapsed['people']} {#if !collapsed['people']}
<ul class="m-0 list-none p-0"> <ul class="m-0 list-none p-0">
{#each people as ctx} {#each people as ctx}
<li> <li>
<button <button class={navItem(currentId === ctx.id)} onclick={() => navigate(ctx.id)}>
class="mb-1 w-full rounded px-2.5 py-2.5 text-left text-sm transition-colors {currentId === ctx.id ? 'bg-accent font-bold text-white' : 'text-[#ccc] hover:bg-white/5 hover:text-white'}"
onclick={() => navigate(ctx.id)}
>
{displayName(ctx)} {displayName(ctx)}
</button> </button>
</li> </li>
{/each} {/each}
{#if creatingType === 'person'}
<li>
<input
class="mb-1 w-full rounded bg-white/10 px-2.5 py-2 text-sm text-white outline-none placeholder:text-muted"
placeholder="Name..."
bind:value={newName}
onkeydown={handleInputKeydown}
onblur={cancelCreating}
use:autofocus
/>
</li>
{/if}
<li>
<button
class="mb-1 w-full rounded px-2.5 py-2.5 text-left text-xs text-[#666] transition-colors hover:bg-white/5 hover:text-[#aaa]"
onclick={() => { goto('/persons'); onnavigate?.(); }}
>
Alle Personen &rarr;
</button>
</li>
</ul> </ul>
{/if} {/if}
<!-- Wiki --> <!-- Wiki -->
<div class="mb-1 mt-6 flex items-center justify-between pl-1 pr-1"> <div class={sectionHeader}>
<button class="text-xs uppercase text-muted hover:text-white flex items-center gap-1" onclick={() => toggleSection('wiki')}> <button class={sectionToggle} onclick={() => toggleSection('wiki')} title="Auf-/Zuklappen">
<span class="inline-block text-[10px] transition-transform {collapsed['wiki'] ? '-rotate-90' : ''}">{@html '&#9660;'}</span> <span class="inline-block transition-transform {collapsed['wiki'] ? '-rotate-90' : ''}">{@html '&#9660;'}</span>
Wiki </button>
<button class={sectionLabel} onclick={() => { goto('/wiki'); onnavigate?.(); }}>
<span>📖</span> Wiki
</button> </button>
<button class="text-muted hover:text-white text-sm leading-none" onclick={() => { goto('/wiki'); onnavigate?.(); }}>↗</button>
</div> </div>
{#if !collapsed['wiki']} {#if !collapsed['wiki']}
<ul class="m-0 list-none p-0"> <ul class="m-0 list-none p-0">
{#each ($wikiNotebooks$ ?? []) as nb} {#each ($wikiNotebooks$ ?? []) as nb}
<li> <li>
<button <button
class="mb-1 w-full rounded px-2.5 py-2.5 text-left text-sm transition-colors text-[#ccc] hover:bg-white/5 hover:text-white" class={navItem(page.url.pathname === `/wiki/notebook/${nb.id}`)}
onclick={() => { goto(`/wiki/notebook/${nb.id}`); onnavigate?.(); }} onclick={() => { goto(`/wiki/notebook/${nb.id}`); onnavigate?.(); }}
> >
{nb.name} {nb.name}
</button> </button>
</li> </li>
{/each} {/each}
<li>
<button
class="mb-1 w-full rounded px-2.5 py-2.5 text-left text-xs text-[#666] transition-colors hover:bg-white/5 hover:text-[#aaa]"
onclick={() => { goto('/wiki'); onnavigate?.(); }}
>
Alle Notizbücher &rarr;
</button>
</li>
</ul> </ul>
{/if} {/if}
<div class="mt-4"> <div class="mt-4">
<button <button
class="mb-1 w-full rounded px-2.5 py-2.5 text-left text-sm transition-colors flex items-center gap-2 text-[#ccc] hover:bg-white/5 hover:text-white" class={navItem(page.url.pathname === '/trash') + ' flex items-center gap-2'}
onclick={() => { goto('/trash'); onnavigate?.(); }} onclick={() => { goto('/trash'); onnavigate?.(); }}
> >
<span>🗑</span> <span>🗑</span>
<span>Papierkorb</span> <span>Papierkorb</span>
{#if ($trashCount$ ?? 0) > 0} {#if ($trashCount$ ?? 0) > 0}
<span class="ml-auto rounded-full bg-danger/70 px-1.5 py-0.5 text-xs text-white leading-none">{$trashCount$}</span> <span class="ml-auto rounded-full bg-white/15 px-1.5 py-0.5 text-xs text-[#888] leading-none">{$trashCount$}</span>
{/if} {/if}
</button> </button>
</div> </div>

Binary file not shown.