Skip to content

Commit 2394d44

Browse files
feat(file-tree): implement multiline parsing with indentation support, create helper functions for position calculation taking in acount indentation
1 parent 933ff76 commit 2394d44

2 files changed

Lines changed: 33 additions & 14 deletions

File tree

src/common/components/mock-components/front-rich-components/file-tree/file-tree.business.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@ export const joinTextContent = (text: string): string[] => {
66
};
77

88
// Symbol -> + Folder - Subfolder * File
9+
// Level -> Level 0: no indentation in Folder / Level 1: 1 indentation (2 spaces) in Subfolder / Level 2: 2 (4 spaces) indentations in File
910
export interface FileTreeItem {
1011
type: 'folder' | 'subfolder' | 'file';
1112
text: string;
13+
level: number;
1214
}
1315

1416
interface FileTreeDynamicSizeParams {
@@ -21,8 +23,11 @@ interface FileTreeDynamicSizeParams {
2123

2224
export const parseFileTreeText = (text: string): FileTreeItem[] => {
2325
return text
24-
.split(',')
26+
.split('\n')
2527
.map(line => {
28+
// First detect indentation
29+
const indentMatch = line.match(/^(\s*)/);
30+
const level = indentMatch ? Math.floor(indentMatch[1].length / 2) : 0;
2631
const trimmed = line.trim();
2732

2833
if (trimmed === '') return null;
@@ -32,27 +37,31 @@ export const parseFileTreeText = (text: string): FileTreeItem[] => {
3237
return {
3338
type: 'folder',
3439
text: trimmed.substring(2).trim(),
40+
level: level,
3541
};
3642
}
3743

3844
if (trimmed.startsWith('- ')) {
3945
return {
4046
type: 'subfolder',
4147
text: trimmed.substring(2).trim(),
48+
level: level,
4249
};
4350
}
4451

4552
if (trimmed.startsWith('* ')) {
4653
return {
4754
type: 'file',
4855
text: trimmed.substring(2).trim(),
56+
level: level,
4957
};
5058
}
5159

5260
// No symbol: will be treated as a folder
5361
return {
5462
type: 'folder',
5563
text: trimmed,
64+
level: level,
5665
};
5766
})
5867
.filter((item): item is FileTreeItem => item !== null);

src/common/components/mock-components/front-rich-components/file-tree/file-tree.tsx

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,13 @@ import { useShapeProps } from '@/common/components/shapes/use-shape-props.hook';
88
import { BASIC_SHAPE } from '../../front-components/shape.const';
99
import {
1010
calculateFileTreeDynamicSize,
11+
FileTreeItem,
1112
parseFileTreeText,
1213
} from './file-tree.business';
1314

1415
const fileTreeShapeRestrictions: ShapeSizeRestrictions = {
1516
minWidth: 220,
16-
minHeight: 280,
17+
minHeight: 180,
1718
maxWidth: -1,
1819
maxHeight: -1,
1920
defaultWidth: 280,
@@ -57,8 +58,8 @@ export const FileTreeShape = forwardRef<any, FileTreeShapeProps>(
5758
const elementHeight = 60;
5859
const paddingX = 40;
5960
const paddingY = 30;
60-
const fileX = 50 + paddingX;
6161
const iconTextSpacing = 10;
62+
const indentationStep = 10;
6263

6364
const restrictedSize = calculateFileTreeDynamicSize(treeItems, {
6465
width,
@@ -70,12 +71,6 @@ export const FileTreeShape = forwardRef<any, FileTreeShapeProps>(
7071

7172
const { width: restrictedWidth, height: restrictedHeight } = restrictedSize;
7273

73-
const folderTextX = iconWidth + iconTextSpacing + paddingX;
74-
const fileTextX = fileX + iconWidth + iconTextSpacing;
75-
76-
const folderAvailableWidth = restrictedWidth - folderTextX - paddingX;
77-
const fileAvailableWidth = restrictedWidth - fileTextX - paddingX;
78-
7974
const { stroke, strokeStyle, fill, textColor, borderRadius } =
8075
useShapeProps(otherProps, BASIC_SHAPE);
8176

@@ -86,6 +81,23 @@ export const FileTreeShape = forwardRef<any, FileTreeShapeProps>(
8681
ref
8782
);
8883

84+
// Helper functions for position calculations
85+
const calculateIconX = (item: FileTreeItem) => {
86+
return (
87+
paddingX +
88+
item.level * indentationStep +
89+
(item.type === 'file' ? 40 : 0)
90+
);
91+
};
92+
93+
const calculateTextX = (item: FileTreeItem) => {
94+
return calculateIconX(item) + iconWidth + iconTextSpacing;
95+
};
96+
97+
const calculateAvailableWidth = (item: FileTreeItem) => {
98+
return restrictedWidth - calculateTextX(item) - paddingX;
99+
};
100+
89101
useEffect(() => {
90102
Promise.all([
91103
loadSvgWithFill('/icons/folder.svg', stroke),
@@ -120,19 +132,17 @@ export const FileTreeShape = forwardRef<any, FileTreeShapeProps>(
120132
{icons[item.type] && (
121133
<Image
122134
image={icons[item.type]!}
123-
x={item.type === 'file' ? fileX : paddingX}
135+
x={calculateIconX(item)}
124136
y={paddingY + elementHeight * index}
125137
width={iconWidth}
126138
height={iconWidth}
127139
/>
128140
)}
129141
<Text
130-
x={item.type === 'file' ? fileTextX : folderTextX}
142+
x={calculateTextX(item)}
131143
y={paddingY + elementHeight * index + 20}
132144
text={item.text}
133-
width={
134-
item.type === 'file' ? fileAvailableWidth : folderAvailableWidth
135-
}
145+
width={calculateAvailableWidth(item)}
136146
height={elementHeight}
137147
fontFamily={BASIC_SHAPE.DEFAULT_FONT_FAMILY}
138148
fontSize={15}

0 commit comments

Comments
 (0)