vzcode 0.17.0 → 0.19.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/README.md +47 -39
- package/dist/assets/index-0053b846.css +1 -0
- package/dist/assets/index-34134182.js +118 -0
- package/dist/index.html +15 -5
- package/package.json +4 -4
- package/src/client/App.tsx +92 -52
- package/src/client/CodeEditor/getOrCreateEditor.ts +33 -9
- package/src/client/CodeEditor/index.tsx +15 -11
- package/src/client/CodeEditor/json1PresenceBroadcast.js +10 -3
- package/src/client/CodeEditor/json1PresenceDisplay.js +7 -2
- package/src/client/CodeEditor/widgets.ts +5 -1
- package/src/client/Resizer/index.tsx +96 -0
- package/src/client/Resizer/styles.scss +29 -0
- package/src/client/Settings.tsx +29 -21
- package/src/client/Sidebar/DirectoryArrowSVG.jsx +4 -1
- package/src/client/Sidebar/DirectoryListing.tsx +17 -5
- package/src/client/Sidebar/FileListing.tsx +4 -1
- package/src/client/Sidebar/Listing.tsx +9 -2
- package/src/client/Sidebar/index.tsx +30 -8
- package/src/client/Sidebar/styles.scss +0 -1
- package/src/client/SplitPaneResizeContext.tsx +77 -0
- package/src/client/TabList/index.tsx +7 -2
- package/src/client/diff.js +7 -1
- package/src/client/featureFlags.js +2 -1
- package/src/client/sortFileTree.ts +3 -1
- package/src/client/style.scss +18 -12
- package/src/client/themes.ts +10 -8
- package/src/client/useDynamicTheme.ts +5 -2
- package/src/client/useOpenDirectories.ts +11 -8
- package/src/client/usePrettier/index.ts +76 -57
- package/src/client/usePrettier/worker.ts +4 -1
- package/src/client/useTabsState.ts +10 -3
- package/src/randomId.js +14 -1
- package/src/server/computeInitialDocument.js +18 -5
- package/src/server/index.js +7 -2
- package/src/types.ts +11 -4
- package/dist/assets/index-ab3ae13e.js +0 -115
- package/dist/assets/index-ccd52a89.css +0 -1
package/src/client/Settings.tsx
CHANGED
|
@@ -3,7 +3,11 @@ import Modal from 'react-bootstrap/Modal';
|
|
|
3
3
|
import Form from 'react-bootstrap/Form';
|
|
4
4
|
import Button from 'react-bootstrap/Button';
|
|
5
5
|
import Select from 'react-select';
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
ThemeLabel,
|
|
8
|
+
themeOptionsByLabel,
|
|
9
|
+
themes,
|
|
10
|
+
} from './themes';
|
|
7
11
|
|
|
8
12
|
const saveTimes = [
|
|
9
13
|
{ value: 1, label: '1 second' },
|
|
@@ -25,25 +29,21 @@ export const Settings = ({
|
|
|
25
29
|
}) => {
|
|
26
30
|
const handleChange = useCallback((selectedOption) => {
|
|
27
31
|
setTheme(selectedOption.label);
|
|
28
|
-
// TODO make this work.
|
|
29
|
-
// Sketch of algorithm:
|
|
30
|
-
// for each editor in the editor cache,
|
|
31
|
-
// update the theme
|
|
32
|
-
// editor.dispatch({
|
|
33
|
-
// effects: themeSet.reconfigure(selectedOption.value),
|
|
34
|
-
// });
|
|
35
32
|
}, []);
|
|
36
33
|
|
|
37
|
-
const handleSaveTimeChange = useCallback(
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
34
|
+
const handleSaveTimeChange = useCallback(
|
|
35
|
+
(selectedOption) => {
|
|
36
|
+
const time = [{ value: selectedOption.value }];
|
|
37
|
+
fetch('/saveTime', {
|
|
38
|
+
method: 'POST',
|
|
39
|
+
headers: {
|
|
40
|
+
'Content-Type': 'application/json',
|
|
41
|
+
},
|
|
42
|
+
body: JSON.stringify(time),
|
|
43
|
+
});
|
|
44
|
+
},
|
|
45
|
+
[],
|
|
46
|
+
);
|
|
47
47
|
|
|
48
48
|
return show ? (
|
|
49
49
|
<Modal
|
|
@@ -58,7 +58,10 @@ export const Settings = ({
|
|
|
58
58
|
<Modal.Body>
|
|
59
59
|
<Form.Group className="mb-3" controlId="formFork">
|
|
60
60
|
<Form.Label>Username</Form.Label>
|
|
61
|
-
<Form.Control
|
|
61
|
+
<Form.Control
|
|
62
|
+
type="text"
|
|
63
|
+
placeholder="Enter username"
|
|
64
|
+
/>
|
|
62
65
|
<Form.Text className="text-muted">
|
|
63
66
|
Enter a username to be displayed on your cursor
|
|
64
67
|
</Form.Text>
|
|
@@ -76,8 +79,13 @@ export const Settings = ({
|
|
|
76
79
|
</Form.Group>
|
|
77
80
|
<Form.Group className="mb-3" controlId="formFork">
|
|
78
81
|
<Form.Label>Auto-Save Time</Form.Label>
|
|
79
|
-
<Select
|
|
80
|
-
|
|
82
|
+
<Select
|
|
83
|
+
options={saveTimes}
|
|
84
|
+
onChange={handleSaveTimeChange}
|
|
85
|
+
/>
|
|
86
|
+
<Form.Text className="text-muted">
|
|
87
|
+
Select an auto save time
|
|
88
|
+
</Form.Text>
|
|
81
89
|
</Form.Group>
|
|
82
90
|
</Modal.Body>
|
|
83
91
|
<Modal.Footer>
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
export const DirectoryArrowSVG = ({
|
|
1
|
+
export const DirectoryArrowSVG = ({
|
|
2
|
+
height = 10,
|
|
3
|
+
fill = 'currentcolor',
|
|
4
|
+
}) => (
|
|
2
5
|
<svg height={height} viewBox={'4 4 16 16'}>
|
|
3
6
|
<path fill={fill} d="M8 17l9-5-9-5v10z" />
|
|
4
7
|
</svg>
|
|
@@ -18,7 +18,10 @@ export const DirectoryListing = ({
|
|
|
18
18
|
path: string;
|
|
19
19
|
children: Array<FileTree | FileTreeFile>;
|
|
20
20
|
handleRenameFileClick: (fileId: string) => void;
|
|
21
|
-
handleDeleteFileClick: (
|
|
21
|
+
handleDeleteFileClick: (
|
|
22
|
+
fileId: string,
|
|
23
|
+
event: React.MouseEvent,
|
|
24
|
+
) => void;
|
|
22
25
|
handleFileClick: (fileId: string) => void;
|
|
23
26
|
isDirectoryOpen: (path: string) => boolean;
|
|
24
27
|
toggleDirectory: (path: string) => void;
|
|
@@ -35,7 +38,10 @@ export const DirectoryListing = ({
|
|
|
35
38
|
console.log('TODO handleRenameDirectoryClick');
|
|
36
39
|
}, []);
|
|
37
40
|
|
|
38
|
-
const isOpen = useMemo(
|
|
41
|
+
const isOpen = useMemo(
|
|
42
|
+
() => isDirectoryOpen(path),
|
|
43
|
+
[isDirectoryOpen, path],
|
|
44
|
+
);
|
|
39
45
|
|
|
40
46
|
return (
|
|
41
47
|
<>
|
|
@@ -47,7 +53,9 @@ export const DirectoryListing = ({
|
|
|
47
53
|
>
|
|
48
54
|
<div
|
|
49
55
|
className="arrow-wrapper"
|
|
50
|
-
style={{
|
|
56
|
+
style={{
|
|
57
|
+
transform: `rotate(${isOpen ? 90 : 0}deg)`,
|
|
58
|
+
}}
|
|
51
59
|
>
|
|
52
60
|
<DirectoryArrowSVG />
|
|
53
61
|
</div>
|
|
@@ -62,8 +70,12 @@ export const DirectoryListing = ({
|
|
|
62
70
|
<Listing
|
|
63
71
|
entity={entity}
|
|
64
72
|
key={fileId || path}
|
|
65
|
-
handleRenameFileClick={
|
|
66
|
-
|
|
73
|
+
handleRenameFileClick={
|
|
74
|
+
handleRenameFileClick
|
|
75
|
+
}
|
|
76
|
+
handleDeleteFileClick={
|
|
77
|
+
handleDeleteFileClick
|
|
78
|
+
}
|
|
67
79
|
handleFileClick={handleFileClick}
|
|
68
80
|
isDirectoryOpen={isDirectoryOpen}
|
|
69
81
|
toggleDirectory={toggleDirectory}
|
|
@@ -12,7 +12,10 @@ export const FileListing = ({
|
|
|
12
12
|
name: string;
|
|
13
13
|
fileId: FileId;
|
|
14
14
|
handleRenameFileClick: (fileId: FileId) => void;
|
|
15
|
-
handleDeleteFileClick: (
|
|
15
|
+
handleDeleteFileClick: (
|
|
16
|
+
fileId: FileId,
|
|
17
|
+
event: React.MouseEvent,
|
|
18
|
+
) => void;
|
|
16
19
|
handleFileClick: (fileId: FileId) => void;
|
|
17
20
|
}) => {
|
|
18
21
|
const handleClick = useCallback(() => {
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { DirectoryListing } from './DirectoryListing';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
FileId,
|
|
4
|
+
FileTree,
|
|
5
|
+
FileTreeFile,
|
|
6
|
+
} from '../../types';
|
|
3
7
|
import { FileListing } from './FileListing';
|
|
4
8
|
|
|
5
9
|
// A "Listing" is a "FileListing" or a "DirectoryListing"
|
|
@@ -14,7 +18,10 @@ export const Listing = ({
|
|
|
14
18
|
}: {
|
|
15
19
|
entity: FileTree | FileTreeFile;
|
|
16
20
|
handleRenameFileClick: (fileId: FileId) => void;
|
|
17
|
-
handleDeleteFileClick: (
|
|
21
|
+
handleDeleteFileClick: (
|
|
22
|
+
fileId: FileId,
|
|
23
|
+
event: React.MouseEvent,
|
|
24
|
+
) => void;
|
|
18
25
|
handleFileClick: (fileId: FileId) => void;
|
|
19
26
|
isDirectoryOpen: (path: string) => boolean;
|
|
20
27
|
toggleDirectory: (path: string) => void;
|
|
@@ -1,11 +1,16 @@
|
|
|
1
|
-
import { useCallback, useMemo } from 'react';
|
|
1
|
+
import { useCallback, useContext, useMemo } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
FileId,
|
|
4
|
+
FileTree,
|
|
5
|
+
FileTreeFile,
|
|
6
|
+
Files,
|
|
7
|
+
} from '../../types';
|
|
2
8
|
import { getFileTree } from '../getFileTree';
|
|
3
9
|
import { sortFileTree } from '../sortFileTree';
|
|
4
10
|
import { disableSettings } from '../featureFlags';
|
|
11
|
+
import { SplitPaneResizeContext } from '../SplitPaneResizeContext';
|
|
5
12
|
import { Listing } from './Listing';
|
|
6
|
-
|
|
7
13
|
import './styles.scss';
|
|
8
|
-
import { FileId, FileTree, FileTreeFile, Files } from '../../types';
|
|
9
14
|
|
|
10
15
|
export const Sidebar = ({
|
|
11
16
|
createFile,
|
|
@@ -20,7 +25,10 @@ export const Sidebar = ({
|
|
|
20
25
|
files: Files;
|
|
21
26
|
createFile?: () => void;
|
|
22
27
|
handleRenameFileClick?: (fileId: FileId) => void;
|
|
23
|
-
handleDeleteFileClick?: (
|
|
28
|
+
handleDeleteFileClick?: (
|
|
29
|
+
fileId: FileId,
|
|
30
|
+
event: React.MouseEvent,
|
|
31
|
+
) => void;
|
|
24
32
|
handleFileClick?: (fileId: FileId) => void;
|
|
25
33
|
setIsSettingsOpen?: (isSettingsOpen: boolean) => void;
|
|
26
34
|
isDirectoryOpen?: (path: string) => boolean;
|
|
@@ -35,8 +43,15 @@ export const Sidebar = ({
|
|
|
35
43
|
setIsSettingsOpen(true);
|
|
36
44
|
}, []);
|
|
37
45
|
|
|
46
|
+
const { codeEditorWidth } = useContext(
|
|
47
|
+
SplitPaneResizeContext,
|
|
48
|
+
);
|
|
49
|
+
|
|
38
50
|
return (
|
|
39
|
-
<div
|
|
51
|
+
<div
|
|
52
|
+
className="vz-sidebar"
|
|
53
|
+
style={{ width: codeEditorWidth + 'px' }}
|
|
54
|
+
>
|
|
40
55
|
<div className="files">
|
|
41
56
|
<div className="full-box">
|
|
42
57
|
<div>
|
|
@@ -61,8 +76,12 @@ export const Sidebar = ({
|
|
|
61
76
|
<Listing
|
|
62
77
|
entity={entity}
|
|
63
78
|
key={key}
|
|
64
|
-
handleRenameFileClick={
|
|
65
|
-
|
|
79
|
+
handleRenameFileClick={
|
|
80
|
+
handleRenameFileClick
|
|
81
|
+
}
|
|
82
|
+
handleDeleteFileClick={
|
|
83
|
+
handleDeleteFileClick
|
|
84
|
+
}
|
|
66
85
|
handleFileClick={handleFileClick}
|
|
67
86
|
isDirectoryOpen={isDirectoryOpen}
|
|
68
87
|
toggleDirectory={toggleDirectory}
|
|
@@ -72,7 +91,10 @@ export const Sidebar = ({
|
|
|
72
91
|
: null}
|
|
73
92
|
</div>
|
|
74
93
|
{disableSettings ? null : (
|
|
75
|
-
<div
|
|
94
|
+
<div
|
|
95
|
+
className="settings"
|
|
96
|
+
onClick={handleSettingsClick}
|
|
97
|
+
>
|
|
76
98
|
Settings
|
|
77
99
|
</div>
|
|
78
100
|
)}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// From https://github.com/vizhub-core/vizhub/edit/main/vizhub-v2/packages/neoFrontend/src/pages/VizPage/SplitPaneResizeContext/index.js
|
|
2
|
+
import {
|
|
3
|
+
useState,
|
|
4
|
+
createContext,
|
|
5
|
+
useReducer,
|
|
6
|
+
useEffect,
|
|
7
|
+
} from 'react';
|
|
8
|
+
|
|
9
|
+
export const SplitPaneResizeContext = createContext<{
|
|
10
|
+
codeEditorWidth: number;
|
|
11
|
+
moveSplitPane: (a: number) => void;
|
|
12
|
+
isDragging: boolean;
|
|
13
|
+
setIsDragging: (a: boolean) => void;
|
|
14
|
+
}>(null);
|
|
15
|
+
|
|
16
|
+
// The amount of time to wait idle before writing to localStorage.
|
|
17
|
+
// This is to avoid writing to localStorage on every resize event.
|
|
18
|
+
// MS = milliseconds
|
|
19
|
+
const localStorageWriteDebounceMS = 800;
|
|
20
|
+
|
|
21
|
+
const localStoragePropertyName = 'vizHubCodeEditorWidth';
|
|
22
|
+
|
|
23
|
+
const initialWidthDefault = 220;
|
|
24
|
+
let initialWidth: number = initialWidthDefault;
|
|
25
|
+
|
|
26
|
+
// If we're in the browser,
|
|
27
|
+
if (typeof window !== 'undefined') {
|
|
28
|
+
//check localStorage for a previously stored width.
|
|
29
|
+
const initialWidthFromLocalStorage: string | null =
|
|
30
|
+
window.localStorage.getItem(localStoragePropertyName);
|
|
31
|
+
|
|
32
|
+
// If there is a previously stored width,
|
|
33
|
+
if (initialWidthFromLocalStorage !== null) {
|
|
34
|
+
// use it as the initial width.
|
|
35
|
+
initialWidth = +initialWidthFromLocalStorage;
|
|
36
|
+
}
|
|
37
|
+
} else {
|
|
38
|
+
// If we're not in the browser, use the default initial width.
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const add = (a: number, b: number) => a + b;
|
|
42
|
+
|
|
43
|
+
export const SplitPaneResizeProvider = ({ children }) => {
|
|
44
|
+
const [codeEditorWidth, moveSplitPane] = useReducer(
|
|
45
|
+
add,
|
|
46
|
+
initialWidth,
|
|
47
|
+
);
|
|
48
|
+
const [isDragging, setIsDragging] = useState(false);
|
|
49
|
+
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
if (codeEditorWidth !== initialWidth) {
|
|
52
|
+
const timeout = setTimeout(() => {
|
|
53
|
+
window.localStorage.setItem(
|
|
54
|
+
localStoragePropertyName,
|
|
55
|
+
'' + codeEditorWidth,
|
|
56
|
+
);
|
|
57
|
+
}, localStorageWriteDebounceMS);
|
|
58
|
+
|
|
59
|
+
return () => {
|
|
60
|
+
clearTimeout(timeout);
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
}, [codeEditorWidth]);
|
|
64
|
+
|
|
65
|
+
return (
|
|
66
|
+
<SplitPaneResizeContext.Provider
|
|
67
|
+
value={{
|
|
68
|
+
codeEditorWidth,
|
|
69
|
+
moveSplitPane,
|
|
70
|
+
isDragging,
|
|
71
|
+
setIsDragging,
|
|
72
|
+
}}
|
|
73
|
+
>
|
|
74
|
+
{children}
|
|
75
|
+
</SplitPaneResizeContext.Provider>
|
|
76
|
+
);
|
|
77
|
+
};
|
|
@@ -6,7 +6,9 @@ import './style.scss';
|
|
|
6
6
|
const fileNameSplit = (fileName) => {
|
|
7
7
|
const split = fileName.split('/');
|
|
8
8
|
if (split.length === 1) return split[split.length - 1];
|
|
9
|
-
return
|
|
9
|
+
return (
|
|
10
|
+
split[split.length - 2] + '/' + split[split.length - 1]
|
|
11
|
+
);
|
|
10
12
|
};
|
|
11
13
|
|
|
12
14
|
const Tab = ({
|
|
@@ -32,7 +34,10 @@ const Tab = ({
|
|
|
32
34
|
[closeTab, fileId],
|
|
33
35
|
);
|
|
34
36
|
|
|
35
|
-
const tabName = useMemo(
|
|
37
|
+
const tabName = useMemo(
|
|
38
|
+
() => fileNameSplit(fileName),
|
|
39
|
+
[fileName],
|
|
40
|
+
);
|
|
36
41
|
|
|
37
42
|
return (
|
|
38
43
|
<div
|
package/src/client/diff.js
CHANGED
|
@@ -3,4 +3,10 @@ import diffMatchPatch from 'diff-match-patch';
|
|
|
3
3
|
import { json1Presence, textUnicode } from '../ot';
|
|
4
4
|
|
|
5
5
|
export const diff = (a, b) =>
|
|
6
|
-
jsondiff(
|
|
6
|
+
jsondiff(
|
|
7
|
+
a,
|
|
8
|
+
b,
|
|
9
|
+
diffMatchPatch,
|
|
10
|
+
json1Presence,
|
|
11
|
+
textUnicode,
|
|
12
|
+
);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
// A feature flag to disable settings for release, until it's completed.
|
|
2
2
|
// See https://vitejs.dev/guide/env-and-mode.html
|
|
3
|
-
export const disableSettings =
|
|
3
|
+
export const disableSettings =
|
|
4
|
+
import.meta.env.VITE_DISABLE_SETTINGS === 'true';
|
|
@@ -11,7 +11,9 @@ export const sortFileTree = (fileTree: FileTree) => {
|
|
|
11
11
|
const aIsFile = (a as FileTreeFile).file ? 1 : 0;
|
|
12
12
|
const bIsFile = (b as FileTreeFile).file ? 1 : 0;
|
|
13
13
|
// Directories before files.
|
|
14
|
-
return
|
|
14
|
+
return (
|
|
15
|
+
aIsFile - bIsFile || a.name.localeCompare(b.name)
|
|
16
|
+
);
|
|
15
17
|
});
|
|
16
18
|
fileTree.children.forEach(sortFileTree);
|
|
17
19
|
}
|
package/src/client/style.scss
CHANGED
|
@@ -1,47 +1,53 @@
|
|
|
1
1
|
:root {
|
|
2
|
-
--vzcode-font-family: ui-monospace, SFMono-Regular,
|
|
3
|
-
Liberation Mono, monospace;
|
|
2
|
+
--vzcode-font-family: ui-monospace, SFMono-Regular,
|
|
3
|
+
SF Mono, Menlo, Consolas, Liberation Mono, monospace;
|
|
4
|
+
--vz-bg-color: rgb(
|
|
5
|
+
41,
|
|
6
|
+
44,
|
|
7
|
+
52
|
|
8
|
+
); /* Variable for the background color */
|
|
4
9
|
}
|
|
5
10
|
|
|
6
|
-
/*
|
|
11
|
+
/* Scrollbar Styles */
|
|
7
12
|
::-webkit-scrollbar {
|
|
8
13
|
width: 10px;
|
|
9
14
|
height: 10px;
|
|
10
15
|
}
|
|
11
16
|
|
|
12
|
-
/* Track */
|
|
13
17
|
::-webkit-scrollbar-track {
|
|
14
|
-
background:
|
|
18
|
+
background: var(--app-bg-color);
|
|
15
19
|
}
|
|
16
20
|
|
|
17
|
-
/* Handle */
|
|
18
21
|
::-webkit-scrollbar-thumb {
|
|
19
22
|
background: rgb(37, 37, 38);
|
|
20
23
|
}
|
|
21
24
|
|
|
22
|
-
/* Handle on hover */
|
|
23
25
|
::-webkit-scrollbar-thumb:hover {
|
|
24
26
|
background: #555;
|
|
25
27
|
}
|
|
26
28
|
|
|
29
|
+
/* Layout Styles */
|
|
27
30
|
html,
|
|
28
31
|
body,
|
|
29
32
|
#root,
|
|
30
33
|
.app {
|
|
31
34
|
height: 100%;
|
|
32
35
|
}
|
|
33
|
-
.app {
|
|
34
|
-
/* TODO use a variable for this */
|
|
35
|
-
background-color: rgb(41, 44, 52);
|
|
36
36
|
|
|
37
|
+
.app {
|
|
38
|
+
background-color: var(--vz-bg-color);
|
|
37
39
|
font-family: 'Poppins', sans-serif;
|
|
38
40
|
display: flex;
|
|
39
41
|
|
|
40
|
-
|
|
42
|
+
/* To support Resizer, which is position: absolute */
|
|
43
|
+
position: relative;
|
|
44
|
+
|
|
45
|
+
.left,
|
|
46
|
+
.right {
|
|
41
47
|
display: flex;
|
|
42
48
|
}
|
|
49
|
+
|
|
43
50
|
.right {
|
|
44
|
-
display: flex;
|
|
45
51
|
flex: 1;
|
|
46
52
|
flex-direction: column;
|
|
47
53
|
min-width: 0;
|
package/src/client/themes.ts
CHANGED
|
@@ -41,14 +41,16 @@ export const themes: Array<ThemeOption> = [
|
|
|
41
41
|
];
|
|
42
42
|
|
|
43
43
|
// Map theme labels to theme values
|
|
44
|
-
export const themeOptionsByLabel: Record<
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
44
|
+
export const themeOptionsByLabel: Record<
|
|
45
|
+
ThemeLabel,
|
|
46
|
+
ThemeOption
|
|
47
|
+
> = themes.reduce(
|
|
48
|
+
(acc, themeOption: ThemeOption) => {
|
|
49
|
+
acc[themeOption.label] = themeOption;
|
|
50
|
+
return acc;
|
|
51
|
+
},
|
|
52
|
+
{} as Record<ThemeLabel, any>,
|
|
53
|
+
);
|
|
52
54
|
|
|
53
55
|
// The default theme
|
|
54
56
|
export const defaultTheme: ThemeLabel = 'oneDark';
|
|
@@ -13,8 +13,11 @@ export const useDynamicTheme = (
|
|
|
13
13
|
isFirstRun.current = false;
|
|
14
14
|
} else {
|
|
15
15
|
// When the user changes the theme, update the theme of all editors.
|
|
16
|
-
for (const editorCacheValue of Array.from(
|
|
17
|
-
|
|
16
|
+
for (const editorCacheValue of Array.from(
|
|
17
|
+
editorCache.values(),
|
|
18
|
+
)) {
|
|
19
|
+
const { editor, themeCompartment } =
|
|
20
|
+
editorCacheValue;
|
|
18
21
|
editor.dispatch({
|
|
19
22
|
effects: themeCompartment.reconfigure([
|
|
20
23
|
themeOptionsByLabel[theme].value,
|
|
@@ -19,21 +19,24 @@ import { useState, useCallback } from 'react';
|
|
|
19
19
|
// https://github.com/vizhub-core/vizhub/blob/main/vizhub-v2/packages/neoFrontend/src/pages/VizPage/Body/Editor/FilesSection/useOpenDirectories.js
|
|
20
20
|
export const useOpenDirectories = () => {
|
|
21
21
|
// The set of open directories by path/
|
|
22
|
-
const [openDirectories, setOpenDirectories] = useState<
|
|
23
|
-
|
|
24
|
-
);
|
|
22
|
+
const [openDirectories, setOpenDirectories] = useState<
|
|
23
|
+
Set<string>
|
|
24
|
+
>(new Set());
|
|
25
25
|
|
|
26
26
|
// Whether a directory is open.
|
|
27
|
-
const isDirectoryOpen: (path: string) => boolean =
|
|
28
|
-
(
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
const isDirectoryOpen: (path: string) => boolean =
|
|
28
|
+
useCallback(
|
|
29
|
+
(path) => openDirectories.has(path),
|
|
30
|
+
[openDirectories],
|
|
31
|
+
);
|
|
31
32
|
|
|
32
33
|
// Toggle whether a directory is open.
|
|
33
34
|
const toggleDirectory = useCallback(
|
|
34
35
|
(path) => {
|
|
35
36
|
const newOpenDirectories = new Set(openDirectories);
|
|
36
|
-
newOpenDirectories[
|
|
37
|
+
newOpenDirectories[
|
|
38
|
+
isDirectoryOpen(path) ? 'delete' : 'add'
|
|
39
|
+
](path);
|
|
37
40
|
setOpenDirectories(newOpenDirectories);
|
|
38
41
|
},
|
|
39
42
|
[openDirectories, isDirectoryOpen],
|