1import { FileCode01Icon, FolderIcon } from '@expo/styleguide-icons'; 2import { HTMLAttributes, ReactNode } from 'react'; 3 4type FileTreeProps = HTMLAttributes<HTMLDivElement> & { 5 files?: string[]; 6}; 7 8type FileObject = { 9 [key: string]: FileObject; 10}; 11 12export function FileTree({ files = [], ...rest }: FileTreeProps) { 13 return ( 14 <div className="text-xs border border-default rounded-md bg-default mb-4 p-2 pb-4" {...rest}> 15 {renderStructure(generateStructure(files))} 16 </div> 17 ); 18} 19 20function generateStructure(files: string[]): FileObject { 21 const structure = {}; 22 files.forEach(path => 23 path.split('/').reduce((acc: FileObject, key) => acc[key] ?? (acc[key] = {}), structure) 24 ); 25 return structure; 26} 27 28function renderStructure(structure: FileObject, level = 0): ReactNode { 29 return Object.entries(structure).map(([key, value]) => { 30 return Object.keys(value).length ? ( 31 <div className="mt-1 pt-1 px-2 rounded-sm flex flex-col"> 32 <div className="flex items-center"> 33 {' '.repeat(level)} 34 <FolderIcon className="text-icon-tertiary mr-2 opacity-60" /> 35 <code className="text-secondary">{key}</code> 36 </div> 37 {renderStructure(value, level + 1)} 38 </div> 39 ) : ( 40 <div className="mt-1 pl-3 pt-1 px-2 rounded-sm flex items-center"> 41 {' '.repeat(level - 1)} 42 <FileCode01Icon className="text-icon-tertiary mr-2" /> 43 <code className="text-default">{key}</code> 44 </div> 45 ); 46 }); 47} 48