89 lines
2.5 KiB
TypeScript
89 lines
2.5 KiB
TypeScript
import { ScrollArea } from "@/components/ui/scroll-area";
|
|
import { cn } from "@/lib/utils";
|
|
import { useNavigate } from "@tanstack/react-router";
|
|
import { useEffect, useState } from "react";
|
|
|
|
const SETTINGS_SECTIONS = [
|
|
{ id: "general-settings", label: "General" },
|
|
{ id: "workflow-settings", label: "Workflow" },
|
|
{ id: "ai-settings", label: "AI" },
|
|
{ id: "provider-settings", label: "Model Providers" },
|
|
{ id: "telemetry", label: "Telemetry" },
|
|
{ id: "integrations", label: "Integrations" },
|
|
{ id: "experiments", label: "Experiments" },
|
|
{ id: "danger-zone", label: "Danger Zone" },
|
|
];
|
|
|
|
export function SettingsList({ show }: { show: boolean }) {
|
|
const navigate = useNavigate();
|
|
const [activeSection, setActiveSection] = useState<string | null>(
|
|
"general-settings",
|
|
);
|
|
|
|
useEffect(() => {
|
|
const observer = new IntersectionObserver(
|
|
(entries) => {
|
|
for (const entry of entries) {
|
|
if (entry.isIntersecting) {
|
|
setActiveSection(entry.target.id);
|
|
return;
|
|
}
|
|
}
|
|
},
|
|
{ rootMargin: "-20% 0px -80% 0px", threshold: 0 },
|
|
);
|
|
|
|
for (const section of SETTINGS_SECTIONS) {
|
|
const el = document.getElementById(section.id);
|
|
if (el) {
|
|
observer.observe(el);
|
|
}
|
|
}
|
|
|
|
return () => {
|
|
observer.disconnect();
|
|
};
|
|
}, []);
|
|
|
|
if (!show) {
|
|
return null;
|
|
}
|
|
|
|
const handleScrollAndNavigateTo = async (id: string) => {
|
|
await navigate({
|
|
to: "/settings",
|
|
});
|
|
const element = document.getElementById(id);
|
|
if (element) {
|
|
element.scrollIntoView({ behavior: "smooth", block: "start" });
|
|
setActiveSection(id);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="flex flex-col h-full">
|
|
<div className="flex-shrink-0 p-4">
|
|
<h2 className="text-lg font-semibold tracking-tight">Settings</h2>
|
|
</div>
|
|
<ScrollArea className="flex-grow">
|
|
<div className="space-y-1 p-4 pt-0">
|
|
{SETTINGS_SECTIONS.map((section) => (
|
|
<button
|
|
key={section.id}
|
|
onClick={() => handleScrollAndNavigateTo(section.id)}
|
|
className={cn(
|
|
"w-full text-left px-3 py-2 rounded-md text-sm transition-colors",
|
|
activeSection === section.id
|
|
? "bg-sidebar-accent text-sidebar-accent-foreground font-semibold"
|
|
: "hover:bg-sidebar-accent",
|
|
)}
|
|
>
|
|
{section.label}
|
|
</button>
|
|
))}
|
|
</div>
|
|
</ScrollArea>
|
|
</div>
|
|
);
|
|
}
|