vzcode 0.84.0 → 0.86.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/{index-J8-kRnnE.css → index-9yhZQKtK.css} +1 -1
- package/dist/assets/{index-9InCi-kT.js → index-DzsReLik.js} +53 -54
- package/dist/index.html +2 -2
- package/package.json +2 -2
- package/src/client/CodeEditor/InteractiveWidgets/boolToggler.ts +12 -0
- package/src/client/CodeEditor/InteractiveWidgets/colorPicker.ts +91 -0
- package/src/client/CodeEditor/InteractiveWidgets/colorsInTextPlugin.ts +139 -0
- package/src/client/CodeEditor/InteractiveWidgets/highlightWidgets.ts +79 -0
- package/src/client/CodeEditor/InteractiveWidgets/index.ts +44 -0
- package/src/client/CodeEditor/InteractiveWidgets/markdownCheckboxToggler.ts +12 -0
- package/src/client/CodeEditor/InteractiveWidgets/numberDragger.ts +20 -0
- package/src/client/CodeEditor/InteractiveWidgets/rotateWidget.ts +143 -0
- package/src/client/CodeEditor/InteractiveWidgets/urlClicker.test.ts +48 -0
- package/src/client/CodeEditor/InteractiveWidgets/urlClicker.ts +12 -0
- package/src/client/CodeEditor/InteractiveWidgets/vec2Slider.ts +25 -0
- package/src/client/CodeEditor/getOrCreateEditor.ts +4 -3
- package/src/client/VZCodeContext.tsx +36 -0
- package/src/client/VZLeft.tsx +2 -0
- package/src/client/VZSettings.tsx +14 -17
- package/src/client/VZSidebar/CreateDirModal.tsx +99 -0
- package/src/client/VZSidebar/index.tsx +21 -1
- package/src/client/VZSidebar/useDragAndDrop.tsx +29 -18
- package/src/client/useFileCRUD.ts +18 -0
- package/src/server/index.js +8 -2
- package/src/client/CodeEditor/widgets.ts +0 -509
|
@@ -57,6 +57,10 @@ export type VZCodeContextValue = {
|
|
|
57
57
|
createFile: (fileName: string, text?: string) => void;
|
|
58
58
|
renameFile: (fileId: string, fileName: string) => void;
|
|
59
59
|
deleteFile: (fileId: string) => void;
|
|
60
|
+
createDirectory: (
|
|
61
|
+
fileName: string,
|
|
62
|
+
text?: string,
|
|
63
|
+
) => void;
|
|
60
64
|
renameDirectory: (
|
|
61
65
|
directoryId: string,
|
|
62
66
|
directoryOldName: string,
|
|
@@ -107,6 +111,12 @@ export type VZCodeContextValue = {
|
|
|
107
111
|
handleOpenCreateFileModal: () => void;
|
|
108
112
|
handleCloseCreateFileModal: () => void;
|
|
109
113
|
handleCreateFileClick: (newFileName: string) => void;
|
|
114
|
+
|
|
115
|
+
isCreateDirModalOpen: boolean;
|
|
116
|
+
handleOpenCreateDirModal: () => void;
|
|
117
|
+
handleCloseCreateDirModal: () => void;
|
|
118
|
+
handleCreateDirClick: (newFileName: string) => void;
|
|
119
|
+
|
|
110
120
|
runPrettierRef: React.MutableRefObject<
|
|
111
121
|
null | (() => void)
|
|
112
122
|
>;
|
|
@@ -237,6 +247,7 @@ export const VZCodeProvider = ({
|
|
|
237
247
|
createFile,
|
|
238
248
|
renameFile,
|
|
239
249
|
deleteFile,
|
|
250
|
+
createDirectory,
|
|
240
251
|
renameDirectory,
|
|
241
252
|
deleteDirectory,
|
|
242
253
|
} = useFileCRUD({
|
|
@@ -265,6 +276,26 @@ export const VZCodeProvider = ({
|
|
|
265
276
|
[createFile, setIsCreateFileModalOpen],
|
|
266
277
|
);
|
|
267
278
|
|
|
279
|
+
// State to control the create directory modal's visibility
|
|
280
|
+
const [isCreateDirModalOpen, setIsCreateDirModalOpen] =
|
|
281
|
+
useState(false);
|
|
282
|
+
|
|
283
|
+
const handleOpenCreateDirModal = useCallback(() => {
|
|
284
|
+
setIsCreateDirModalOpen(true);
|
|
285
|
+
}, []);
|
|
286
|
+
|
|
287
|
+
const handleCloseCreateDirModal = useCallback(() => {
|
|
288
|
+
setIsCreateDirModalOpen(false);
|
|
289
|
+
}, []);
|
|
290
|
+
|
|
291
|
+
const handleCreateDirClick = useCallback(
|
|
292
|
+
(newDirName: string) => {
|
|
293
|
+
createDirectory(newDirName);
|
|
294
|
+
setIsCreateDirModalOpen(false);
|
|
295
|
+
},
|
|
296
|
+
[createDirectory, setIsCreateDirModalOpen],
|
|
297
|
+
);
|
|
298
|
+
|
|
268
299
|
// Isolate the files object from the document.
|
|
269
300
|
const files: Files | null = content
|
|
270
301
|
? content.files
|
|
@@ -296,6 +327,7 @@ export const VZCodeProvider = ({
|
|
|
296
327
|
createFile,
|
|
297
328
|
renameFile,
|
|
298
329
|
deleteFile,
|
|
330
|
+
createDirectory,
|
|
299
331
|
renameDirectory,
|
|
300
332
|
deleteDirectory,
|
|
301
333
|
|
|
@@ -333,6 +365,10 @@ export const VZCodeProvider = ({
|
|
|
333
365
|
handleOpenCreateFileModal,
|
|
334
366
|
handleCloseCreateFileModal,
|
|
335
367
|
handleCreateFileClick,
|
|
368
|
+
isCreateDirModalOpen,
|
|
369
|
+
handleOpenCreateDirModal,
|
|
370
|
+
handleCloseCreateDirModal,
|
|
371
|
+
handleCreateDirClick,
|
|
336
372
|
runPrettierRef,
|
|
337
373
|
runCodeRef,
|
|
338
374
|
|
package/src/client/VZLeft.tsx
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { VZSettings } from './VZSettings';
|
|
2
2
|
import { VZSidebar } from './VZSidebar';
|
|
3
3
|
import { CreateFileModal } from './VZSidebar/CreateFileModal';
|
|
4
|
+
import { CreateDirModal } from './VZSidebar/CreateDirModal';
|
|
4
5
|
|
|
5
6
|
// The middle portion of the VZCode environment, containing:
|
|
6
7
|
// * The sidebar
|
|
@@ -14,6 +15,7 @@ export const VZLeft = ({ enableUsernameField = true }) => {
|
|
|
14
15
|
enableUsernameField={enableUsernameField}
|
|
15
16
|
/>
|
|
16
17
|
<CreateFileModal />
|
|
18
|
+
<CreateDirModal />
|
|
17
19
|
</div>
|
|
18
20
|
);
|
|
19
21
|
};
|
|
@@ -34,27 +34,24 @@ export const VZSettings = ({
|
|
|
34
34
|
[],
|
|
35
35
|
);
|
|
36
36
|
|
|
37
|
-
//
|
|
38
|
-
|
|
39
|
-
const [
|
|
40
|
-
useState('Roboto Mono');
|
|
41
|
-
const [selectedFontSize, setSelectedFontSize] =
|
|
42
|
-
useState('16px');
|
|
37
|
+
// Initialize font and size from localStorage or defaults
|
|
38
|
+
const [selectedFont, setSelectedFont] = useState(localStorage.getItem('vzcodeSelectedFont') || 'Roboto Mono');
|
|
39
|
+
const [selectedFontSize, setSelectedFontSize] = useState(localStorage.getItem('vzcodeSelectedFontSize') || '16px');
|
|
43
40
|
|
|
44
41
|
// Called when the user selects a different font
|
|
45
|
-
const handleFontChange = useCallback(
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
);
|
|
42
|
+
const handleFontChange = useCallback((event: React.ChangeEvent<HTMLSelectElement>) => {
|
|
43
|
+
const newFont = event.target.value;
|
|
44
|
+
localStorage.setItem('vzcodeSelectedFont', newFont);
|
|
45
|
+
setSelectedFont(newFont);
|
|
46
|
+
}, []);
|
|
51
47
|
|
|
52
48
|
// Called when the user selects a different font size
|
|
53
|
-
const handleFontSizeChange = (
|
|
54
|
-
event
|
|
55
|
-
|
|
56
|
-
setSelectedFontSize(
|
|
57
|
-
};
|
|
49
|
+
const handleFontSizeChange = useCallback((event: React.ChangeEvent<HTMLSelectElement>) => {
|
|
50
|
+
const newSize = event.target.value;
|
|
51
|
+
localStorage.setItem('vzcodeSelectedFontSize', newSize);
|
|
52
|
+
setSelectedFontSize(newSize);
|
|
53
|
+
}, []);
|
|
54
|
+
|
|
58
55
|
|
|
59
56
|
useEffect(() => {
|
|
60
57
|
document.body.style.setProperty(
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import {
|
|
2
|
+
useState,
|
|
3
|
+
useCallback,
|
|
4
|
+
useRef,
|
|
5
|
+
useEffect,
|
|
6
|
+
useContext,
|
|
7
|
+
} from 'react';
|
|
8
|
+
import { Modal, Form, Button } from '../bootstrap';
|
|
9
|
+
import { VZCodeContext } from '../VZCodeContext';
|
|
10
|
+
|
|
11
|
+
export const CreateDirModal = ({
|
|
12
|
+
initialFileName = '',
|
|
13
|
+
}) => {
|
|
14
|
+
const [newName, setNewName] = useState(initialFileName);
|
|
15
|
+
const inputRef = useRef(null);
|
|
16
|
+
|
|
17
|
+
const {
|
|
18
|
+
isCreateDirModalOpen,
|
|
19
|
+
handleCloseCreateDirModal,
|
|
20
|
+
handleCreateDirClick,
|
|
21
|
+
} = useContext(VZCodeContext);
|
|
22
|
+
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
if (isCreateDirModalOpen && inputRef.current) {
|
|
25
|
+
inputRef.current.focus();
|
|
26
|
+
}
|
|
27
|
+
}, [isCreateDirModalOpen]);
|
|
28
|
+
|
|
29
|
+
const handleNameChange = useCallback((event) => {
|
|
30
|
+
setNewName(event.target.value);
|
|
31
|
+
}, []);
|
|
32
|
+
|
|
33
|
+
const onCreateClick = useCallback(() => {
|
|
34
|
+
handleCreateDirClick(newName);
|
|
35
|
+
setNewName('');
|
|
36
|
+
}, [newName, handleCreateDirClick]);
|
|
37
|
+
|
|
38
|
+
// Returns true if file name is valid, false otherwise.
|
|
39
|
+
const validateFileName = useCallback(
|
|
40
|
+
(fileName: string) => {
|
|
41
|
+
const regex =
|
|
42
|
+
/^[a-zA-Z0-9](?:[a-zA-Z0-9 ./+=_-]*[a-zA-Z0-9])?$/;
|
|
43
|
+
return regex.test(fileName);
|
|
44
|
+
},
|
|
45
|
+
[],
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
const handleKeyDown = useCallback(
|
|
49
|
+
(e) => {
|
|
50
|
+
if (
|
|
51
|
+
e.key === 'Enter' &&
|
|
52
|
+
validateFileName(newName) &&
|
|
53
|
+
(e.ctrlKey ||
|
|
54
|
+
e.shiftKey ||
|
|
55
|
+
(!e.altKey && !e.metaKey))
|
|
56
|
+
) {
|
|
57
|
+
onCreateClick();
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
[onCreateClick, validateFileName, newName],
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
return isCreateDirModalOpen ? (
|
|
64
|
+
<Modal
|
|
65
|
+
show={isCreateDirModalOpen}
|
|
66
|
+
onHide={handleCloseCreateDirModal}
|
|
67
|
+
animation={false}
|
|
68
|
+
onKeyDown={handleKeyDown}
|
|
69
|
+
>
|
|
70
|
+
<Modal.Header closeButton>
|
|
71
|
+
<Modal.Title>Create Directory</Modal.Title>
|
|
72
|
+
</Modal.Header>
|
|
73
|
+
<Modal.Body>
|
|
74
|
+
<Form.Group className="mb-3" controlId="fileName">
|
|
75
|
+
<Form.Label>Directory Name</Form.Label>
|
|
76
|
+
<Form.Control
|
|
77
|
+
type="text"
|
|
78
|
+
value={newName}
|
|
79
|
+
onChange={handleNameChange}
|
|
80
|
+
ref={inputRef}
|
|
81
|
+
spellCheck="false"
|
|
82
|
+
/>
|
|
83
|
+
<Form.Text className="text-muted">
|
|
84
|
+
Enter the name for your file
|
|
85
|
+
</Form.Text>
|
|
86
|
+
</Form.Group>
|
|
87
|
+
</Modal.Body>
|
|
88
|
+
<Modal.Footer>
|
|
89
|
+
<Button
|
|
90
|
+
variant="primary"
|
|
91
|
+
onClick={onCreateClick}
|
|
92
|
+
disabled={!validateFileName(newName)}
|
|
93
|
+
>
|
|
94
|
+
Create Directory
|
|
95
|
+
</Button>
|
|
96
|
+
</Modal.Footer>
|
|
97
|
+
</Modal>
|
|
98
|
+
) : null;
|
|
99
|
+
};
|
|
@@ -14,7 +14,7 @@ import { getFileTree } from '../getFileTree';
|
|
|
14
14
|
import { sortFileTree } from '../sortFileTree';
|
|
15
15
|
import { disableSettings } from '../featureFlags';
|
|
16
16
|
import { SplitPaneResizeContext } from '../SplitPaneResizeContext';
|
|
17
|
-
import { BugSVG, GearSVG, NewSVG } from '../Icons';
|
|
17
|
+
import { BugSVG, GearSVG, NewSVG, FileSVG } from '../Icons';
|
|
18
18
|
import { Listing } from './Listing';
|
|
19
19
|
import { VZCodeContext } from '../VZCodeContext';
|
|
20
20
|
import { useDragAndDrop } from './useDragAndDrop';
|
|
@@ -27,10 +27,12 @@ const enableConnectionStatus = true;
|
|
|
27
27
|
|
|
28
28
|
export const VZSidebar = ({
|
|
29
29
|
createFileTooltipText = 'New File',
|
|
30
|
+
createDirTooltipText = 'New Directory',
|
|
30
31
|
openSettingsTooltipText = 'Open Settings',
|
|
31
32
|
reportBugTooltipText = 'Report Bug',
|
|
32
33
|
}: {
|
|
33
34
|
createFileTooltipText?: string;
|
|
35
|
+
createDirTooltipText?: string;
|
|
34
36
|
openSettingsTooltipText?: string;
|
|
35
37
|
reportBugTooltipText?: string;
|
|
36
38
|
}) => {
|
|
@@ -46,6 +48,7 @@ export const VZSidebar = ({
|
|
|
46
48
|
isDirectoryOpen,
|
|
47
49
|
toggleDirectory,
|
|
48
50
|
handleOpenCreateFileModal,
|
|
51
|
+
handleOpenCreateDirModal,
|
|
49
52
|
connected,
|
|
50
53
|
} = useContext(VZCodeContext);
|
|
51
54
|
|
|
@@ -157,6 +160,23 @@ export const VZSidebar = ({
|
|
|
157
160
|
<NewSVG />
|
|
158
161
|
</i>
|
|
159
162
|
</OverlayTrigger>
|
|
163
|
+
|
|
164
|
+
{/*Directory Rename*/}
|
|
165
|
+
<OverlayTrigger
|
|
166
|
+
placement="left"
|
|
167
|
+
overlay={
|
|
168
|
+
<Tooltip id="create-dir-tooltip">
|
|
169
|
+
{createDirTooltipText}
|
|
170
|
+
</Tooltip>
|
|
171
|
+
}
|
|
172
|
+
>
|
|
173
|
+
<i
|
|
174
|
+
onClick={handleOpenCreateDirModal}
|
|
175
|
+
className="icon-button icon-button-dark"
|
|
176
|
+
>
|
|
177
|
+
<FileSVG />
|
|
178
|
+
</i>
|
|
179
|
+
</OverlayTrigger>
|
|
160
180
|
</div>
|
|
161
181
|
</div>
|
|
162
182
|
{isDragOver ? (
|
|
@@ -37,24 +37,35 @@ export const useDragAndDrop = () => {
|
|
|
37
37
|
event.preventDefault();
|
|
38
38
|
event.stopPropagation();
|
|
39
39
|
setIsDragOver(false);
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
40
|
+
|
|
41
|
+
const items = event.dataTransfer.items;
|
|
42
|
+
|
|
43
|
+
const processEntry = (entry, path) => {
|
|
44
|
+
if (entry.isFile) {
|
|
45
|
+
entry.file((file) => {
|
|
46
|
+
const reader = new FileReader();
|
|
47
|
+
reader.onload = (e) => {
|
|
48
|
+
const content = e.target.result as string;
|
|
49
|
+
createFile(`${path}${file.name}`, content);
|
|
50
|
+
};
|
|
51
|
+
reader.readAsText(file);
|
|
52
|
+
});
|
|
53
|
+
} else if (entry.isDirectory) {
|
|
54
|
+
const dirReader = entry.createReader();
|
|
55
|
+
dirReader.readEntries((entries) => {
|
|
56
|
+
const newPath = `${path}${entry.name}/`;
|
|
57
|
+
for (const entry of entries) {
|
|
58
|
+
processEntry(entry, newPath);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
const itemsArray = Array.from(items);
|
|
64
|
+
itemsArray.forEach((item) => {
|
|
65
|
+
const entry = item.webkitGetAsEntry();
|
|
66
|
+
if (entry) {
|
|
67
|
+
processEntry(entry, '');
|
|
68
|
+
}
|
|
58
69
|
});
|
|
59
70
|
},
|
|
60
71
|
[createFile],
|
|
@@ -45,6 +45,23 @@ export const useFileCRUD = ({
|
|
|
45
45
|
[submitOperation],
|
|
46
46
|
);
|
|
47
47
|
|
|
48
|
+
const createDirectory = useCallback(
|
|
49
|
+
(name: string, text = null) => {
|
|
50
|
+
if (name) {
|
|
51
|
+
name += '/';
|
|
52
|
+
const fileId: FileId = randomId();
|
|
53
|
+
submitOperation((document: VZCodeContent) => ({
|
|
54
|
+
...document,
|
|
55
|
+
files: {
|
|
56
|
+
...document.files,
|
|
57
|
+
[fileId]: { name, text },
|
|
58
|
+
},
|
|
59
|
+
}));
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
[submitOperation],
|
|
63
|
+
);
|
|
64
|
+
|
|
48
65
|
// Called when a file in the sidebar is renamed.
|
|
49
66
|
const renameFile = useCallback(
|
|
50
67
|
(fileId: FileId, newName: string) => {
|
|
@@ -148,6 +165,7 @@ export const useFileCRUD = ({
|
|
|
148
165
|
createFile,
|
|
149
166
|
renameFile,
|
|
150
167
|
deleteFile,
|
|
168
|
+
createDirectory,
|
|
151
169
|
renameDirectory,
|
|
152
170
|
deleteDirectory,
|
|
153
171
|
};
|
package/src/server/index.js
CHANGED
|
@@ -217,10 +217,16 @@ const save = () => {
|
|
|
217
217
|
}
|
|
218
218
|
}
|
|
219
219
|
|
|
220
|
-
// Handle creating files.
|
|
220
|
+
// Handle creating files and Directories.
|
|
221
221
|
if (!previous && current) {
|
|
222
|
-
|
|
222
|
+
//File Creation
|
|
223
|
+
if(!isDirectory(current.name)){
|
|
224
|
+
fs.writeFileSync(current.name, current.text);
|
|
225
|
+
}else{
|
|
226
|
+
fs.mkdirSync(current.name, { recursive: true });
|
|
227
|
+
}
|
|
223
228
|
}
|
|
229
|
+
|
|
224
230
|
}
|
|
225
231
|
// TODO deleted all directories under directoriesToDelete
|
|
226
232
|
|