ui fixes
This commit is contained in:
parent
7886947a65
commit
d63c75e551
|
|
@ -1 +1 @@
|
|||
1.1.7
|
||||
1.1.11
|
||||
|
|
@ -49,12 +49,19 @@
|
|||
editing = false;
|
||||
}
|
||||
}
|
||||
|
||||
const headerColor = $derived(
|
||||
showScopeSwitch
|
||||
? (journalScope === 'private' ? $scopeSettings.privateColor : $scopeSettings.businessColor)
|
||||
: $scopeSettings.businessColor
|
||||
);
|
||||
</script>
|
||||
|
||||
<h1 class="flex items-center justify-between border-b-2 border-accent pb-2.5 mb-5">
|
||||
<h1 class="flex items-center justify-between border-b-2 pb-2.5 mb-5" style="border-color: {headerColor}">
|
||||
{#if editing}
|
||||
<input
|
||||
class="text-2xl font-bold bg-transparent border-b-2 border-accent text-inherit outline-none w-full mr-4"
|
||||
class="text-2xl font-bold bg-transparent border-b-2 text-inherit outline-none w-full mr-4"
|
||||
style="border-color: {headerColor}"
|
||||
bind:value={nameInput}
|
||||
onkeydown={onKeydown}
|
||||
onblur={saveEdit}
|
||||
|
|
|
|||
|
|
@ -346,6 +346,15 @@
|
|||
<input class="rounded border border-[#555] bg-[#111] px-2.5 py-1.5 text-[#ddd]"
|
||||
value={meta.links} onchange={(e) => updateMeta('links', e.currentTarget.value)} />
|
||||
</div>
|
||||
<div class="mb-2.5 flex flex-col">
|
||||
<label class="mb-1 text-sm text-[#aaa]">Notizen:</label>
|
||||
<EditableMarkdown
|
||||
content={(context.meta as ProjectMeta)?.notes ?? ''}
|
||||
placeholder="Notizen..."
|
||||
minHeight="60px"
|
||||
onchange={(md) => updateMeta('notes', md)}
|
||||
/>
|
||||
</div>
|
||||
{:else if isCompany}
|
||||
{@const meta = (context.meta ?? { website: '', address: '' }) as CompanyMeta}
|
||||
<div class="mb-2.5 flex flex-col">
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
import ConfirmDialog from './ConfirmDialog.svelte';
|
||||
import WiedervorlageSection from './WiedervorlageSection.svelte';
|
||||
import LinkTitle from './LinkTitle.svelte';
|
||||
import { currentScope } from '$lib/stores/scopeContext';
|
||||
import { currentScope, scopeSettings } from '$lib/stores/scopeContext';
|
||||
|
||||
interface Props {
|
||||
contextId: string;
|
||||
|
|
@ -120,12 +120,14 @@
|
|||
let editingId = $state<string | null>(null);
|
||||
let editTitle = $state('');
|
||||
let editBody = $state('');
|
||||
let editIsPrivate = $state(false);
|
||||
|
||||
function startEdit(entry: { id: string; text: string }) {
|
||||
function startEdit(entry: { id: string; text: string; isPrivate?: boolean }) {
|
||||
const lines = entry.text.split('\n');
|
||||
editingId = entry.id;
|
||||
editTitle = lines[0];
|
||||
editBody = lines.slice(1).join('\n').trim();
|
||||
editIsPrivate = !!entry.isPrivate;
|
||||
}
|
||||
|
||||
function cancelEdit() {
|
||||
|
|
@ -135,7 +137,7 @@
|
|||
async function saveEdit() {
|
||||
if (!editingId || !editTitle.trim()) return;
|
||||
const text = editBody.trim() ? `${editTitle.trim()}\n${editBody.trim()}` : editTitle.trim();
|
||||
await updateHistoryEntry(editingId, text);
|
||||
await updateHistoryEntry(editingId, text, editIsPrivate);
|
||||
editingId = null;
|
||||
}
|
||||
|
||||
|
|
@ -273,7 +275,8 @@
|
|||
/>
|
||||
<div class="flex items-center gap-4">
|
||||
<button
|
||||
class="rounded bg-accent px-4 py-2 font-bold text-white hover:brightness-110"
|
||||
class="rounded px-4 py-2 font-bold text-white hover:brightness-110"
|
||||
style="background-color: {journalScope === 'private' ? $scopeSettings.privateColor : $scopeSettings.businessColor}"
|
||||
onclick={handleAddEntry}
|
||||
>
|
||||
+ {selectedLinkedContextId ? 'Thema hinzufügen' : 'Notiz hinzufügen'}
|
||||
|
|
@ -312,7 +315,7 @@
|
|||
wikiScope={journalScope === 'private'}
|
||||
onchange={(md) => editBody = md}
|
||||
/>
|
||||
<div class="flex gap-2">
|
||||
<div class="flex items-center gap-2 flex-wrap">
|
||||
<button
|
||||
class="rounded bg-accent px-3 py-1 text-sm font-bold text-white hover:brightness-110"
|
||||
onclick={saveEdit}
|
||||
|
|
@ -321,6 +324,17 @@
|
|||
class="rounded bg-[#444] px-3 py-1 text-sm text-white hover:bg-[#555]"
|
||||
onclick={cancelEdit}
|
||||
>Abbrechen</button>
|
||||
<div class="ml-auto flex gap-1 rounded-full bg-[#333] p-0.5">
|
||||
<button
|
||||
class="rounded-full px-2.5 py-1 text-xs font-bold transition-all {!editIsPrivate ? 'bg-accent text-white shadow' : 'text-[#aaa] hover:text-white'}"
|
||||
onclick={() => editIsPrivate = false}
|
||||
>Firma</button>
|
||||
<button
|
||||
class="rounded-full px-2.5 py-1 text-xs font-bold transition-all {editIsPrivate ? 'text-white shadow' : 'text-[#aaa] hover:text-white'}"
|
||||
style={editIsPrivate ? `background-color: ${$scopeSettings.privateColor}` : ''}
|
||||
onclick={() => editIsPrivate = true}
|
||||
>Privat</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
|
|
@ -330,10 +344,13 @@
|
|||
<div class="group mb-3 flex items-start gap-2 rounded bg-card-bg p-2.5">
|
||||
<span class="mt-0.5 text-xs text-muted whitespace-nowrap">{formatTime(entry.updatedAt)}</span>
|
||||
<div class="flex-1">
|
||||
<div class="font-bold">
|
||||
<div class="flex flex-wrap items-center gap-1.5 font-bold">
|
||||
<LinkTitle text={title} />
|
||||
{#if entry.wiedervorlageDate && !entry.wiedervorlageResolvedAt}
|
||||
<span class="text-base leading-none text-amber-400" title="In Wiedervorlage bis {entry.wiedervorlageDate}">⏰</span>
|
||||
{/if}
|
||||
{#if entry.linkedContextId}
|
||||
<span class="ml-1 inline-block rounded bg-accent/20 px-1.5 py-0.5 text-xs font-normal text-accent">
|
||||
<span class="inline-block rounded bg-accent/20 px-1.5 py-0.5 text-xs font-normal text-accent">
|
||||
{contextNameMap().get(entry.linkedContextId) ?? entry.linkedContextId}
|
||||
</span>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { softDeleteContext, toggleFavorite } from '$lib/db/repositories';
|
||||
import { softDeleteContext, toggleFavorite, reorderContext } from '$lib/db/repositories';
|
||||
import ConfirmDialog from '$lib/components/ConfirmDialog.svelte';
|
||||
import type { AgendaContext, PersonMeta, PersonSubType } from '@ka-note/shared';
|
||||
|
||||
|
|
@ -41,9 +41,13 @@
|
|||
|
||||
{#if persons.length > 0}
|
||||
<div class="flex flex-col gap-2">
|
||||
{#each persons as ctx (ctx.id)}
|
||||
{#each persons as ctx, i (ctx.id)}
|
||||
{@const subType = ((ctx.meta as PersonMeta | null)?.personSubType ?? 'contact') as PersonSubType}
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="flex flex-col">
|
||||
<button class="text-[#555] hover:text-[#aaa] disabled:opacity-20 leading-none px-1" onclick={() => reorderContext(ctx.id, 'up')} disabled={i === 0} title="Nach oben">▲</button>
|
||||
<button class="text-[#555] hover:text-[#aaa] disabled:opacity-20 leading-none px-1" onclick={() => reorderContext(ctx.id, 'down')} disabled={i === persons.length - 1} title="Nach unten">▼</button>
|
||||
</div>
|
||||
<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)}
|
||||
|
|
|
|||
|
|
@ -98,23 +98,27 @@
|
|||
>Abbrechen</button>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="flex gap-2">
|
||||
<div class="flex gap-1.5">
|
||||
<button
|
||||
class="rounded bg-green-700 px-3 py-1 text-sm font-bold text-white hover:brightness-110"
|
||||
class="rounded bg-green-700 px-2.5 py-1.5 text-base leading-none text-white hover:brightness-110 active:brightness-90"
|
||||
title="Erledigt"
|
||||
onclick={handleOk}
|
||||
>Ok</button>
|
||||
>✓</button>
|
||||
<button
|
||||
class="rounded bg-amber-700 px-3 py-1 text-sm text-white hover:brightness-110"
|
||||
class="rounded bg-amber-700 px-2.5 py-1.5 text-base leading-none text-white hover:brightness-110 active:brightness-90"
|
||||
title="Verschieben"
|
||||
onclick={() => showVerschieben = true}
|
||||
>Verschieben</button>
|
||||
>📅</button>
|
||||
<button
|
||||
class="rounded bg-[#444] px-3 py-1 text-sm text-white hover:bg-[#555]"
|
||||
class="rounded bg-[#444] px-2.5 py-1.5 text-base leading-none text-white hover:bg-[#555] active:bg-[#555]"
|
||||
title="In Thema wandeln"
|
||||
onclick={() => showConvert = true}
|
||||
>In Thema wandeln</button>
|
||||
>↗</button>
|
||||
<button
|
||||
class="ml-auto rounded bg-red-900/60 px-3 py-1 text-sm text-red-300 hover:bg-red-800"
|
||||
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"
|
||||
title="Löschen"
|
||||
onclick={handleDelete}
|
||||
>Löschen</button>
|
||||
>🗑</button>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -66,6 +66,21 @@ export async function toggleFavorite(id: string): Promise<void> {
|
|||
}
|
||||
}
|
||||
|
||||
export async function reorderContext(id: string, direction: 'up' | 'down'): Promise<void> {
|
||||
const ctx = await db.contexts.get(id);
|
||||
if (!ctx) return;
|
||||
const siblings = await db.contexts
|
||||
.filter(c => !c.deletedAt && c.type === ctx.type)
|
||||
.sortBy('sortOrder');
|
||||
const idx = siblings.findIndex(c => c.id === id);
|
||||
const swapIdx = direction === 'up' ? idx - 1 : idx + 1;
|
||||
if (swapIdx < 0 || swapIdx >= siblings.length) return;
|
||||
const other = siblings[swapIdx];
|
||||
const ts = now();
|
||||
await db.contexts.update(id, { sortOrder: other.sortOrder, updatedAt: ts, version: ctx.version + 1 });
|
||||
await db.contexts.update(other.id, { sortOrder: ctx.sortOrder, updatedAt: ts, version: other.version + 1 });
|
||||
}
|
||||
|
||||
export async function findContextByMentionName(name: string, type: 'person' | 'project' | 'company'): Promise<AgendaContext | undefined> {
|
||||
const q = name.toLowerCase();
|
||||
return db.contexts
|
||||
|
|
@ -257,10 +272,12 @@ export async function convertToTopic(entryId: string, contextId: string): Promis
|
|||
return topic;
|
||||
}
|
||||
|
||||
export async function updateHistoryEntry(id: string, text: string): Promise<void> {
|
||||
export async function updateHistoryEntry(id: string, text: string, isPrivate?: boolean): Promise<void> {
|
||||
const entry = await db.historyEntries.get(id);
|
||||
if (entry) {
|
||||
await db.historyEntries.update(id, { text, updatedAt: now(), version: entry.version + 1 });
|
||||
const patch: Record<string, unknown> = { text, updatedAt: now(), version: entry.version + 1 };
|
||||
if (isPrivate !== undefined) patch.isPrivate = isPrivate;
|
||||
await db.historyEntries.update(id, patch);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -381,6 +398,13 @@ export async function upsertPage(page: Partial<Page> & { id: string }): Promise<
|
|||
}
|
||||
}
|
||||
|
||||
export async function togglePageFavorite(id: string): Promise<void> {
|
||||
const p = await db.pages.get(id);
|
||||
if (p) {
|
||||
await db.pages.update(id, { isFavorite: !p.isFavorite, updatedAt: now(), version: p.version + 1 });
|
||||
}
|
||||
}
|
||||
|
||||
export async function softDeletePage(id: string): Promise<void> {
|
||||
const page = await db.pages.get(id);
|
||||
if (page) {
|
||||
|
|
@ -469,6 +493,21 @@ export async function toggleNotebookFavorite(id: string): Promise<void> {
|
|||
}
|
||||
}
|
||||
|
||||
export async function reorderNotebook(id: string, direction: 'up' | 'down'): Promise<void> {
|
||||
const nb = await db.notebooks.get(id);
|
||||
if (!nb) return;
|
||||
const siblings = await db.notebooks
|
||||
.filter(n => !n.deletedAt)
|
||||
.sortBy('sortOrder');
|
||||
const idx = siblings.findIndex(n => n.id === id);
|
||||
const swapIdx = direction === 'up' ? idx - 1 : idx + 1;
|
||||
if (swapIdx < 0 || swapIdx >= siblings.length) return;
|
||||
const other = siblings[swapIdx];
|
||||
const ts = now();
|
||||
await db.notebooks.update(id, { sortOrder: other.sortOrder, updatedAt: ts, version: nb.version + 1 });
|
||||
await db.notebooks.update(other.id, { sortOrder: nb.sortOrder, updatedAt: ts, version: other.version + 1 });
|
||||
}
|
||||
|
||||
export async function softDeleteNotebook(id: string): Promise<void> {
|
||||
const nb = await db.notebooks.get(id);
|
||||
if (nb) {
|
||||
|
|
|
|||
|
|
@ -118,6 +118,14 @@ export class KaNoteDB extends Dexie {
|
|||
if (nb.isFavorite === undefined) nb.isFavorite = false;
|
||||
});
|
||||
});
|
||||
|
||||
this.version(12).stores({
|
||||
pages: '&id, deletedAt, isPrivate, isFavorite',
|
||||
}).upgrade(tx => {
|
||||
return tx.table('pages').toCollection().modify((p: Record<string, unknown>) => {
|
||||
if (p.isFavorite === undefined) p.isFavorite = false;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,12 @@ export function notebooksForContext(contextId: string) {
|
|||
);
|
||||
}
|
||||
|
||||
export function favoritePages() {
|
||||
return liveQuery(() =>
|
||||
db.pages.filter(p => !p.deletedAt && !!p.isFavorite).sortBy('title')
|
||||
);
|
||||
}
|
||||
|
||||
export function allPages() {
|
||||
return liveQuery(() =>
|
||||
db.pages.filter(p => !p.deletedAt).sortBy('title')
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
import { goto } from '$app/navigation';
|
||||
import { liveQuery } from 'dexie';
|
||||
import { db } from '$lib/db/schema';
|
||||
import { softDeleteContext, toggleFavorite, upsertContext } from '$lib/db/repositories';
|
||||
import { softDeleteContext, toggleFavorite, upsertContext, reorderContext } from '$lib/db/repositories';
|
||||
import { newId } from '$lib/db/helpers';
|
||||
import ConfirmDialog from '$lib/components/ConfirmDialog.svelte';
|
||||
|
||||
|
|
@ -67,8 +67,12 @@
|
|||
|
||||
{#if companies.length > 0}
|
||||
<div class="flex flex-col gap-2">
|
||||
{#each companies as ctx (ctx.id)}
|
||||
{#each companies as ctx, i (ctx.id)}
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="flex flex-col">
|
||||
<button class="text-[#555] hover:text-[#aaa] disabled:opacity-20 leading-none px-1" onclick={() => reorderContext(ctx.id, 'up')} disabled={i === 0} title="Nach oben">▲</button>
|
||||
<button class="text-[#555] hover:text-[#aaa] disabled:opacity-20 leading-none px-1" onclick={() => reorderContext(ctx.id, 'down')} disabled={i === companies.length - 1} title="Nach unten">▼</button>
|
||||
</div>
|
||||
<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)}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
import { goto } from '$app/navigation';
|
||||
import { liveQuery } from 'dexie';
|
||||
import { db } from '$lib/db/schema';
|
||||
import { softDeleteContext, toggleFavorite, upsertContext } from '$lib/db/repositories';
|
||||
import { softDeleteContext, toggleFavorite, upsertContext, reorderContext } from '$lib/db/repositories';
|
||||
import { newId } from '$lib/db/helpers';
|
||||
import ConfirmDialog from '$lib/components/ConfirmDialog.svelte';
|
||||
|
||||
|
|
@ -63,8 +63,12 @@
|
|||
|
||||
{#if meetings.length > 0}
|
||||
<div class="flex flex-col gap-2">
|
||||
{#each meetings as ctx (ctx.id)}
|
||||
{#each meetings as ctx, i (ctx.id)}
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="flex flex-col">
|
||||
<button class="text-[#555] hover:text-[#aaa] disabled:opacity-20 leading-none px-1" onclick={() => reorderContext(ctx.id, 'up')} disabled={i === 0} title="Nach oben">▲</button>
|
||||
<button class="text-[#555] hover:text-[#aaa] disabled:opacity-20 leading-none px-1" onclick={() => reorderContext(ctx.id, 'down')} disabled={i === meetings.length - 1} title="Nach unten">▼</button>
|
||||
</div>
|
||||
<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)}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
import { goto } from '$app/navigation';
|
||||
import { liveQuery } from 'dexie';
|
||||
import { db } from '$lib/db/schema';
|
||||
import { softDeleteContext, toggleFavorite, upsertContext } from '$lib/db/repositories';
|
||||
import { softDeleteContext, toggleFavorite, upsertContext, reorderContext } 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';
|
||||
|
|
@ -74,8 +74,12 @@
|
|||
{#if activeProjects.length > 0}
|
||||
<h2 class="mb-3 text-sm font-bold uppercase text-[#aaa]">Aktiv</h2>
|
||||
<div class="mb-8 flex flex-col gap-2">
|
||||
{#each activeProjects as ctx (ctx.id)}
|
||||
{#each activeProjects as ctx, i (ctx.id)}
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="flex flex-col">
|
||||
<button class="text-[#555] hover:text-[#aaa] disabled:opacity-20 leading-none px-1" onclick={() => reorderContext(ctx.id, 'up')} disabled={i === 0} title="Nach oben">▲</button>
|
||||
<button class="text-[#555] hover:text-[#aaa] disabled:opacity-20 leading-none px-1" onclick={() => reorderContext(ctx.id, 'down')} disabled={i === activeProjects.length - 1} title="Nach unten">▼</button>
|
||||
</div>
|
||||
<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)}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { allNotebooks, unassignedPages } from '$lib/stores/wiki';
|
||||
import { createNotebook, createPage, toggleNotebookFavorite, upsertNotebook } from '$lib/db/repositories';
|
||||
import { allNotebooks, unassignedPages, favoritePages } from '$lib/stores/wiki';
|
||||
import { createNotebook, createPage, toggleNotebookFavorite, upsertNotebook, reorderNotebook } from '$lib/db/repositories';
|
||||
import { currentScope, scopeSettings } from '$lib/stores/scopeContext';
|
||||
|
||||
const notebooks$ = allNotebooks();
|
||||
const unassigned$ = unassignedPages();
|
||||
const favoritePages$ = favoritePages();
|
||||
|
||||
const SCOPE_KEY = 'wiki-scope';
|
||||
let scope = $state<'business' | 'private'>(
|
||||
|
|
@ -20,6 +21,10 @@
|
|||
($unassigned$ ?? []).filter(p => p.isPrivate === (scope === 'private'))
|
||||
);
|
||||
|
||||
const filteredFavoritePages = $derived(
|
||||
($favoritePages$ ?? []).filter(p => p.isPrivate === (scope === 'private'))
|
||||
);
|
||||
|
||||
let creatingNotebook = $state(false);
|
||||
let newNotebookName = $state('');
|
||||
|
||||
|
|
@ -71,6 +76,24 @@
|
|||
</div>
|
||||
</h1>
|
||||
|
||||
<!-- Favorite pages -->
|
||||
{#if filteredFavoritePages.length > 0}
|
||||
<section>
|
||||
<h2 class="mb-2 text-sm font-semibold uppercase text-muted">Favoriten</h2>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
{#each filteredFavoritePages as page (page.id)}
|
||||
<button
|
||||
class="flex items-center gap-1.5 rounded-lg border border-warning/40 bg-warning/10 px-3 py-1.5 text-sm text-warning hover:bg-warning/20 transition-colors"
|
||||
onclick={() => goto(`/wiki/${page.id}`)}
|
||||
>
|
||||
<span class="text-xs">★</span>
|
||||
<span>{page.title}</span>
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
</section>
|
||||
{/if}
|
||||
|
||||
<div class="flex items-center justify-between">
|
||||
<h2 class="text-sm font-semibold uppercase text-muted">Notizbücher</h2>
|
||||
<div class="flex items-center gap-3">
|
||||
|
|
@ -83,8 +106,12 @@
|
|||
</div>
|
||||
|
||||
<div class="space-y-1">
|
||||
{#each filteredNotebooks as nb (nb.id)}
|
||||
{#each filteredNotebooks as nb, i (nb.id)}
|
||||
<div class="flex items-center gap-1 rounded hover:bg-white/5 group">
|
||||
<div class="flex flex-col pl-1">
|
||||
<button class="text-[#555] hover:text-[#aaa] disabled:opacity-20 leading-none text-[10px] px-0.5" onclick={() => reorderNotebook(nb.id, 'up')} disabled={i === 0} title="Nach oben">▲</button>
|
||||
<button class="text-[#555] hover:text-[#aaa] disabled:opacity-20 leading-none text-[10px] px-0.5" onclick={() => reorderNotebook(nb.id, 'down')} disabled={i === filteredNotebooks.length - 1} title="Nach unten">▼</button>
|
||||
</div>
|
||||
<button
|
||||
class="flex flex-1 items-center gap-2 px-3 py-2 text-left text-sm text-[#ccc] hover:text-white"
|
||||
onclick={() => goto(`/wiki/notebook/${nb.id}`)}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
import { page } from '$app/stores';
|
||||
import { goto } from '$app/navigation';
|
||||
import { db } from '$lib/db/schema';
|
||||
import { upsertPage, softDeletePage, getNotebooksForPage, getBacklinksForPage, assignPageToNotebook, removePageFromNotebook, getAllNotebooks } from '$lib/db/repositories';
|
||||
import { upsertPage, softDeletePage, togglePageFavorite, getNotebooksForPage, getBacklinksForPage, assignPageToNotebook, removePageFromNotebook, getAllNotebooks } from '$lib/db/repositories';
|
||||
import MarkdownEditor from '$lib/components/MarkdownEditor.svelte';
|
||||
import RenderedMarkdown from '$lib/components/RenderedMarkdown.svelte';
|
||||
import ConfirmDialog from '$lib/components/ConfirmDialog.svelte';
|
||||
|
|
@ -59,6 +59,7 @@
|
|||
async function saveBody() {
|
||||
const body = editorRef?.getMarkdown() ?? '';
|
||||
await upsertPage({ id: pageId, body });
|
||||
if (currentPage) currentPage = { ...currentPage, body };
|
||||
}
|
||||
|
||||
async function switchToRead() {
|
||||
|
|
@ -137,6 +138,11 @@
|
|||
>
|
||||
{editing ? '✓ Fertig' : '✎ Bearbeiten'}
|
||||
</button>
|
||||
<button
|
||||
class="rounded px-2 py-1.5 text-base transition-colors {currentPage.isFavorite ? 'text-warning' : 'text-muted hover:text-warning'}"
|
||||
onclick={async () => { await togglePageFavorite(pageId); currentPage = { ...currentPage!, isFavorite: !currentPage!.isFavorite }; }}
|
||||
title={currentPage.isFavorite ? 'Favorit entfernen' : 'Als Favorit markieren'}
|
||||
>★</button>
|
||||
<button
|
||||
class="rounded px-2 py-1.5 text-xs text-muted hover:bg-danger/20 hover:text-danger ml-auto"
|
||||
onclick={() => confirmDelete = true}
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -23,6 +23,7 @@ export interface ProjectMeta {
|
|||
status: string;
|
||||
owner: string;
|
||||
links: string;
|
||||
notes?: string;
|
||||
}
|
||||
|
||||
export interface PersonMeta {
|
||||
|
|
@ -91,6 +92,7 @@ export interface Page extends SyncEntity {
|
|||
body: string;
|
||||
isPrivate: boolean;
|
||||
sortOrder: number;
|
||||
isFavorite?: boolean;
|
||||
}
|
||||
|
||||
export interface Notebook extends SyncEntity {
|
||||
|
|
|
|||
Loading…
Reference in New Issue