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