feat: persist favorite folder collapse state across navigation

This commit is contained in:
2026-07-01 03:44:11 +07:00
parent d6d9c54ed6
commit 2fda2a2732
3 changed files with 28 additions and 2 deletions
@@ -1,26 +1,33 @@
import { useState, type ReactNode } from "react";
import { ChevronDown, ChevronRight } from "lucide-react";
import { LABEL_HEADING } from "./styles";
import { useCollapsed } from "../../store/ui";
export function CollapsibleCard({
title,
count,
action,
defaultOpen = true,
persistKey,
children,
}: {
title: string;
count?: number | string;
action?: ReactNode;
defaultOpen?: boolean;
persistKey?: string;
children: ReactNode;
}) {
const [open, setOpen] = useState(defaultOpen);
const local = useState(defaultOpen);
const persisted = useCollapsed(persistKey ?? "", defaultOpen);
const [open, toggle] = persistKey
? persisted
: [local[0], () => local[1]((v) => !v)];
return (
<section className="rounded-xl border border-border bg-surface-2 p-5 shadow-sm">
<div className={`flex items-center gap-1.5 ${open ? "mb-3" : ""}`}>
<button
onClick={() => setOpen((v) => !v)}
onClick={toggle}
className={`flex flex-1 items-center gap-1.5 ${LABEL_HEADING}`}
>
<span className="text-faint">
@@ -174,6 +174,7 @@ export function MyFavoriteWorldsSection({ filter }: { filter?: WorldFilter }) {
{shown.map((folder) => (
<CollapsibleCard
key={folder.name}
persistKey={`fav-worlds:${folder.name}`}
title={folder.displayName}
count={`${folder.count} / ${maxPerGroup}`}
action={
+18
View File
@@ -0,0 +1,18 @@
import { create } from "zustand";
interface UiState {
collapsed: Record<string, boolean>;
toggleCollapsed: (key: string) => void;
}
export const useUi = create<UiState>((set) => ({
collapsed: {},
toggleCollapsed: (key) =>
set((st) => ({ collapsed: { ...st.collapsed, [key]: !st.collapsed[key] } })),
}));
export function useCollapsed(key: string, defaultOpen: boolean): [boolean, () => void] {
const open = useUi((s) => (key in s.collapsed ? !s.collapsed[key] : defaultOpen));
const toggle = useUi((s) => s.toggleCollapsed);
return [open, () => toggle(key)];
}