Files
OpenCut/apps/web/src/components/editor/assets-panel/tabbar.tsx
T
2026-01-21 12:52:34 +01:00

110 lines
3.0 KiB
TypeScript

"use client";
import { cn } from "@/utils/ui";
import {
TAB_KEYS,
tabs,
useAssetsPanelStore,
} from "../../../stores/assets-panel-store";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { useEffect, useRef, useState } from "react";
export function TabBar() {
const { activeTab, setActiveTab } = useAssetsPanelStore();
const scrollRef = useRef<HTMLDivElement>(null);
const [showTopFade, setShowTopFade] = useState(false);
const [showBottomFade, setShowBottomFade] = useState(false);
const checkScrollPosition = () => {
const element = scrollRef.current;
if (!element) return;
const { scrollTop, scrollHeight, clientHeight } = element;
setShowTopFade(scrollTop > 0);
setShowBottomFade(scrollTop < scrollHeight - clientHeight - 1);
};
useEffect(() => {
const element = scrollRef.current;
if (!element) return;
checkScrollPosition();
element.addEventListener("scroll", checkScrollPosition);
const resizeObserver = new ResizeObserver(checkScrollPosition);
resizeObserver.observe(element);
return () => {
element.removeEventListener("scroll", checkScrollPosition);
resizeObserver.disconnect();
};
}, []);
return (
<div className="relative flex">
<div
ref={scrollRef}
className="scrollbar-hidden relative flex h-full w-full flex-col items-center justify-start gap-5 overflow-y-auto px-4 py-4"
>
{TAB_KEYS.map((tabKey) => {
const tab = tabs[tabKey];
return (
<div
className={cn(
"flex cursor-pointer flex-col items-center gap-0.5",
activeTab === tabKey
? "text-primary !opacity-100"
: "text-muted-foreground",
)}
onClick={() => setActiveTab(tabKey)}
key={tabKey}
>
<Tooltip delayDuration={10}>
<TooltipTrigger asChild>
<tab.icon className="size-[1.1rem]! opacity-100 hover:opacity-75" />
</TooltipTrigger>
<TooltipContent
side="right"
align="center"
variant="sidebar"
sideOffset={8}
>
<div className="text-foreground text-sm leading-none font-medium">
{tab.label}
</div>
</TooltipContent>
</Tooltip>
</div>
);
})}
</div>
<FadeOverlay direction="top" show={showTopFade} />
<FadeOverlay direction="bottom" show={showBottomFade} />
</div>
);
}
function FadeOverlay({
direction,
show,
}: {
direction: "top" | "bottom";
show: boolean;
}) {
return (
<div
className={cn(
"pointer-events-none absolute right-0 left-0 h-6 transition-opacity duration-200",
direction === "top" && show
? "from-panel top-0 bg-gradient-to-b to-transparent"
: "from-panel bottom-0 bg-gradient-to-t to-transparent",
)}
/>
);
}