diff --git a/apps/web/src/components/Sidebar.tsx b/apps/web/src/components/Sidebar.tsx
index 44730796594cd0226ebba952c4436f61c17741a5..914480d077430c24ac459cdc365141176bfd068f 100644
--- a/apps/web/src/components/Sidebar.tsx
+++ b/apps/web/src/components/Sidebar.tsx
@@ -61,6 +61,7 @@ import {
} from "./desktopUpdate.logic";
import { Alert, AlertAction, AlertDescription, AlertTitle } from "./ui/alert";
import { Button } from "./ui/button";
+import { Collapsible, CollapsibleContent } from "./ui/collapsible";
import { Tooltip, TooltipPopup, TooltipTrigger } from "./ui/tooltip";
import {
SidebarContent,
@@ -231,18 +232,20 @@ function SortableProjectItem({
const { attributes, listeners, setNodeRef, transform, transition, isDragging, isOver } =
useSortable({ id: projectId });
return (
-
{children({ attributes, listeners })}
-
+
);
}
@@ -294,14 +297,7 @@ export default function Sidebar() {
const renamingCommittedRef = useRef(false);
const renamingInputRef = useRef(null);
const dragInProgressRef = useRef(false);
- const suppressProjectClickFromGestureRef = useRef(false);
- const suppressProjectClickResetTimerRef = useRef(null);
- const projectTitlePointerRef = useRef<{
- pointerId: number;
- startX: number;
- startY: number;
- moved: boolean;
- } | null>(null);
+ const suppressProjectClickAfterDragRef = useRef(false);
const [desktopUpdateState, setDesktopUpdateState] = useState(null);
const shouldBrowseForProjectImmediately = isElectron;
const shouldShowProjectPathEntry = addingProject && !shouldBrowseForProjectImmediately;
@@ -861,64 +857,20 @@ export default function Sidebar() {
const handleProjectDragStart = useCallback((_event: DragStartEvent) => {
dragInProgressRef.current = true;
+ suppressProjectClickAfterDragRef.current = true;
}, []);
const handleProjectDragCancel = useCallback((_event: DragCancelEvent) => {
dragInProgressRef.current = false;
}, []);
- const handleProjectTitlePointerDownCapture = useCallback(
- (event: React.PointerEvent) => {
- projectTitlePointerRef.current = {
- pointerId: event.pointerId,
- startX: event.clientX,
- startY: event.clientY,
- moved: false,
- };
- },
- [],
- );
-
- const handleProjectTitlePointerMoveCapture = useCallback(
- (event: React.PointerEvent) => {
- const pointer = projectTitlePointerRef.current;
- if (!pointer || pointer.pointerId !== event.pointerId) return;
- const movedX = Math.abs(event.clientX - pointer.startX);
- const movedY = Math.abs(event.clientY - pointer.startY);
- if (movedX > 3 || movedY > 3) {
- pointer.moved = true;
- }
- },
- [],
- );
-
- const handleProjectTitlePointerUpCapture = useCallback(
- (event: React.PointerEvent) => {
- const pointer = projectTitlePointerRef.current;
- if (pointer?.pointerId === event.pointerId) {
- if (pointer.moved) {
- suppressProjectClickFromGestureRef.current = true;
- if (suppressProjectClickResetTimerRef.current !== null) {
- window.clearTimeout(suppressProjectClickResetTimerRef.current);
- }
- suppressProjectClickResetTimerRef.current = window.setTimeout(() => {
- suppressProjectClickFromGestureRef.current = false;
- suppressProjectClickResetTimerRef.current = null;
- }, 0);
- }
- projectTitlePointerRef.current = null;
- }
- },
- [],
- );
-
- const handleProjectTitlePointerCancelCapture = useCallback(() => {
- projectTitlePointerRef.current = null;
+ const handleProjectTitlePointerDownCapture = useCallback(() => {
+ suppressProjectClickAfterDragRef.current = false;
}, []);
const handleProjectTitleClick = useCallback(
(event: React.MouseEvent, projectId: ProjectId) => {
- if (dragInProgressRef.current || suppressProjectClickFromGestureRef.current) {
+ if (dragInProgressRef.current || suppressProjectClickAfterDragRef.current) {
event.preventDefault();
event.stopPropagation();
return;
@@ -940,14 +892,6 @@ export default function Sidebar() {
[toggleProject],
);
- useEffect(() => {
- return () => {
- if (suppressProjectClickResetTimerRef.current !== null) {
- window.clearTimeout(suppressProjectClickResetTimerRef.current);
- }
- };
- }, []);
-
useEffect(() => {
const onWindowKeyDown = (event: KeyboardEvent) => {
const activeThread = routeThreadId
@@ -1318,7 +1262,10 @@ export default function Sidebar() {
return (
{(dragHandleProps) => (
-
+
handleProjectTitleClick(event, project.id)}
onKeyDown={(event) => handleProjectTitleKeyDown(event, project.id)}
onContextMenu={(event) => {
@@ -1379,15 +1323,8 @@ export default function Sidebar() {
-
-
-
+
+
{visibleThreads.map((thread) => {
const isActive = routeThreadId === thread.id;
const threadStatus = resolveThreadStatusPill({
@@ -1558,9 +1495,8 @@ export default function Sidebar() {
)}
-
-
-
+
+
)}
);
diff --git a/apps/web/src/components/ui/collapsible.tsx b/apps/web/src/components/ui/collapsible.tsx
index 180d0a95b38f4dfdfb7ef8836e7de6c80300d050..e5f3db03c3f5e8bedcc3ac7ba1904656b6cded6d 100644
--- a/apps/web/src/components/ui/collapsible.tsx
+++ b/apps/web/src/components/ui/collapsible.tsx
@@ -22,7 +22,7 @@ function CollapsiblePanel({ className, ...props }: CollapsiblePrimitive.Panel.Pr
return (
@@ -22,14 +24,19 @@ function ScrollArea({
scrollFade &&
"mask-t-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-y-start)))] mask-b-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-y-end)))] mask-l-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-x-start)))] mask-r-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-x-end)))] [--fade-size:1.5rem]",
scrollbarGutter && "data-has-overflow-y:pe-2.5 data-has-overflow-x:pb-2.5",
+ hideScrollbars && "[-ms-overflow-style:none] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
)}
data-slot="scroll-area-viewport"
>
{children}
-
-
-
+ {!hideScrollbars && (
+ <>
+
+
+
+ >
+ )}
);
}
diff --git a/apps/web/src/components/ui/sidebar.tsx b/apps/web/src/components/ui/sidebar.tsx
index 16b9ec4ed377c1d54298740c94108afa1d5caf17..3876d35132505cb7205625316926f49d9ec72bb2 100644
--- a/apps/web/src/components/ui/sidebar.tsx
+++ b/apps/web/src/components/ui/sidebar.tsx
@@ -651,10 +651,10 @@ function SidebarSeparator({ className, ...props }: React.ComponentProps) {
return (
-
+