vzcode 0.24.0 → 0.26.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-9c8bbae0.js → index-284b7339.js} +50 -50
- package/dist/assets/index-e160f758.css +1 -0
- package/dist/index.html +2 -6
- package/package.json +7 -5
- package/src/client/App.tsx +47 -213
- package/src/client/CodeEditor/getOrCreateEditor.ts +3 -0
- package/src/client/CodeEditor/index.tsx +36 -6
- package/src/client/CodeEditor/{json1PresenceBroadcast.js → json1PresenceBroadcast.ts} +5 -3
- package/src/client/CodeEditor/{json1PresenceDisplay.js → json1PresenceDisplay.ts} +9 -3
- package/src/client/CodeEditor/widgets.ts +112 -10
- package/src/client/PresenceNotifications/index.tsx +0 -2
- package/src/client/TabList/Tab.tsx +56 -0
- package/src/client/TabList/index.tsx +11 -62
- package/src/client/TabList/style.scss +21 -9
- package/src/client/{Settings.tsx → VZSettings.tsx} +1 -1
- package/src/client/{Sidebar → VZSidebar}/FileListing.tsx +3 -0
- package/src/client/{Sidebar → VZSidebar}/Item.tsx +10 -7
- package/src/client/{Sidebar → VZSidebar}/Listing.tsx +3 -0
- package/src/client/{Sidebar → VZSidebar}/index.tsx +5 -6
- package/src/client/{Sidebar → VZSidebar}/styles.scss +17 -12
- package/src/client/bootstrap.ts +3 -0
- package/src/client/style.scss +5 -2
- package/src/client/themes/index.ts +7 -0
- package/src/client/{themes.ts → themes/themes.ts} +5 -5
- package/src/client/{useDynamicTheme.ts → themes/useDynamicTheme.ts} +1 -1
- package/src/client/themes/vizhubTheme/colors.ts +80 -0
- package/src/client/themes/vizhubTheme/index.ts +166 -0
- package/src/client/useActions.ts +74 -0
- package/src/client/useFileCRUD.ts +101 -0
- package/src/client/useOpenDirectories.ts +25 -7
- package/src/client/useSubmitOperation.ts +25 -0
- package/src/client/vzReducer.ts +118 -0
- package/src/index.ts +34 -0
- package/src/server/index.js +13 -2
- package/dist/assets/index-cf19de3b.css +0 -1
- package/src/client/reducer.ts +0 -122
- package/src/client/useTabsState.ts +0 -95
- package/src/client/vizhubTheme.js +0 -1
- /package/src/client/{Sidebar → VZSidebar}/ConfirmationBox.tsx +0 -0
- /package/src/client/{Sidebar → VZSidebar}/DirectoryArrowSVG.jsx +0 -0
- /package/src/client/{Sidebar → VZSidebar}/DirectoryListing.tsx +0 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { useCallback, useMemo } from 'react';
|
|
2
|
+
import { FileId } from '../../types';
|
|
3
|
+
|
|
4
|
+
// Supports adding the file's containing folder to the tab name
|
|
5
|
+
const fileNameSplit = (fileName: string) => {
|
|
6
|
+
const split = fileName.split('/');
|
|
7
|
+
if (split.length === 1) return split[split.length - 1];
|
|
8
|
+
return (
|
|
9
|
+
split[split.length - 2] + '/' + split[split.length - 1]
|
|
10
|
+
);
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const Tab = ({
|
|
14
|
+
fileId,
|
|
15
|
+
isActive,
|
|
16
|
+
setActiveFileId,
|
|
17
|
+
closeTabs,
|
|
18
|
+
fileName,
|
|
19
|
+
}: {
|
|
20
|
+
fileId: FileId;
|
|
21
|
+
isActive: boolean;
|
|
22
|
+
setActiveFileId: (fileId: FileId) => void;
|
|
23
|
+
closeTabs: (fileIds: FileId[]) => void;
|
|
24
|
+
fileName: string;
|
|
25
|
+
}) => {
|
|
26
|
+
const handleCloseClick = useCallback(
|
|
27
|
+
(event: React.MouseEvent) => {
|
|
28
|
+
// Stop propagation so that the outer listener doesn't fire.
|
|
29
|
+
event.stopPropagation();
|
|
30
|
+
|
|
31
|
+
closeTabs([fileId]);
|
|
32
|
+
},
|
|
33
|
+
[closeTabs, fileId],
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
const tabName = useMemo(
|
|
37
|
+
() => fileNameSplit(fileName),
|
|
38
|
+
[fileName],
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<div
|
|
43
|
+
className={isActive ? 'tab active' : 'tab'}
|
|
44
|
+
onClick={() => {
|
|
45
|
+
setActiveFileId(fileId);
|
|
46
|
+
}}
|
|
47
|
+
>
|
|
48
|
+
{tabName}
|
|
49
|
+
<div
|
|
50
|
+
// className={isActive ? 'bx bx-x tab-close' : ''}
|
|
51
|
+
className={'bx bx-x tab-close'}
|
|
52
|
+
onClick={handleCloseClick}
|
|
53
|
+
></div>
|
|
54
|
+
</div>
|
|
55
|
+
);
|
|
56
|
+
};
|
|
@@ -1,89 +1,37 @@
|
|
|
1
|
-
import { useCallback,
|
|
1
|
+
import { useCallback, useEffect } from 'react';
|
|
2
2
|
import { FileId, Files } from '../../types';
|
|
3
|
+
import { Tab } from './Tab';
|
|
3
4
|
import './style.scss';
|
|
4
5
|
|
|
5
|
-
// Supports adding the file's containing folder to the tab name
|
|
6
|
-
const fileNameSplit = (fileName) => {
|
|
7
|
-
const split = fileName.split('/');
|
|
8
|
-
if (split.length === 1) return split[split.length - 1];
|
|
9
|
-
return (
|
|
10
|
-
split[split.length - 2] + '/' + split[split.length - 1]
|
|
11
|
-
);
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
const Tab = ({
|
|
15
|
-
fileId,
|
|
16
|
-
isActive,
|
|
17
|
-
setActiveFileId,
|
|
18
|
-
closeTab,
|
|
19
|
-
fileName,
|
|
20
|
-
}: {
|
|
21
|
-
fileId: FileId;
|
|
22
|
-
isActive: boolean;
|
|
23
|
-
setActiveFileId: (fileId: FileId) => void;
|
|
24
|
-
closeTab: (fileId: FileId) => void;
|
|
25
|
-
fileName: string;
|
|
26
|
-
}) => {
|
|
27
|
-
const handleCloseClick = useCallback(
|
|
28
|
-
(event: React.MouseEvent) => {
|
|
29
|
-
// Stop propagation so that the outer listener doesn't fire.
|
|
30
|
-
event.stopPropagation();
|
|
31
|
-
|
|
32
|
-
closeTab(fileId);
|
|
33
|
-
},
|
|
34
|
-
[closeTab, fileId],
|
|
35
|
-
);
|
|
36
|
-
|
|
37
|
-
const tabName = useMemo(
|
|
38
|
-
() => fileNameSplit(fileName),
|
|
39
|
-
[fileName],
|
|
40
|
-
);
|
|
41
|
-
|
|
42
|
-
return (
|
|
43
|
-
<div
|
|
44
|
-
className={isActive ? 'tab active' : 'tab'}
|
|
45
|
-
onClick={() => {
|
|
46
|
-
setActiveFileId(fileId);
|
|
47
|
-
}}
|
|
48
|
-
>
|
|
49
|
-
{tabName}
|
|
50
|
-
<div
|
|
51
|
-
className={isActive ? 'bx bx-x tab-close' : ''}
|
|
52
|
-
onClick={handleCloseClick}
|
|
53
|
-
></div>
|
|
54
|
-
</div>
|
|
55
|
-
);
|
|
56
|
-
};
|
|
57
|
-
|
|
58
6
|
// Displays the list of tabs above the code editor.
|
|
59
7
|
export const TabList = ({
|
|
60
8
|
files,
|
|
61
9
|
tabList,
|
|
62
10
|
activeFileId,
|
|
63
11
|
setActiveFileId,
|
|
64
|
-
|
|
12
|
+
closeTabs,
|
|
65
13
|
}: {
|
|
66
14
|
files: Files;
|
|
67
15
|
tabList: FileId[];
|
|
68
16
|
activeFileId: FileId;
|
|
69
17
|
setActiveFileId: (fileId: FileId) => void;
|
|
70
|
-
|
|
18
|
+
closeTabs: (fileIds: FileId[]) => void;
|
|
71
19
|
}) => {
|
|
72
|
-
//
|
|
20
|
+
// Close the active tab on alt+w
|
|
73
21
|
const handleKeyPress = useCallback(
|
|
74
22
|
(event: { altKey: boolean; key: string }) => {
|
|
75
23
|
if (event.altKey == true) {
|
|
76
24
|
if (event.key == 'w') {
|
|
77
|
-
|
|
25
|
+
closeTabs([activeFileId]);
|
|
78
26
|
}
|
|
79
27
|
}
|
|
80
28
|
},
|
|
81
|
-
[
|
|
29
|
+
[closeTabs, activeFileId],
|
|
82
30
|
);
|
|
31
|
+
|
|
32
|
+
// Add the global keydown event listener
|
|
83
33
|
useEffect(() => {
|
|
84
|
-
// attach the event listener
|
|
85
34
|
document.addEventListener('keydown', handleKeyPress);
|
|
86
|
-
// remove the event listener
|
|
87
35
|
return () => {
|
|
88
36
|
document.removeEventListener(
|
|
89
37
|
'keydown',
|
|
@@ -91,6 +39,7 @@ export const TabList = ({
|
|
|
91
39
|
);
|
|
92
40
|
};
|
|
93
41
|
}, [handleKeyPress]);
|
|
42
|
+
|
|
94
43
|
return (
|
|
95
44
|
<div className="vz-tab-list">
|
|
96
45
|
{files &&
|
|
@@ -100,7 +49,7 @@ export const TabList = ({
|
|
|
100
49
|
fileId={fileId}
|
|
101
50
|
isActive={fileId === activeFileId}
|
|
102
51
|
setActiveFileId={setActiveFileId}
|
|
103
|
-
|
|
52
|
+
closeTabs={closeTabs}
|
|
104
53
|
fileName={files[fileId].name}
|
|
105
54
|
/>
|
|
106
55
|
))}
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
.vz-tab-list {
|
|
2
2
|
display: flex;
|
|
3
|
-
background-color:
|
|
3
|
+
background-color: #33415b;
|
|
4
4
|
// When the tab list becomes too large, a horizontal scroll bar appears.
|
|
5
5
|
overflow-x: auto;
|
|
6
6
|
|
|
7
7
|
.tab {
|
|
8
|
-
background:
|
|
8
|
+
// background: #47546b;
|
|
9
9
|
color: #fff;
|
|
10
10
|
font-family: var(--vzcode-font-family);
|
|
11
11
|
align-items: center;
|
|
12
12
|
display: flex;
|
|
13
13
|
padding-top: 2px;
|
|
14
|
-
padding-left:
|
|
15
|
-
padding-right:
|
|
16
|
-
border-top-left-radius:
|
|
17
|
-
border-top-right-radius:
|
|
14
|
+
padding-left: 8px;
|
|
15
|
+
padding-right: 5px;
|
|
16
|
+
border-top-left-radius: 12px;
|
|
17
|
+
border-top-right-radius: 12px;
|
|
18
18
|
margin-top: 5px;
|
|
19
19
|
margin-left: 2px;
|
|
20
20
|
margin-right: 2px;
|
|
@@ -24,13 +24,25 @@
|
|
|
24
24
|
|
|
25
25
|
.tab-close {
|
|
26
26
|
margin-left: 5px;
|
|
27
|
+
margin-bottom: 2px;
|
|
27
28
|
}
|
|
28
29
|
.tab-close:hover {
|
|
29
|
-
border-radius:
|
|
30
|
-
background-color:
|
|
30
|
+
border-radius: 50%;
|
|
31
|
+
background-color: rgba(255, 255, 255, 0.2);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// No left margin for first child
|
|
35
|
+
&:first-child {
|
|
36
|
+
margin-left: 0;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// on hover
|
|
40
|
+
&:hover {
|
|
41
|
+
background-color: #47546b;
|
|
31
42
|
}
|
|
32
43
|
}
|
|
44
|
+
|
|
33
45
|
.tab.active {
|
|
34
|
-
background-color:
|
|
46
|
+
background-color: #202e46;
|
|
35
47
|
}
|
|
36
48
|
}
|
|
@@ -8,6 +8,7 @@ export const FileListing = ({
|
|
|
8
8
|
handleRenameFileClick,
|
|
9
9
|
handleDeleteFileClick,
|
|
10
10
|
handleFileClick,
|
|
11
|
+
isActive,
|
|
11
12
|
}: {
|
|
12
13
|
name: string;
|
|
13
14
|
fileId: FileId;
|
|
@@ -20,6 +21,7 @@ export const FileListing = ({
|
|
|
20
21
|
event: React.MouseEvent,
|
|
21
22
|
) => void;
|
|
22
23
|
handleFileClick: (fileId: FileId) => void;
|
|
24
|
+
isActive: boolean;
|
|
23
25
|
}) => {
|
|
24
26
|
const handleClick = useCallback(() => {
|
|
25
27
|
handleFileClick(fileId);
|
|
@@ -46,6 +48,7 @@ export const FileListing = ({
|
|
|
46
48
|
handleDeleteClick={handleDeleteClick}
|
|
47
49
|
handleRenameClick={handleRenameClick}
|
|
48
50
|
isDir={false}
|
|
51
|
+
isActive={isActive}
|
|
49
52
|
>
|
|
50
53
|
{name}
|
|
51
54
|
</Item>
|
|
@@ -8,6 +8,7 @@ export const Item = ({
|
|
|
8
8
|
handleRenameClick,
|
|
9
9
|
handleDeleteClick,
|
|
10
10
|
isDir,
|
|
11
|
+
isActive = false,
|
|
11
12
|
}) => {
|
|
12
13
|
// Tracks whether the mouse is hovering over the file or directory
|
|
13
14
|
const [isHovered, setIsHovered] = useState(false);
|
|
@@ -19,9 +20,9 @@ export const Item = ({
|
|
|
19
20
|
const [renameValue, setRenameValue] = useState('');
|
|
20
21
|
|
|
21
22
|
const onKeyDown = useCallback((event) => {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
if (event.key === 'Enter'
|
|
23
|
+
if (event.key === 'Escape') {
|
|
24
|
+
setIsRenaming(false);
|
|
25
|
+
} else if (event.key === 'Enter') {
|
|
25
26
|
event.target.blur();
|
|
26
27
|
}
|
|
27
28
|
}, []);
|
|
@@ -82,7 +83,9 @@ export const Item = ({
|
|
|
82
83
|
|
|
83
84
|
return (
|
|
84
85
|
<div
|
|
85
|
-
className=
|
|
86
|
+
className={`full-box file-or-directory ${
|
|
87
|
+
isActive ? 'active-file' : ''
|
|
88
|
+
}`}
|
|
86
89
|
onClick={isRenaming ? null : handleClick}
|
|
87
90
|
onMouseEnter={handleMouseEnter}
|
|
88
91
|
onMouseLeave={handleMouseLeave}
|
|
@@ -105,7 +108,7 @@ export const Item = ({
|
|
|
105
108
|
<div className="utils">
|
|
106
109
|
<i
|
|
107
110
|
className="bx bxs-edit utilities"
|
|
108
|
-
style={{ color: '#
|
|
111
|
+
style={{ color: '#9edcff' }}
|
|
109
112
|
onClick={(event: React.MouseEvent) => {
|
|
110
113
|
event.stopPropagation();
|
|
111
114
|
setIsRenaming(!isRenaming);
|
|
@@ -113,8 +116,8 @@ export const Item = ({
|
|
|
113
116
|
}}
|
|
114
117
|
></i>
|
|
115
118
|
<i
|
|
116
|
-
className="bx bx-trash"
|
|
117
|
-
style={{ color: '#
|
|
119
|
+
className="bx bx-trash utilities"
|
|
120
|
+
style={{ color: '#ff006b' }}
|
|
118
121
|
onClick={handleModalOpen}
|
|
119
122
|
></i>
|
|
120
123
|
</div>
|
|
@@ -15,6 +15,7 @@ export const Listing = ({
|
|
|
15
15
|
handleFileClick,
|
|
16
16
|
isDirectoryOpen,
|
|
17
17
|
toggleDirectory,
|
|
18
|
+
activeFileId,
|
|
18
19
|
}: {
|
|
19
20
|
entity: FileTree | FileTreeFile;
|
|
20
21
|
handleRenameFileClick: (
|
|
@@ -28,6 +29,7 @@ export const Listing = ({
|
|
|
28
29
|
handleFileClick: (fileId: FileId) => void;
|
|
29
30
|
isDirectoryOpen: (path: string) => boolean;
|
|
30
31
|
toggleDirectory: (path: string) => void;
|
|
32
|
+
activeFileId: FileId;
|
|
31
33
|
}) => {
|
|
32
34
|
const { name, file, fileId } = entity as FileTreeFile;
|
|
33
35
|
const { path, children } = entity as FileTree;
|
|
@@ -38,6 +40,7 @@ export const Listing = ({
|
|
|
38
40
|
handleRenameFileClick={handleRenameFileClick}
|
|
39
41
|
handleDeleteFileClick={handleDeleteFileClick}
|
|
40
42
|
handleFileClick={handleFileClick}
|
|
43
|
+
isActive={fileId === activeFileId}
|
|
41
44
|
/>
|
|
42
45
|
) : (
|
|
43
46
|
<DirectoryListing
|
|
@@ -12,7 +12,7 @@ import { SplitPaneResizeContext } from '../SplitPaneResizeContext';
|
|
|
12
12
|
import { Listing } from './Listing';
|
|
13
13
|
import './styles.scss';
|
|
14
14
|
|
|
15
|
-
export const
|
|
15
|
+
export const VZSidebar = ({
|
|
16
16
|
createFile,
|
|
17
17
|
files,
|
|
18
18
|
handleRenameFileClick,
|
|
@@ -21,6 +21,7 @@ export const Sidebar = ({
|
|
|
21
21
|
setIsSettingsOpen,
|
|
22
22
|
isDirectoryOpen,
|
|
23
23
|
toggleDirectory,
|
|
24
|
+
activeFileId,
|
|
24
25
|
}: {
|
|
25
26
|
files: Files;
|
|
26
27
|
createFile?: () => void;
|
|
@@ -36,6 +37,7 @@ export const Sidebar = ({
|
|
|
36
37
|
setIsSettingsOpen?: (isSettingsOpen: boolean) => void;
|
|
37
38
|
isDirectoryOpen?: (path: string) => boolean;
|
|
38
39
|
toggleDirectory?: (path: string) => void;
|
|
40
|
+
activeFileId?: FileId;
|
|
39
41
|
}) => {
|
|
40
42
|
const fileTree = useMemo(
|
|
41
43
|
() => (files ? sortFileTree(getFileTree(files)) : null),
|
|
@@ -57,11 +59,7 @@ export const Sidebar = ({
|
|
|
57
59
|
>
|
|
58
60
|
<div className="files">
|
|
59
61
|
<div className="full-box">
|
|
60
|
-
<div>
|
|
61
|
-
<a className="link-name" href="#">
|
|
62
|
-
Files
|
|
63
|
-
</a>
|
|
64
|
-
</div>
|
|
62
|
+
<div className="sidebar-section-hint">Files</div>
|
|
65
63
|
<div>
|
|
66
64
|
<i
|
|
67
65
|
className="bx bxs-file-plus new-btn"
|
|
@@ -88,6 +86,7 @@ export const Sidebar = ({
|
|
|
88
86
|
handleFileClick={handleFileClick}
|
|
89
87
|
isDirectoryOpen={isDirectoryOpen}
|
|
90
88
|
toggleDirectory={toggleDirectory}
|
|
89
|
+
activeFileId={activeFileId}
|
|
91
90
|
/>
|
|
92
91
|
);
|
|
93
92
|
})
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
.vz-sidebar {
|
|
2
2
|
height: 100%;
|
|
3
|
-
|
|
3
|
+
color: #d6d9de;
|
|
4
|
+
background: #33415b;
|
|
4
5
|
display: flex;
|
|
5
6
|
flex-direction: column;
|
|
6
7
|
justify-content: space-between;
|
|
7
8
|
|
|
8
9
|
.full-box {
|
|
9
|
-
padding:
|
|
10
|
+
padding: 3px 6px;
|
|
10
11
|
display: flex;
|
|
11
12
|
flex-direction: row;
|
|
12
13
|
align-items: center;
|
|
@@ -24,16 +25,14 @@
|
|
|
24
25
|
justify-content: space-between;
|
|
25
26
|
cursor: pointer;
|
|
26
27
|
margin: 0 10px;
|
|
27
|
-
|
|
28
|
-
border-radius: 5px;
|
|
28
|
+
border-radius: 4px;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
.
|
|
32
|
-
margin-top: 30px;
|
|
31
|
+
.sidebar-section-hint {
|
|
32
|
+
// margin-top: 30px;
|
|
33
33
|
margin-left: 10px;
|
|
34
|
-
color: rgb(154, 160, 172);
|
|
35
34
|
font-size: 12px;
|
|
36
|
-
|
|
35
|
+
color: #99a0ad;
|
|
37
36
|
}
|
|
38
37
|
|
|
39
38
|
.new-btn {
|
|
@@ -44,14 +43,21 @@
|
|
|
44
43
|
|
|
45
44
|
.utils {
|
|
46
45
|
display: flex;
|
|
46
|
+
gap: 8px;
|
|
47
47
|
}
|
|
48
48
|
.utilities {
|
|
49
|
-
margin-right: 3px;
|
|
49
|
+
// margin-right: 3px;
|
|
50
|
+
transform: scale(1.2);
|
|
50
51
|
}
|
|
51
52
|
|
|
52
53
|
.file-or-directory:hover,
|
|
53
54
|
.settings:hover {
|
|
54
|
-
background-color:
|
|
55
|
+
background-color: #47546b;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.active-file,
|
|
59
|
+
.active-file:hover {
|
|
60
|
+
background-color: #202e46;
|
|
55
61
|
}
|
|
56
62
|
|
|
57
63
|
.name {
|
|
@@ -71,13 +77,12 @@
|
|
|
71
77
|
|
|
72
78
|
.settings {
|
|
73
79
|
height: 30px;
|
|
74
|
-
color: rgb(219, 221, 225);
|
|
75
80
|
cursor: pointer;
|
|
76
81
|
display: flex;
|
|
77
82
|
align-items: center;
|
|
78
83
|
justify-content: center;
|
|
79
84
|
padding: 14px 0;
|
|
80
85
|
margin: 10px;
|
|
81
|
-
border-radius:
|
|
86
|
+
border-radius: 4px;
|
|
82
87
|
}
|
|
83
88
|
}
|
package/src/client/bootstrap.ts
CHANGED
|
@@ -5,4 +5,7 @@ import Form from 'react-bootstrap/cjs/Form.js';
|
|
|
5
5
|
import Button from 'react-bootstrap/cjs/Button.js';
|
|
6
6
|
import Modal from 'react-bootstrap/cjs/Modal.js';
|
|
7
7
|
|
|
8
|
+
// Pull in custom CSS from vizhub-ui.
|
|
9
|
+
import 'vizhub-ui/dist/vizhub-ui.css';
|
|
10
|
+
|
|
8
11
|
export { Form, Button, Modal };
|
package/src/client/style.scss
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
:root {
|
|
2
2
|
--vzcode-font-family: ui-monospace, SFMono-Regular,
|
|
3
|
-
SF Mono, Menlo, Consolas, Liberation Mono, monospace;
|
|
3
|
+
'SF Mono', Menlo, Consolas, 'Liberation Mono', monospace !important;
|
|
4
|
+
/* Variable for the background color */
|
|
4
5
|
--vz-bg-color: rgb(
|
|
5
6
|
41,
|
|
6
7
|
44,
|
|
@@ -36,7 +37,9 @@ body,
|
|
|
36
37
|
|
|
37
38
|
.app {
|
|
38
39
|
background-color: var(--vz-bg-color);
|
|
39
|
-
font-family: '
|
|
40
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI',
|
|
41
|
+
'Noto Sans', Helvetica, Arial, sans-serif,
|
|
42
|
+
'Apple Color Emoji', 'Segoe UI Emoji';
|
|
40
43
|
display: flex;
|
|
41
44
|
|
|
42
45
|
/* To support Resizer, which is position: absolute */
|
|
@@ -7,7 +7,7 @@ import { githubDark } from '@uiw/codemirror-theme-github';
|
|
|
7
7
|
import { material } from '@uiw/codemirror-theme-material';
|
|
8
8
|
import { nord } from '@uiw/codemirror-theme-nord';
|
|
9
9
|
import { xcodeLight } from '@uiw/codemirror-theme-xcode';
|
|
10
|
-
|
|
10
|
+
import { vizhubTheme } from './vizhubTheme';
|
|
11
11
|
|
|
12
12
|
// CodeMirror themes
|
|
13
13
|
export type ThemeLabel =
|
|
@@ -19,8 +19,8 @@ export type ThemeLabel =
|
|
|
19
19
|
| 'oneDark'
|
|
20
20
|
| 'okaidia'
|
|
21
21
|
| 'github'
|
|
22
|
-
| 'xcode'
|
|
23
|
-
|
|
22
|
+
| 'xcode'
|
|
23
|
+
| 'vizhub';
|
|
24
24
|
|
|
25
25
|
export type ThemeOption = {
|
|
26
26
|
value: any;
|
|
@@ -37,7 +37,7 @@ export const themes: Array<ThemeOption> = [
|
|
|
37
37
|
{ value: okaidia, label: 'okaidia' },
|
|
38
38
|
{ value: githubDark, label: 'github' },
|
|
39
39
|
{ value: xcodeLight, label: 'xcode' },
|
|
40
|
-
|
|
40
|
+
{ value: vizhubTheme, label: 'vizhub' },
|
|
41
41
|
];
|
|
42
42
|
|
|
43
43
|
// Map theme labels to theme values
|
|
@@ -53,4 +53,4 @@ export const themeOptionsByLabel: Record<
|
|
|
53
53
|
);
|
|
54
54
|
|
|
55
55
|
// The default theme
|
|
56
|
-
export const defaultTheme: ThemeLabel = '
|
|
56
|
+
export const defaultTheme: ThemeLabel = 'vizhub';
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// import { hcl } from 'd3-color';
|
|
2
|
+
|
|
3
|
+
// This module defines all the colors for the VizHub theme.
|
|
4
|
+
// Ported from the CodeMirror 5 theme defined here:
|
|
5
|
+
// https://github.com/vizhub-core/vizhub-legacy/blob/01cadfb78a2611df32f981b1fd8136b70447de9e/vizhub-v2/packages/neoFrontend/src/pages/VizPage/Body/Editor/themes/vizHub.js
|
|
6
|
+
|
|
7
|
+
// This is how the colors were generated:
|
|
8
|
+
// const sidebarDark = hcl('#3d4b65');
|
|
9
|
+
// const sidebarLight = hcl('#5b677d');
|
|
10
|
+
// const luminaceDifference = sidebarLight.l - sidebarDark.l;
|
|
11
|
+
// const backgroundLuminance =
|
|
12
|
+
// sidebarDark.l - luminaceDifference * 1.1;
|
|
13
|
+
// const luminance = 90;
|
|
14
|
+
// export const backgroundColor = hcl(
|
|
15
|
+
// sidebarDark.h,
|
|
16
|
+
// sidebarDark.c,
|
|
17
|
+
// backgroundLuminance,
|
|
18
|
+
// ).formatHex();
|
|
19
|
+
// export const light = hcl(0, 0, luminance).formatHex();
|
|
20
|
+
// export const dark = hcl(
|
|
21
|
+
// sidebarDark.h,
|
|
22
|
+
// sidebarDark.c,
|
|
23
|
+
// 80,
|
|
24
|
+
// ).formatHex();
|
|
25
|
+
// console.log(
|
|
26
|
+
// JSON.stringify(
|
|
27
|
+
// {
|
|
28
|
+
// backgroundColor,
|
|
29
|
+
// light,
|
|
30
|
+
// dark,
|
|
31
|
+
// },
|
|
32
|
+
// null,
|
|
33
|
+
// 2,
|
|
34
|
+
// ),
|
|
35
|
+
// );
|
|
36
|
+
|
|
37
|
+
// These are inlined from the above code, but the code is kept around for future reference.
|
|
38
|
+
export const backgroundColor = '#202e46';
|
|
39
|
+
export const light = '#e2e2e2';
|
|
40
|
+
export const dark = '#b9c7e6';
|
|
41
|
+
|
|
42
|
+
export const lineNumbers = 'rgba(255,255,255,0.2)';
|
|
43
|
+
export const lineNumbersActive = 'rgba(255,255,255,0.5)';
|
|
44
|
+
export const selectionBackground = '#000';
|
|
45
|
+
export const selectionBackgroundMatch = 'rgba(0,0,0,0.4)';
|
|
46
|
+
export const lineHighlight = 'rgba(0,0,0,0.1)';
|
|
47
|
+
export const caretColor = 'white';
|
|
48
|
+
|
|
49
|
+
// Compute 6 colors that are evenly spaced in terms of hue
|
|
50
|
+
// Keeping this code around for future reference
|
|
51
|
+
// const rotation = 0.397;
|
|
52
|
+
// const numColors = 6;
|
|
53
|
+
// const highlightColors = Array.from(
|
|
54
|
+
// { length: numColors },
|
|
55
|
+
// (_, i) => {
|
|
56
|
+
// let t = (i / numColors + rotation) % 1;
|
|
57
|
+
// return hcl(t * 360, saturation, luminance).formatHex();
|
|
58
|
+
// },
|
|
59
|
+
// );
|
|
60
|
+
// console.log(JSON.stringify(highlightColors));
|
|
61
|
+
|
|
62
|
+
// We inline the colors here, but the code above is how they were generated.
|
|
63
|
+
const highlightColors = [
|
|
64
|
+
'#77fd8c',
|
|
65
|
+
'#00ffff',
|
|
66
|
+
'#66ecff',
|
|
67
|
+
'#ffb9ff',
|
|
68
|
+
'#ffabb3',
|
|
69
|
+
'#ffdb56',
|
|
70
|
+
];
|
|
71
|
+
|
|
72
|
+
export const MINT = highlightColors[0];
|
|
73
|
+
export const AQUA = highlightColors[1];
|
|
74
|
+
export const SKY = highlightColors[2];
|
|
75
|
+
export const LAVENDER = highlightColors[3];
|
|
76
|
+
export const SALMON = highlightColors[4];
|
|
77
|
+
export const GOLDENROD = highlightColors[5];
|
|
78
|
+
|
|
79
|
+
// Red that's not too bright, for errors
|
|
80
|
+
export const PANIC = '#ff2222';
|