ui opt
|
|
@ -1 +1 @@
|
|||
1.1.73
|
||||
1.1.74
|
||||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -87,6 +87,26 @@ export async function reorderContext(id: string, direction: 'up' | 'down'): Prom
|
|||
}
|
||||
}
|
||||
|
||||
export async function contextNameExists(name: string, type: ContextType): Promise<boolean> {
|
||||
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<boolean> {
|
||||
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<boolean> {
|
||||
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<AgendaContext | undefined> {
|
||||
const q = name.toLowerCase();
|
||||
return db.contexts
|
||||
|
|
|
|||
|
|
@ -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}<p class="mb-3 -mt-2 text-xs text-red-400">{createError}</p>{/if}
|
||||
{/if}
|
||||
|
||||
{#if companies.length > 0}
|
||||
|
|
|
|||
|
|
@ -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}<p class="mb-3 -mt-2 text-xs text-yellow-400">{createWarning}</p>{/if}
|
||||
{/if}
|
||||
|
||||
{#if meetings.length > 0}
|
||||
|
|
|
|||
|
|
@ -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 = ''; }
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
@ -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}<p class="mb-3 -mt-2 text-xs text-red-400">{createError}</p>{/if}
|
||||
{/if}
|
||||
|
||||
<PersonList {persons} />
|
||||
|
|
|
|||
|
|
@ -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}<p class="mb-3 -mt-2 text-xs text-red-400">{createError}</p>{/if}
|
||||
{/if}
|
||||
|
||||
{#if activeProjects.length > 0}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { allNotebooks, unassignedPages, favoritePages, recentlyEditedPages, type PageWithNotebooks } from '$lib/stores/wiki';
|
||||
import { createNotebook, createPage, toggleNotebookFavorite, upsertNotebook, reorderNotebook } from '$lib/db/repositories';
|
||||
import { createNotebook, createPage, toggleNotebookFavorite, upsertNotebook, reorderNotebook, notebookNameExists } from '$lib/db/repositories';
|
||||
import { currentScope, scopeSettings } from '$lib/stores/scopeContext';
|
||||
|
||||
const notebooks$ = allNotebooks();
|
||||
|
|
@ -45,6 +45,7 @@
|
|||
|
||||
let creatingNotebook = $state(false);
|
||||
let newNotebookName = $state('');
|
||||
let notebookError = $state('');
|
||||
|
||||
function setScope(s: 'business' | 'private') {
|
||||
scope = s;
|
||||
|
|
@ -58,9 +59,14 @@
|
|||
async function addNotebook() {
|
||||
const name = newNotebookName.trim();
|
||||
if (!name) return;
|
||||
if (await notebookNameExists(name)) {
|
||||
notebookError = `"${name}" existiert bereits`;
|
||||
return;
|
||||
}
|
||||
await createNotebook(name, null, scope === 'private');
|
||||
newNotebookName = '';
|
||||
creatingNotebook = false;
|
||||
notebookError = '';
|
||||
}
|
||||
|
||||
async function addPage() {
|
||||
|
|
@ -70,7 +76,7 @@
|
|||
|
||||
function handleInputKeydown(e: KeyboardEvent) {
|
||||
if (e.key === 'Enter') { e.preventDefault(); addNotebook(); }
|
||||
else if (e.key === 'Escape') { creatingNotebook = false; newNotebookName = ''; }
|
||||
else if (e.key === 'Escape') { creatingNotebook = false; newNotebookName = ''; notebookError = ''; }
|
||||
}
|
||||
|
||||
function autofocus(node: HTMLElement) { node.focus(); }
|
||||
|
|
@ -164,13 +170,15 @@
|
|||
{/each}
|
||||
{#if creatingNotebook}
|
||||
<input
|
||||
class="w-full rounded-b-lg bg-white/10 px-4 py-2.5 text-sm text-white outline-none placeholder:text-muted"
|
||||
class="w-full bg-white/10 px-4 py-2.5 text-sm text-white outline-none placeholder:text-muted"
|
||||
placeholder="Notizbuchname..."
|
||||
bind:value={newNotebookName}
|
||||
onkeydown={handleInputKeydown}
|
||||
onblur={() => setTimeout(() => { creatingNotebook = false; newNotebookName = ''; }, 150)}
|
||||
oninput={() => notebookError = ''}
|
||||
onblur={() => setTimeout(() => { creatingNotebook = false; newNotebookName = ''; notebookError = ''; }, 150)}
|
||||
use:autofocus
|
||||
/>
|
||||
{#if notebookError}<p class="rounded-b-lg bg-white/5 px-4 py-1.5 text-xs text-red-400">{notebookError}</p>{/if}
|
||||
{/if}
|
||||
</div>
|
||||
<!-- Unassigned pages (shown below notebooks) -->
|
||||
|
|
|
|||
|
|
@ -1,4 +1,10 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
||||
<rect width="32" height="32" rx="4" fill="#007acc"/>
|
||||
<text x="16" y="23" font-family="Segoe UI, sans-serif" font-size="18" font-weight="bold" fill="white" text-anchor="middle">K</text>
|
||||
<defs>
|
||||
<linearGradient id="bg" x1="0" y1="0" x2="1" y2="1">
|
||||
<stop offset="0%" stop-color="#3366ff"/>
|
||||
<stop offset="100%" stop-color="#8b5cf6"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<rect width="32" height="32" rx="6" fill="url(#bg)"/>
|
||||
<text x="16" y="23.5" font-family="'Inter', 'Segoe UI', sans-serif" font-size="17" font-weight="800" fill="white" text-anchor="middle" letter-spacing="-1">KA</text>
|
||||
</svg>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 257 B After Width: | Height: | Size: 485 B |
|
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 71 KiB |
|
|
@ -1,32 +1,30 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
|
||||
<!-- Dark background -->
|
||||
<rect width="512" height="512" fill="#3a3a3a" rx="80"/>
|
||||
<defs>
|
||||
<!-- Vibrant blue-purple gradient background -->
|
||||
<linearGradient id="bg" x1="0" y1="0" x2="1" y2="1">
|
||||
<stop offset="0%" stop-color="#3366ff"/>
|
||||
<stop offset="100%" stop-color="#8b5cf6"/>
|
||||
</linearGradient>
|
||||
<!-- Subtle inner glow -->
|
||||
<radialGradient id="glow" cx="50%" cy="40%" r="60%">
|
||||
<stop offset="0%" stop-color="#ffffff" stop-opacity="0.12"/>
|
||||
<stop offset="100%" stop-color="#ffffff" stop-opacity="0"/>
|
||||
</radialGradient>
|
||||
</defs>
|
||||
|
||||
<!-- White circle -->
|
||||
<circle cx="256" cy="256" r="170" fill="#ffffff"/>
|
||||
<!-- Rounded background -->
|
||||
<rect width="512" height="512" rx="108" fill="url(#bg)"/>
|
||||
<!-- Glow overlay -->
|
||||
<rect width="512" height="512" rx="108" fill="url(#glow)"/>
|
||||
|
||||
<!-- Open book shape -->
|
||||
<!-- Book spine (center line) -->
|
||||
<!-- Left page -->
|
||||
<path d="M130 195 Q130 185 140 183 L248 183 L248 330 Q200 325 152 335 Q130 338 130 320 Z" fill="#f0ede8"/>
|
||||
<!-- Right page -->
|
||||
<path d="M264 183 L372 183 Q382 185 382 195 L382 320 Q382 338 360 335 Q312 325 264 330 Z" fill="#f0ede8"/>
|
||||
<!-- Book spine shadow -->
|
||||
<rect x="248" y="183" width="16" height="147" fill="#e0dbd2" rx="2"/>
|
||||
|
||||
<!-- Left page: orange/amber checkmark -->
|
||||
<polyline points="160,255 190,285 230,220" fill="none" stroke="#f59e0b" stroke-width="16" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
|
||||
<!-- Right page: teal horizontal lines -->
|
||||
<line x1="280" y1="220" x2="360" y2="220" stroke="#0d9488" stroke-width="8" stroke-linecap="round"/>
|
||||
<line x1="280" y1="245" x2="355" y2="245" stroke="#0d9488" stroke-width="8" stroke-linecap="round"/>
|
||||
<line x1="280" y1="270" x2="350" y2="270" stroke="#0d9488" stroke-width="8" stroke-linecap="round"/>
|
||||
<line x1="280" y1="295" x2="345" y2="295" stroke="#0d9488" stroke-width="8" stroke-linecap="round"/>
|
||||
|
||||
<!-- Right page: teal clock icon (top-right corner of right page) -->
|
||||
<!-- Clock circle -->
|
||||
<circle cx="358" cy="200" r="18" fill="none" stroke="#0d9488" stroke-width="5"/>
|
||||
<!-- Clock hands -->
|
||||
<line x1="358" y1="200" x2="358" y2="191" stroke="#0d9488" stroke-width="4" stroke-linecap="round"/>
|
||||
<line x1="358" y1="200" x2="365" y2="204" stroke="#0d9488" stroke-width="4" stroke-linecap="round"/>
|
||||
<!-- "KA" lettering — bold, modern, white -->
|
||||
<text
|
||||
x="256" y="330"
|
||||
font-family="'Inter', 'Segoe UI', 'Helvetica Neue', Arial, sans-serif"
|
||||
font-size="260"
|
||||
font-weight="800"
|
||||
fill="#ffffff"
|
||||
text-anchor="middle"
|
||||
letter-spacing="-12"
|
||||
>KA</text>
|
||||
</svg>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.0 KiB |
|
|
@ -155,7 +155,7 @@ async function upsertEntity(
|
|||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
console.error(`[sync] insert failed [${entityType}] id=${id}`, msg);
|
||||
throw err;
|
||||
return false; // skip bad entity, don't abort entire push
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||