From 22d811716d630ea7329625b91d64fb383ecd5619 Mon Sep 17 00:00:00 2001 From: beo3000 Date: Wed, 25 Feb 2026 16:53:11 +0100 Subject: [PATCH] ui opt --- ka-note/VERSION | 2 +- .../src/lib/components/CommandBar.svelte | 129 +++++------------- ka-note/client/src/lib/db/repositories.ts | 20 +++ .../client/src/routes/companies/+page.svelte | 17 ++- .../client/src/routes/meetings/+page.svelte | 15 +- .../client/src/routes/persons/+page.svelte | 17 ++- .../client/src/routes/projects/+page.svelte | 17 ++- ka-note/client/src/routes/wiki/+page.svelte | 16 ++- ka-note/client/static/favicon.svg | 10 +- ka-note/client/static/icon-192.png | Bin 5139 -> 21060 bytes ka-note/client/static/icon-512.png | Bin 16016 -> 72560 bytes ka-note/client/static/icon-512.svg | 54 ++++---- ka-note/server/ka-note.db-shm | Bin 32768 -> 32768 bytes ka-note/server/ka-note.db-wal | Bin 185432 -> 267832 bytes ka-note/server/src/lib/sync-service.ts | 2 +- 15 files changed, 153 insertions(+), 146 deletions(-) diff --git a/ka-note/VERSION b/ka-note/VERSION index b89c021..13ceb8d 100644 --- a/ka-note/VERSION +++ b/ka-note/VERSION @@ -1 +1 @@ -1.1.73 \ No newline at end of file +1.1.74 \ No newline at end of file diff --git a/ka-note/client/src/lib/components/CommandBar.svelte b/ka-note/client/src/lib/components/CommandBar.svelte index 7ba2e1e..cfa75e3 100644 --- a/ka-note/client/src/lib/components/CommandBar.svelte +++ b/ka-note/client/src/lib/components/CommandBar.svelte @@ -10,9 +10,11 @@ getOrCreateJournalTopic, createHistoryEntry, createPage, - createTopic, + upsertContext, + contextNameExists, + pageNameExists, } from "$lib/db/repositories"; - import { today } from "$lib/db/helpers"; + import { newId, today } from "$lib/db/helpers"; const contextsQuery = allActiveContexts(); const pagesQuery = allPages(); @@ -212,6 +214,10 @@ badge: "BEFEHL", action: async () => { if (!text) return; + if (await pageNameExists(text)) { + alert(`Wiki-Seite "${text}" existiert bereits.`); + return; + } const isPrivateScope = $currentScope === "private"; const page = await createPage(text, isPrivateScope); closeBar(); @@ -231,6 +237,10 @@ badge: "BEFEHL", action: async () => { if (!text) return; + if (await pageNameExists(text)) { + alert(`Wiki-Seite "${text}" existiert bereits.`); + return; + } const page = await createPage(text, true); closeBar(); goto(`/wiki/${page.id}`); @@ -249,6 +259,10 @@ badge: "BEFEHL", action: async () => { if (!text) return; + if (await pageNameExists(text)) { + alert(`Wiki-Seite "${text}" existiert bereits.`); + return; + } const page = await createPage(text, false); closeBar(); goto(`/wiki/${page.id}`); @@ -261,56 +275,19 @@ id: "cmd-person", type: "action", icon: "👤", - label: text - ? `Person (${$currentScope === "private" ? "Privat" : "Firma"}): "${text}"` - : `Neu: Person (${$currentScope === "private" ? "Privat" : "Firma"})`, + label: text ? `Person: "${text}"` : `Neu: Person`, badge: "BEFEHL", action: async () => { if (!text) return; - const isPrivateScope = $currentScope === "private"; - const topic = await createTopic( - text, - "person", - isPrivateScope, - ); + const fullName = `Person ${text}`; + if (await contextNameExists(fullName, "person")) { + alert(`Person "${text}" existiert bereits.`); + return; + } + const id = newId(); + await upsertContext({ id, name: fullName, type: "person" }); closeBar(); - goto(`/context/${topic.id}`); - }, - }); - } - - if ("/pperson".startsWith(cmd)) { - actions.push({ - id: "cmd-pperson", - type: "action", - icon: "👤", - label: text - ? `Person (Privat): "${text}"` - : `Neu: Person (Privat)`, - badge: "BEFEHL", - action: async () => { - if (!text) return; - const topic = await createTopic(text, "person", true); - closeBar(); - goto(`/context/${topic.id}`); - }, - }); - } - - if ("/bperson".startsWith(cmd)) { - actions.push({ - id: "cmd-bperson", - type: "action", - icon: "👤", - label: text - ? `Person (Firma): "${text}"` - : `Neu: Person (Firma)`, - badge: "BEFEHL", - action: async () => { - if (!text) return; - const topic = await createTopic(text, "person", false); - closeBar(); - goto(`/context/${topic.id}`); + goto(`/context/${id}`); }, }); } @@ -320,60 +297,22 @@ id: "cmd-firma", type: "action", icon: "🏢", - label: text - ? `Firma (${$currentScope === "private" ? "Privat" : "Firma"}): "${text}"` - : `Neu: Firma (${$currentScope === "private" ? "Privat" : "Firma"})`, + label: text ? `Firma: "${text}"` : `Neu: Firma`, badge: "BEFEHL", action: async () => { if (!text) return; - const isPrivateScope = $currentScope === "private"; - const topic = await createTopic( - text, - "company", - isPrivateScope, - ); + const fullName = `Firma ${text}`; + if (await contextNameExists(fullName, "company")) { + alert(`Firma "${text}" existiert bereits.`); + return; + } + const id = newId(); + await upsertContext({ id, name: fullName, type: "company" }); closeBar(); - goto(`/context/${topic.id}`); + goto(`/context/${id}`); }, }); } - - if ("/pfirma".startsWith(cmd)) { - actions.push({ - id: "cmd-pfirma", - type: "action", - icon: "🏢", - label: text - ? `Firma (Privat): "${text}"` - : `Neu: Firma (Privat)`, - badge: "BEFEHL", - action: async () => { - if (!text) return; - const topic = await createTopic(text, "company", true); - closeBar(); - goto(`/context/${topic.id}`); - }, - }); - } - - if ("/bfirma".startsWith(cmd)) { - actions.push({ - id: "cmd-bfirma", - type: "action", - icon: "🏢", - label: text - ? `Firma (Firma): "${text}"` - : `Neu: Firma (Firma)`, - badge: "BEFEHL", - action: async () => { - if (!text) return; - const topic = await createTopic(text, "company", false); - closeBar(); - goto(`/context/${topic.id}`); - }, - }); - } - if ("/sidebar".startsWith(cmd)) { actions.push({ id: "cmd-sidebar", diff --git a/ka-note/client/src/lib/db/repositories.ts b/ka-note/client/src/lib/db/repositories.ts index 9e4eca7..611edb4 100644 --- a/ka-note/client/src/lib/db/repositories.ts +++ b/ka-note/client/src/lib/db/repositories.ts @@ -87,6 +87,26 @@ export async function reorderContext(id: string, direction: 'up' | 'down'): Prom } } +export async function contextNameExists(name: string, type: ContextType): Promise { + const q = name.toLowerCase(); + const count = await db.contexts + .filter(c => !c.deletedAt && c.type === type && c.name.toLowerCase() === q) + .count(); + return count > 0; +} + +export async function pageNameExists(title: string): Promise { + const q = title.toLowerCase(); + const count = await db.pages.filter(p => !p.deletedAt && p.title.toLowerCase() === q).count(); + return count > 0; +} + +export async function notebookNameExists(name: string): Promise { + const q = name.toLowerCase(); + const count = await db.notebooks.filter(n => !n.deletedAt && n.name.toLowerCase() === q).count(); + return count > 0; +} + export async function findContextByMentionName(name: string, type: 'person' | 'project' | 'company'): Promise { const q = name.toLowerCase(); return db.contexts diff --git a/ka-note/client/src/routes/companies/+page.svelte b/ka-note/client/src/routes/companies/+page.svelte index 0ace510..d28f37e 100644 --- a/ka-note/client/src/routes/companies/+page.svelte +++ b/ka-note/client/src/routes/companies/+page.svelte @@ -2,26 +2,33 @@ import { goto } from '$app/navigation'; import { liveQuery } from 'dexie'; import { db } from '$lib/db/schema'; - import { softDeleteContext, toggleFavorite, upsertContext, reorderContext } from '$lib/db/repositories'; + import { softDeleteContext, toggleFavorite, upsertContext, reorderContext, contextNameExists } from '$lib/db/repositories'; import { newId } from '$lib/db/helpers'; import ConfirmDialog from '$lib/components/ConfirmDialog.svelte'; let creating = $state(false); let newName = $state(''); + let createError = $state(''); async function create() { const name = newName.trim(); if (!name) return; + const fullName = `Firma ${name}`; + if (await contextNameExists(fullName, 'company')) { + createError = `"${name}" existiert bereits`; + return; + } const id = newId(); - await upsertContext({ id, name: `Firma ${name}`, type: 'company' }); + await upsertContext({ id, name: fullName, type: 'company' }); newName = ''; creating = false; + createError = ''; goto(`/context/${id}`); } function onKeydown(e: KeyboardEvent) { if (e.key === 'Enter') { e.preventDefault(); create(); } - else if (e.key === 'Escape') { creating = false; newName = ''; } + else if (e.key === 'Escape') { creating = false; newName = ''; createError = ''; } } const allCompanies = liveQuery(() => @@ -60,9 +67,11 @@ placeholder="Firmenname..." bind:value={newName} onkeydown={onKeydown} - onblur={() => setTimeout(() => { creating = false; newName = ''; }, 150)} + oninput={() => createError = ''} + onblur={() => setTimeout(() => { creating = false; newName = ''; createError = ''; }, 150)} autofocus /> + {#if createError}

{createError}

{/if} {/if} {#if companies.length > 0} diff --git a/ka-note/client/src/routes/meetings/+page.svelte b/ka-note/client/src/routes/meetings/+page.svelte index ff2291e..6619af8 100644 --- a/ka-note/client/src/routes/meetings/+page.svelte +++ b/ka-note/client/src/routes/meetings/+page.svelte @@ -2,26 +2,33 @@ import { goto } from '$app/navigation'; import { liveQuery } from 'dexie'; import { db } from '$lib/db/schema'; - import { softDeleteContext, toggleFavorite, upsertContext, reorderContext } from '$lib/db/repositories'; + import { softDeleteContext, toggleFavorite, upsertContext, reorderContext, contextNameExists } from '$lib/db/repositories'; import { newId } from '$lib/db/helpers'; import ConfirmDialog from '$lib/components/ConfirmDialog.svelte'; let creating = $state(false); let newName = $state(''); + let createWarning = $state(''); async function create() { const name = newName.trim(); if (!name) return; + if (await contextNameExists(name, 'meeting')) { + createWarning = `"${name}" existiert bereits`; + } else { + createWarning = ''; + } const id = newId(); await upsertContext({ id, name, type: 'meeting' }); newName = ''; creating = false; + createWarning = ''; goto(`/context/${id}`); } function onKeydown(e: KeyboardEvent) { if (e.key === 'Enter') { e.preventDefault(); create(); } - else if (e.key === 'Escape') { creating = false; newName = ''; } + else if (e.key === 'Escape') { creating = false; newName = ''; createWarning = ''; } } const allMeetings = liveQuery(() => @@ -56,9 +63,11 @@ placeholder="Name des Jour Fix..." bind:value={newName} onkeydown={onKeydown} - onblur={() => setTimeout(() => { creating = false; newName = ''; }, 150)} + oninput={() => createWarning = ''} + onblur={() => setTimeout(() => { creating = false; newName = ''; createWarning = ''; }, 150)} autofocus /> + {#if createWarning}

{createWarning}

{/if} {/if} {#if meetings.length > 0} diff --git a/ka-note/client/src/routes/persons/+page.svelte b/ka-note/client/src/routes/persons/+page.svelte index 28e846e..069b743 100644 --- a/ka-note/client/src/routes/persons/+page.svelte +++ b/ka-note/client/src/routes/persons/+page.svelte @@ -2,7 +2,7 @@ import { goto } from '$app/navigation'; import { liveQuery } from 'dexie'; import { db } from '$lib/db/schema'; - import { upsertContext } from '$lib/db/repositories'; + import { upsertContext, contextNameExists } from '$lib/db/repositories'; import { newId } from '$lib/db/helpers'; import PersonList from '$lib/components/PersonList.svelte'; @@ -14,20 +14,27 @@ let creating = $state(false); let newName = $state(''); + let createError = $state(''); async function create() { const name = newName.trim(); if (!name) return; + const fullName = `Person ${name}`; + if (await contextNameExists(fullName, 'person')) { + createError = `"${name}" existiert bereits`; + return; + } const id = newId(); - await upsertContext({ id, name: `Person ${name}`, type: 'person' }); + await upsertContext({ id, name: fullName, type: 'person', meta: { fullName: name, email: '', phone: '', duSince: '' } }); newName = ''; creating = false; + createError = ''; goto(`/context/${id}`); } function onKeydown(e: KeyboardEvent) { if (e.key === 'Enter') { e.preventDefault(); create(); } - else if (e.key === 'Escape') { creating = false; newName = ''; } + else if (e.key === 'Escape') { creating = false; newName = ''; createError = ''; } } @@ -43,9 +50,11 @@ placeholder="Name der Person..." bind:value={newName} onkeydown={onKeydown} - onblur={() => setTimeout(() => { creating = false; newName = ''; }, 150)} + oninput={() => createError = ''} + onblur={() => setTimeout(() => { creating = false; newName = ''; createError = ''; }, 150)} autofocus /> + {#if createError}

{createError}

{/if} {/if} diff --git a/ka-note/client/src/routes/projects/+page.svelte b/ka-note/client/src/routes/projects/+page.svelte index 465deac..eab1904 100644 --- a/ka-note/client/src/routes/projects/+page.svelte +++ b/ka-note/client/src/routes/projects/+page.svelte @@ -2,27 +2,34 @@ import { goto } from '$app/navigation'; import { liveQuery } from 'dexie'; import { db } from '$lib/db/schema'; - import { softDeleteContext, toggleFavorite, upsertContext, reorderContext } from '$lib/db/repositories'; + import { softDeleteContext, toggleFavorite, upsertContext, reorderContext, contextNameExists } from '$lib/db/repositories'; import { newId } from '$lib/db/helpers'; import ConfirmDialog from '$lib/components/ConfirmDialog.svelte'; import type { AgendaContext, ProjectMeta } from '@ka-note/shared'; let creating = $state(false); let newName = $state(''); + let createError = $state(''); async function create() { const name = newName.trim(); if (!name) return; + const fullName = `Project ${name}`; + if (await contextNameExists(fullName, 'project')) { + createError = `"${name}" existiert bereits`; + return; + } const id = newId(); - await upsertContext({ id, name: `Project ${name}`, type: 'project' }); + await upsertContext({ id, name: fullName, type: 'project' }); newName = ''; creating = false; + createError = ''; goto(`/context/${id}`); } function onKeydown(e: KeyboardEvent) { if (e.key === 'Enter') { e.preventDefault(); create(); } - else if (e.key === 'Escape') { creating = false; newName = ''; } + else if (e.key === 'Escape') { creating = false; newName = ''; createError = ''; } } const allProjects = liveQuery(() => @@ -66,9 +73,11 @@ placeholder="Projektname..." bind:value={newName} onkeydown={onKeydown} - onblur={() => setTimeout(() => { creating = false; newName = ''; }, 150)} + oninput={() => createError = ''} + onblur={() => setTimeout(() => { creating = false; newName = ''; createError = ''; }, 150)} autofocus /> + {#if createError}

{createError}

{/if} {/if} {#if activeProjects.length > 0} diff --git a/ka-note/client/src/routes/wiki/+page.svelte b/ka-note/client/src/routes/wiki/+page.svelte index 0e1876d..cfd47f6 100644 --- a/ka-note/client/src/routes/wiki/+page.svelte +++ b/ka-note/client/src/routes/wiki/+page.svelte @@ -1,7 +1,7 @@