mirror of
https://github.com/YuzuZensai/VRC-Circle.git
synced 2026-09-13 10:58:59 +00:00
✨ feat: persist favorite folder collapse state across navigation
This commit is contained in:
@@ -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={
|
||||
|
||||
@@ -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)];
|
||||
}
|
||||
Reference in New Issue
Block a user