-
Notifications
You must be signed in to change notification settings - Fork 2k
feat: Sidebar UI updates #4748
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Sidebar UI updates #4748
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PR Summary
This PR refactors the sidebar UI to fix chat dragging within groups while introducing a new standardized sidebar component system. The changes primarily focus on improving the user experience and fixing a specific dragging issue.
- New
sidebar.tsx
component introduces a comprehensive, accessible sidebar system with proper TypeScript typing and mobile responsiveness - Removed drag handle from
ChatSessionDisplay.tsx
in favor of making the entire chat item draggable ChatGroup.tsx
now uses a collapsible menu structure but has commented-out props that need reviewuseIsMobile
hook needs SSR consideration and consistent width checking between initial load and subsequent changes- Potential state management concerns in
PagesTab.tsx
with commented-out drag-and-drop implementation
9 file(s) reviewed, 11 comment(s)
Edit PR Review Bot Settings | Greptile
<CollapsibleContent> | ||
<SidebarMenuSub> | ||
{chatSessions.map((chatSession) => ( | ||
<SidebarMenuSubItem key={chatSession.name}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logic: Using chatSession.name as key is unsafe. Should use chatSession.id for stable list rendering
<SidebarMenuSubItem key={chatSession.name}> | |
<SidebarMenuSubItem key={chatSession.id}> |
// showShareModal={showShareModal} | ||
// showDeleteModal={showDeleteModal} | ||
// closeSidebar={closeSidebar} | ||
// isDragging={isDraggingSessionId === chat.id} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logic: Critical props are commented out. These need to be properly passed through or the chat sharing, deletion and dragging functionality will break
draggable={!isMobile} | ||
onDragStart={!isMobile ? handleDragStart : undefined} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logic: draggable and onDragStart are only set when !isMobile, but handleTouchStart is never used. Mobile drag-and-drop functionality may be broken.
open={hasChatsToShow && expanded} | ||
defaultOpen={true} | ||
> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: Conflicting open states - defaultOpen is true but open depends on hasChatsToShow && expanded. This could cause unexpected behavior
const groupedChatSessionsLength = Object.entries(groupedChatSesssions).length; | ||
const foldersLength = (folders ?? []).length; | ||
const totalLength = groupedChatSessionsLength + foldersLength; | ||
const [expands, setExpands] = useState<boolean[]>( | ||
Array(totalLength).fill(true) | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logic: Initial state of expands array depends on dynamic length calculation, which could cause UI flicker if folders/chats load asynchronously
>(({ className, ...props }, ref) => ( | ||
<SheetPrimitive.Overlay | ||
className={cn( | ||
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
syntax: Extra space after bg-black/80 in className string could cause inconsistent styling
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0", | |
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0", |
"inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom", | ||
left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm", | ||
right: | ||
"inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
syntax: Extra space after w-3/4 in className string could cause inconsistent styling
"inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm", | |
"inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm", |
ref={ref} | ||
data-sidebar="rail" | ||
aria-label="Toggle Sidebar" | ||
tabIndex={-1} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: tabIndex={-1} on a clickable button may cause accessibility issues for keyboard users.
tabIndex={-1} | |
aria-label="Toggle Sidebar" | |
onClick={toggleSidebar} | |
title="Toggle Sidebar" |
const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`); | ||
const onChange = () => { | ||
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logic: Inconsistent width checking between matchMedia and innerWidth. Use mql.matches instead of innerWidth for consistency
const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`); | |
const onChange = () => { | |
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT); | |
}; | |
const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`); | |
const onChange = () => { | |
setIsMobile(mql.matches); | |
}; |
React.useEffect(() => { | ||
const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`); | ||
const onChange = () => { | ||
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT); | ||
}; | ||
mql.addEventListener("change", onChange); | ||
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT); | ||
return () => mql.removeEventListener("change", onChange); | ||
}, []); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: Add check for window object to support SSR: if (typeof window === 'undefined') return false
React.useEffect(() => { | |
const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`); | |
const onChange = () => { | |
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT); | |
}; | |
mql.addEventListener("change", onChange); | |
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT); | |
return () => mql.removeEventListener("change", onChange); | |
}, []); | |
React.useEffect(() => { | |
if (typeof window === 'undefined') return; | |
const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`); | |
const onChange = () => { | |
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT); | |
}; | |
mql.addEventListener("change", onChange); | |
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT); | |
return () => mql.removeEventListener("change", onChange); | |
}, []); |
- this cancels the editing state
This PR is stale because it has been open 75 days with no activity. Remove stale label or comment or this will be closed in 15 days. |
This PR was closed because it has been stalled for 90 days with no activity. |
Description
UI updates to sidebar.
How Has This Been Tested?
This is a pure UI change; no tests were written.