Skip to content

Commit 0d496f9

Browse files
committed
remember side bar status
1 parent 4ae9ea0 commit 0d496f9

File tree

7 files changed

+165
-121
lines changed

7 files changed

+165
-121
lines changed

src/chatgpt.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,8 @@ class Chat {
338338
console.log("line", line);
339339
try {
340340
const jsonStr = line.slice("data:".length).trim();
341-
if (jsonStr === "keep-alive") { // for deepseek https://api-docs.deepseek.com/quick_start/rate_limit
341+
if (jsonStr === "keep-alive") {
342+
// for deepseek https://api-docs.deepseek.com/quick_start/rate_limit
342343
continue;
343344
}
344345
const json = JSON.parse(jsonStr) as StreamingResponseChunk;

src/components/ListAPI.tsx

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ import { Label } from "./ui/label";
4545
import { Input } from "./ui/input";
4646
import { SetAPIsTemplate } from "./setAPIsTemplate";
4747
import { isVailedJSON } from "@/utils/isVailedJSON";
48-
import { toast } from 'sonner';
48+
import { toast } from "sonner";
4949
import { ConfirmationDialog } from "./ui/confirmation-dialog";
5050

5151
interface APITemplateDropdownProps {
@@ -61,7 +61,11 @@ interface EditTemplateDialogProps {
6161
onClose: () => void;
6262
}
6363

64-
function EditTemplateDialog({ template, onSave, onClose }: EditTemplateDialogProps) {
64+
function EditTemplateDialog({
65+
template,
66+
onSave,
67+
onClose,
68+
}: EditTemplateDialogProps) {
6569
const [name, setName] = useState(template.name);
6670
const [endpoint, setEndpoint] = useState(template.endpoint);
6771
const [key, setKey] = useState(template.key);
@@ -151,9 +155,13 @@ function APIsDropdownList({
151155
} = useContext(AppContext);
152156
const { toast } = useToast();
153157
const [open, setOpen] = React.useState(false);
154-
const [editingTemplate, setEditingTemplate] = useState<TemplateAPI | null>(null);
158+
const [editingTemplate, setEditingTemplate] = useState<TemplateAPI | null>(
159+
null
160+
);
155161
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
156-
const [templateToDelete, setTemplateToDelete] = useState<TemplateAPI | null>(null);
162+
const [templateToDelete, setTemplateToDelete] = useState<TemplateAPI | null>(
163+
null
164+
);
157165

158166
let API = templateAPIs;
159167
let setAPI = setTemplateAPIs;
@@ -176,7 +184,7 @@ function APIsDropdownList({
176184
};
177185

178186
const handleSave = (updatedTemplate: TemplateAPI) => {
179-
const index = API.findIndex(t => t.name === updatedTemplate.name);
187+
const index = API.findIndex((t) => t.name === updatedTemplate.name);
180188
if (index !== -1) {
181189
const newAPI = [...API];
182190
newAPI[index] = updatedTemplate;
@@ -195,7 +203,7 @@ function APIsDropdownList({
195203

196204
const confirmDelete = () => {
197205
if (templateToDelete) {
198-
const newAPI = API.filter(t => t.name !== templateToDelete.name);
206+
const newAPI = API.filter((t) => t.name !== templateToDelete.name);
199207
setAPI(newAPI);
200208
toast({
201209
title: "Success",
@@ -375,7 +383,11 @@ interface EditChatTemplateDialogProps {
375383
onClose: () => void;
376384
}
377385

378-
function EditChatTemplateDialog({ template, onSave, onClose }: EditChatTemplateDialogProps) {
386+
function EditChatTemplateDialog({
387+
template,
388+
onSave,
389+
onClose,
390+
}: EditChatTemplateDialogProps) {
379391
const [name, setName] = useState(template.name);
380392
const [jsonContent, setJsonContent] = useState(() => {
381393
const { name: _, ...rest } = template;
@@ -389,26 +401,26 @@ function EditChatTemplateDialog({ template, onSave, onClose }: EditChatTemplateD
389401

390402
const handleFormat = () => {
391403
if (editor) {
392-
editor.getAction('editor.action.formatDocument').run();
404+
editor.getAction("editor.action.formatDocument").run();
393405
}
394406
};
395407

396408
const handleSave = () => {
397409
if (!name.trim()) {
398-
toast.error('Template name cannot be empty');
410+
toast.error("Template name cannot be empty");
399411
return;
400412
}
401413

402414
try {
403415
const parsedJson = JSON.parse(jsonContent);
404416
const updatedTemplate: TemplateChatStore = {
405417
name: name.trim(),
406-
...parsedJson
418+
...parsedJson,
407419
};
408420
onSave(updatedTemplate);
409-
toast.success('Template updated successfully');
421+
toast.success("Template updated successfully");
410422
} catch (error) {
411-
toast.error('Invalid JSON format');
423+
toast.error("Invalid JSON format");
412424
}
413425
};
414426

@@ -444,16 +456,16 @@ function EditChatTemplateDialog({ template, onSave, onClose }: EditChatTemplateD
444456
height="400px"
445457
defaultLanguage="json"
446458
value={jsonContent}
447-
onChange={(value) => setJsonContent(value || '')}
459+
onChange={(value) => setJsonContent(value || "")}
448460
onMount={handleEditorDidMount}
449461
options={{
450462
minimap: { enabled: false },
451463
fontSize: 14,
452-
lineNumbers: 'on',
464+
lineNumbers: "on",
453465
scrollBeyondLastLine: false,
454466
automaticLayout: true,
455467
tabSize: 2,
456-
wordWrap: 'on'
468+
wordWrap: "on",
457469
}}
458470
/>
459471
</div>
@@ -476,19 +488,22 @@ function ChatTemplateDropdownList() {
476488
const { chatStore, setChatStore } = useContext(AppChatStoreContext);
477489
const { templates, setTemplates } = useContext(AppContext);
478490
const [open, setOpen] = React.useState(false);
479-
const [editingTemplate, setEditingTemplate] = useState<TemplateChatStore | null>(null);
491+
const [editingTemplate, setEditingTemplate] =
492+
useState<TemplateChatStore | null>(null);
480493
const { toast } = useToast();
481494
const [confirmDialogOpen, setConfirmDialogOpen] = useState(false);
482-
const [templateToApply, setTemplateToApply] = useState<TemplateChatStore | null>(null);
495+
const [templateToApply, setTemplateToApply] =
496+
useState<TemplateChatStore | null>(null);
483497
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
484-
const [templateToDelete, setTemplateToDelete] = useState<TemplateChatStore | null>(null);
498+
const [templateToDelete, setTemplateToDelete] =
499+
useState<TemplateChatStore | null>(null);
485500

486501
const handleEdit = (template: TemplateChatStore) => {
487502
setEditingTemplate(template);
488503
};
489504

490505
const handleSave = (updatedTemplate: TemplateChatStore) => {
491-
const index = templates.findIndex(t => t.name === updatedTemplate.name);
506+
const index = templates.findIndex((t) => t.name === updatedTemplate.name);
492507
if (index !== -1) {
493508
const newTemplates = [...templates];
494509
newTemplates[index] = updatedTemplate;
@@ -507,7 +522,9 @@ function ChatTemplateDropdownList() {
507522

508523
const confirmDelete = () => {
509524
if (templateToDelete) {
510-
const newTemplates = templates.filter(t => t.name !== templateToDelete.name);
525+
const newTemplates = templates.filter(
526+
(t) => t.name !== templateToDelete.name
527+
);
511528
setTemplates(newTemplates);
512529
toast({
513530
title: "Success",

src/components/ui/confirmation-dialog.tsx

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@ interface ConfirmationDialogProps {
1717
description: string;
1818
}
1919

20-
export function ConfirmationDialog({
21-
isOpen,
22-
onClose,
23-
onConfirm,
24-
title,
25-
description
20+
export function ConfirmationDialog({
21+
isOpen,
22+
onClose,
23+
onConfirm,
24+
title,
25+
description,
2626
}: ConfirmationDialogProps) {
2727
return (
2828
<Dialog open={isOpen} onOpenChange={onClose}>
@@ -35,14 +35,17 @@ export function ConfirmationDialog({
3535
<Button variant="outline" onClick={onClose}>
3636
Cancel
3737
</Button>
38-
<Button variant="destructive" onClick={() => {
39-
onConfirm();
40-
onClose();
41-
}}>
38+
<Button
39+
variant="destructive"
40+
onClick={() => {
41+
onConfirm();
42+
onClose();
43+
}}
44+
>
4245
Confirm
4346
</Button>
4447
</DialogFooter>
4548
</DialogContent>
4649
</Dialog>
4750
);
48-
}
51+
}

src/components/ui/controlled-input.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,4 @@ const ControlledInput = forwardRef<HTMLInputElement, ComponentProps<"input">>(
1818
);
1919
ControlledInput.displayName = "ControlledInput";
2020

21-
export { ControlledInput };
21+
export { ControlledInput };

src/components/ui/sidebar.tsx

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@ import {
1717
TooltipTrigger,
1818
} from "@/components/ui/tooltip";
1919

20-
const SIDEBAR_COOKIE_NAME = "sidebar:state";
21-
const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;
20+
const SIDEBAR_LOCALSTORAGE_KEY = "sidebar:state";
2221
const SIDEBAR_WIDTH = "16rem";
2322
const SIDEBAR_WIDTH_MOBILE = "18rem";
2423
const SIDEBAR_WIDTH_ICON = "3rem";
@@ -68,9 +67,25 @@ const SidebarProvider = React.forwardRef<
6867
const isMobile = useIsMobile();
6968
const [openMobile, setOpenMobile] = React.useState(false);
7069

70+
// 从localStorage读取初始状态
71+
const getInitialState = React.useCallback(() => {
72+
if (typeof window === "undefined") return defaultOpen;
73+
74+
try {
75+
const saved = localStorage.getItem(SIDEBAR_LOCALSTORAGE_KEY);
76+
if (saved !== null) {
77+
return saved === "true";
78+
}
79+
} catch (error) {
80+
console.warn("Failed to read sidebar state from localStorage:", error);
81+
}
82+
83+
return defaultOpen;
84+
}, [defaultOpen]);
85+
7186
// This is the internal state of the sidebar.
7287
// We use openProp and setOpenProp for control from outside the component.
73-
const [_open, _setOpen] = React.useState(defaultOpen);
88+
const [_open, _setOpen] = React.useState(getInitialState);
7489
const open = openProp ?? _open;
7590
const setOpen = React.useCallback(
7691
(value: boolean | ((value: boolean) => boolean)) => {
@@ -81,8 +96,12 @@ const SidebarProvider = React.forwardRef<
8196
_setOpen(openState);
8297
}
8398

84-
// This sets the cookie to keep the sidebar state.
85-
document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`;
99+
// 使用localStorage保存状态
100+
try {
101+
localStorage.setItem(SIDEBAR_LOCALSTORAGE_KEY, String(openState));
102+
} catch (error) {
103+
console.warn("Failed to save sidebar state to localStorage:", error);
104+
}
86105
},
87106
[setOpenProp, open]
88107
);

0 commit comments

Comments
 (0)