mirror of
https://github.com/luxfi/explore.git
synced 2026-09-24 00:28:18 +00:00
style file explorer
This commit is contained in:
@@ -32,7 +32,7 @@ const CodeEditorFileExplorer = ({ data, onFileSelect }: Props) => {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Box pb="22px">
|
||||
<CoderEditorCollapseButton onClick={ handleCollapseButtonClick } label="Collapse folders"/>
|
||||
<CodeEditorFileTree key={ key } tree={ tree } onItemClick={ handleFileClick } isCollapsed={ key > 0 }/>
|
||||
</Box>
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
import type { ChakraProps } from '@chakra-ui/react';
|
||||
import { Accordion, AccordionButton, AccordionIcon, AccordionItem, AccordionPanel } from '@chakra-ui/react';
|
||||
import { Accordion, AccordionButton, AccordionIcon, AccordionItem, AccordionPanel, Icon, chakra, useColorModeValue } from '@chakra-ui/react';
|
||||
import React from 'react';
|
||||
|
||||
import type { FileTree } from './types';
|
||||
|
||||
import iconFile from './icons/file.svg';
|
||||
import iconFolderOpen from './icons/folder-open.svg';
|
||||
import iconFolder from './icons/folder.svg';
|
||||
import iconSolidity from './icons/solidity.svg';
|
||||
|
||||
interface Props {
|
||||
tree: FileTree;
|
||||
level?: number;
|
||||
@@ -13,35 +18,68 @@ interface Props {
|
||||
|
||||
const CodeEditorFileTree = ({ tree, level = 0, onItemClick, isCollapsed }: Props) => {
|
||||
const itemProps: ChakraProps = {
|
||||
ml: level ? 4 : 0,
|
||||
borderWidth: '0px',
|
||||
cursor: 'pointer',
|
||||
lineHeight: '22px',
|
||||
_last: {
|
||||
borderBottomWidth: '0px',
|
||||
},
|
||||
cursor: 'pointer',
|
||||
};
|
||||
const rowHoverBgColor = useColorModeValue('blackAlpha.200', 'whiteAlpha.200');
|
||||
|
||||
return (
|
||||
<Accordion allowMultiple defaultIndex={ isCollapsed ? undefined : tree.map((item, index) => index) } reduceMotion>
|
||||
{
|
||||
tree.map((leaf, index) => {
|
||||
const leafName = <chakra.span overflow="hidden" textOverflow="ellipsis" whiteSpace="nowrap">{ leaf.name }</chakra.span>;
|
||||
|
||||
if ('children' in leaf) {
|
||||
return (
|
||||
<AccordionItem key={ index } { ...itemProps }>
|
||||
<AccordionButton p={ 0 } _hover={{ bgColor: 'inherit' }} fontSize="sm">
|
||||
<AccordionIcon/>
|
||||
<span>{ leaf.name }</span>
|
||||
</AccordionButton>
|
||||
<AccordionPanel p={ 0 }>
|
||||
<CodeEditorFileTree tree={ leaf.children } level={ level + 1 } onItemClick={ onItemClick } isCollapsed={ isCollapsed }/>
|
||||
</AccordionPanel>
|
||||
{ ({ isExpanded }) => (
|
||||
<>
|
||||
<AccordionButton
|
||||
pr="8px"
|
||||
py="0"
|
||||
pl={ `${ 8 + 8 * level }px` }
|
||||
_hover={{ bgColor: rowHoverBgColor }}
|
||||
fontSize="13px"
|
||||
lineHeight="22px"
|
||||
h="22px"
|
||||
transitionDuration="0"
|
||||
>
|
||||
<AccordionIcon transform={ isExpanded ? 'rotate(0deg)' : 'rotate(-90deg)' } boxSize="16px"/>
|
||||
<Icon as={ isExpanded ? iconFolderOpen : iconFolder } boxSize="16px" mr="4px"/>
|
||||
{ leafName }
|
||||
</AccordionButton>
|
||||
<AccordionPanel p="0">
|
||||
<CodeEditorFileTree tree={ leaf.children } level={ level + 1 } onItemClick={ onItemClick } isCollapsed={ isCollapsed }/>
|
||||
</AccordionPanel>
|
||||
</>
|
||||
) }
|
||||
</AccordionItem>
|
||||
);
|
||||
}
|
||||
|
||||
const icon = /.sol|.yul|.vy$/.test(leaf.name) ? iconSolidity : iconFile;
|
||||
|
||||
return (
|
||||
<AccordionItem key={ index } { ...itemProps } onClick={ onItemClick } data-file-path={ leaf.file_path }>
|
||||
{ leaf.name }
|
||||
<AccordionItem
|
||||
key={ index }
|
||||
{ ...itemProps }
|
||||
pl={ `${ 24 + (level * 8) }px` }
|
||||
pr="8px"
|
||||
onClick={ onItemClick }
|
||||
data-file-path={ leaf.file_path }
|
||||
display="flex"
|
||||
alignItems="center"
|
||||
overflow="hidden"
|
||||
_hover={{
|
||||
bgColor: rowHoverBgColor,
|
||||
}}
|
||||
>
|
||||
<Icon as={ icon } boxSize="16px" mr="4px"/>
|
||||
{ leafName }
|
||||
</AccordionItem>
|
||||
);
|
||||
})
|
||||
|
||||
@@ -71,11 +71,12 @@ const CodeEditorSearch = ({ monaco, data, onFileSelect }: Props) => {
|
||||
}, [ expandedSections.length, searchResults ]);
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Box px={ 2 }>
|
||||
<CoderEditorCollapseButton
|
||||
onClick={ handleToggleCollapseClick }
|
||||
label={ expandedSections.length === 0 ? 'Expand all' : 'Collapse all' }
|
||||
isDisabled={ searchResults.length === 0 }
|
||||
isCollapsed={ expandedSections.length === 0 }
|
||||
/>
|
||||
<Input size="xs" onChange={ handleSearchTermChange } value={ searchTerm } placeholder="Search"/>
|
||||
<Accordion
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { HTMLChakraProps } from '@chakra-ui/react';
|
||||
import { Box, Tab, TabList, TabPanel, TabPanels, Tabs } from '@chakra-ui/react';
|
||||
import { Box, Tab, TabList, TabPanel, TabPanels, Tabs, useColorModeValue } from '@chakra-ui/react';
|
||||
import _throttle from 'lodash/throttle';
|
||||
import React from 'react';
|
||||
|
||||
import type { File, Monaco } from './types';
|
||||
@@ -15,10 +16,13 @@ interface Props {
|
||||
|
||||
const CodeEditorSideBar = ({ onFileSelect, data, monaco }: Props) => {
|
||||
|
||||
const [ isStuck, setIsStuck ] = React.useState(false);
|
||||
|
||||
const tabProps: HTMLChakraProps<'button'> = {
|
||||
fontFamily: 'heading',
|
||||
textTransform: 'uppercase',
|
||||
fontSize: 'xs',
|
||||
fontSize: '11px',
|
||||
lineHeight: '35px',
|
||||
fontWeight: 500,
|
||||
color: 'gray.600',
|
||||
_selected: {
|
||||
@@ -28,10 +32,26 @@ const CodeEditorSideBar = ({ onFileSelect, data, monaco }: Props) => {
|
||||
letterSpacing: 0.3,
|
||||
};
|
||||
|
||||
const bgColor = useColorModeValue('#eee', '#222');
|
||||
|
||||
const handleScrollThrottled = React.useRef(_throttle((event: React.SyntheticEvent) => {
|
||||
setIsStuck((event.target as HTMLDivElement).scrollTop > 0);
|
||||
}, 100));
|
||||
|
||||
return (
|
||||
<Box w="250px" flexShrink={ 0 } bgColor="lightpink" fontSize="sm" overflowY="scroll" px={ 3 }>
|
||||
<Tabs isLazy lazyBehavior="keepMounted" variant="unstyled" size="sm">
|
||||
<TabList columnGap={ 3 } position="sticky" top={ 0 } left={ 0 } bgColor="lightcoral" zIndex="sticky">
|
||||
<Box w="250px" flexShrink={ 0 } bgColor={ bgColor } fontSize="13px" overflowY="scroll" onScroll={ handleScrollThrottled.current }>
|
||||
<Tabs isLazy lazyBehavior="keepMounted" variant="unstyled" size="13px">
|
||||
<TabList
|
||||
columnGap={ 3 }
|
||||
position="sticky"
|
||||
top={ 0 }
|
||||
left={ 0 }
|
||||
bgColor={ bgColor }
|
||||
zIndex="1"
|
||||
px={ 2 }
|
||||
boxShadow={ isStuck ? 'md' : 'none' }
|
||||
borderTopRadius="md"
|
||||
>
|
||||
<Tab { ...tabProps }>Explorer</Tab>
|
||||
<Tab { ...tabProps }>Search</Tab>
|
||||
</TabList>
|
||||
|
||||
@@ -1,28 +1,29 @@
|
||||
import { Flex, IconButton, Tooltip } from '@chakra-ui/react';
|
||||
import { Tooltip, Box } from '@chakra-ui/react';
|
||||
import React from 'react';
|
||||
|
||||
import iconCopy from 'icons/copy.svg';
|
||||
|
||||
interface Props {
|
||||
onClick: () => void;
|
||||
label: string;
|
||||
isDisabled?: boolean;
|
||||
isCollapsed?: boolean;
|
||||
}
|
||||
|
||||
const CoderEditorCollapseButton = ({ onClick, label, isDisabled }: Props) => {
|
||||
const CoderEditorCollapseButton = ({ onClick, label, isDisabled, isCollapsed }: Props) => {
|
||||
return (
|
||||
<Tooltip label={ label } isDisabled={ isDisabled }>
|
||||
<Flex position="absolute" right={ 3 } top={ 2 } zIndex="sticky">
|
||||
<IconButton
|
||||
as={ iconCopy }
|
||||
boxSize={ 4 }
|
||||
variant="unstyled"
|
||||
cursor="pointer"
|
||||
aria-label="collapse"
|
||||
onClick={ onClick }
|
||||
isDisabled={ isDisabled }
|
||||
/>
|
||||
</Flex>
|
||||
<Box
|
||||
position="absolute"
|
||||
right={ 3 }
|
||||
top={ 2 }
|
||||
zIndex="sticky1"
|
||||
className={ isCollapsed ? 'codicon codicon-search-expand-results' : 'codicon codicon-collapse-all' }
|
||||
opacity={ isDisabled ? 0.6 : 1 }
|
||||
_before={{
|
||||
content: isCollapsed ? '"\\eb95"' : '"\\eac5"',
|
||||
}}
|
||||
onClick={ onClick }
|
||||
cursor="pointer"
|
||||
/>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M13 9h5.5L13 3.5V9M6 2h8l6 6v12a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V4c0-1.11.89-2 2-2m5 2H6v16h12v-9h-7V4z" fill="#42a5f5"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 198 B |
@@ -0,0 +1,3 @@
|
||||
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M19 20H4a2 2 0 0 1-2-2V6c0-1.11.89-2 2-2h6l2 2h7a2 2 0 0 1 2 2H4v10l2.14-8h17.07l-2.28 8.5c-.23.87-1.01 1.5-1.93 1.5z" fill="#90a4ae"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 215 B |
@@ -0,0 +1,3 @@
|
||||
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10 4H4c-1.11 0-2 .89-2 2v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-8l-2-2z" fill="#90a4ae"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 182 B |
@@ -0,0 +1,6 @@
|
||||
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<g fill="#0288d1">
|
||||
<path d="m5.747 14.046 6.254 8.61 6.252-8.61-6.254 3.807z"/>
|
||||
<path d="M11.999 1.343 5.747 11.83l6.252 3.807 6.253-3.807z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 228 B |
Reference in New Issue
Block a user