feat: sidebar toggle (Ctrl+B, /sidebar command, toggle button)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
8bffebfd36
commit
22e14def5f
|
|
@ -1 +1 @@
|
||||||
1.1.71
|
1.1.73
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
import { allActiveContexts } from "$lib/stores/agenda";
|
import { allActiveContexts } from "$lib/stores/agenda";
|
||||||
import { allPages } from "$lib/stores/wiki";
|
import { allPages } from "$lib/stores/wiki";
|
||||||
import { currentScope, scopeSettings } from "$lib/stores/scopeContext";
|
import { currentScope, scopeSettings } from "$lib/stores/scopeContext";
|
||||||
|
import { sidebarCollapsed } from "$lib/stores/sidebarCollapsed";
|
||||||
import {
|
import {
|
||||||
getOrCreateJournalTopic,
|
getOrCreateJournalTopic,
|
||||||
createHistoryEntry,
|
createHistoryEntry,
|
||||||
|
|
@ -373,6 +374,20 @@
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ("/sidebar".startsWith(cmd)) {
|
||||||
|
actions.push({
|
||||||
|
id: "cmd-sidebar",
|
||||||
|
type: "action",
|
||||||
|
icon: $sidebarCollapsed ? "▶" : "◀",
|
||||||
|
label: $sidebarCollapsed ? "Sidebar einblenden" : "Sidebar ausblenden",
|
||||||
|
badge: "BEFEHL",
|
||||||
|
action: () => {
|
||||||
|
sidebarCollapsed.toggle();
|
||||||
|
closeBar();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if ("/jf".startsWith(cmd)) {
|
if ("/jf".startsWith(cmd)) {
|
||||||
actions.push({
|
actions.push({
|
||||||
id: "cmd-jf",
|
id: "cmd-jf",
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
import { writable } from 'svelte/store';
|
||||||
|
|
||||||
|
const KEY = 'sidebarCollapsed';
|
||||||
|
|
||||||
|
function createSidebarCollapsed() {
|
||||||
|
const initial = typeof localStorage !== 'undefined'
|
||||||
|
? localStorage.getItem(KEY) === 'true'
|
||||||
|
: false;
|
||||||
|
const { subscribe, set, update } = writable(initial);
|
||||||
|
|
||||||
|
return {
|
||||||
|
subscribe,
|
||||||
|
toggle() {
|
||||||
|
update(v => {
|
||||||
|
const next = !v;
|
||||||
|
localStorage.setItem(KEY, String(next));
|
||||||
|
return next;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
set(value: boolean) {
|
||||||
|
localStorage.setItem(KEY, String(value));
|
||||||
|
set(value);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const sidebarCollapsed = createSidebarCollapsed();
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
import AiLockBanner from "$lib/components/AiLockBanner.svelte";
|
import AiLockBanner from "$lib/components/AiLockBanner.svelte";
|
||||||
import CommandBar from "$lib/components/CommandBar.svelte";
|
import CommandBar from "$lib/components/CommandBar.svelte";
|
||||||
import { commandBarOpen } from "$lib/stores/commandBar";
|
import { commandBarOpen } from "$lib/stores/commandBar";
|
||||||
|
import { sidebarCollapsed } from "$lib/stores/sidebarCollapsed";
|
||||||
import { seedIfEmpty } from "$lib/db/seed";
|
import { seedIfEmpty } from "$lib/db/seed";
|
||||||
import { sync } from "$lib/sync/syncService";
|
import { sync } from "$lib/sync/syncService";
|
||||||
import { refreshLockStatus } from "$lib/stores/aiLock";
|
import { refreshLockStatus } from "$lib/stores/aiLock";
|
||||||
|
|
@ -81,6 +82,10 @@
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
$commandBarOpen = !$commandBarOpen;
|
$commandBarOpen = !$commandBarOpen;
|
||||||
}
|
}
|
||||||
|
if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "b") {
|
||||||
|
e.preventDefault();
|
||||||
|
sidebarCollapsed.toggle();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
afterNavigate(({ to }) => {
|
afterNavigate(({ to }) => {
|
||||||
|
|
@ -174,14 +179,28 @@
|
||||||
|
|
||||||
<!-- Desktop sidebar -->
|
<!-- Desktop sidebar -->
|
||||||
<aside
|
<aside
|
||||||
class="hidden md:flex md:w-[250px] md:flex-col md:border-r md:border-border md:bg-sidebar md:p-5 md:overflow-y-auto"
|
class="hidden md:flex md:flex-col md:border-r md:border-border md:bg-sidebar md:overflow-y-auto transition-all duration-200
|
||||||
|
{$sidebarCollapsed ? 'md:w-0 md:p-0 md:overflow-hidden md:border-r-0' : 'md:w-[250px] md:p-5'}"
|
||||||
>
|
>
|
||||||
<Sidebar onnavigate={closeSidebar} />
|
{#if !$sidebarCollapsed}
|
||||||
|
<Sidebar onnavigate={closeSidebar} />
|
||||||
|
{/if}
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
<!-- Main content -->
|
<!-- Main content -->
|
||||||
<main class="flex-1 overflow-y-auto p-5 pt-safe md:pt-5 pb-20 md:pb-5">
|
<main class="flex-1 overflow-y-auto p-5 pt-safe md:pt-5 pb-20 md:pb-5">
|
||||||
<div class="mx-auto max-w-[900px]">
|
<div class="mx-auto max-w-[900px]">
|
||||||
|
<!-- Desktop sidebar toggle button -->
|
||||||
|
<div class="hidden md:flex mb-3 -mt-1">
|
||||||
|
<button
|
||||||
|
onclick={() => sidebarCollapsed.toggle()}
|
||||||
|
class="text-muted hover:text-white transition-colors text-xs flex items-center gap-1 opacity-40 hover:opacity-100"
|
||||||
|
aria-label="Sidebar ein-/ausblenden"
|
||||||
|
title="Sidebar ein-/ausblenden (Ctrl+B)"
|
||||||
|
>
|
||||||
|
{$sidebarCollapsed ? '›' : '‹'}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
<AiLockBanner />
|
<AiLockBanner />
|
||||||
{@render children()}
|
{@render children()}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
-- no-op: is_favorite column added in 0012_chunky_stature.sql
|
SELECT 1; -- no-op: is_favorite column added in 0012_chunky_stature.sql
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue