mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-05-21 18:55:16 +02:00
refactor(sidebar): update sidebar resizing logic to use pointer events; enhance drag cursor handling and improve sidebar width persistence
This commit is contained in:
parent
331589275b
commit
147be71238
5 changed files with 208 additions and 166 deletions
|
|
@ -27,15 +27,9 @@ interface SidebarButtonProps {
|
|||
buttonProps?: React.ButtonHTMLAttributes<HTMLButtonElement>;
|
||||
}
|
||||
|
||||
const expandedClassName = cn(
|
||||
"flex items-center gap-2 rounded-md mx-2 px-2 py-1.5 text-sm transition-colors text-left",
|
||||
"hover:bg-accent hover:text-accent-foreground",
|
||||
"focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
|
||||
);
|
||||
|
||||
const collapsedClassName = cn(
|
||||
"relative flex h-10 w-10 items-center justify-center rounded-md transition-colors",
|
||||
"hover:bg-accent hover:text-accent-foreground",
|
||||
const baseClassName = cn(
|
||||
"group/sidebar-button relative flex h-9 items-center rounded-md mx-2 px-2 text-sm text-left",
|
||||
"transition-colors hover:bg-accent hover:text-accent-foreground",
|
||||
"focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
|
||||
);
|
||||
|
||||
|
|
@ -56,53 +50,67 @@ export function SidebarButton({
|
|||
}: SidebarButtonProps) {
|
||||
const activeClassName = "bg-accent text-accent-foreground";
|
||||
|
||||
if (isCollapsed) {
|
||||
return (
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClick}
|
||||
className={cn(collapsedClassName, isActive && activeClassName, className)}
|
||||
{...buttonProps}
|
||||
>
|
||||
{collapsedIconNode ?? <Icon className="h-3.5 w-3.5" />}
|
||||
{collapsedOverlay}
|
||||
<span className="sr-only">{label}</span>
|
||||
</button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="right" className="max-w-xs">
|
||||
{tooltipContent ?? (
|
||||
<>
|
||||
{label}
|
||||
{typeof badge === "string" && ` (${badge})`}
|
||||
</>
|
||||
)}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
const iconNode = isCollapsed
|
||||
? (collapsedIconNode ?? <Icon className="h-3.5 w-3.5" />)
|
||||
: (expandedIconNode ?? <Icon className="h-3.5 w-3.5 shrink-0" />);
|
||||
|
||||
const button = (
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClick}
|
||||
className={cn(expandedClassName, isActive && activeClassName, className)}
|
||||
aria-label={isCollapsed ? label : undefined}
|
||||
className={cn(baseClassName, isActive && activeClassName, className)}
|
||||
{...buttonProps}
|
||||
>
|
||||
{expandedIconNode ?? <Icon className="h-3.5 w-3.5 shrink-0" />}
|
||||
<span className="flex-1 truncate">{label}</span>
|
||||
{trailingContent}
|
||||
{badge && typeof badge !== "string" ? badge : null}
|
||||
{badge && typeof badge === "string" ? (
|
||||
<span className="inline-flex items-center justify-center min-w-4 h-4 px-1 rounded-full bg-red-500 text-white text-[10px] font-medium">
|
||||
<span
|
||||
className={cn(
|
||||
"flex min-w-0 items-center translate-x-0.5 transition-transform duration-200 ease-out",
|
||||
isCollapsed ? "shrink-0" : "flex-1"
|
||||
)}
|
||||
>
|
||||
<span className="flex h-3.5 w-3.5 shrink-0 items-center justify-center">
|
||||
{iconNode}
|
||||
</span>
|
||||
|
||||
<span
|
||||
className={cn(
|
||||
"min-w-0 overflow-hidden whitespace-nowrap text-left",
|
||||
"transition-[max-width,opacity,margin-left] duration-200 ease-out",
|
||||
isCollapsed
|
||||
? "max-w-0 opacity-0 ml-0"
|
||||
: "max-w-[260px] flex-1 opacity-100 ml-2"
|
||||
)}
|
||||
>
|
||||
<span className="block truncate">{label}</span>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
{!isCollapsed && trailingContent}
|
||||
{!isCollapsed && badge && typeof badge !== "string" ? badge : null}
|
||||
{!isCollapsed && badge && typeof badge === "string" ? (
|
||||
<span className="ml-1 inline-flex items-center justify-center min-w-4 h-4 px-1 rounded-full bg-red-500 text-white text-[10px] font-medium">
|
||||
{badge}
|
||||
</span>
|
||||
) : null}
|
||||
|
||||
{collapsedOverlay && (
|
||||
<span
|
||||
aria-hidden={!isCollapsed}
|
||||
className={cn(
|
||||
"pointer-events-none absolute inset-0 transition-opacity duration-150",
|
||||
isCollapsed ? "opacity-100" : "opacity-0"
|
||||
)}
|
||||
>
|
||||
{collapsedOverlay}
|
||||
</span>
|
||||
)}
|
||||
|
||||
<span className="sr-only">{label}</span>
|
||||
</button>
|
||||
);
|
||||
|
||||
if (!tooltipContent) {
|
||||
const renderTooltip = isCollapsed || !!tooltipContent;
|
||||
if (!renderTooltip) {
|
||||
return button;
|
||||
}
|
||||
|
||||
|
|
@ -110,7 +118,14 @@ export function SidebarButton({
|
|||
<Tooltip>
|
||||
<TooltipTrigger asChild>{button}</TooltipTrigger>
|
||||
<TooltipContent side="right" className="max-w-xs">
|
||||
{tooltipContent}
|
||||
{isCollapsed
|
||||
? (tooltipContent ?? (
|
||||
<>
|
||||
{label}
|
||||
{typeof badge === "string" && ` (${badge})`}
|
||||
</>
|
||||
))
|
||||
: tooltipContent}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue