upd meniu
This commit is contained in:
parent
fa4d3046d0
commit
81a5a90b20
|
|
@ -21,10 +21,16 @@
|
|||
const contexts = liveQuery(() => db.contexts.filter(c => !c.deletedAt && !c.archivedAt).sortBy('sortOrder'));
|
||||
|
||||
const dailyLog = $derived(($contexts ?? []).find((c: AgendaContext) => c.id === 'daily-log'));
|
||||
const meetings = $derived(($contexts ?? []).filter((c: AgendaContext) => c.type === 'meeting' && c.id !== 'daily-log'));
|
||||
const projects = $derived(($contexts ?? []).filter((c: AgendaContext) => c.type === 'project'));
|
||||
const companies = $derived(($contexts ?? []).filter((c: AgendaContext) => c.type === 'company'));
|
||||
const people = $derived(($contexts ?? []).filter((c: AgendaContext) => c.type === 'person'));
|
||||
const meetings = $derived(($contexts ?? []).filter((c: AgendaContext) => c.type === 'meeting' && c.id !== 'daily-log' && c.isFavorite));
|
||||
const projects = $derived(($contexts ?? []).filter((c: AgendaContext) => c.type === 'project' && c.isFavorite));
|
||||
const companies = $derived(($contexts ?? []).filter((c: AgendaContext) => c.type === 'company' && c.isFavorite));
|
||||
const people = $derived(($contexts ?? []).filter((c: AgendaContext) => c.type === 'person' && c.isFavorite));
|
||||
|
||||
let collapsed: Record<string, boolean> = $state({});
|
||||
|
||||
function toggleSection(key: string) {
|
||||
collapsed[key] = !collapsed[key];
|
||||
}
|
||||
|
||||
let creatingType: ContextType | null = $state(null);
|
||||
let newName = $state('');
|
||||
|
|
@ -103,9 +109,13 @@
|
|||
|
||||
<!-- Jour Fixes -->
|
||||
<div class="mb-1 mt-4 flex items-center justify-between pl-1 pr-1">
|
||||
<span class="text-xs uppercase text-muted">Jour Fixes</span>
|
||||
<button class="text-xs uppercase text-muted hover:text-white flex items-center gap-1" onclick={() => toggleSection('meetings')}>
|
||||
<span class="inline-block text-[10px] transition-transform {collapsed['meetings'] ? '-rotate-90' : ''}">{@html '▼'}</span>
|
||||
Jour Fixes
|
||||
</button>
|
||||
<button class="text-muted hover:text-white text-sm leading-none" onclick={() => startCreating('meeting')}>+</button>
|
||||
</div>
|
||||
{#if !collapsed['meetings']}
|
||||
<ul class="m-0 list-none p-0">
|
||||
{#each meetings as ctx}
|
||||
<li>
|
||||
|
|
@ -138,12 +148,17 @@
|
|||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
{/if}
|
||||
|
||||
<!-- Projects -->
|
||||
<div class="mb-1 mt-4 flex items-center justify-between pl-1 pr-1">
|
||||
<span class="text-xs uppercase text-muted">Projects</span>
|
||||
<button class="text-xs uppercase text-muted hover:text-white flex items-center gap-1" onclick={() => toggleSection('projects')}>
|
||||
<span class="inline-block text-[10px] transition-transform {collapsed['projects'] ? '-rotate-90' : ''}">{@html '▼'}</span>
|
||||
Projects
|
||||
</button>
|
||||
<button class="text-muted hover:text-white text-sm leading-none" onclick={() => startCreating('project')}>+</button>
|
||||
</div>
|
||||
{#if !collapsed['projects']}
|
||||
<ul class="m-0 list-none p-0">
|
||||
{#each projects as ctx}
|
||||
<li>
|
||||
|
|
@ -176,12 +191,17 @@
|
|||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
{/if}
|
||||
|
||||
<!-- Companies -->
|
||||
<div class="mb-1 mt-4 flex items-center justify-between pl-1 pr-1">
|
||||
<span class="text-xs uppercase text-muted">Firmen</span>
|
||||
<button class="text-xs uppercase text-muted hover:text-white flex items-center gap-1" onclick={() => toggleSection('companies')}>
|
||||
<span class="inline-block text-[10px] transition-transform {collapsed['companies'] ? '-rotate-90' : ''}">{@html '▼'}</span>
|
||||
Firmen
|
||||
</button>
|
||||
<button class="text-muted hover:text-white text-sm leading-none" onclick={() => startCreating('company')}>+</button>
|
||||
</div>
|
||||
{#if !collapsed['companies']}
|
||||
<ul class="m-0 list-none p-0">
|
||||
{#each companies as ctx}
|
||||
<li>
|
||||
|
|
@ -214,12 +234,17 @@
|
|||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
{/if}
|
||||
|
||||
<!-- People -->
|
||||
<div class="mb-1 mt-4 flex items-center justify-between pl-1 pr-1">
|
||||
<span class="text-xs uppercase text-muted">People</span>
|
||||
<button class="text-xs uppercase text-muted hover:text-white flex items-center gap-1" onclick={() => toggleSection('people')}>
|
||||
<span class="inline-block text-[10px] transition-transform {collapsed['people'] ? '-rotate-90' : ''}">{@html '▼'}</span>
|
||||
People
|
||||
</button>
|
||||
<button class="text-muted hover:text-white text-sm leading-none" onclick={() => startCreating('person')}>+</button>
|
||||
</div>
|
||||
{#if !collapsed['people']}
|
||||
<ul class="m-0 list-none p-0">
|
||||
{#each people as ctx}
|
||||
<li>
|
||||
|
|
@ -252,6 +277,7 @@
|
|||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
{/if}
|
||||
|
||||
{#if isDev}
|
||||
<div class="mt-auto border-t border-border pt-3">
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ export async function upsertContext(ctx: Partial<AgendaContext> & { id: string }
|
|||
sortOrder: 0,
|
||||
meta: null,
|
||||
archivedAt: null,
|
||||
isFavorite: false,
|
||||
deletedAt: null,
|
||||
updatedAt: now(),
|
||||
version: 1,
|
||||
|
|
@ -57,6 +58,13 @@ export async function unarchiveContext(id: string): Promise<void> {
|
|||
}
|
||||
}
|
||||
|
||||
export async function toggleFavorite(id: string): Promise<void> {
|
||||
const ctx = await db.contexts.get(id);
|
||||
if (ctx) {
|
||||
await db.contexts.update(id, { isFavorite: !ctx.isFavorite, updatedAt: now(), version: ctx.version + 1 });
|
||||
}
|
||||
}
|
||||
|
||||
export async function findContextByMentionName(name: string, type: 'person' | 'project' | 'company'): Promise<AgendaContext | undefined> {
|
||||
const q = name.toLowerCase();
|
||||
return db.contexts
|
||||
|
|
|
|||
|
|
@ -60,6 +60,14 @@ export class KaNoteDB extends Dexie {
|
|||
if (rating.comment === undefined) rating.comment = null;
|
||||
});
|
||||
});
|
||||
|
||||
this.version(6).stores({
|
||||
contexts: 'id, type, sortOrder, deletedAt, archivedAt, isFavorite'
|
||||
}).upgrade(tx => {
|
||||
return tx.table('contexts').toCollection().modify(ctx => {
|
||||
if (ctx.isFavorite === undefined) ctx.isFavorite = false;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,16 +13,16 @@ export async function seedIfEmpty(): Promise<void> {
|
|||
const ts = now();
|
||||
|
||||
const contexts: AgendaContext[] = [
|
||||
{ id: 'daily-log', name: 'Daily Log / Inbox', type: 'meeting', sortOrder: 0, meta: null, archivedAt: null, updatedAt: ts, deletedAt: null, version: 1 },
|
||||
{ id: 'jf-sysadmins', name: 'JF Team Sysadmins', type: 'meeting', sortOrder: 1, meta: null, archivedAt: null, updatedAt: ts, deletedAt: null, version: 1 },
|
||||
{ id: 'jf-devs', name: 'JF Developer', type: 'meeting', sortOrder: 2, meta: null, archivedAt: null, updatedAt: ts, deletedAt: null, version: 1 },
|
||||
{ id: 'p-tisax', name: 'Project TISAX', type: 'project', sortOrder: 0, meta: { status: '#stInArbeit', owner: 'STEFE', links: 'FileServer/Projects/TISAX' }, archivedAt: null, updatedAt: ts, deletedAt: null, version: 1 },
|
||||
{ id: 'p-cloud-migration', name: 'Project CLOUD-MIGRATION', type: 'project', sortOrder: 1, meta: { status: '#stBlocked', owner: 'CHFI', links: 'Jira-1234' }, archivedAt: null, updatedAt: ts, deletedAt: null, version: 1 },
|
||||
{ id: 'u-stefe', name: 'Person STEFE', type: 'person', sortOrder: 0, meta: { fullName: 'Stefan E.', email: 'stefe@example.com', phone: '+49 123 456', duSince: '2020', personSubType: 'employee' }, archivedAt: null, updatedAt: ts, deletedAt: null, version: 1 },
|
||||
{ id: 'u-chfi', name: 'Person CHFI', type: 'person', sortOrder: 1, meta: { fullName: 'Christoph F.', email: 'chfi@example.com', phone: '98765', duSince: '2024', personSubType: 'employee' }, archivedAt: null, updatedAt: ts, deletedAt: null, version: 1 },
|
||||
{ id: 'u-vendor-x', name: 'Person VENDOR-X', type: 'person', sortOrder: 2, meta: { fullName: 'Hr. Müller (Vendor X)', email: 'sales@vendor-x.com', phone: '', duSince: '', personSubType: 'contact' }, archivedAt: null, updatedAt: ts, deletedAt: null, version: 1 },
|
||||
{ id: 'u-chrkl', name: 'Person ChrKl', type: 'person', sortOrder: 3, meta: { fullName: 'Christian Kl.', email: '', phone: '', duSince: '', personSubType: 'colleague' }, archivedAt: null, updatedAt: ts, deletedAt: null, version: 1 },
|
||||
{ id: 'f-vendor-x', name: 'Firma VENDOR-X', type: 'company', sortOrder: 0, meta: { website: 'https://vendor-x.com', address: 'Musterstr. 1, 12345 Berlin' }, archivedAt: null, updatedAt: ts, deletedAt: null, version: 1 }
|
||||
{ id: 'daily-log', name: 'Daily Log / Inbox', type: 'meeting', sortOrder: 0, meta: null, archivedAt: null, isFavorite: true, updatedAt: ts, deletedAt: null, version: 1 },
|
||||
{ id: 'jf-sysadmins', name: 'JF Team Sysadmins', type: 'meeting', sortOrder: 1, meta: null, archivedAt: null, isFavorite: true, updatedAt: ts, deletedAt: null, version: 1 },
|
||||
{ id: 'jf-devs', name: 'JF Developer', type: 'meeting', sortOrder: 2, meta: null, archivedAt: null, isFavorite: true, updatedAt: ts, deletedAt: null, version: 1 },
|
||||
{ id: 'p-tisax', name: 'Project TISAX', type: 'project', sortOrder: 0, meta: { status: '#stInArbeit', owner: 'STEFE', links: 'FileServer/Projects/TISAX' }, archivedAt: null, isFavorite: true, updatedAt: ts, deletedAt: null, version: 1 },
|
||||
{ id: 'p-cloud-migration', name: 'Project CLOUD-MIGRATION', type: 'project', sortOrder: 1, meta: { status: '#stBlocked', owner: 'CHFI', links: 'Jira-1234' }, archivedAt: null, isFavorite: false, updatedAt: ts, deletedAt: null, version: 1 },
|
||||
{ id: 'u-stefe', name: 'Person STEFE', type: 'person', sortOrder: 0, meta: { fullName: 'Stefan E.', email: 'stefe@example.com', phone: '+49 123 456', duSince: '2020', personSubType: 'employee' }, archivedAt: null, isFavorite: true, updatedAt: ts, deletedAt: null, version: 1 },
|
||||
{ id: 'u-chfi', name: 'Person CHFI', type: 'person', sortOrder: 1, meta: { fullName: 'Christoph F.', email: 'chfi@example.com', phone: '98765', duSince: '2024', personSubType: 'employee' }, archivedAt: null, isFavorite: false, updatedAt: ts, deletedAt: null, version: 1 },
|
||||
{ id: 'u-vendor-x', name: 'Person VENDOR-X', type: 'person', sortOrder: 2, meta: { fullName: 'Hr. Müller (Vendor X)', email: 'sales@vendor-x.com', phone: '', duSince: '', personSubType: 'contact' }, archivedAt: null, isFavorite: false, updatedAt: ts, deletedAt: null, version: 1 },
|
||||
{ id: 'u-chrkl', name: 'Person ChrKl', type: 'person', sortOrder: 3, meta: { fullName: 'Christian Kl.', email: '', phone: '', duSince: '', personSubType: 'colleague' }, archivedAt: null, isFavorite: false, updatedAt: ts, deletedAt: null, version: 1 },
|
||||
{ id: 'f-vendor-x', name: 'Firma VENDOR-X', type: 'company', sortOrder: 0, meta: { website: 'https://vendor-x.com', address: 'Musterstr. 1, 12345 Berlin' }, archivedAt: null, isFavorite: true, updatedAt: ts, deletedAt: null, version: 1 }
|
||||
];
|
||||
|
||||
// Topic IDs
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@
|
|||
|
||||
<!-- Sidebar -->
|
||||
<aside
|
||||
class="fixed z-40 flex h-full w-[250px] flex-col border-r border-border bg-sidebar p-5 transition-transform md:static md:translate-x-0 {sidebarOpen ? 'translate-x-0' : '-translate-x-full'}"
|
||||
class="fixed z-40 flex h-full w-[250px] flex-col border-r border-border bg-sidebar p-5 overflow-y-auto transition-transform md:static md:translate-x-0 {sidebarOpen ? 'translate-x-0' : '-translate-x-full'}"
|
||||
>
|
||||
<Sidebar onnavigate={closeSidebar} />
|
||||
</aside>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
import { goto } from '$app/navigation';
|
||||
import { liveQuery } from 'dexie';
|
||||
import { db } from '$lib/db/schema';
|
||||
import { softDeleteContext } from '$lib/db/repositories';
|
||||
import { softDeleteContext, toggleFavorite } from '$lib/db/repositories';
|
||||
import ConfirmDialog from '$lib/components/ConfirmDialog.svelte';
|
||||
|
||||
const allCompanies = liveQuery(() =>
|
||||
|
|
@ -36,6 +36,11 @@
|
|||
<div class="flex flex-col gap-2">
|
||||
{#each companies as ctx (ctx.id)}
|
||||
<div class="flex items-center gap-2">
|
||||
<button
|
||||
class="rounded border border-[#444] bg-sidebar px-2.5 py-2.5 transition-colors hover:border-[#666] {ctx.isFavorite ? 'text-yellow-400' : 'text-[#555] hover:text-yellow-400/60'}"
|
||||
onclick={() => toggleFavorite(ctx.id)}
|
||||
title={ctx.isFavorite ? 'Aus Sidebar entfernen' : 'In Sidebar anzeigen'}
|
||||
>★</button>
|
||||
<button
|
||||
class="flex flex-1 items-center justify-between rounded-lg border border-[#444] bg-sidebar px-4 py-3 text-left transition-colors hover:border-[#666] hover:bg-[#2a2a2a]"
|
||||
onclick={() => goto(`/context/${ctx.id}`)}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
import { goto } from '$app/navigation';
|
||||
import { liveQuery } from 'dexie';
|
||||
import { db } from '$lib/db/schema';
|
||||
import { softDeleteContext } from '$lib/db/repositories';
|
||||
import { softDeleteContext, toggleFavorite } from '$lib/db/repositories';
|
||||
import ConfirmDialog from '$lib/components/ConfirmDialog.svelte';
|
||||
|
||||
const allMeetings = liveQuery(() =>
|
||||
|
|
@ -32,6 +32,11 @@
|
|||
<div class="flex flex-col gap-2">
|
||||
{#each meetings as ctx (ctx.id)}
|
||||
<div class="flex items-center gap-2">
|
||||
<button
|
||||
class="rounded border border-[#444] bg-sidebar px-2.5 py-2.5 transition-colors hover:border-[#666] {ctx.isFavorite ? 'text-yellow-400' : 'text-[#555] hover:text-yellow-400/60'}"
|
||||
onclick={() => toggleFavorite(ctx.id)}
|
||||
title={ctx.isFavorite ? 'Aus Sidebar entfernen' : 'In Sidebar anzeigen'}
|
||||
>★</button>
|
||||
<button
|
||||
class="flex flex-1 items-center justify-between rounded-lg border border-[#444] bg-sidebar px-4 py-3 text-left transition-colors hover:border-[#666] hover:bg-[#2a2a2a]"
|
||||
onclick={() => goto(`/context/${ctx.id}`)}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
import { goto } from '$app/navigation';
|
||||
import { liveQuery } from 'dexie';
|
||||
import { db } from '$lib/db/schema';
|
||||
import { softDeleteContext } from '$lib/db/repositories';
|
||||
import { softDeleteContext, toggleFavorite } from '$lib/db/repositories';
|
||||
import ConfirmDialog from '$lib/components/ConfirmDialog.svelte';
|
||||
import type { PersonMeta, PersonSubType } from '@ka-note/shared';
|
||||
|
||||
|
|
@ -50,6 +50,11 @@
|
|||
{#each persons as ctx (ctx.id)}
|
||||
{@const subType = ((ctx.meta as PersonMeta | null)?.personSubType ?? 'contact') as PersonSubType}
|
||||
<div class="flex items-center gap-2">
|
||||
<button
|
||||
class="rounded border border-[#444] bg-sidebar px-2.5 py-2.5 transition-colors hover:border-[#666] {ctx.isFavorite ? 'text-yellow-400' : 'text-[#555] hover:text-yellow-400/60'}"
|
||||
onclick={() => toggleFavorite(ctx.id)}
|
||||
title={ctx.isFavorite ? 'Aus Sidebar entfernen' : 'In Sidebar anzeigen'}
|
||||
>★</button>
|
||||
<button
|
||||
class="flex flex-1 items-center justify-between rounded-lg border border-[#444] bg-sidebar px-4 py-3 text-left transition-colors hover:border-[#666] hover:bg-[#2a2a2a]"
|
||||
onclick={() => goto(`/context/${ctx.id}`)}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
import { goto } from '$app/navigation';
|
||||
import { liveQuery } from 'dexie';
|
||||
import { db } from '$lib/db/schema';
|
||||
import { softDeleteContext } from '$lib/db/repositories';
|
||||
import { softDeleteContext, toggleFavorite } from '$lib/db/repositories';
|
||||
import ConfirmDialog from '$lib/components/ConfirmDialog.svelte';
|
||||
import type { AgendaContext, ProjectMeta } from '@ka-note/shared';
|
||||
|
||||
|
|
@ -43,6 +43,11 @@
|
|||
<div class="mb-8 flex flex-col gap-2">
|
||||
{#each activeProjects as ctx (ctx.id)}
|
||||
<div class="flex items-center gap-2">
|
||||
<button
|
||||
class="rounded border border-[#444] bg-sidebar px-2.5 py-2.5 transition-colors hover:border-[#666] {ctx.isFavorite ? 'text-yellow-400' : 'text-[#555] hover:text-yellow-400/60'}"
|
||||
onclick={() => toggleFavorite(ctx.id)}
|
||||
title={ctx.isFavorite ? 'Aus Sidebar entfernen' : 'In Sidebar anzeigen'}
|
||||
>★</button>
|
||||
<button
|
||||
class="flex flex-1 items-center justify-between rounded-lg border border-[#444] bg-sidebar px-4 py-3 text-left transition-colors hover:border-[#666] hover:bg-[#2a2a2a]"
|
||||
onclick={() => goto(`/context/${ctx.id}`)}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ export const contexts = sqliteTable('contexts', {
|
|||
sortOrder: integer('sort_order').notNull().default(0),
|
||||
meta: text('meta'), // JSON string
|
||||
archivedAt: text('archived_at'),
|
||||
isFavorite: integer('is_favorite', { mode: 'boolean' }).notNull().default(false),
|
||||
updatedAt: text('updated_at').notNull(),
|
||||
deletedAt: text('deleted_at'),
|
||||
version: integer('version').notNull().default(1),
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ function mapContext(row: typeof contexts.$inferSelect): AgendaContext {
|
|||
sortOrder: row.sortOrder,
|
||||
meta: row.meta ? JSON.parse(row.meta) : null,
|
||||
archivedAt: row.archivedAt,
|
||||
isFavorite: row.isFavorite,
|
||||
updatedAt: row.updatedAt,
|
||||
deletedAt: row.deletedAt,
|
||||
version: row.version,
|
||||
|
|
@ -219,6 +220,7 @@ export async function seedDailyLog(): Promise<void> {
|
|||
sortOrder: 0,
|
||||
meta: null,
|
||||
archivedAt: null,
|
||||
isFavorite: true,
|
||||
updatedAt: now(),
|
||||
deletedAt: null,
|
||||
version: 1,
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ export interface AgendaContext extends SyncEntity {
|
|||
sortOrder: number;
|
||||
meta: ProjectMeta | PersonMeta | CompanyMeta | null;
|
||||
archivedAt: string | null;
|
||||
isFavorite: boolean;
|
||||
}
|
||||
|
||||
export interface ProjectMeta {
|
||||
|
|
|
|||
Loading…
Reference in New Issue