mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-05-06 06:12:40 +02:00
feat: implement smooth scrolling for provider sidebar in ModelSelector
This commit is contained in:
parent
5e756c8dfa
commit
e95e417cc8
1 changed files with 80 additions and 12 deletions
|
|
@ -320,6 +320,30 @@ export function ModelSelector({
|
||||||
[isMobile]
|
[isMobile]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const scrollProviderSidebar = useCallback(
|
||||||
|
(direction: "backward" | "forward") => {
|
||||||
|
const el = providerSidebarRef.current;
|
||||||
|
if (!el) return;
|
||||||
|
const delta = isMobile
|
||||||
|
? Math.max(56, Math.floor(el.clientWidth * 0.5))
|
||||||
|
: Math.max(44, Math.floor(el.clientHeight * 0.4));
|
||||||
|
|
||||||
|
if (isMobile) {
|
||||||
|
el.scrollBy({
|
||||||
|
left: direction === "backward" ? -delta : delta,
|
||||||
|
behavior: "smooth",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
el.scrollBy({
|
||||||
|
top: direction === "backward" ? -delta : delta,
|
||||||
|
behavior: "smooth",
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[isMobile]
|
||||||
|
);
|
||||||
|
|
||||||
// Cmd/Ctrl+M shortcut (desktop only)
|
// Cmd/Ctrl+M shortcut (desktop only)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isMobile) return;
|
if (isMobile) return;
|
||||||
|
|
@ -716,17 +740,40 @@ export function ModelSelector({
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
"shrink-0 border-border/50 flex",
|
"shrink-0 border-border/50 flex relative",
|
||||||
isMobile ? "flex-row items-center border-b border-border/40" : "flex-col w-10 border-r"
|
isMobile
|
||||||
|
? "flex-row items-center border-b border-border/40"
|
||||||
|
: "flex-col w-10 border-r"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{!isMobile && sidebarScrollPos !== "top" && (
|
{!isMobile && (
|
||||||
<div className="flex items-center justify-center py-0.5 pointer-events-none">
|
<div
|
||||||
<ChevronUp className="size-3 text-muted-foreground" />
|
className={cn(
|
||||||
|
"absolute top-0 left-0 right-0 z-10 h-5 flex items-center justify-center transition-all duration-200 ease-out",
|
||||||
|
sidebarScrollPos === "top"
|
||||||
|
? "opacity-0 -translate-y-1 pointer-events-none"
|
||||||
|
: "opacity-100 translate-y-0 pointer-events-auto"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
aria-label="Scroll providers up"
|
||||||
|
onClick={() => scrollProviderSidebar("backward")}
|
||||||
|
className="flex h-4 w-4 items-center justify-center rounded-sm text-muted-foreground/90 hover:text-foreground hover:bg-accent/60 transition-colors"
|
||||||
|
>
|
||||||
|
<ChevronUp className="size-3" />
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{isMobile && sidebarScrollPos !== "top" && (
|
{isMobile && (
|
||||||
<div className="flex items-center justify-center px-0.5 shrink-0 pointer-events-none">
|
<div
|
||||||
|
className={cn(
|
||||||
|
"absolute left-0 top-0 bottom-0 z-10 w-5 flex items-center justify-center transition-all duration-200 ease-out pointer-events-none",
|
||||||
|
sidebarScrollPos === "top"
|
||||||
|
? "opacity-0 -translate-x-1"
|
||||||
|
: "opacity-100 translate-x-0"
|
||||||
|
)}
|
||||||
|
>
|
||||||
<ChevronLeft className="size-3 text-muted-foreground" />
|
<ChevronLeft className="size-3 text-muted-foreground" />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
@ -802,13 +849,34 @@ export function ModelSelector({
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
{!isMobile && sidebarScrollPos !== "bottom" && (
|
{!isMobile && (
|
||||||
<div className="flex items-center justify-center py-0.5 pointer-events-none">
|
<div
|
||||||
<ChevronDown className="size-3 text-muted-foreground" />
|
className={cn(
|
||||||
|
"absolute bottom-0 left-0 right-0 z-10 h-5 flex items-center justify-center transition-all duration-200 ease-out",
|
||||||
|
sidebarScrollPos === "bottom"
|
||||||
|
? "opacity-0 translate-y-1 pointer-events-none"
|
||||||
|
: "opacity-100 translate-y-0 pointer-events-auto"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
aria-label="Scroll providers down"
|
||||||
|
onClick={() => scrollProviderSidebar("forward")}
|
||||||
|
className="flex h-4 w-4 items-center justify-center rounded-sm text-muted-foreground/90 hover:text-foreground hover:bg-accent/60 transition-colors"
|
||||||
|
>
|
||||||
|
<ChevronDown className="size-3" />
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{isMobile && sidebarScrollPos !== "bottom" && (
|
{isMobile && (
|
||||||
<div className="flex items-center justify-center px-0.5 shrink-0 pointer-events-none">
|
<div
|
||||||
|
className={cn(
|
||||||
|
"absolute right-0 top-0 bottom-0 z-10 w-5 flex items-center justify-center transition-all duration-200 ease-out pointer-events-none",
|
||||||
|
sidebarScrollPos === "bottom"
|
||||||
|
? "opacity-0 translate-x-1"
|
||||||
|
: "opacity-100 translate-x-0"
|
||||||
|
)}
|
||||||
|
>
|
||||||
<ChevronRight className="size-3 text-muted-foreground" />
|
<ChevronRight className="size-3 text-muted-foreground" />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue