ui fixes
This commit is contained in:
parent
a62ada936d
commit
d1286cd717
|
|
@ -1 +1 @@
|
|||
1.1.62
|
||||
1.1.68
|
||||
|
|
@ -6,8 +6,9 @@
|
|||
interface Props {
|
||||
entry: HistoryEntry;
|
||||
onedit?: (id: string, text: string, date: string) => void;
|
||||
onediting?: (active: boolean) => void;
|
||||
}
|
||||
let { entry, onedit }: Props = $props();
|
||||
let { entry, onedit, onediting }: Props = $props();
|
||||
|
||||
let editing = $state(false);
|
||||
let editText = $state('');
|
||||
|
|
@ -17,15 +18,18 @@
|
|||
editText = entry.text;
|
||||
editDate = entry.date;
|
||||
editing = true;
|
||||
onediting?.(true);
|
||||
}
|
||||
|
||||
function saveEdit() {
|
||||
onedit?.(entry.id, editText, editDate);
|
||||
editing = false;
|
||||
onediting?.(false);
|
||||
}
|
||||
|
||||
function cancelEdit() {
|
||||
editing = false;
|
||||
onediting?.(false);
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
@ -44,7 +48,20 @@
|
|||
</div>
|
||||
|
||||
{#if editing}
|
||||
<div>
|
||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||
<div onkeydown={(e) => { if (e.key === 'Escape') cancelEdit(); }}>
|
||||
<div class="flex items-center gap-2 mb-1 flex-wrap">
|
||||
<input
|
||||
type="date"
|
||||
class="rounded border border-[#444] bg-bg px-2 py-1 text-sm text-white"
|
||||
bind:value={editDate}
|
||||
title="Datum des Eintrags"
|
||||
/>
|
||||
<div class="ml-auto flex gap-1">
|
||||
<button class="rounded bg-[#444] px-3 py-1 text-sm text-[#ccc] hover:bg-[#555]" onclick={cancelEdit}>Abbrechen</button>
|
||||
<button class="rounded bg-success px-3 py-1 text-sm font-bold text-white" onclick={saveEdit}>Speichern</button>
|
||||
</div>
|
||||
</div>
|
||||
<MarkdownEditor
|
||||
content={editText}
|
||||
wikiScope={null}
|
||||
|
|
@ -66,7 +83,10 @@
|
|||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
<RenderedMarkdown text={entry.text} />
|
||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||
<div ondblclick={startEdit}>
|
||||
<RenderedMarkdown text={entry.text} />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -236,7 +236,7 @@
|
|||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="mb-8 flex flex-col gap-2.5 rounded-lg border border-border bg-sidebar p-4">
|
||||
<div class="mb-8 flex flex-col gap-2.5 rounded-lg border border-border bg-sidebar p-4" class:hidden={editingId !== null}>
|
||||
<MarkdownEditor
|
||||
bind:this={entryEditor}
|
||||
placeholder="Was ist passiert? (1. Zeile = Titel)"
|
||||
|
|
@ -301,12 +301,41 @@
|
|||
<div class="mb-4 text-xl font-bold text-accent">{selectedDate}</div>
|
||||
{#each filteredEntries as entry (entry.id)}
|
||||
{#if editingId === entry.id}
|
||||
<div class="mb-3 flex flex-col gap-2 rounded border border-accent bg-card-bg p-2.5">
|
||||
<input
|
||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||
<div class="mb-3 flex flex-col gap-2 rounded border border-accent bg-card-bg p-2.5" onkeydown={(e) => { if (e.key === 'Escape') cancelEdit(); }}>
|
||||
<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}
|
||||
>Speichern</button>
|
||||
<button
|
||||
class="rounded bg-[#444] px-3 py-1 text-sm text-white hover:bg-[#555]"
|
||||
onclick={cancelEdit}
|
||||
>Abbrechen</button>
|
||||
<input
|
||||
type="date"
|
||||
class="rounded border border-[#444] bg-bg px-2 py-1 text-sm text-white"
|
||||
bind:value={editDate}
|
||||
title="Datum des Eintrags"
|
||||
/>
|
||||
<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>
|
||||
<input
|
||||
type="text"
|
||||
class="rounded border border-[#444] bg-bg px-2.5 py-1.5 font-mono text-white"
|
||||
bind:value={editTitle}
|
||||
use:mention
|
||||
onkeydown={(e) => { if (e.key === 'Enter' && (e.ctrlKey || e.metaKey)) { e.preventDefault(); saveEdit(); } }}
|
||||
/>
|
||||
<MarkdownEditor
|
||||
content={editBody}
|
||||
|
|
@ -314,6 +343,7 @@
|
|||
minHeight="60px"
|
||||
wikiScope={journalScope === 'private'}
|
||||
onchange={(md) => editBody = md}
|
||||
onsave={saveEdit}
|
||||
/>
|
||||
<div class="flex items-center gap-2 flex-wrap">
|
||||
<button
|
||||
|
|
@ -347,7 +377,8 @@
|
|||
{@const lines = entry.text.split('\n')}
|
||||
{@const title = lines[0].replace(/^#{1,6}\s+/, '')}
|
||||
{@const body = lines.slice(1).join('\n').trim()}
|
||||
<div class="group mb-3 flex items-start gap-2 rounded bg-card-bg p-2.5">
|
||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||
<div class="group mb-3 flex items-start gap-2 rounded bg-card-bg p-2.5" ondblclick={() => startEdit(entry)}>
|
||||
<span class="mt-0.5 text-xs text-muted whitespace-nowrap">{formatTime(entry)}</span>
|
||||
<div class="flex-1">
|
||||
<div class="flex flex-wrap items-center gap-1.5 font-bold">
|
||||
|
|
|
|||
|
|
@ -114,6 +114,8 @@
|
|||
}
|
||||
}
|
||||
|
||||
let historyEditing = $state(false);
|
||||
|
||||
function handleEditHistory(id: string, text: string, date: string) {
|
||||
updateHistoryEntry(id, text, undefined, date);
|
||||
}
|
||||
|
|
@ -238,7 +240,7 @@
|
|||
{#if !collapsed}
|
||||
<div class="px-5 pb-5 border-t border-[#444]">
|
||||
<!-- Note input -->
|
||||
<div class="mt-2.5 flex flex-col gap-1">
|
||||
<div class="mt-2.5 flex flex-col gap-1" class:hidden={historyEditing}>
|
||||
<MarkdownEditor
|
||||
bind:this={noteEditor}
|
||||
placeholder="- Notiz... (z.B. '-> NAME' or '@P:PROJECT')"
|
||||
|
|
@ -319,7 +321,7 @@
|
|||
class="mt-4 max-h-[300px] overflow-y-auto rounded border border-[#333] bg-[#222] p-2.5"
|
||||
>
|
||||
{#each $history as entry (entry.id)}
|
||||
<HistoryItem {entry} onedit={handleEditHistory} />
|
||||
<HistoryItem {entry} onedit={handleEditHistory} onediting={(a) => historyEditing = a} />
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,31 @@ import { liveQuery } from 'dexie';
|
|||
import { db } from '$lib/db/schema';
|
||||
import type { Page, Notebook } from '@ka-note/shared';
|
||||
|
||||
export interface PageWithNotebooks extends Page {
|
||||
notebooks: Pick<Notebook, 'id' | 'name'>[];
|
||||
}
|
||||
|
||||
async function enrichWithNotebooks(pages: Page[]): Promise<PageWithNotebooks[]> {
|
||||
if (pages.length === 0) return [];
|
||||
const allJoins = await db.pageNotebooks
|
||||
.where('pageId').anyOf(pages.map(p => p.id))
|
||||
.filter(pn => !pn.deletedAt)
|
||||
.toArray();
|
||||
const notebookIds = [...new Set(allJoins.map(j => j.notebookId))];
|
||||
const notebooks = notebookIds.length > 0
|
||||
? (await db.notebooks.bulkGet(notebookIds)).filter((n): n is Notebook => !!n && !n.deletedAt)
|
||||
: [];
|
||||
const nbMap = new Map(notebooks.map(n => [n.id, n]));
|
||||
return pages.map(p => ({
|
||||
...p,
|
||||
notebooks: allJoins
|
||||
.filter(j => j.pageId === p.id)
|
||||
.map(j => nbMap.get(j.notebookId))
|
||||
.filter((n): n is Notebook => !!n)
|
||||
.map(n => ({ id: n.id, name: n.name }))
|
||||
}));
|
||||
}
|
||||
|
||||
export function allNotebooks() {
|
||||
return liveQuery(() =>
|
||||
db.notebooks.filter(n => !n.deletedAt).sortBy('sortOrder')
|
||||
|
|
@ -30,9 +55,10 @@ export function notebooksForContext(contextId: string) {
|
|||
}
|
||||
|
||||
export function favoritePages() {
|
||||
return liveQuery(() =>
|
||||
db.pages.filter(p => !p.deletedAt && !!p.isFavorite).sortBy('title')
|
||||
);
|
||||
return liveQuery(async () => {
|
||||
const pages = await db.pages.filter(p => !p.deletedAt && !!p.isFavorite).sortBy('title');
|
||||
return enrichWithNotebooks(pages);
|
||||
});
|
||||
}
|
||||
|
||||
export function allPages() {
|
||||
|
|
@ -54,6 +80,16 @@ export function pagesForNotebook(notebookId: string) {
|
|||
});
|
||||
}
|
||||
|
||||
export function recentlyEditedPages(limit = 10) {
|
||||
return liveQuery(async () => {
|
||||
const pages = await db.pages.filter(p => !p.deletedAt).toArray();
|
||||
const sorted = pages
|
||||
.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt))
|
||||
.slice(0, limit);
|
||||
return enrichWithNotebooks(sorted);
|
||||
});
|
||||
}
|
||||
|
||||
export function unassignedPages() {
|
||||
return liveQuery(async () => {
|
||||
const allPages = await db.pages.filter(p => !p.deletedAt).toArray();
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ export function extractTitleAndBody(
|
|||
maxLen = DEFAULT_MAX_TITLE_LENGTH
|
||||
): { title: string; body: string } {
|
||||
const lines = raw.split('\n');
|
||||
const firstLine = lines[0].replace(/^#{1,6}\s*/, '').trim();
|
||||
const firstLine = lines[0].replace(/^#{1,6}\s*/, '').replace(/\\$/, '').trim();
|
||||
const rest = lines.slice(1).join('\n').trim();
|
||||
return normalizeTitleAndBody(firstLine, rest, maxLen);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { allNotebooks, unassignedPages, favoritePages } from '$lib/stores/wiki';
|
||||
import { allNotebooks, unassignedPages, favoritePages, recentlyEditedPages, type PageWithNotebooks } 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 recentPages$ = recentlyEditedPages();
|
||||
|
||||
const SCOPE_KEY = 'wiki-scope';
|
||||
let scope = $state<'business' | 'private'>(
|
||||
|
|
@ -25,6 +26,23 @@
|
|||
($favoritePages$ ?? []).filter(p => p.isPrivate === (scope === 'private'))
|
||||
);
|
||||
|
||||
const filteredRecentPages = $derived(
|
||||
($recentPages$ ?? []).filter(p => p.isPrivate === (scope === 'private'))
|
||||
);
|
||||
|
||||
const TAB_KEY = 'wiki-tab';
|
||||
let activeTab = $state<'notebooks' | 'favorites' | 'recent'>(
|
||||
(typeof localStorage !== 'undefined' ? localStorage.getItem(TAB_KEY) as 'notebooks' | 'favorites' | 'recent' : null) ?? 'notebooks'
|
||||
);
|
||||
function setTab(t: 'notebooks' | 'favorites' | 'recent') {
|
||||
activeTab = t;
|
||||
localStorage.setItem(TAB_KEY, t);
|
||||
}
|
||||
|
||||
const quickTabPages = $derived<PageWithNotebooks[]>(
|
||||
activeTab === 'favorites' ? filteredFavoritePages : filteredRecentPages
|
||||
);
|
||||
|
||||
let creatingNotebook = $state(false);
|
||||
let newNotebookName = $state('');
|
||||
|
||||
|
|
@ -76,86 +94,130 @@
|
|||
</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">
|
||||
<section class="rounded-lg border border-[#333] bg-[#1a1a1a]">
|
||||
<!-- Tab bar -->
|
||||
<div class="flex border-b border-[#333]">
|
||||
<button
|
||||
class="rounded bg-accent px-3 py-1.5 text-sm font-medium text-white hover:bg-accent/80"
|
||||
onclick={addPage}
|
||||
>+ Neue Seite</button>
|
||||
<button class="rounded bg-white/10 px-3 py-1.5 text-sm font-medium text-muted hover:bg-white/20 hover:text-white" onclick={() => creatingNotebook = true}>+ Notizbuch</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="space-y-1">
|
||||
{#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>
|
||||
class="flex items-center gap-1.5 px-4 py-2.5 text-sm font-semibold transition-colors border-b-2 -mb-px {activeTab === 'notebooks' ? 'border-accent text-accent' : 'border-transparent text-muted hover:text-white'}"
|
||||
onclick={() => setTab('notebooks')}
|
||||
>
|
||||
<span>📓</span>
|
||||
<span>Notizbücher</span>
|
||||
{#if filteredNotebooks.length > 0}
|
||||
<span class="rounded-full bg-white/10 px-1.5 py-0.5 text-xs">{filteredNotebooks.length}</span>
|
||||
{/if}
|
||||
</button>
|
||||
<button
|
||||
class="flex items-center gap-1.5 px-4 py-2.5 text-sm font-semibold transition-colors border-b-2 -mb-px {activeTab === 'favorites' ? 'border-warning text-warning' : 'border-transparent text-muted hover:text-white'}"
|
||||
onclick={() => setTab('favorites')}
|
||||
>
|
||||
<span>★</span>
|
||||
<span>Favoriten</span>
|
||||
{#if filteredFavoritePages.length > 0}
|
||||
<span class="rounded-full bg-white/10 px-1.5 py-0.5 text-xs">{filteredFavoritePages.length}</span>
|
||||
{/if}
|
||||
</button>
|
||||
<button
|
||||
class="flex items-center gap-1.5 px-4 py-2.5 text-sm font-semibold transition-colors border-b-2 -mb-px {activeTab === 'recent' ? 'border-[#aaa] text-[#ccc]' : 'border-transparent text-muted hover:text-white'}"
|
||||
onclick={() => setTab('recent')}
|
||||
>
|
||||
<span>✎</span>
|
||||
<span>Zuletzt bearbeitet</span>
|
||||
</button>
|
||||
<!-- Actions (right side) -->
|
||||
{#if activeTab === 'notebooks'}
|
||||
<div class="ml-auto flex items-center gap-2 px-3">
|
||||
<button
|
||||
class="rounded bg-accent px-3 py-1.5 text-sm font-medium text-white hover:bg-accent/80"
|
||||
onclick={addPage}
|
||||
>+ Seite</button>
|
||||
<button
|
||||
class="rounded bg-white/10 px-3 py-1.5 text-sm font-medium text-muted hover:bg-white/20 hover:text-white"
|
||||
onclick={() => creatingNotebook = true}
|
||||
>+ Notizbuch</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}`)}
|
||||
>
|
||||
<span class="flex-1">{nb.name}</span>
|
||||
</button>
|
||||
<button
|
||||
class="pr-3 text-base transition-opacity {nb.isFavorite ? 'text-warning' : 'text-muted hover:text-warning'}"
|
||||
onclick={() => toggleNotebookFavorite(nb.id)}
|
||||
title={nb.isFavorite ? 'Aus Sidebar entfernen' : 'In Sidebar anzeigen'}
|
||||
>★</button>
|
||||
</div>
|
||||
{:else}
|
||||
<p class="text-sm text-muted px-3">Keine {scope === 'private' ? 'privaten' : 'Firma'}-Notizbücher vorhanden.</p>
|
||||
{/each}
|
||||
{#if creatingNotebook}
|
||||
<input
|
||||
class="w-full rounded bg-white/10 px-3 py-2 text-sm text-white outline-none placeholder:text-muted"
|
||||
placeholder="Notizbuchname..."
|
||||
bind:value={newNotebookName}
|
||||
onkeydown={handleInputKeydown}
|
||||
onblur={() => setTimeout(() => { creatingNotebook = false; newNotebookName = ''; }, 150)}
|
||||
use:autofocus
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<!-- Unassigned pages -->
|
||||
{#if filteredUnassigned.length > 0}
|
||||
<section>
|
||||
<h2 class="mb-2 text-sm font-semibold uppercase text-muted">
|
||||
Nicht zugeordnet
|
||||
<span class="ml-1 rounded-full bg-white/10 px-1.5 py-0.5 text-xs">{filteredUnassigned.length}</span>
|
||||
</h2>
|
||||
<div class="space-y-1">
|
||||
{#each filteredUnassigned as page (page.id)}
|
||||
<button
|
||||
class="flex w-full items-center justify-between rounded px-3 py-2 text-left text-sm text-[#ccc] hover:bg-white/5 hover:text-white"
|
||||
onclick={() => goto(`/wiki/${page.id}`)}
|
||||
>
|
||||
<span>{page.title}</span>
|
||||
</button>
|
||||
{/each}
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<!-- Notebooks tab -->
|
||||
{#if activeTab === 'notebooks'}
|
||||
<div class="divide-y divide-[#2a2a2a]">
|
||||
{#each filteredNotebooks as nb, i (nb.id)}
|
||||
<div class="flex items-center gap-1 hover:bg-white/5 group">
|
||||
<div class="flex flex-col pl-2">
|
||||
<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.5 text-left text-sm text-[#ccc] hover:text-white"
|
||||
onclick={() => goto(`/wiki/notebook/${nb.id}`)}
|
||||
>{nb.name}</button>
|
||||
<button
|
||||
class="pr-3 text-base transition-opacity {nb.isFavorite ? 'text-warning' : 'text-muted hover:text-warning'}"
|
||||
onclick={() => toggleNotebookFavorite(nb.id)}
|
||||
title={nb.isFavorite ? 'Aus Sidebar entfernen' : 'In Sidebar anzeigen'}
|
||||
>★</button>
|
||||
</div>
|
||||
{:else}
|
||||
<p class="px-4 py-3 text-sm text-muted">Keine {scope === 'private' ? 'privaten' : 'Firma'}-Notizbücher vorhanden.</p>
|
||||
{/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"
|
||||
placeholder="Notizbuchname..."
|
||||
bind:value={newNotebookName}
|
||||
onkeydown={handleInputKeydown}
|
||||
onblur={() => setTimeout(() => { creatingNotebook = false; newNotebookName = ''; }, 150)}
|
||||
use:autofocus
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
<!-- Unassigned pages (shown below notebooks) -->
|
||||
{#if filteredUnassigned.length > 0}
|
||||
<div class="border-t border-[#333] px-4 py-2">
|
||||
<span class="text-xs font-semibold uppercase text-muted">Nicht zugeordnet</span>
|
||||
<span class="ml-1 rounded-full bg-white/10 px-1.5 py-0.5 text-xs text-muted">{filteredUnassigned.length}</span>
|
||||
</div>
|
||||
<div class="divide-y divide-[#2a2a2a]">
|
||||
{#each filteredUnassigned as page (page.id)}
|
||||
<button
|
||||
class="flex w-full items-center px-4 py-2 text-left text-sm text-[#ccc] hover:bg-white/5 hover:text-white"
|
||||
onclick={() => goto(`/wiki/${page.id}`)}
|
||||
>{page.title}</button>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- Favorites / Recent tab -->
|
||||
{:else}
|
||||
{#if quickTabPages.length > 0}
|
||||
<ul class="divide-y divide-[#2a2a2a]">
|
||||
{#each quickTabPages as page (page.id)}
|
||||
<li class="flex items-center gap-2 px-3 py-2 hover:bg-white/5">
|
||||
<button
|
||||
class="flex-1 text-left text-sm text-[#ddd] hover:text-white font-medium"
|
||||
onclick={() => goto(`/wiki/${page.id}`)}
|
||||
title={activeTab === 'recent' && page.updatedAt ? new Date(page.updatedAt).toLocaleString('de-DE') : undefined}
|
||||
>{page.title}</button>
|
||||
{#if page.notebooks.length > 0}
|
||||
<div class="flex items-center gap-1 flex-shrink-0">
|
||||
{#each page.notebooks as nb}
|
||||
<button
|
||||
class="rounded bg-white/10 px-2 py-0.5 text-xs text-muted hover:bg-white/20 hover:text-white transition-colors"
|
||||
onclick={(e) => { e.stopPropagation(); goto(`/wiki/notebook/${nb.id}`); }}
|
||||
title="Notizbuch: {nb.name}"
|
||||
>{nb.name}</button>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
{:else}
|
||||
<p class="px-4 py-3 text-sm text-muted">
|
||||
{activeTab === 'favorites' ? 'Keine Favoriten vorhanden.' : 'Noch keine bearbeiteten Seiten.'}
|
||||
</p>
|
||||
{/if}
|
||||
{/if}
|
||||
</section>
|
||||
{/if}
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in New Issue