feat(kon): collapsible sidebar — toggle with [ key, auto-collapse below 900px, icons-only mode

- Add sidebarCollapsed to settings defaults (persists via localStorage on saveSettings)
- Sidebar collapses to 48px icons-only view with smooth 200ms transition
- Toggle button (chevron) at top of nav; [ keyboard shortcut in layout (input-safe)
- Auto-collapse on window resize below 900px (checked on mount and on resize event)
- Titlebar left spacer tracks sidebar width reactively (48px / 210px)
- All labels, profile selector, status text hidden in collapsed mode; nav items show tooltips via title attribute

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
jake
2026-03-17 02:26:08 +00:00
parent 4bfc4c1374
commit 3f6d718bb2
4 changed files with 141 additions and 42 deletions

View File

@@ -5,7 +5,7 @@
import Sidebar from "$lib/Sidebar.svelte";
import TaskSidebar from "$lib/components/TaskSidebar.svelte";
import Titlebar from "$lib/components/Titlebar.svelte";
import { page, settings } from "$lib/stores/page.svelte.js";
import { page, settings, saveSettings } from "$lib/stores/page.svelte.js";
import { page as sveltePage } from "$app/stores";
@@ -76,8 +76,35 @@
document.documentElement.style.setProperty("--font-size-transcript", `${settings.fontSize}px`);
});
// First-run detection: check if any models are downloaded
// Check whether the keydown originates from a text input (avoid triggering while typing)
function isInputFocused(e) {
const tag = e.target?.tagName;
return tag === "INPUT" || tag === "TEXTAREA" || e.target?.isContentEditable;
}
function handleKeydown(e) {
if (e.key === "Escape" && page.taskSidebarOpen) {
page.taskSidebarOpen = false;
return;
}
if (e.key === "[" && !isInputFocused(e)) {
settings.sidebarCollapsed = !settings.sidebarCollapsed;
saveSettings();
}
}
function handleResize() {
if (window.innerWidth < 900 && !settings.sidebarCollapsed) {
settings.sidebarCollapsed = true;
saveSettings();
}
}
onMount(async () => {
// Auto-collapse if window is already narrow on first load
handleResize();
window.addEventListener("resize", handleResize);
try {
const whisper = await invoke("list_models");
const parakeet = await invoke("list_parakeet_models");
@@ -90,6 +117,7 @@
});
onDestroy(() => {
window.removeEventListener("resize", handleResize);
if (registeredHotkey) {
import("@tauri-apps/plugin-global-shortcut")
.then((mod) => mod.unregister(registeredHotkey))
@@ -98,7 +126,7 @@
});
</script>
<svelte:window onmousemove={handleMouseMove} onkeydown={(e) => { if (e.key === "Escape" && page.taskSidebarOpen) page.taskSidebarOpen = false; }} />
<svelte:window onmousemove={handleMouseMove} onkeydown={handleKeydown} />
{#if page.recording}
<div