feat: remember sidebar state

This commit is contained in:
Henry Li
2026-01-16 23:03:39 +08:00
parent f9853f037c
commit 6464a67230
4 changed files with 59 additions and 34 deletions

View File

@@ -26,7 +26,7 @@ export default function ChatPage() {
[threadIdFromPath],
);
const [threadId, setThreadId] = useState<string | null>(null);
const { threadContext, setThreadContext } = useLocalSettings();
const [settings, setSettings] = useLocalSettings();
useEffect(() => {
if (threadIdFromPath !== "new") {
@@ -43,7 +43,7 @@ export default function ChatPage() {
isNewThread,
threadId,
thread,
threadContext,
threadContext: settings.context,
afterSubmit() {
router.push(pathOfThread(threadId!));
},
@@ -71,8 +71,8 @@ export default function ChatPage() {
className="w-full max-w-(--container-width-md)"
autoFocus={isNewThread}
status={thread.isLoading ? "streaming" : "ready"}
context={threadContext}
onContextChange={setThreadContext}
context={settings.context}
onContextChange={(context) => setSettings("context", context)}
onSubmit={handleSubmit}
onStop={handleStop}
/>

View File

@@ -1,16 +1,30 @@
"use client";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { useCallback, useEffect, useState } from "react";
import { SidebarInset, SidebarProvider } from "@/components/ui/sidebar";
import { Overscroll } from "@/components/workspace/overscroll";
import { WorkspaceSidebar } from "@/components/workspace/workspace-sidebar";
import { useLocalSettings } from "@/core/settings";
const queryClient = new QueryClient();
export default function WorkspaceLayout({
children,
}: Readonly<{ children: React.ReactNode }>) {
const [settings, setSettings] = useLocalSettings();
const [open, setOpen] = useState(false);
useEffect(() => {
setOpen(!settings.layout.sidebar_collapsed);
}, [settings.layout.sidebar_collapsed]);
const handleOpenChange = useCallback(
(open: boolean) => {
setOpen(open);
setSettings("layout", { sidebar_collapsed: !open });
},
[setSettings],
);
return (
<QueryClientProvider client={queryClient}>
<SidebarProvider
@@ -19,6 +33,8 @@ export default function WorkspaceLayout({
"--sidebar-width": "calc(var(--spacing) * 72)",
} as React.CSSProperties
}
open={open}
onOpenChange={handleOpenChange}
>
<Overscroll behavior="none" overflow="hidden" />
<WorkspaceSidebar />

View File

@@ -1,34 +1,46 @@
import { useCallback, useState } from "react";
import { useEffect } from "react";
import type { AgentThreadContext } from "../threads";
import {
DEFAULT_LOCAL_SETTINGS,
getLocalSettings,
updateContextOfLocalSettings,
saveLocalSettings,
type LocalSettings,
} from "./local";
export function useLocalSettings() {
export function useLocalSettings(): [
LocalSettings,
(
key: keyof LocalSettings,
value: Partial<LocalSettings[keyof LocalSettings]>,
) => void,
] {
const [mounted, setMounted] = useState(false);
const [threadContextState, setThreadContextState] = useState<
Omit<AgentThreadContext, "thread_id">
>(DEFAULT_LOCAL_SETTINGS.context);
const [state, setState] = useState<LocalSettings>(DEFAULT_LOCAL_SETTINGS);
useEffect(() => {
if (!mounted) {
setThreadContextState(getLocalSettings().context);
setState(getLocalSettings());
}
setMounted(true);
}, [mounted]);
const setThreadContext = useCallback(
(context: Omit<AgentThreadContext, "thread_id">) => {
setThreadContextState(context);
updateContextOfLocalSettings(context);
const setter = useCallback(
(
key: keyof LocalSettings,
value: Partial<LocalSettings[keyof LocalSettings]>,
) => {
setState((prev) => {
const newState = {
...prev,
[key]: {
...prev[key],
...value,
},
};
saveLocalSettings(newState);
return newState;
});
},
[],
);
return {
threadContext: threadContextState,
setThreadContext,
};
return [state, setter];
}

View File

@@ -5,12 +5,18 @@ export const DEFAULT_LOCAL_SETTINGS: LocalSettings = {
model_name: "deepseek-v3.2",
thinking_enabled: true,
},
layout: {
sidebar_collapsed: false,
},
};
const LOCAL_SETTINGS_KEY = "deerflow.local-settings";
export interface LocalSettings {
context: Omit<AgentThreadContext, "thread_id">;
layout: {
sidebar_collapsed: boolean;
};
}
export function getLocalSettings(): LocalSettings {
@@ -20,7 +26,11 @@ export function getLocalSettings(): LocalSettings {
const json = localStorage.getItem(LOCAL_SETTINGS_KEY);
try {
if (json) {
return JSON.parse(json);
const settings = JSON.parse(json);
return {
...DEFAULT_LOCAL_SETTINGS,
...settings,
};
}
} catch {}
return DEFAULT_LOCAL_SETTINGS;
@@ -29,16 +39,3 @@ export function getLocalSettings(): LocalSettings {
export function saveLocalSettings(settings: LocalSettings) {
localStorage.setItem(LOCAL_SETTINGS_KEY, JSON.stringify(settings));
}
export function updateContextOfLocalSettings(
context: LocalSettings["context"],
) {
const settings = getLocalSettings();
saveLocalSettings({
...settings,
context: {
...settings.context,
...context,
},
});
}