Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions components/AIMode/AIModeOverlay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,10 @@ export function AIModeOverlay() {
const { close, layout, setLayout } = useAIMode();
const state = useAIModeChat();
const { target } = state;
// Below the tablet breakpoint the sidebar lives in a bottom drawer.
const [listDrawerOpen, setListDrawerOpen] = useState(false);
const closeListDrawer = useCallback(() => setListDrawerOpen(false), []);
// Below the tablet breakpoint the sidebar is a screen of its own, opened
// from the chat header.
const [listOpen, setListOpen] = useState(false);
const closeList = useCallback(() => setListOpen(false), []);

const doc = useAIModeDocument({
note: state.note,
Expand Down Expand Up @@ -175,15 +176,15 @@ export function AIModeOverlay() {
isBelowTablet={isBelowTablet}
sidebarWidth={{ ...listWidth, min: LIST_MIN_WIDTH, max: LIST_MAX_WIDTH }}
sideWidth={{ ...sideWidth, min: sideMinWidth, max: sideMaxWidth }}
listDrawerOpen={listDrawerOpen}
onCloseListDrawer={closeListDrawer}
listOpen={listOpen}
onCloseList={closeList}
onCloseDocumentDrawer={closeDocument}
container={rootEl}
sidebar={<WorkspaceSidebar state={state} onNavigate={closeListDrawer} />}
sidebar={<WorkspaceSidebar state={state} onNavigate={closeList} />}
chat={
<ChatPane
state={state}
onOpenConversations={() => setListDrawerOpen(true)}
onOpenConversations={() => setListOpen(true)}
documentCard={documentCard}
documentCardExecutionId={documentCardExecutionId}
headerActions={
Expand Down
6 changes: 3 additions & 3 deletions components/AIMode/chat/ChatPane.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use client';

import { useEffect, useRef, useState, type ReactNode } from 'react';
import { Menu } from 'lucide-react';
import { PanelLeft } from 'lucide-react';
import { ChatComposer } from '@/components/AgentChat/ChatComposer';
import { ChatTranscript } from '@/components/AgentChat/ChatTranscript';
import { JumpToLatestButton } from '@/components/AgentChat/JumpToLatestButton';
Expand Down Expand Up @@ -132,10 +132,10 @@ export function ChatPane({
<button
type="button"
onClick={onOpenConversations}
aria-label="Conversations"
aria-label="Show conversations and documents"
className="rounded-lg p-1.5 text-gray-500 transition-colors hover:bg-gray-100 hover:text-gray-900 tablet:!hidden"
>
<Menu className="h-4 w-4" />
<PanelLeft className="h-4 w-4" />
</button>
)}
{renaming && chatId != null ? (
Expand Down
48 changes: 32 additions & 16 deletions components/AIMode/shell/WorkspacePanes.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use client';

import type { ReactNode } from 'react';
import { PanelLeft } from 'lucide-react';
import { ResizeHandle } from '@/components/ui/ResizeHandle';
import { SwipeableDrawer } from '@/components/ui/SwipeableDrawer';
import type { useResizableWidth } from '@/hooks/useResizableWidth';
Expand All @@ -23,8 +24,9 @@
readonly isBelowTablet: boolean;
readonly sidebarWidth: ResizableWidth & { readonly min: number; readonly max: number };
readonly sideWidth: ResizableWidth & { readonly min: number; readonly max: number };
readonly listDrawerOpen: boolean;
readonly onCloseListDrawer: () => void;
/** Below the tablet breakpoint the sidebar is a screen of its own; this shows it. */
readonly listOpen: boolean;
readonly onCloseList: () => void;
readonly onCloseDocumentDrawer: () => void;
/** The overlay's root, which the drawers render inside so they stay live. */
readonly container: HTMLElement | null;
Expand All @@ -35,7 +37,8 @@
* their places in the tree whichever is the main pane — swapping them would
* remount the editor and the transcript — and trade places on screen with
* flex order. Both side panes drag; the main pane takes the rest. Below the
* tablet breakpoint the sidebar and the document live in bottom drawers.
* tablet breakpoint the sidebar takes the whole screen when asked for and
* the document lives in a bottom drawer.
*/
export function WorkspacePanes({
layout,
Expand All @@ -46,8 +49,8 @@
isBelowTablet,
sidebarWidth,
sideWidth,
listDrawerOpen,
onCloseListDrawer,
listOpen,
onCloseList,
onCloseDocumentDrawer,
container,
}: WorkspacePanesProps) {
Expand Down Expand Up @@ -98,19 +101,32 @@
{document}
</aside>
)}

{listOpen && isBelowTablet && (
<div
role="dialog"
aria-label="Conversations and documents"
className="absolute inset-0 z-10 flex flex-col bg-gray-100"
>

Check warning on line 110 in components/AIMode/shell/WorkspacePanes.tsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use <dialog> instead of the "dialog" role to ensure accessibility across all devices.

See more on https://sonarcloud.io/project/issues?id=ResearchHub_web&issues=AaDIX-4MSEGDz0Tbc9PJ&open=AaDIX-4MSEGDz0Tbc9PJ&pullRequest=1123
<div className="flex h-12 shrink-0 items-center gap-1 border-b border-gray-200 bg-white pl-0.5 pr-3">
<button
type="button"
onClick={onCloseList}
aria-label="Hide conversations and documents"
aria-pressed="true"
className="flex h-11 w-11 items-center justify-center rounded-lg text-primary-700"
>
<PanelLeft className="h-[18px] w-[18px]" />
</button>
<h2 className="text-sm font-medium text-gray-800">Conversations and documents</h2>
</div>
<div className="min-h-0 flex-1">{sidebar}</div>
</div>
)}
</div>

{/* Drawers portal to the body, so they need to stack above this overlay
(z-9500) while staying under BaseModal (9999). */}
<SwipeableDrawer
isOpen={listDrawerOpen}
onClose={onCloseListDrawer}
height="70vh"
zIndex={AI_MODE_DRAWER_Z_INDEX}
container={container}
>
{sidebar}
</SwipeableDrawer>
{/* The drawer portals to the body, so it needs to stack above this
overlay (z-9500) while staying under BaseModal (9999). */}
<SwipeableDrawer
isOpen={documentOpen && isBelowTablet}
onClose={onCloseDocumentDrawer}
Expand Down
Loading