Skip to content

Commit 39c5296

Browse files
siddharthkpCompuIves
authored andcommitted
embed: make folders collapsable (codesandbox#2370)
* embed: make folders collapsable * move util functions down * move onClick logic to Files * put logic for default calculation inside lazy
1 parent 9dca49d commit 39c5296

File tree

2 files changed

+93
-32
lines changed

2 files changed

+93
-32
lines changed

packages/app/src/embed/components/File/index.js

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,12 @@ import EntryTitle from 'app/pages/Sandbox/Editor/Workspace/Files/DirectoryEntry/
77
import { LeftOffset } from './elements';
88

99
type Props = {
10-
id: string,
11-
setCurrentModule: (id: string) => void,
1210
title: string,
1311
depth: number,
1412
type: string,
1513
active?: boolean,
1614
alternative?: boolean,
15+
onClick?: () => void,
1716
};
1817

1918
export default class File extends React.PureComponent<Props> {
@@ -22,21 +21,15 @@ export default class File extends React.PureComponent<Props> {
2221
alternative: false,
2322
};
2423

25-
setCurrentModule = () => {
26-
const { id, setCurrentModule } = this.props;
27-
28-
setCurrentModule(id);
29-
};
30-
3124
render() {
32-
const { title, depth, type, active, alternative } = this.props;
25+
const { title, depth, type, active, alternative, onClick } = this.props;
3326
return (
3427
<div>
3528
<Entry
3629
alternative={alternative}
3730
active={active}
38-
onClick={this.setCurrentModule}
3931
type={type}
32+
onClick={onClick}
4033
>
4134
<LeftOffset depth={depth}>
4235
<EntryIcons type={type} />

packages/app/src/embed/components/Files/index.js

Lines changed: 90 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33
import * as React from 'react';
44
import { sortBy } from 'lodash-es';
55

6-
import type { Module, Directory } from '@codesandbox/common/lib/types';
6+
import type {
7+
Module,
8+
Directory as DirectoryType,
9+
} from '@codesandbox/common/lib/types';
710

811
import { isMainModule } from '@codesandbox/common/lib/sandbox/modules';
912
// eslint-disable-next-line import/extensions
@@ -14,8 +17,8 @@ import File from '../File';
1417
import { Container } from './elements';
1518

1619
type Props = {
17-
modules: Array<Module>,
18-
directories: Array<Directory>,
20+
modules: Module[],
21+
directories: DirectoryType[],
1922
directoryId: ?string,
2023
depth?: number,
2124
currentModule: string,
@@ -44,28 +47,21 @@ function Files({
4447

4548
return (
4649
<Container>
47-
{sortBy(childrenDirectories, d => d.title).map(d => (
48-
<div key={d.shortid}>
49-
<File
50-
id={d.id}
51-
shortid={d.shortid}
52-
title={d.title}
53-
type="directory-open"
54-
depth={depth}
55-
setCurrentModule={setCurrentModule}
56-
/>
57-
<Files
58-
modules={modules}
59-
directories={directories}
60-
directoryId={d.shortid}
61-
depth={depth + 1}
50+
{sortBy(childrenDirectories, directory => directory.title).map(
51+
directory => (
52+
<Directory
53+
key={directory.shortid}
54+
directory={directory}
55+
currentModuleId={currentModule}
6256
setCurrentModule={setCurrentModule}
63-
currentModule={currentModule}
6457
template={template}
6558
entry={entry}
59+
modules={modules}
60+
directories={directories}
61+
depth={depth}
6662
/>
67-
</div>
68-
))}
63+
)
64+
)}
6965
{sortBy(childrenModules, m => m.title).map(m => (
7066
<File
7167
id={m.id}
@@ -74,13 +70,85 @@ function Files({
7470
key={m.shortid}
7571
type={getType(m.title)}
7672
depth={depth}
77-
setCurrentModule={setCurrentModule}
7873
active={m.id === currentModule}
7974
alternative={isMainModule(m, modules, directories, entry)}
75+
onClick={() => setCurrentModule(m.id)}
8076
/>
8177
))}
8278
</Container>
8379
);
8480
}
8581

82+
/** Utils to help identify module tree */
83+
84+
const getCurrentModule = (modules, currentModuleId) =>
85+
modules.find(module => module.id === currentModuleId);
86+
87+
const getParentDirectory = (directories, child) =>
88+
directories.find(directory => directory.shortid === child.directoryShortid);
89+
90+
const getCurrentModuleTree = (directories, currentModule) => {
91+
const currentModuleTree = [currentModule];
92+
93+
let parentDirectory = getParentDirectory(directories, currentModule);
94+
95+
while (parentDirectory) {
96+
currentModuleTree.push(parentDirectory);
97+
// get parent directory of the parent directory
98+
parentDirectory = getParentDirectory(directories, parentDirectory);
99+
}
100+
101+
return currentModuleTree;
102+
};
103+
104+
function Directory({
105+
directory,
106+
currentModuleId,
107+
setCurrentModule,
108+
template,
109+
entry,
110+
modules,
111+
directories,
112+
depth,
113+
}) {
114+
/** directory should be open by default if currentModule is inside it */
115+
const [open, setOpen] = React.useState(function() {
116+
const currentModule = getCurrentModule(modules, currentModuleId);
117+
const currentModuleTree = getCurrentModuleTree(directories, currentModule);
118+
119+
let openByDefault = false;
120+
if (currentModuleTree.find(module => module.id === directory.id)) {
121+
openByDefault = true;
122+
}
123+
return openByDefault;
124+
});
125+
126+
return (
127+
<div>
128+
<File
129+
id={directory.id}
130+
shortid={directory.shortid}
131+
title={directory.title}
132+
type={open ? 'directory-open' : 'directory'}
133+
depth={depth}
134+
onClick={() => {
135+
setOpen(!open);
136+
}}
137+
/>
138+
{open ? (
139+
<Files
140+
modules={modules}
141+
directories={directories}
142+
directoryId={directory.shortid}
143+
depth={depth + 1}
144+
currentModule={currentModuleId}
145+
setCurrentModule={setCurrentModule}
146+
template={template}
147+
entry={entry}
148+
/>
149+
) : null}
150+
</div>
151+
);
152+
}
153+
86154
export default Files;

0 commit comments

Comments
 (0)