mirror of
https://github.com/OpenCut-app/OpenCut.git
synced 2026-07-13 21:52:53 +02:00
110 lines
3.0 KiB
TypeScript
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",
|
|
)}
|
|
/>
|
|
);
|
|
}
|