icon und menu update
This commit is contained in:
parent
3a4fc0e8e0
commit
cf220dd3a0
|
|
@ -1 +1 @@
|
|||
1.2.14
|
||||
1.2.17
|
||||
|
|
@ -25,6 +25,7 @@
|
|||
"dexie": "^4.0.11",
|
||||
"dompurify": "^3.3.1",
|
||||
"highlight.js": "^11.11.1",
|
||||
"lucide-svelte": "^0.576.0",
|
||||
"marked": "^17.0.3",
|
||||
"tiptap-markdown": "^0.9.0"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
import { page } from "$app/state";
|
||||
import { goto } from "$app/navigation";
|
||||
import { commandBarOpen } from "$lib/stores/commandBar";
|
||||
import { LayoutList, CalendarRange, FolderOpen, BookOpen, Search, Menu } from "lucide-svelte";
|
||||
import type { Component } from "svelte";
|
||||
|
||||
interface Props {
|
||||
onsidebaropen: () => void;
|
||||
|
|
@ -13,7 +15,8 @@
|
|||
interface Tab {
|
||||
id: string;
|
||||
label: string;
|
||||
icon: string;
|
||||
icon: Component;
|
||||
color: string;
|
||||
action: () => void;
|
||||
active: boolean;
|
||||
}
|
||||
|
|
@ -22,42 +25,48 @@
|
|||
{
|
||||
id: "daily",
|
||||
label: "Daily Log",
|
||||
icon: "📋",
|
||||
icon: LayoutList,
|
||||
color: "text-slate-400",
|
||||
action: () => goto("/context/daily-log"),
|
||||
active: currentPath === "/context/daily-log" || currentPath === "/",
|
||||
},
|
||||
{
|
||||
id: "meetings",
|
||||
label: "Meetings",
|
||||
icon: "👥",
|
||||
icon: CalendarRange,
|
||||
color: "text-violet-400",
|
||||
action: () => goto("/meetings"),
|
||||
active: currentPath === "/meetings",
|
||||
},
|
||||
{
|
||||
id: "projects",
|
||||
label: "Projekte",
|
||||
icon: "📁",
|
||||
icon: FolderOpen,
|
||||
color: "text-amber-400",
|
||||
action: () => goto("/projects"),
|
||||
active: currentPath === "/projects",
|
||||
},
|
||||
{
|
||||
id: "wiki",
|
||||
label: "Wiki",
|
||||
icon: "📖",
|
||||
icon: BookOpen,
|
||||
color: "text-orange-400",
|
||||
action: () => goto("/wiki"),
|
||||
active: currentPath.startsWith("/wiki"),
|
||||
},
|
||||
{
|
||||
id: "search",
|
||||
label: "Suche",
|
||||
icon: "🔍",
|
||||
icon: Search,
|
||||
color: "text-muted",
|
||||
action: () => ($commandBarOpen = true),
|
||||
active: false,
|
||||
},
|
||||
{
|
||||
id: "more",
|
||||
label: "Mehr",
|
||||
icon: "☰",
|
||||
icon: Menu,
|
||||
color: "text-muted",
|
||||
action: () => onsidebaropen(),
|
||||
active: false,
|
||||
},
|
||||
|
|
@ -69,12 +78,13 @@
|
|||
style="padding-bottom: env(safe-area-inset-bottom, 0px);"
|
||||
>
|
||||
{#each tabs as tab}
|
||||
{@const Icon = tab.icon}
|
||||
<button
|
||||
class="flex flex-1 flex-col items-center gap-0.5 py-2.5 text-xs transition-colors
|
||||
{tab.active ? 'text-accent' : 'text-muted'}"
|
||||
class="flex flex-1 flex-col items-center justify-center gap-1 py-2.5 min-h-[52px] text-xs transition-colors
|
||||
{tab.active ? tab.color + ' font-medium' : 'text-muted'}"
|
||||
onclick={tab.action}
|
||||
>
|
||||
<span class="text-lg leading-none">{tab.icon}</span>
|
||||
<Icon size={22} />
|
||||
<span>{tab.label}</span>
|
||||
</button>
|
||||
{/each}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
import { updateEvent, updateEventNotes, softDeleteContext } from '$lib/db/repositories';
|
||||
import { notesTopicId } from '$lib/db/repositories';
|
||||
import { mention } from '$lib/actions/mention';
|
||||
import { Pencil, Trash2 } from 'lucide-svelte';
|
||||
import { handlePersonClick } from '$lib/actions/refClick';
|
||||
import { goto } from '$app/navigation';
|
||||
|
||||
|
|
@ -179,8 +180,8 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="flex gap-1 opacity-0 transition-opacity group-hover:opacity-100">
|
||||
<button class="rounded p-1 text-muted hover:text-white" onclick={(e) => { e.stopPropagation(); startEditMeta(); }} title="Bearbeiten">✏️</button>
|
||||
<button class="rounded p-1 text-muted hover:text-red-400" onclick={(e) => { e.stopPropagation(); handleDelete(); }} title="Löschen">🗑️</button>
|
||||
<button class="rounded p-1 text-muted hover:text-white" onclick={(e) => { e.stopPropagation(); startEditMeta(); }} title="Bearbeiten"><Pencil size={14} /></button>
|
||||
<button class="rounded p-1 text-muted hover:text-red-400" onclick={(e) => { e.stopPropagation(); handleDelete(); }} title="Löschen"><Trash2 size={14} /></button>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,11 @@
|
|||
import { deletedItemCount } from '$lib/stores/agenda';
|
||||
import { favoriteNotebooks } from '$lib/stores/wiki';
|
||||
import { scopeColor, scopeIcon } from '$lib/stores/scopeContext';
|
||||
import {
|
||||
CalendarDays, CalendarRange, Users, FolderOpen, Building2, User, BookOpen,
|
||||
LayoutList, Archive, Trash2, Settings, HardDrive, LogOut,
|
||||
ChevronDown, Home, RefreshCw
|
||||
} from 'lucide-svelte';
|
||||
|
||||
const isDev = import.meta.env.DEV;
|
||||
const trashCount$ = deletedItemCount();
|
||||
|
|
@ -55,14 +60,14 @@
|
|||
// Active nav item style: subtle left border indicator
|
||||
function navItem(active: boolean) {
|
||||
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';
|
||||
? 'mb-1 w-full rounded-r px-3 py-2.5 text-left text-sm border-l-2 border-accent bg-white/10 font-semibold text-white'
|
||||
: 'mb-1 w-full rounded px-3 py-2.5 text-left text-sm border-l-2 border-transparent text-[#aaa] hover:bg-white/5 hover:text-white transition-colors';
|
||||
}
|
||||
|
||||
// Section header: ▼ toggle (small) + label (navigates to overview)
|
||||
const sectionHeader = 'flex items-center gap-2 mt-6 mb-1 pl-1 pr-1';
|
||||
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';
|
||||
const sectionToggle = 'text-xs text-muted hover:text-white transition-colors flex-shrink-0 px-2 py-1.5';
|
||||
const sectionLabel = 'text-sm text-muted hover:text-white flex items-center gap-1.5 transition-colors flex-1 text-left font-semibold';
|
||||
</script>
|
||||
|
||||
{#if !hideLogo}
|
||||
|
|
@ -74,21 +79,25 @@
|
|||
{/if}
|
||||
|
||||
<!-- General -->
|
||||
<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>
|
||||
<div class="mb-1 mt-6 pl-1 text-sm text-muted flex items-center gap-2 font-semibold">
|
||||
<Home size={15} class="flex-shrink-0 text-slate-400" /> General
|
||||
</div>
|
||||
<ul class="m-0 list-none p-0">
|
||||
{#if dailyLog}
|
||||
<li>
|
||||
<button class={navItem(currentId === 'daily-log')} onclick={() => navigate('daily-log')}>
|
||||
{dailyLog.name}
|
||||
<button class={navItem(currentId === 'daily-log') + ' flex items-center gap-2'} onclick={() => navigate('daily-log')}>
|
||||
<LayoutList size={15} class="flex-shrink-0 text-slate-400" />
|
||||
<span class="truncate">{dailyLog.name}</span>
|
||||
</button>
|
||||
</li>
|
||||
{/if}
|
||||
<li>
|
||||
<button
|
||||
class={navItem(page.url.pathname.startsWith('/journal/archive'))}
|
||||
class={navItem(page.url.pathname.startsWith('/journal/archive')) + ' flex items-center gap-2'}
|
||||
onclick={() => { goto('/journal/archive'); onnavigate?.(); }}
|
||||
>
|
||||
Archiv
|
||||
<Archive size={15} class="flex-shrink-0 text-slate-400" />
|
||||
<span class="truncate">Archiv</span>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
@ -96,18 +105,19 @@
|
|||
<!-- Jour Fixes -->
|
||||
<div class={sectionHeader}>
|
||||
<button class={sectionToggle} onclick={() => toggleSection('meetings')} title="Auf-/Zuklappen">
|
||||
<span class="inline-block transition-transform {collapsed['meetings'] ? '-rotate-90' : ''}">{@html '▼'}</span>
|
||||
<ChevronDown size={14} class="transition-transform {collapsed['meetings'] ? '-rotate-90' : ''}" />
|
||||
</button>
|
||||
<button class={sectionLabel} onclick={() => { goto('/meetings'); onnavigate?.(); }}>
|
||||
<span>💬</span> Jour Fixes
|
||||
<CalendarRange size={15} class="flex-shrink-0 text-violet-400" /> Jour Fixes
|
||||
</button>
|
||||
</div>
|
||||
{#if !collapsed['meetings']}
|
||||
<ul class="m-0 list-none p-0">
|
||||
{#each meetings as ctx}
|
||||
<li>
|
||||
<button class={navItem(currentId === ctx.id)} onclick={() => navigate(ctx.id)}>
|
||||
{ctx.name}
|
||||
<button class={navItem(currentId === ctx.id) + ' flex items-center gap-2'} onclick={() => navigate(ctx.id)}>
|
||||
<CalendarDays size={14} class="flex-shrink-0 text-violet-400/60" />
|
||||
<span class="truncate">{ctx.name}</span>
|
||||
</button>
|
||||
</li>
|
||||
{/each}
|
||||
|
|
@ -117,18 +127,19 @@
|
|||
<!-- Projects -->
|
||||
<div class={sectionHeader}>
|
||||
<button class={sectionToggle} onclick={() => toggleSection('projects')} title="Auf-/Zuklappen">
|
||||
<span class="inline-block transition-transform {collapsed['projects'] ? '-rotate-90' : ''}">{@html '▼'}</span>
|
||||
<ChevronDown size={14} class="transition-transform {collapsed['projects'] ? '-rotate-90' : ''}" />
|
||||
</button>
|
||||
<button class={sectionLabel} onclick={() => { goto('/projects'); onnavigate?.(); }}>
|
||||
<span>📁</span> Projects
|
||||
<FolderOpen size={15} class="flex-shrink-0 text-amber-400" /> Projects
|
||||
</button>
|
||||
</div>
|
||||
{#if !collapsed['projects']}
|
||||
<ul class="m-0 list-none p-0">
|
||||
{#each projects as ctx}
|
||||
<li>
|
||||
<button class={navItem(currentId === ctx.id)} onclick={() => navigate(ctx.id)}>
|
||||
{displayName(ctx)}
|
||||
<button class={navItem(currentId === ctx.id) + ' flex items-center gap-2'} onclick={() => navigate(ctx.id)}>
|
||||
<FolderOpen size={14} class="flex-shrink-0 text-amber-400/60" />
|
||||
<span class="truncate">{displayName(ctx)}</span>
|
||||
</button>
|
||||
</li>
|
||||
{/each}
|
||||
|
|
@ -138,18 +149,19 @@
|
|||
<!-- Companies -->
|
||||
<div class={sectionHeader}>
|
||||
<button class={sectionToggle} onclick={() => toggleSection('companies')} title="Auf-/Zuklappen">
|
||||
<span class="inline-block transition-transform {collapsed['companies'] ? '-rotate-90' : ''}">{@html '▼'}</span>
|
||||
<ChevronDown size={14} class="transition-transform {collapsed['companies'] ? '-rotate-90' : ''}" />
|
||||
</button>
|
||||
<button class={sectionLabel} onclick={() => { goto('/companies'); onnavigate?.(); }}>
|
||||
<span>🏢</span> Firmen
|
||||
<Building2 size={15} class="flex-shrink-0 text-sky-400" /> Firmen
|
||||
</button>
|
||||
</div>
|
||||
{#if !collapsed['companies']}
|
||||
<ul class="m-0 list-none p-0">
|
||||
{#each companies as ctx}
|
||||
<li>
|
||||
<button class={navItem(currentId === ctx.id)} onclick={() => navigate(ctx.id)}>
|
||||
{displayName(ctx)}
|
||||
<button class={navItem(currentId === ctx.id) + ' flex items-center gap-2'} onclick={() => navigate(ctx.id)}>
|
||||
<Building2 size={14} class="flex-shrink-0 text-sky-400/60" />
|
||||
<span class="truncate">{displayName(ctx)}</span>
|
||||
</button>
|
||||
</li>
|
||||
{/each}
|
||||
|
|
@ -159,18 +171,19 @@
|
|||
<!-- People -->
|
||||
<div class={sectionHeader}>
|
||||
<button class={sectionToggle} onclick={() => toggleSection('people')} title="Auf-/Zuklappen">
|
||||
<span class="inline-block transition-transform {collapsed['people'] ? '-rotate-90' : ''}">{@html '▼'}</span>
|
||||
<ChevronDown size={14} class="transition-transform {collapsed['people'] ? '-rotate-90' : ''}" />
|
||||
</button>
|
||||
<button class={sectionLabel} onclick={() => { goto('/persons'); onnavigate?.(); }}>
|
||||
<span>👤</span> People
|
||||
<Users size={15} class="flex-shrink-0 text-emerald-400" /> People
|
||||
</button>
|
||||
</div>
|
||||
{#if !collapsed['people']}
|
||||
<ul class="m-0 list-none p-0">
|
||||
{#each people as ctx}
|
||||
<li>
|
||||
<button class={navItem(currentId === ctx.id)} onclick={() => navigate(ctx.id)}>
|
||||
{displayName(ctx)}
|
||||
<button class={navItem(currentId === ctx.id) + ' flex items-center gap-2'} onclick={() => navigate(ctx.id)}>
|
||||
<User size={14} class="flex-shrink-0 text-emerald-400/60" />
|
||||
<span class="truncate">{displayName(ctx)}</span>
|
||||
</button>
|
||||
</li>
|
||||
{/each}
|
||||
|
|
@ -180,10 +193,10 @@
|
|||
<!-- Wiki -->
|
||||
<div class={sectionHeader}>
|
||||
<button class={sectionToggle} onclick={() => toggleSection('wiki')} title="Auf-/Zuklappen">
|
||||
<span class="inline-block transition-transform {collapsed['wiki'] ? '-rotate-90' : ''}">{@html '▼'}</span>
|
||||
<ChevronDown size={14} class="transition-transform {collapsed['wiki'] ? '-rotate-90' : ''}" />
|
||||
</button>
|
||||
<button class={sectionLabel} onclick={() => { goto('/wiki'); onnavigate?.(); }}>
|
||||
<span>📖</span> Wiki
|
||||
<BookOpen size={15} class="flex-shrink-0 text-orange-400" /> Wiki
|
||||
</button>
|
||||
</div>
|
||||
{#if !collapsed['wiki']}
|
||||
|
|
@ -191,39 +204,35 @@
|
|||
{#each ($wikiNotebooks$ ?? []) as nb}
|
||||
<li>
|
||||
<button
|
||||
class={navItem(page.url.pathname === `/wiki/notebook/${nb.id}`)}
|
||||
class={navItem(page.url.pathname === `/wiki/notebook/${nb.id}`) + ' flex items-center gap-2'}
|
||||
onclick={() => { goto(`/wiki/notebook/${nb.id}`); onnavigate?.(); }}
|
||||
>
|
||||
{nb.name}
|
||||
<BookOpen size={14} class="flex-shrink-0 text-orange-400/60" />
|
||||
<span class="truncate">{nb.name}</span>
|
||||
</button>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
{/if}
|
||||
|
||||
<div class="mt-4">
|
||||
<div class="mt-auto border-t border-border pt-3">
|
||||
<button
|
||||
class={navItem(page.url.pathname === '/trash') + ' flex items-center gap-2'}
|
||||
class={navItem(page.url.pathname === '/trash') + ' flex items-center gap-2 mb-2'}
|
||||
onclick={() => { goto('/trash'); onnavigate?.(); }}
|
||||
>
|
||||
<span>🗑</span>
|
||||
<Trash2 size={15} class="flex-shrink-0 text-red-400/70" />
|
||||
<span>Papierkorb</span>
|
||||
{#if ($trashCount$ ?? 0) > 0}
|
||||
<span class="ml-auto rounded-full bg-white/15 px-1.5 py-0.5 text-xs text-[#888] leading-none">{$trashCount$}</span>
|
||||
{/if}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="mt-auto border-t border-border pt-3">
|
||||
<div class="mb-2 flex items-center justify-between px-1">
|
||||
<button
|
||||
class="flex items-center gap-1.5 text-xs text-muted hover:text-white transition-colors"
|
||||
onclick={() => { goto('/sync'); onnavigate?.(); }}
|
||||
>
|
||||
{#if $syncStatus === 'syncing'}
|
||||
<svg class="h-3 w-3 animate-spin" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M21 12a9 9 0 1 1-6.219-8.56" stroke-linecap="round"/>
|
||||
</svg>
|
||||
<RefreshCw size={12} class="animate-spin" />
|
||||
<span>Syncing…</span>
|
||||
{:else if $syncStatus === 'auth-required'}
|
||||
<span class="text-yellow-400">⚠ Neu anmelden</span>
|
||||
|
|
@ -240,13 +249,13 @@
|
|||
onclick={() => fullSync()}
|
||||
disabled={$syncStatus === 'syncing'}
|
||||
title="Full sync"
|
||||
>⟳</button>
|
||||
><RefreshCw size={13} /></button>
|
||||
</div>
|
||||
<button
|
||||
class="mb-1 w-full rounded px-2.5 py-2 text-left text-xs text-muted transition-colors hover:bg-white/5 hover:text-white flex items-center gap-1"
|
||||
class="mb-1 w-full rounded px-3 py-2.5 text-left text-sm text-muted transition-colors hover:bg-white/5 hover:text-white flex items-center gap-2"
|
||||
onclick={() => toggleSection('user')}
|
||||
>
|
||||
<span class="inline-block text-[10px] transition-transform {collapsed['user'] ? '-rotate-90' : ''}">{@html '▼'}</span>
|
||||
<ChevronDown size={14} class="flex-shrink-0 transition-transform {collapsed['user'] ? '-rotate-90' : ''}" />
|
||||
{#if $account}
|
||||
<span class="truncate" title={$account.username}>{$account.name ?? $account.username}</span>
|
||||
{:else}
|
||||
|
|
@ -255,22 +264,25 @@
|
|||
</button>
|
||||
{#if !collapsed['user']}
|
||||
<button
|
||||
class="mb-1 w-full rounded px-2.5 py-2 text-left text-xs text-muted transition-colors hover:bg-white/5 hover:text-white pl-5"
|
||||
class="mb-1 w-full rounded px-3 py-2.5 text-left text-sm text-muted transition-colors hover:bg-white/5 hover:text-white flex items-center gap-2 pl-6"
|
||||
onclick={() => { goto('/settings'); onnavigate?.(); }}
|
||||
>
|
||||
Einstellungen
|
||||
<Settings size={14} class="flex-shrink-0 opacity-60" />
|
||||
<span>Einstellungen</span>
|
||||
</button>
|
||||
<button
|
||||
class="mb-1 w-full rounded px-2.5 py-2 text-left text-xs text-muted transition-colors hover:bg-white/5 hover:text-white pl-5"
|
||||
class="mb-1 w-full rounded px-3 py-2.5 text-left text-sm text-muted transition-colors hover:bg-white/5 hover:text-white flex items-center gap-2 pl-6"
|
||||
onclick={() => { goto('/backup'); onnavigate?.(); }}
|
||||
>
|
||||
Backup
|
||||
<HardDrive size={14} class="flex-shrink-0 opacity-60" />
|
||||
<span>Backup</span>
|
||||
</button>
|
||||
<button
|
||||
class="mb-1 w-full rounded px-2.5 py-2 text-left text-xs text-muted transition-colors hover:bg-white/5 hover:text-white pl-5"
|
||||
class="mb-1 w-full rounded px-3 py-2.5 text-left text-sm text-muted transition-colors hover:bg-white/5 hover:text-white flex items-center gap-2 pl-6"
|
||||
onclick={() => logout()}
|
||||
>
|
||||
Sign out
|
||||
<LogOut size={14} class="flex-shrink-0 opacity-60" />
|
||||
<span>Sign out</span>
|
||||
</button>
|
||||
{/if}
|
||||
{#if isDev}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
import type { HistoryEntry } from '@ka-note/shared';
|
||||
import HistoryEntryText from './HistoryEntryText.svelte';
|
||||
import LinkTitle from './LinkTitle.svelte';
|
||||
import { Check, CalendarDays, ArrowUpRight, Trash2 } from 'lucide-svelte';
|
||||
|
||||
interface Props {
|
||||
entry: HistoryEntry;
|
||||
|
|
@ -100,25 +101,25 @@
|
|||
{:else}
|
||||
<div class="flex gap-1.5">
|
||||
<button
|
||||
class="rounded bg-green-700 px-2.5 py-1.5 text-base leading-none text-white hover:brightness-110 active:brightness-90"
|
||||
class="flex items-center justify-center rounded bg-green-700 px-2.5 py-1.5 text-white hover:brightness-110 active:brightness-90"
|
||||
title="Erledigt"
|
||||
onclick={handleOk}
|
||||
>✓</button>
|
||||
><Check size={15} /></button>
|
||||
<button
|
||||
class="rounded bg-amber-700 px-2.5 py-1.5 text-base leading-none text-white hover:brightness-110 active:brightness-90"
|
||||
class="flex items-center justify-center rounded bg-amber-700 px-2.5 py-1.5 text-white hover:brightness-110 active:brightness-90"
|
||||
title="Verschieben"
|
||||
onclick={() => showVerschieben = true}
|
||||
>📅</button>
|
||||
><CalendarDays size={15} /></button>
|
||||
<button
|
||||
class="rounded bg-[#444] px-2.5 py-1.5 text-base leading-none text-white hover:bg-[#555] active:bg-[#555]"
|
||||
class="flex items-center justify-center rounded bg-[#444] px-2.5 py-1.5 text-white hover:bg-[#555] active:bg-[#555]"
|
||||
title="In Thema wandeln"
|
||||
onclick={() => showConvert = true}
|
||||
>↗</button>
|
||||
><ArrowUpRight size={15} /></button>
|
||||
<button
|
||||
class="ml-auto rounded bg-red-900/60 px-2.5 py-1.5 text-base leading-none text-red-300 hover:bg-red-800 active:bg-red-800"
|
||||
class="ml-auto flex items-center justify-center rounded bg-red-900/60 px-2.5 py-1.5 text-red-300 hover:bg-red-800 active:bg-red-800"
|
||||
title="Löschen"
|
||||
onclick={handleDelete}
|
||||
>🗑</button>
|
||||
><Trash2 size={15} /></button>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -370,7 +370,7 @@ export async function createHistoryEntry(topicId: string, date: string, text: st
|
|||
updatedAt: now(),
|
||||
deletedAt: null,
|
||||
version: 1,
|
||||
...(isPrivate ? { isPrivate: true } : {})
|
||||
isPrivate: !!isPrivate
|
||||
};
|
||||
await db.historyEntries.put(entry);
|
||||
return entry;
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@
|
|||
"dexie": "^4.0.11",
|
||||
"dompurify": "^3.3.1",
|
||||
"highlight.js": "^11.11.1",
|
||||
"lucide-svelte": "^0.576.0",
|
||||
"marked": "^17.0.3",
|
||||
"tiptap-markdown": "^0.9.0"
|
||||
},
|
||||
|
|
@ -2665,7 +2666,6 @@
|
|||
"version": "0.3.13",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
|
||||
"integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@jridgewell/sourcemap-codec": "^1.5.0",
|
||||
|
|
@ -2676,7 +2676,6 @@
|
|||
"version": "2.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
|
||||
"integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@jridgewell/gen-mapping": "^0.3.5",
|
||||
|
|
@ -2687,7 +2686,6 @@
|
|||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
|
||||
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
|
|
@ -2708,14 +2706,12 @@
|
|||
"version": "1.5.5",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
|
||||
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@jridgewell/trace-mapping": {
|
||||
"version": "0.3.31",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
|
||||
"integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@jridgewell/resolve-uri": "^3.1.0",
|
||||
|
|
@ -3344,7 +3340,6 @@
|
|||
"version": "1.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.9.tgz",
|
||||
"integrity": "sha512-lVJX6qEgs/4DOcRTpo56tmKzVPtoWAaVbL4hfO7t7NVwl9AAXzQR6cihesW1BmNMPl+bK6dreu2sOKBP2Q9CIA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"acorn": "^8.9.0"
|
||||
|
|
@ -3969,7 +3964,6 @@
|
|||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
|
||||
"integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/linkify-it": {
|
||||
|
|
@ -4015,14 +4009,12 @@
|
|||
"version": "2.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
|
||||
"integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
|
||||
"devOptional": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/acorn": {
|
||||
"version": "8.16.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
|
||||
"integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
|
|
@ -4112,7 +4104,6 @@
|
|||
"version": "5.3.2",
|
||||
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz",
|
||||
"integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
|
|
@ -4241,7 +4232,6 @@
|
|||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz",
|
||||
"integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
|
|
@ -4657,7 +4647,6 @@
|
|||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
|
||||
"integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
|
|
@ -5004,7 +4993,6 @@
|
|||
"version": "5.6.3",
|
||||
"resolved": "https://registry.npmjs.org/devalue/-/devalue-5.6.3.tgz",
|
||||
"integrity": "sha512-nc7XjUU/2Lb+SvEFVGcWLiKkzfw8+qHI7zn8WYXKkLMgfGSHbgCEaR6bJpev8Cm6Rmrb19Gfd/tZvGqx9is3wg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/dexie": {
|
||||
|
|
@ -5959,14 +5947,12 @@
|
|||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.2.tgz",
|
||||
"integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/esrap": {
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/esrap/-/esrap-2.2.3.tgz",
|
||||
"integrity": "sha512-8fOS+GIGCQZl/ZIlhl59htOlms6U8NvX6ZYgYHpRU/b6tVSh3uHkOHZikl3D4cMbYM0JlpBe+p/BkZEi8J9XIQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@jridgewell/sourcemap-codec": "^1.4.15"
|
||||
|
|
@ -6960,7 +6946,6 @@
|
|||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz",
|
||||
"integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/estree": "^1.0.6"
|
||||
|
|
@ -7330,7 +7315,6 @@
|
|||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz",
|
||||
"integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash": {
|
||||
|
|
@ -7364,11 +7348,19 @@
|
|||
"yallist": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/lucide-svelte": {
|
||||
"version": "0.576.0",
|
||||
"resolved": "https://registry.npmjs.org/lucide-svelte/-/lucide-svelte-0.576.0.tgz",
|
||||
"integrity": "sha512-bm7RCoptI8unoEyo9H9sRHTHgnleuBW8npge05ZtxHkNsDNnO3p/BQEU79sshf4k+MSrjqlWvsCN5vVZtgV7ww==",
|
||||
"license": "ISC",
|
||||
"peerDependencies": {
|
||||
"svelte": "^3 || ^4 || ^5.0.0-next.42"
|
||||
}
|
||||
},
|
||||
"node_modules/magic-string": {
|
||||
"version": "0.30.21",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
|
||||
"integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@jridgewell/sourcemap-codec": "^1.5.5"
|
||||
|
|
@ -9247,7 +9239,6 @@
|
|||
"version": "5.53.0",
|
||||
"resolved": "https://registry.npmjs.org/svelte/-/svelte-5.53.0.tgz",
|
||||
"integrity": "sha512-7dhHkSamGS2vtoBmIW2hRab+gl5Z60alEHZB4910ePqqJNxAWnDAxsofVmlZ2tREmWyHNE+A1nCKwICAquoD2A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@jridgewell/remapping": "^2.3.4",
|
||||
|
|
@ -11046,7 +11037,6 @@
|
|||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.4.tgz",
|
||||
"integrity": "sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/zod": {
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,13 @@
|
|||
import { readFileSync, writeFileSync } from 'fs';
|
||||
let sql = readFileSync('dump-fixed.sql', 'utf8');
|
||||
// unistr('\uXXXX') -> plain UTF-8 string
|
||||
sql = sql.replace(/unistr\('((?:[^'\\]|\\.)*)'\)/g, (_, inner) => {
|
||||
const decoded = inner.replace(/\\u([0-9a-fA-F]{4})/g, (_, hex) =>
|
||||
String.fromCharCode(parseInt(hex, 16))
|
||||
);
|
||||
return `'${decoded}'`;
|
||||
});
|
||||
// ROLLBACK at end of corrupt dump -> COMMIT so import doesn't discard everything
|
||||
sql = sql.replace(/^ROLLBACK;.*$/m, 'COMMIT;');
|
||||
writeFileSync('dump-fixed2.sql', sql, 'utf8');
|
||||
console.log('done');
|
||||
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue