Skip to content

Commit

Permalink
arrow navigation in left sidebar, allow switching focus between panel…
Browse files Browse the repository at this point in the history
…s using cmd+0/1/2
  • Loading branch information
anastasiya1155 committed Jan 10, 2024
1 parent b15355f commit 48879dc
Show file tree
Hide file tree
Showing 14 changed files with 287 additions and 93 deletions.
3 changes: 1 addition & 2 deletions client/src/CommandBar/steps/Initial.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,11 @@ const InitialCommandBar = ({}: Props) => {
];
const projectItems: CommandBarItemGeneralType[] = projects
.map(
(p, i): CommandBarItemGeneralType => ({
(p): CommandBarItemGeneralType => ({
label: p.name,
Icon: MagazineIcon,
id: `project-${p.id}`,
key: `project-${p.id}`,
shortcut: i < 9 ? ['cmd', (i + 1).toString()] : undefined,
onClick: () => switchProject(p.id),
footerHint:
project?.id === p.id
Expand Down
37 changes: 22 additions & 15 deletions client/src/Project/CurrentTabContent/ChatTab/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { ChatTabType } from '../../../types/general';
import { ProjectContext } from '../../../context/projectContext';
import { CommandBarContext } from '../../../context/commandBarContext';
import { openInSplitViewShortcut } from '../../../consts/commandBar';
import { UIContext } from '../../../context/uiContext';
import Conversation from './Conversation';
import ActionsDropdown from './ActionsDropdown';

Expand All @@ -41,6 +42,7 @@ const ChatTab = ({
const { t } = useTranslation();
const { focusedPanel } = useContext(TabsContext.All);
const { closeTab } = useContext(TabsContext.Handlers);
const { isLeftSidebarFocused } = useContext(UIContext.Focus);
const { setFocusedTabItems } = useContext(CommandBarContext.Handlers);
const { project, refreshCurrentProjectConversations } = useContext(
ProjectContext.Current,
Expand Down Expand Up @@ -74,7 +76,10 @@ const ChatTab = ({
},
[handleMoveToAnotherSide],
);
useKeyboardNavigation(handleKeyEvent, focusedPanel !== side);
useKeyboardNavigation(
handleKeyEvent,
focusedPanel !== side || isLeftSidebarFocused,
);

useEffect(() => {
if (focusedPanel === side) {
Expand Down Expand Up @@ -108,21 +113,23 @@ const ChatTab = ({
/>
{title || t('New chat')}
</div>
<Dropdown
DropdownComponent={ActionsDropdown}
dropdownComponentProps={dropdownComponentProps}
appendTo={document.body}
dropdownPlacement="bottom-end"
>
<Button
variant="tertiary"
size="mini"
onlyIcon
title={t('More actions')}
{focusedPanel === side && (
<Dropdown
DropdownComponent={ActionsDropdown}
dropdownComponentProps={dropdownComponentProps}
appendTo={document.body}
dropdownPlacement="bottom-end"
>
<MoreHorizontalIcon sizeClassName="w-3.5 h-3.5" />
</Button>
</Dropdown>
<Button
variant="tertiary"
size="mini"
onlyIcon
title={t('More actions')}
>
<MoreHorizontalIcon sizeClassName="w-3.5 h-3.5" />
</Button>
</Dropdown>
)}
</div>
<div className="flex-1 flex flex-col max-w-full px-4 overflow-auto">
<Conversation side={side} tabKey={tabKey} />
Expand Down
34 changes: 19 additions & 15 deletions client/src/Project/CurrentTabContent/FileTab/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import { CommandBarContext } from '../../../context/commandBarContext';
import { openInSplitViewShortcut } from '../../../consts/commandBar';
import BreadcrumbsPathContainer from '../../../components/Breadcrumbs/PathContainer';
import { RepositoriesContext } from '../../../context/repositoriesContext';
import { UIContext } from '../../../context/uiContext';
import ActionsDropdown from './ActionsDropdown';

type Props = {
Expand Down Expand Up @@ -76,6 +77,7 @@ const FileTab = ({
const [isPending, startTransition] = useTransition();
const { openNewTab, updateTabProperty } = useContext(TabsContext.Handlers);
const { focusedPanel } = useContext(TabsContext.All);
const { isLeftSidebarFocused } = useContext(UIContext.Focus);
const { fileHighlights, hoveredLines } = useContext(
FileHighlightsContext.Values,
);
Expand Down Expand Up @@ -166,7 +168,7 @@ const FileTab = ({
);
useKeyboardNavigation(
handleKeyEvent,
!file?.contents || focusedPanel !== side,
!file?.contents || focusedPanel !== side || isLeftSidebarFocused,
);

useEffect(() => {
Expand Down Expand Up @@ -227,21 +229,23 @@ const FileTab = ({
nonInteractive
/>
</div>
<Dropdown
DropdownComponent={ActionsDropdown}
dropdownComponentProps={dropdownComponentProps}
dropdownPlacement="bottom-end"
appendTo={document.body}
>
<Button
variant="tertiary"
size="mini"
onlyIcon
title={t('More actions')}
{focusedPanel === side && (
<Dropdown
DropdownComponent={ActionsDropdown}
dropdownComponentProps={dropdownComponentProps}
dropdownPlacement="bottom-end"
appendTo={document.body}
>
<MoreHorizontalIcon sizeClassName="w-3.5 h-3.5" />
</Button>
</Dropdown>
<Button
variant="tertiary"
size="mini"
onlyIcon
title={t('More actions')}
>
<MoreHorizontalIcon sizeClassName="w-3.5 h-3.5" />
</Button>
</Dropdown>
)}
</div>
<div className="flex-1 h-full max-w-full pl-4 py-4 overflow-auto relative">
{file?.lang === 'jupyter notebook' ? (
Expand Down
3 changes: 3 additions & 0 deletions client/src/Project/CurrentTabContent/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Trans } from 'react-i18next';
import { TabsContext } from '../../context/tabsContext';
import { DraggableTabItem, TabType, TabTypesEnum } from '../../types/general';
import { SplitViewIcon } from '../../icons';
import { UIContext } from '../../context/uiContext';
import EmptyTab from './EmptyTab';
import FileTab from './FileTab';
import Header from './Header';
Expand All @@ -26,6 +27,7 @@ const CurrentTabContent = ({
TabsContext[side === 'left' ? 'CurrentLeft' : 'CurrentRight'],
);
const { setFocusedPanel } = useContext(TabsContext.Handlers);
const { setIsLeftSidebarFocused } = useContext(UIContext.Focus);

const [{ isOver, canDrop }, drop] = useDrop(
() => ({
Expand All @@ -44,6 +46,7 @@ const CurrentTabContent = ({

const focusPanel = useCallback(() => {
setFocusedPanel(side);
setIsLeftSidebarFocused(false);
}, [side]);

const handleMoveToAnotherSide = useCallback(() => {
Expand Down
48 changes: 32 additions & 16 deletions client/src/Project/LeftSidebar/NavPanel/Conversations.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,18 @@ import ConversationEntry from './CoversationEntry';
type Props = {
setExpanded: Dispatch<SetStateAction<number>>;
isExpanded: boolean;
focusedIndex: string;
index: number;
};

const reactRoot = document.getElementById('root')!;

const ConversationsNav = ({ isExpanded, setExpanded }: Props) => {
const ConversationsNav = ({
isExpanded,
setExpanded,
focusedIndex,
index,
}: Props) => {
const { t } = useTranslation();
const { project } = useContext(ProjectContext.Current);
const containerRef = useRef<HTMLDivElement>(null);
Expand All @@ -46,18 +53,25 @@ const ConversationsNav = ({ isExpanded, setExpanded }: Props) => {
e?.stopPropagation();
}, []);

useEffect(() => {
if (focusedIndex === index.toString() && containerRef.current) {
containerRef.current.scrollIntoView({ block: 'nearest' });
}
}, [focusedIndex, index]);

return (
<div
className="select-none overflow-hidden w-full flex-shrink-0"
ref={containerRef}
>
<div className="select-none overflow-hidden w-full flex-shrink-0">
<span
role="button"
tabIndex={0}
className={`h-10 flex items-center gap-3 px-4 bg-bg-sub ellipsis ${
className={`h-10 flex items-center gap-3 px-4 ellipsis ${
isExpanded ? 'sticky z-10 top-0 left-0' : ''
} ${
focusedIndex === index.toString() ? 'bg-bg-sub-hover' : 'bg-bg-sub'
}`}
onClick={toggleExpanded}
ref={containerRef}
data-node-index={index.toString()}
>
<ChatBubblesIcon
sizeClassName="w-3.5 h-3.5"
Expand Down Expand Up @@ -94,16 +108,18 @@ const ConversationsNav = ({ isExpanded, setExpanded }: Props) => {
</div>
)}
</span>
<div
style={{
maxHeight: isExpanded ? undefined : 0,
}}
className={'overflow-hidden'}
>
{project?.conversations.map((c) => (
<ConversationEntry key={c.id} {...c} />
))}
</div>
{isExpanded && (
<div className={'overflow-hidden'}>
{project?.conversations.map((c, ci) => (
<ConversationEntry
key={c.id}
{...c}
index={`${index}-${ci}`}
focusedIndex={focusedIndex}
/>
))}
</div>
)}
</div>
);
};
Expand Down
16 changes: 12 additions & 4 deletions client/src/Project/LeftSidebar/NavPanel/CoversationEntry.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@ import { ConversationShortType } from '../../../types/api';
import { TabsContext } from '../../../context/tabsContext';
import { TabTypesEnum } from '../../../types/general';

type Props = ConversationShortType & {};
type Props = ConversationShortType & {
index: string;
focusedIndex: string;
};

const ConversationEntry = ({ title, id }: Props) => {
const ConversationEntry = ({ title, id, index, focusedIndex }: Props) => {
const { openNewTab } = useContext(TabsContext.Handlers);

const handleClick = useCallback(() => {
Expand All @@ -16,9 +19,14 @@ const ConversationEntry = ({ title, id }: Props) => {
<a
href="#"
className={`w-full text-left h-7 flex-shrink-0 flex items-center gap-3 pr-2 cursor-pointer
ellipsis body-mini group
hover:bg-bg-base-hover hover:text-label-title active:bg-transparent text-label-base pl-[2.625rem]`}
ellipsis body-mini group ${
focusedIndex === index
? 'bg-bg-sub-hover text-label-title'
: 'text-label-base'
}
hover:bg-bg-base-hover hover:text-label-title active:bg-transparent pl-[2.625rem]`}
onClick={handleClick}
data-node-index={index}
>
<span className="ellipsis">{title}</span>
</a>
Expand Down
67 changes: 40 additions & 27 deletions client/src/Project/LeftSidebar/NavPanel/Repo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ type Props = {
allBranches: { name: string; last_commit_unix_secs: number }[];
indexedBranches: string[];
indexingData?: RepoIndexingStatusType;
focusedIndex: string;
index: number;
};

const reactRoot = document.getElementById('root')!;
Expand All @@ -56,6 +58,8 @@ const RepoNav = ({
lastIndex,
currentPath,
indexingData,
focusedIndex,
index,
}: Props) => {
const { t } = useTranslation();
const [files, setFiles] = useState<DirectoryEntry[]>([]);
Expand Down Expand Up @@ -122,15 +126,25 @@ const RepoNav = ({
].includes(indexingData.status);
}, [indexingData]);

useEffect(() => {
if (focusedIndex === index.toString() && containerRef.current) {
containerRef.current.scrollIntoView({ block: 'nearest' });
}
}, [focusedIndex, index]);

return (
<div className="select-none flex-shrink-0" ref={containerRef}>
<div className="select-none flex-shrink-0">
<span
role="button"
tabIndex={0}
className={`h-10 flex items-center gap-3 px-4 bg-bg-sub ellipsis ${
className={`h-10 flex items-center gap-3 px-4 ellipsis ${
isExpanded ? 'sticky z-10 top-0 left-0' : ''
} ${
focusedIndex === index.toString() ? 'bg-bg-sub-hover' : 'bg-bg-sub'
}`}
onClick={toggleExpanded}
data-node-index={`${index}`}
ref={containerRef}
>
{isIndexing && indexingData ? (
<Tooltip
Expand Down Expand Up @@ -181,31 +195,30 @@ const RepoNav = ({
</div>
)}
</span>
<div
style={{
maxHeight: isExpanded && files.length ? undefined : 0,
}}
className={isExpanded ? 'overflow-auto' : 'overflow-hidden'}
>
{files.map((f) => (
<RepoEntry
key={f.name}
name={f.name}
indexed={
f.entry_data !== 'Directory' ? f.entry_data.File.indexed : true
}
isDirectory={f.entry_data === 'Directory'}
level={1}
fetchFiles={fetchFiles}
fullPath={f.name}
repoRef={repoRef}
currentPath={currentPath}
lastIndex={lastIndex}
branch={branch}
indexingData={indexingData}
/>
))}
</div>
{isExpanded && (
<div className={isExpanded ? 'overflow-auto' : 'overflow-hidden'}>
{files.map((f, fi) => (
<RepoEntry
key={f.name}
name={f.name}
indexed={
f.entry_data !== 'Directory' ? f.entry_data.File.indexed : true
}
isDirectory={f.entry_data === 'Directory'}
level={1}
fetchFiles={fetchFiles}
fullPath={f.name}
repoRef={repoRef}
currentPath={currentPath}
lastIndex={lastIndex}
branch={branch}
indexingData={indexingData}
focusedIndex={focusedIndex}
index={`${index}-${fi}`}
/>
))}
</div>
)}
</div>
);
};
Expand Down
Loading

0 comments on commit 48879dc

Please sign in to comment.