Commit 9d7c3849 authored by tom's avatar tom

improve sidebar action button

parent 941f5c8b
...@@ -11,7 +11,7 @@ import useIsMobile from 'lib/hooks/useIsMobile'; ...@@ -11,7 +11,7 @@ import useIsMobile from 'lib/hooks/useIsMobile';
import CodeEditorBreadcrumbs from './CodeEditorBreadcrumbs'; import CodeEditorBreadcrumbs from './CodeEditorBreadcrumbs';
import CodeEditorLoading from './CodeEditorLoading'; import CodeEditorLoading from './CodeEditorLoading';
import CodeEditorSideBar from './CodeEditorSideBar'; import CodeEditorSideBar, { CONTAINER_WIDTH as SIDE_BAR_WIDTH } from './CodeEditorSideBar';
import CodeEditorTabs from './CodeEditorTabs'; import CodeEditorTabs from './CodeEditorTabs';
import * as themes from './utils/themes'; import * as themes from './utils/themes';
...@@ -25,7 +25,6 @@ const EDITOR_OPTIONS: EditorProps['options'] = { ...@@ -25,7 +25,6 @@ const EDITOR_OPTIONS: EditorProps['options'] = {
const TABS_HEIGHT = 35; const TABS_HEIGHT = 35;
const BREADCRUMBS_HEIGHT = 22; const BREADCRUMBS_HEIGHT = 22;
const SIDE_BAR_WIDTH = 250;
const EDITOR_HEIGHT = 500; const EDITOR_HEIGHT = 500;
interface Props { interface Props {
......
...@@ -11,14 +11,26 @@ interface Props { ...@@ -11,14 +11,26 @@ interface Props {
data: Array<File>; data: Array<File>;
onFileSelect: (index: number) => void; onFileSelect: (index: number) => void;
selectedFile: string; selectedFile: string;
isActive: boolean;
setActionBarRenderer: React.Dispatch<React.SetStateAction<(() => JSX.Element) | undefined>>;
} }
const CodeEditorFileExplorer = ({ data, onFileSelect, selectedFile }: Props) => { const CodeEditorFileExplorer = ({ data, onFileSelect, selectedFile, isActive, setActionBarRenderer }: Props) => {
const [ key, setKey ] = React.useState(0); const [ key, setKey ] = React.useState(0);
const tree = React.useMemo(() => { const tree = React.useMemo(() => {
return composeFileTree(data); return composeFileTree(data);
}, [ data ]); }, [ data ]);
const handleCollapseButtonClick = React.useCallback(() => {
setKey((prev) => prev + 1);
}, []);
const renderActionBar = React.useCallback(() => {
return (
<CoderEditorCollapseButton onClick={ handleCollapseButtonClick } label="Collapse folders"/>
);
}, [ handleCollapseButtonClick ]);
const handleFileClick = React.useCallback((event: React.MouseEvent) => { const handleFileClick = React.useCallback((event: React.MouseEvent) => {
const filePath = (event.currentTarget as HTMLDivElement).getAttribute('data-file-path'); const filePath = (event.currentTarget as HTMLDivElement).getAttribute('data-file-path');
const fileIndex = data.findIndex((item) => item.file_path === filePath); const fileIndex = data.findIndex((item) => item.file_path === filePath);
...@@ -28,13 +40,12 @@ const CodeEditorFileExplorer = ({ data, onFileSelect, selectedFile }: Props) => ...@@ -28,13 +40,12 @@ const CodeEditorFileExplorer = ({ data, onFileSelect, selectedFile }: Props) =>
} }
}, [ data, onFileSelect ]); }, [ data, onFileSelect ]);
const handleCollapseButtonClick = React.useCallback(() => { React.useEffect(() => {
setKey((prev) => prev + 1); isActive && setActionBarRenderer(() => renderActionBar);
}, []); }, [ isActive, renderActionBar, setActionBarRenderer ]);
return ( return (
<Box> <Box>
<CoderEditorCollapseButton onClick={ handleCollapseButtonClick } label="Collapse folders"/>
<CodeEditorFileTree key={ key } tree={ tree } onItemClick={ handleFileClick } isCollapsed={ key > 0 } selectedFile={ selectedFile }/> <CodeEditorFileTree key={ key } tree={ tree } onItemClick={ handleFileClick } isCollapsed={ key > 0 } selectedFile={ selectedFile }/>
</Box> </Box>
); );
......
...@@ -15,9 +15,11 @@ interface Props { ...@@ -15,9 +15,11 @@ interface Props {
monaco: Monaco | undefined; monaco: Monaco | undefined;
onFileSelect: (index: number, lineNumber?: number) => void; onFileSelect: (index: number, lineNumber?: number) => void;
isInputStuck: boolean; isInputStuck: boolean;
isActive: boolean;
setActionBarRenderer: React.Dispatch<React.SetStateAction<(() => JSX.Element) | undefined>>;
} }
const CodeEditorSearch = ({ monaco, data, onFileSelect, isInputStuck }: Props) => { const CodeEditorSearch = ({ monaco, data, onFileSelect, isInputStuck, isActive, setActionBarRenderer }: Props) => {
const [ searchTerm, changeSearchTerm ] = React.useState(''); const [ searchTerm, changeSearchTerm ] = React.useState('');
const [ searchResults, setSearchResults ] = React.useState<Array<SearchResult>>([]); const [ searchResults, setSearchResults ] = React.useState<Array<SearchResult>>([]);
const [ expandedSections, setExpandedSections ] = React.useState<Array<number>>([]); const [ expandedSections, setExpandedSections ] = React.useState<Array<number>>([]);
...@@ -78,6 +80,21 @@ const CodeEditorSearch = ({ monaco, data, onFileSelect, isInputStuck }: Props) = ...@@ -78,6 +80,21 @@ const CodeEditorSearch = ({ monaco, data, onFileSelect, isInputStuck }: Props) =
} }
}, [ expandedSections.length, searchResults ]); }, [ expandedSections.length, searchResults ]);
const renderActionBar = React.useCallback(() => {
return (
<CoderEditorCollapseButton
onClick={ handleToggleCollapseClick }
label={ expandedSections.length === 0 ? 'Expand all' : 'Collapse all' }
isDisabled={ searchResults.length === 0 }
isCollapsed={ expandedSections.length === 0 }
/>
);
}, [ expandedSections.length, handleToggleCollapseClick, searchResults.length ]);
React.useEffect(() => {
isActive && setActionBarRenderer(() => renderActionBar);
}, [ isActive, renderActionBar, setActionBarRenderer ]);
const buttonProps: ChakraProps = { const buttonProps: ChakraProps = {
boxSize: '20px', boxSize: '20px',
p: '1px', p: '1px',
...@@ -111,12 +128,6 @@ const CodeEditorSearch = ({ monaco, data, onFileSelect, isInputStuck }: Props) = ...@@ -111,12 +128,6 @@ const CodeEditorSearch = ({ monaco, data, onFileSelect, isInputStuck }: Props) =
return ( return (
<Box> <Box>
<CoderEditorCollapseButton
onClick={ handleToggleCollapseClick }
label={ expandedSections.length === 0 ? 'Expand all' : 'Collapse all' }
isDisabled={ searchResults.length === 0 }
isCollapsed={ expandedSections.length === 0 }
/>
<InputGroup <InputGroup
px="8px" px="8px"
position="sticky" position="sticky"
......
...@@ -16,12 +16,14 @@ interface Props { ...@@ -16,12 +16,14 @@ interface Props {
selectedFile: string; selectedFile: string;
} }
const CONTAINER_WIDTH = 250; export const CONTAINER_WIDTH = 250;
const CodeEditorSideBar = ({ onFileSelect, data, monaco, selectedFile }: Props) => { const CodeEditorSideBar = ({ onFileSelect, data, monaco, selectedFile }: Props) => {
const [ isStuck, setIsStuck ] = React.useState(false); const [ isStuck, setIsStuck ] = React.useState(false);
const [ isDrawerOpen, setIsDrawerOpen ] = useBoolean(false); const [ isDrawerOpen, setIsDrawerOpen ] = useBoolean(false);
const [ tabIndex, setTabIndex ] = React.useState(0);
const [ actionBarRenderer, setActionBarRenderer ] = React.useState<() => JSX.Element>();
const themeColors = useThemeColors(); const themeColors = useThemeColors();
...@@ -57,8 +59,8 @@ const CodeEditorSideBar = ({ onFileSelect, data, monaco, selectedFile }: Props) ...@@ -57,8 +59,8 @@ const CodeEditorSideBar = ({ onFileSelect, data, monaco, selectedFile }: Props)
fontSize="13px" fontSize="13px"
overflowY="scroll" overflowY="scroll"
onScroll={ handleScrollThrottled.current } onScroll={ handleScrollThrottled.current }
position={{ base: 'absolute', lg: 'static' }} position={{ base: 'absolute', lg: 'relative' }}
right={{ base: isDrawerOpen ? '0' : `-${ CONTAINER_WIDTH }px`, lg: undefined }} right={{ base: isDrawerOpen ? '0' : `-${ CONTAINER_WIDTH }px`, lg: '0' }}
top={{ base: 0, lg: undefined }} top={{ base: 0, lg: undefined }}
h="100%" h="100%"
pb="22px" pb="22px"
...@@ -70,7 +72,7 @@ const CodeEditorSideBar = ({ onFileSelect, data, monaco, selectedFile }: Props) ...@@ -70,7 +72,7 @@ const CodeEditorSideBar = ({ onFileSelect, data, monaco, selectedFile }: Props)
borderTopRightRadius="md" borderTopRightRadius="md"
borderBottomRightRadius="md" borderBottomRightRadius="md"
> >
<Tabs isLazy lazyBehavior="keepMounted" variant="unstyled" size="13px"> <Tabs isLazy lazyBehavior="keepMounted" variant="unstyled" size="13px" index={ tabIndex } onChange={ setTabIndex }>
<TabList <TabList
columnGap={ 3 } columnGap={ 3 }
position="sticky" position="sticky"
...@@ -84,14 +86,27 @@ const CodeEditorSideBar = ({ onFileSelect, data, monaco, selectedFile }: Props) ...@@ -84,14 +86,27 @@ const CodeEditorSideBar = ({ onFileSelect, data, monaco, selectedFile }: Props)
> >
<Tab { ...tabProps }>Explorer</Tab> <Tab { ...tabProps }>Explorer</Tab>
<Tab { ...tabProps }>Search</Tab> <Tab { ...tabProps }>Search</Tab>
{ actionBarRenderer?.() }
</TabList> </TabList>
<TabPanels> <TabPanels>
<TabPanel p={ 0 }> <TabPanel p={ 0 }>
<CodeEditorFileExplorer data={ data } onFileSelect={ handleFileSelect } selectedFile={ selectedFile }/> <CodeEditorFileExplorer
data={ data }
onFileSelect={ handleFileSelect }
selectedFile={ selectedFile }
isActive={ tabIndex === 0 }
setActionBarRenderer={ setActionBarRenderer }
/>
</TabPanel> </TabPanel>
<TabPanel p={ 0 }> <TabPanel p={ 0 }>
<CodeEditorSearch data={ data } onFileSelect={ handleFileSelect } monaco={ monaco } isInputStuck={ isStuck }/> <CodeEditorSearch
data={ data }
onFileSelect={ handleFileSelect }
monaco={ monaco }
isInputStuck={ isStuck }
isActive={ tabIndex === 1 }
setActionBarRenderer={ setActionBarRenderer }
/>
</TabPanel> </TabPanel>
</TabPanels> </TabPanels>
</Tabs> </Tabs>
......
...@@ -15,10 +15,8 @@ const CoderEditorCollapseButton = ({ onClick, label, isDisabled, isCollapsed }: ...@@ -15,10 +15,8 @@ const CoderEditorCollapseButton = ({ onClick, label, isDisabled, isCollapsed }:
return ( return (
<Box <Box
position="absolute" ml="auto"
right="12px" alignSelf="center"
top="8px"
zIndex="sticky1"
className={ isCollapsed ? 'codicon codicon-search-expand-results' : 'codicon codicon-collapse-all' } className={ isCollapsed ? 'codicon codicon-search-expand-results' : 'codicon codicon-collapse-all' }
opacity={ isDisabled ? 0.6 : 1 } opacity={ isDisabled ? 0.6 : 1 }
boxSize="20px" boxSize="20px"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment