vzcode 0.70.0 → 0.72.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 +1 -1
- package/dist/assets/{index-Bfl2hCW9.js → index-BfS1mzJK.js} +47 -47
- package/dist/assets/index-CpIQ8AoQ.css +1 -0
- package/dist/assets/{worker-D0nKlL79.js → worker-CH5jA9Si.js} +44 -44
- package/dist/index.html +2 -2
- package/package.json +20 -20
- package/src/client/AIAssist/AIAssistWidget/index.tsx +10 -3
- package/src/client/AIAssist/AIAssistWidget/style.scss +4 -2
- package/src/client/AIAssist/index.ts +0 -1
- package/src/client/App/index.tsx +2 -0
- package/src/client/App/style.scss +6 -0
- package/src/client/App/useShareDB.ts +12 -0
- package/src/client/CodeEditor/index.tsx +6 -5
- package/src/client/CodeEditor/style.scss +4 -0
- package/src/client/Fonts/fonts.ts +8 -0
- package/src/client/Icons/PlaySVG.tsx +16 -0
- package/src/client/Icons/index.tsx +1 -0
- package/src/client/RunCodeWidget/index.tsx +53 -0
- package/src/client/RunCodeWidget/style.scss +7 -0
- package/src/client/TabList/style.scss +4 -4
- package/src/client/VZCodeContext.tsx +20 -8
- package/src/client/VZMiddle.tsx +2 -0
- package/src/client/VZSettings.tsx +96 -7
- package/src/client/VZSidebar/index.tsx +8 -4
- package/src/client/VZSidebar/styles.scss +13 -11
- package/src/client/shouldTriggerRun.ts +0 -2
- package/src/client/useKeyboardShortcuts.ts +54 -16
- package/src/client/usePrettier/index.ts +34 -102
- package/src/client/useRunCode.tsx +28 -0
- package/src/client/useTypeScript/worker.ts +8 -1
- package/src/server/computeInitialDocument.js +2 -1
- package/src/server/index.js +1 -49
- package/src/types.ts +10 -0
- package/dist/assets/index-DOd2vdTJ.css +0 -1
package/dist/index.html
CHANGED
|
@@ -20,8 +20,8 @@
|
|
|
20
20
|
href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap"
|
|
21
21
|
rel="stylesheet"
|
|
22
22
|
/>
|
|
23
|
-
<script type="module" crossorigin src="/assets/index-
|
|
24
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
23
|
+
<script type="module" crossorigin src="/assets/index-BfS1mzJK.js"></script>
|
|
24
|
+
<link rel="stylesheet" crossorigin href="/assets/index-CpIQ8AoQ.css">
|
|
25
25
|
</head>
|
|
26
26
|
<body>
|
|
27
27
|
<div id="root"></div>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vzcode",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.72.0",
|
|
4
4
|
"description": "Multiplayer code editor system",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"type": "module",
|
|
@@ -66,12 +66,12 @@
|
|
|
66
66
|
"@codemirror/autocomplete": "^6.12.0",
|
|
67
67
|
"@codemirror/lang-css": "^6.2.1",
|
|
68
68
|
"@codemirror/lang-html": "^6.4.8",
|
|
69
|
-
"@codemirror/lang-javascript": "^6.2.
|
|
69
|
+
"@codemirror/lang-javascript": "^6.2.2",
|
|
70
70
|
"@codemirror/lang-json": "^6.0.1",
|
|
71
71
|
"@codemirror/lang-markdown": "^6.2.4",
|
|
72
|
-
"@codemirror/state": "^6.4.
|
|
72
|
+
"@codemirror/state": "^6.4.1",
|
|
73
73
|
"@codemirror/theme-one-dark": "^6.1.2",
|
|
74
|
-
"@codemirror/view": "^6.24.
|
|
74
|
+
"@codemirror/view": "^6.24.1",
|
|
75
75
|
"@lezer/highlight": "^1.2.0",
|
|
76
76
|
"@replit/codemirror-indentation-markers": "^6.5.0",
|
|
77
77
|
"@replit/codemirror-interact": "^6.3.0",
|
|
@@ -79,27 +79,27 @@
|
|
|
79
79
|
"@replit/codemirror-vscode-keymap": "^6.0.2",
|
|
80
80
|
"@teamwork/websocket-json-stream": "^2.0.0",
|
|
81
81
|
"@typescript/vfs": "^1.5.0",
|
|
82
|
-
"@uiw/codemirror-theme-abcdef": "^4.21.
|
|
83
|
-
"@uiw/codemirror-theme-dracula": "^4.21.
|
|
84
|
-
"@uiw/codemirror-theme-eclipse": "^4.21.
|
|
85
|
-
"@uiw/codemirror-theme-github": "^4.21.
|
|
86
|
-
"@uiw/codemirror-theme-material": "^4.21.
|
|
87
|
-
"@uiw/codemirror-theme-nord": "^4.21.
|
|
88
|
-
"@uiw/codemirror-theme-okaidia": "^4.21.
|
|
89
|
-
"@uiw/codemirror-theme-xcode": "^4.21.
|
|
90
|
-
"@uiw/codemirror-themes": "^4.21.
|
|
82
|
+
"@uiw/codemirror-theme-abcdef": "^4.21.24",
|
|
83
|
+
"@uiw/codemirror-theme-dracula": "^4.21.24",
|
|
84
|
+
"@uiw/codemirror-theme-eclipse": "^4.21.24",
|
|
85
|
+
"@uiw/codemirror-theme-github": "^4.21.24",
|
|
86
|
+
"@uiw/codemirror-theme-material": "^4.21.24",
|
|
87
|
+
"@uiw/codemirror-theme-nord": "^4.21.24",
|
|
88
|
+
"@uiw/codemirror-theme-okaidia": "^4.21.24",
|
|
89
|
+
"@uiw/codemirror-theme-xcode": "^4.21.24",
|
|
90
|
+
"@uiw/codemirror-themes": "^4.21.24",
|
|
91
91
|
"body-parser": "^1.20.2",
|
|
92
92
|
"codemirror": "^6.0.1",
|
|
93
93
|
"codemirror-ot": "^4.2.0",
|
|
94
94
|
"color-hash": "^2.0.2",
|
|
95
95
|
"d3-array": "^3.2.4",
|
|
96
96
|
"diff-match-patch": "^1.0.5",
|
|
97
|
-
"dotenv": "^16.4.
|
|
97
|
+
"dotenv": "^16.4.5",
|
|
98
98
|
"express": "^4.18.2",
|
|
99
99
|
"ignore": "^5.3.1",
|
|
100
100
|
"json0-ot-diff": "^1.1.2",
|
|
101
101
|
"ngrok": "^4.3.3",
|
|
102
|
-
"open": "^10.0.
|
|
102
|
+
"open": "^10.0.4",
|
|
103
103
|
"openai": "^4.28.0",
|
|
104
104
|
"prettier-plugin-svelte": "^3.2.1",
|
|
105
105
|
"react": "^18.2.0",
|
|
@@ -108,18 +108,18 @@
|
|
|
108
108
|
"react-router-dom": "^6.22.1",
|
|
109
109
|
"sharedb": "^4.1.2",
|
|
110
110
|
"sharedb-client-browser": "^4.4.0",
|
|
111
|
-
"vizhub-ui": "^3.
|
|
111
|
+
"vizhub-ui": "^3.21.0",
|
|
112
112
|
"ws": "^8.16.0"
|
|
113
113
|
},
|
|
114
114
|
"devDependencies": {
|
|
115
|
-
"@types/react": "^18.2.
|
|
115
|
+
"@types/react": "^18.2.60",
|
|
116
116
|
"@types/react-dom": "^18.2.19",
|
|
117
117
|
"@vitejs/plugin-react": "^4.2.1",
|
|
118
118
|
"concurrently": "^8.2.2",
|
|
119
119
|
"prettier": "^3.2.5",
|
|
120
|
-
"sass": "^1.71.
|
|
120
|
+
"sass": "^1.71.1",
|
|
121
121
|
"typescript": "^5.3.3",
|
|
122
|
-
"vite": "^5.1.
|
|
123
|
-
"vitest": "^1.3.
|
|
122
|
+
"vite": "^5.1.4",
|
|
123
|
+
"vitest": "^1.3.1"
|
|
124
124
|
}
|
|
125
125
|
}
|
|
@@ -11,11 +11,11 @@ import {
|
|
|
11
11
|
RequestId,
|
|
12
12
|
generateRequestId,
|
|
13
13
|
} from '../../generateRequestId';
|
|
14
|
-
import { SparklesSVG
|
|
14
|
+
import { SparklesSVG } from '../../Icons';
|
|
15
15
|
import { startAIAssist } from '../startAIAssist';
|
|
16
|
-
import './style.scss';
|
|
17
16
|
import { Spinner } from '../Spinner';
|
|
18
17
|
import { VZCodeContext } from '../../VZCodeContext';
|
|
18
|
+
import './style.scss';
|
|
19
19
|
|
|
20
20
|
const enableStopGeneration = false;
|
|
21
21
|
|
|
@@ -45,7 +45,8 @@ export const AIAssistWidget = ({
|
|
|
45
45
|
const [aiStreamId, setAiStreamId] =
|
|
46
46
|
useState<RequestId | null>(null);
|
|
47
47
|
|
|
48
|
-
const { runPrettierRef } =
|
|
48
|
+
const { runPrettierRef, runCodeRef } =
|
|
49
|
+
useContext(VZCodeContext);
|
|
49
50
|
|
|
50
51
|
const handleClick = useCallback(async () => {
|
|
51
52
|
const isCurrentlyGenerationg = aiStreamId !== null;
|
|
@@ -72,6 +73,12 @@ export const AIAssistWidget = ({
|
|
|
72
73
|
runPrettier();
|
|
73
74
|
}
|
|
74
75
|
|
|
76
|
+
// Run the code after the AI Assist.
|
|
77
|
+
const runCode = runCodeRef.current;
|
|
78
|
+
if (runCode !== null) {
|
|
79
|
+
runCode();
|
|
80
|
+
}
|
|
81
|
+
|
|
75
82
|
// Handles the case that the user has started,
|
|
76
83
|
// stopped, and started again before the first request
|
|
77
84
|
// has finished, bu comparing the current stream ID
|
package/src/client/App/index.tsx
CHANGED
|
@@ -61,6 +61,7 @@ function App() {
|
|
|
61
61
|
localPresence,
|
|
62
62
|
docPresence,
|
|
63
63
|
submitOperation,
|
|
64
|
+
connected,
|
|
64
65
|
} = useShareDB({
|
|
65
66
|
connection,
|
|
66
67
|
});
|
|
@@ -87,6 +88,7 @@ function App() {
|
|
|
87
88
|
prettierWorker={prettierWorker}
|
|
88
89
|
typeScriptWorker={typeScriptWorker}
|
|
89
90
|
initialUsername={initialUsername}
|
|
91
|
+
connected={connected}
|
|
90
92
|
>
|
|
91
93
|
<div className="app">
|
|
92
94
|
<VZLeft />
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
@import url('https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,100..700;1,100..700&display=swap');
|
|
2
|
+
@import url('https://fonts.googleapis.com/css2?family=Inconsolata:wght@200..900&display=swap');
|
|
3
|
+
@import url('https://fonts.googleapis.com/css2?family=Source+Code+Pro:ital,wght@0,200..900;1,200..900&display=swap');
|
|
4
|
+
@import url('https://fonts.googleapis.com/css2?family=Ubuntu+Mono:ital,wght@0,400;0,700;1,400;1,700&display=swap');
|
|
5
|
+
@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:ital,wght@0,100..800;1,100..800&display=swap');
|
|
6
|
+
@import url('https://fonts.googleapis.com/css2?family=Fira+Code:wght@300..700&display=swap');
|
|
1
7
|
:root {
|
|
2
8
|
// --vzcode-font-family: ui-monospace, SFMono-Regular,
|
|
3
9
|
// 'SF Mono', Menlo, Consolas, 'Liberation Mono', monospace !important;
|
|
@@ -28,7 +28,18 @@ export const useShareDB = ({
|
|
|
28
28
|
const [content, setContent] =
|
|
29
29
|
useState<VZCodeContent | null>(null);
|
|
30
30
|
|
|
31
|
+
const [connected, setConnected] =
|
|
32
|
+
useState<boolean>(false);
|
|
31
33
|
useEffect(() => {
|
|
34
|
+
// Listen for connection state changes
|
|
35
|
+
connection.on('connected', () => {
|
|
36
|
+
setConnected(true);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
connection.on('disconnected', () => {
|
|
40
|
+
setConnected(false);
|
|
41
|
+
});
|
|
42
|
+
|
|
32
43
|
// Since there is only ever a single document,
|
|
33
44
|
// these things are pretty arbitrary.
|
|
34
45
|
// * `collection` - the ShareDB collection to use
|
|
@@ -106,5 +117,6 @@ export const useShareDB = ({
|
|
|
106
117
|
localPresence,
|
|
107
118
|
docPresence,
|
|
108
119
|
submitOperation,
|
|
120
|
+
connected,
|
|
109
121
|
};
|
|
110
122
|
};
|
|
@@ -80,13 +80,14 @@ export const CodeEditor = ({
|
|
|
80
80
|
clearTimeout(interactTimeoutRef.current);
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
// Set `isInteracting:
|
|
83
|
+
// Set `isInteracting: undefined` after a delay.
|
|
84
84
|
interactTimeoutRef.current = setTimeout(() => {
|
|
85
85
|
interactTimeoutRef.current = null;
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
86
|
+
|
|
87
|
+
// This logic deletes the `isInteracting` property from the document.
|
|
88
|
+
submitOperation(
|
|
89
|
+
({ isInteracting, ...newDocument }) => newDocument,
|
|
90
|
+
);
|
|
90
91
|
}, 800);
|
|
91
92
|
}, [submitOperation]);
|
|
92
93
|
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export const PlaySVG = () => (
|
|
2
|
+
<svg
|
|
3
|
+
width="24"
|
|
4
|
+
height="24"
|
|
5
|
+
fill="none"
|
|
6
|
+
viewBox="0 0 24 24"
|
|
7
|
+
strokeWidth={1.5}
|
|
8
|
+
stroke="currentColor"
|
|
9
|
+
>
|
|
10
|
+
<path
|
|
11
|
+
strokeLinecap="round"
|
|
12
|
+
strokeLinejoin="round"
|
|
13
|
+
d="M5.25 5.653c0-.856.917-1.398 1.667-.986l11.54 6.347a1.125 1.125 0 0 1 0 1.972l-11.54 6.347a1.125 1.125 0 0 1-1.667-.986V5.653Z"
|
|
14
|
+
/>
|
|
15
|
+
</svg>
|
|
16
|
+
);
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { useCallback, useContext } from 'react';
|
|
2
|
+
import { PlaySVG } from '../Icons';
|
|
3
|
+
import { VZCodeContext } from '../VZCodeContext';
|
|
4
|
+
import { OverlayTrigger, Tooltip } from '../bootstrap';
|
|
5
|
+
import './style.scss';
|
|
6
|
+
|
|
7
|
+
export const RunCodeWidget = ({
|
|
8
|
+
runCodeWidgetTooltipText = (
|
|
9
|
+
<>
|
|
10
|
+
<strong>Run Code</strong>
|
|
11
|
+
<div>(Shift + Enter or Ctrl + s)</div>
|
|
12
|
+
</>
|
|
13
|
+
),
|
|
14
|
+
}: {
|
|
15
|
+
runCodeWidgetTooltipText?: JSX.Element;
|
|
16
|
+
}) => {
|
|
17
|
+
const { runCodeRef, runPrettierRef } =
|
|
18
|
+
useContext(VZCodeContext);
|
|
19
|
+
|
|
20
|
+
const handleClick = useCallback(() => {
|
|
21
|
+
// Run Prettier
|
|
22
|
+
const runPrettier = runPrettierRef.current;
|
|
23
|
+
if (runPrettier !== null) {
|
|
24
|
+
runPrettier();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Run the code
|
|
28
|
+
const runCode = runCodeRef.current;
|
|
29
|
+
if (runCode !== null) {
|
|
30
|
+
runCode();
|
|
31
|
+
}
|
|
32
|
+
}, []);
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<div className="vz-code-run-code-widget">
|
|
36
|
+
<OverlayTrigger
|
|
37
|
+
placement="left"
|
|
38
|
+
overlay={
|
|
39
|
+
<Tooltip id="run-code-widget-tooltip">
|
|
40
|
+
{runCodeWidgetTooltipText}
|
|
41
|
+
</Tooltip>
|
|
42
|
+
}
|
|
43
|
+
>
|
|
44
|
+
<i
|
|
45
|
+
className="icon-button icon-button-dark"
|
|
46
|
+
onClick={handleClick}
|
|
47
|
+
>
|
|
48
|
+
<PlaySVG />
|
|
49
|
+
</i>
|
|
50
|
+
</OverlayTrigger>
|
|
51
|
+
</div>
|
|
52
|
+
);
|
|
53
|
+
};
|
|
@@ -12,10 +12,10 @@
|
|
|
12
12
|
align-items: center;
|
|
13
13
|
display: flex;
|
|
14
14
|
gap: 8px;
|
|
15
|
-
padding:
|
|
16
|
-
border-top-left-radius:
|
|
17
|
-
border-top-right-radius:
|
|
18
|
-
margin-top:
|
|
15
|
+
padding: 6px 6px 6px 16px;
|
|
16
|
+
border-top-left-radius: 8px;
|
|
17
|
+
border-top-right-radius: 8px;
|
|
18
|
+
margin-top: 6px;
|
|
19
19
|
margin-left: 2px;
|
|
20
20
|
margin-right: 2px;
|
|
21
21
|
cursor: pointer;
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
import {
|
|
8
8
|
Files,
|
|
9
9
|
ShareDBDoc,
|
|
10
|
+
SubmitOperation,
|
|
10
11
|
Username,
|
|
11
12
|
VZCodeContent,
|
|
12
13
|
} from '../types';
|
|
@@ -31,6 +32,7 @@ import {
|
|
|
31
32
|
} from './useEditorCache';
|
|
32
33
|
import { useURLSync } from './useURLSync';
|
|
33
34
|
import { useKeyboardShortcuts } from './useKeyboardShortcuts';
|
|
35
|
+
import { useRunCode } from './useRunCode';
|
|
34
36
|
|
|
35
37
|
// This context centralizes all the "smart" logic
|
|
36
38
|
// to do with the application state. This includes
|
|
@@ -98,6 +100,9 @@ export type VZCodeContextValue = {
|
|
|
98
100
|
runPrettierRef: React.MutableRefObject<
|
|
99
101
|
null | (() => void)
|
|
100
102
|
>;
|
|
103
|
+
runCodeRef: React.MutableRefObject<null | (() => void)>;
|
|
104
|
+
|
|
105
|
+
connected: boolean;
|
|
101
106
|
};
|
|
102
107
|
|
|
103
108
|
export const VZCodeProvider = ({
|
|
@@ -112,12 +117,11 @@ export const VZCodeProvider = ({
|
|
|
112
117
|
children,
|
|
113
118
|
codeError = null,
|
|
114
119
|
enableManualPretter = true,
|
|
120
|
+
connected,
|
|
115
121
|
}: {
|
|
116
122
|
content: VZCodeContent;
|
|
117
123
|
shareDBDoc: ShareDBDoc<VZCodeContent>;
|
|
118
|
-
submitOperation:
|
|
119
|
-
next: (content: VZCodeContent) => VZCodeContent,
|
|
120
|
-
) => void;
|
|
124
|
+
submitOperation: SubmitOperation;
|
|
121
125
|
localPresence: any;
|
|
122
126
|
docPresence: any;
|
|
123
127
|
prettierWorker: Worker;
|
|
@@ -126,6 +130,7 @@ export const VZCodeProvider = ({
|
|
|
126
130
|
children: React.ReactNode;
|
|
127
131
|
codeError?: string | null;
|
|
128
132
|
enableManualPretter?: boolean;
|
|
133
|
+
connected: boolean;
|
|
129
134
|
}) => {
|
|
130
135
|
// Auto-run Pretter after local changes.
|
|
131
136
|
const {
|
|
@@ -143,6 +148,8 @@ export const VZCodeProvider = ({
|
|
|
143
148
|
enableManualPretter,
|
|
144
149
|
});
|
|
145
150
|
|
|
151
|
+
const runCodeRef = useRunCode(submitOperation);
|
|
152
|
+
|
|
146
153
|
// The error message shows either:
|
|
147
154
|
// * `prettierError` - errors from Prettier, client-side only
|
|
148
155
|
// * `codeError` - errors from an external source, such as
|
|
@@ -247,19 +254,21 @@ export const VZCodeProvider = ({
|
|
|
247
254
|
[createFile, setIsCreateFileModalOpen],
|
|
248
255
|
);
|
|
249
256
|
|
|
257
|
+
// Isolate the files object from the document.
|
|
258
|
+
const files: Files | null = content
|
|
259
|
+
? content.files
|
|
260
|
+
: null;
|
|
261
|
+
|
|
250
262
|
useKeyboardShortcuts({
|
|
251
263
|
closeTabs,
|
|
252
264
|
activeFileId,
|
|
253
265
|
handleOpenCreateFileModal,
|
|
254
266
|
setActiveFileLeft,
|
|
255
267
|
setActiveFileRight,
|
|
268
|
+
runPrettierRef,
|
|
269
|
+
runCodeRef,
|
|
256
270
|
});
|
|
257
271
|
|
|
258
|
-
// Isolate the files object from the document.
|
|
259
|
-
const files: Files | null = content
|
|
260
|
-
? content.files
|
|
261
|
-
: null;
|
|
262
|
-
|
|
263
272
|
// The value provided by this context.
|
|
264
273
|
const value: VZCodeContextValue = {
|
|
265
274
|
content,
|
|
@@ -309,6 +318,9 @@ export const VZCodeProvider = ({
|
|
|
309
318
|
handleCloseCreateFileModal,
|
|
310
319
|
handleCreateFileClick,
|
|
311
320
|
runPrettierRef,
|
|
321
|
+
runCodeRef,
|
|
322
|
+
|
|
323
|
+
connected,
|
|
312
324
|
};
|
|
313
325
|
|
|
314
326
|
return (
|
package/src/client/VZMiddle.tsx
CHANGED
|
@@ -6,6 +6,7 @@ import { CodeErrorOverlay } from './CodeErrorOverlay';
|
|
|
6
6
|
import { PresenceNotifications } from './PresenceNotifications';
|
|
7
7
|
import { AIAssistWidget } from './AIAssist/AIAssistWidget';
|
|
8
8
|
import { VZCodeContext } from './VZCodeContext';
|
|
9
|
+
import { RunCodeWidget } from './RunCodeWidget';
|
|
9
10
|
|
|
10
11
|
// The middle portion of the VZCode environment, containing:
|
|
11
12
|
// * The list of tabs at the top
|
|
@@ -106,6 +107,7 @@ export const VZMiddle = ({
|
|
|
106
107
|
aiAssistClickOverride={aiAssistClickOverride}
|
|
107
108
|
/>
|
|
108
109
|
) : null}
|
|
110
|
+
<RunCodeWidget />
|
|
109
111
|
<CodeErrorOverlay
|
|
110
112
|
errorMessage={errorMessage}
|
|
111
113
|
content={content}
|
|
@@ -1,7 +1,16 @@
|
|
|
1
|
-
import
|
|
1
|
+
import React, {
|
|
2
|
+
useCallback,
|
|
3
|
+
useContext,
|
|
4
|
+
useEffect,
|
|
5
|
+
useRef,
|
|
6
|
+
useState,
|
|
7
|
+
} from 'react';
|
|
2
8
|
import { Button, Modal, Form } from './bootstrap';
|
|
3
|
-
import { themes } from './themes';
|
|
9
|
+
import { ThemeLabel, themes } from './themes';
|
|
4
10
|
import { VZCodeContext } from './VZCodeContext';
|
|
11
|
+
import { fonts } from './Fonts/fonts';
|
|
12
|
+
|
|
13
|
+
const fontSizes = ['16px', '18px', '20px', '24px'];
|
|
5
14
|
|
|
6
15
|
export const VZSettings = ({
|
|
7
16
|
enableUsernameField = true,
|
|
@@ -18,11 +27,51 @@ export const VZSettings = ({
|
|
|
18
27
|
setUsername,
|
|
19
28
|
} = useContext(VZCodeContext);
|
|
20
29
|
|
|
21
|
-
const handleThemeChange = useCallback(
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
30
|
+
const handleThemeChange = useCallback(
|
|
31
|
+
(event: React.ChangeEvent<HTMLSelectElement>) => {
|
|
32
|
+
setTheme(event.target.value as ThemeLabel);
|
|
33
|
+
},
|
|
34
|
+
[],
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
// Track selected font and font size.
|
|
38
|
+
// TODO store these in local storage
|
|
39
|
+
const [selectedFont, setSelectedFont] =
|
|
40
|
+
useState('Roboto Mono');
|
|
41
|
+
const [selectedFontSize, setSelectedFontSize] =
|
|
42
|
+
useState('16px');
|
|
43
|
+
|
|
44
|
+
// Called when the user selects a different font
|
|
45
|
+
const handleFontChange = useCallback(
|
|
46
|
+
(event: React.ChangeEvent<HTMLSelectElement>) => {
|
|
47
|
+
setSelectedFont(event.target.value);
|
|
48
|
+
},
|
|
49
|
+
[],
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
// Called when the user selects a different font size
|
|
53
|
+
const handleFontSizeChange = (
|
|
54
|
+
event: React.ChangeEvent<HTMLSelectElement>,
|
|
55
|
+
) => {
|
|
56
|
+
setSelectedFontSize(event.target.value);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
useEffect(() => {
|
|
60
|
+
document.body.style.setProperty(
|
|
61
|
+
'--vzcode-font-family',
|
|
62
|
+
selectedFont,
|
|
63
|
+
);
|
|
64
|
+
}, [selectedFont]);
|
|
65
|
+
|
|
66
|
+
useEffect(() => {
|
|
67
|
+
// const fontSize = event.target.value;
|
|
68
|
+
// const root = document.documentElement;
|
|
69
|
+
// root.style.setProperty('--vzcode-font-size', fontSize);
|
|
70
|
+
document.body.style.setProperty(
|
|
71
|
+
'--vzcode-font-size',
|
|
72
|
+
selectedFontSize,
|
|
73
|
+
);
|
|
74
|
+
}, [selectedFontSize]);
|
|
26
75
|
|
|
27
76
|
const usernameRef = useRef<HTMLInputElement>(null);
|
|
28
77
|
|
|
@@ -77,6 +126,46 @@ export const VZSettings = ({
|
|
|
77
126
|
Select a color theme for the editor
|
|
78
127
|
</Form.Text>
|
|
79
128
|
</Form.Group>
|
|
129
|
+
|
|
130
|
+
<Form.Group className="mb-3" controlId="formFork">
|
|
131
|
+
<Form.Label>Font</Form.Label>
|
|
132
|
+
|
|
133
|
+
<select
|
|
134
|
+
className="form-select"
|
|
135
|
+
onChange={handleFontChange}
|
|
136
|
+
value={selectedFont}
|
|
137
|
+
>
|
|
138
|
+
{fonts.map((font) => (
|
|
139
|
+
<option key={font} value={font}>
|
|
140
|
+
{font}
|
|
141
|
+
</option>
|
|
142
|
+
))}
|
|
143
|
+
</select>
|
|
144
|
+
|
|
145
|
+
<Form.Text className="text-muted">
|
|
146
|
+
Select font for the editor
|
|
147
|
+
</Form.Text>
|
|
148
|
+
</Form.Group>
|
|
149
|
+
|
|
150
|
+
<Form.Group className="mb-3" controlId="formFork">
|
|
151
|
+
<Form.Label>Font Size</Form.Label>
|
|
152
|
+
|
|
153
|
+
<select
|
|
154
|
+
className="form-select"
|
|
155
|
+
onChange={handleFontSizeChange}
|
|
156
|
+
value={selectedFontSize}
|
|
157
|
+
>
|
|
158
|
+
{fontSizes.map((size) => (
|
|
159
|
+
<option key={size} value={size}>
|
|
160
|
+
{size}
|
|
161
|
+
</option>
|
|
162
|
+
))}
|
|
163
|
+
</select>
|
|
164
|
+
|
|
165
|
+
<Form.Text className="text-muted">
|
|
166
|
+
Select a font size for the editor
|
|
167
|
+
</Form.Text>
|
|
168
|
+
</Form.Group>
|
|
80
169
|
</Modal.Body>
|
|
81
170
|
<Modal.Footer>
|
|
82
171
|
<Button variant="primary" onClick={closeSettings}>
|
|
@@ -17,7 +17,7 @@ import './styles.scss';
|
|
|
17
17
|
// TODO turn this UI back on when we are actually detecting
|
|
18
18
|
// the connection status.
|
|
19
19
|
// See https://github.com/vizhub-core/vzcode/issues/456
|
|
20
|
-
const enableConnectionStatus =
|
|
20
|
+
const enableConnectionStatus = true;
|
|
21
21
|
|
|
22
22
|
export const VZSidebar = ({
|
|
23
23
|
createFileTooltipText = 'New File',
|
|
@@ -39,6 +39,7 @@ export const VZSidebar = ({
|
|
|
39
39
|
isDirectoryOpen,
|
|
40
40
|
toggleDirectory,
|
|
41
41
|
handleOpenCreateFileModal,
|
|
42
|
+
connected,
|
|
42
43
|
} = useContext(VZCodeContext);
|
|
43
44
|
|
|
44
45
|
const fileTree = useMemo(
|
|
@@ -174,10 +175,13 @@ export const VZSidebar = ({
|
|
|
174
175
|
|
|
175
176
|
{enableConnectionStatus && (
|
|
176
177
|
<div className="connection-status">
|
|
177
|
-
Connection
|
|
178
|
+
{connected ? 'Connected' : 'Connection Lost'}
|
|
178
179
|
<div className="connection">
|
|
179
|
-
|
|
180
|
-
|
|
180
|
+
<div
|
|
181
|
+
className={`connection-status-indicator ${
|
|
182
|
+
connected ? 'connected' : 'disconnected'
|
|
183
|
+
}`}
|
|
184
|
+
/>
|
|
181
185
|
</div>
|
|
182
186
|
</div>
|
|
183
187
|
)}
|
|
@@ -131,18 +131,20 @@
|
|
|
131
131
|
display: flex;
|
|
132
132
|
justify-content: space-between;
|
|
133
133
|
padding: 10px;
|
|
134
|
-
|
|
134
|
+
font-size: 12px;
|
|
135
135
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
136
|
+
.connection-status-indicator {
|
|
137
|
+
width: 16px;
|
|
138
|
+
height: 16px;
|
|
139
|
+
border-radius: 50%;
|
|
140
|
+
|
|
141
|
+
&.connected {
|
|
142
|
+
background-color: var(--vh-color-success-01);
|
|
143
|
+
}
|
|
141
144
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
background-color: #34eb52;
|
|
145
|
+
&.disconnected {
|
|
146
|
+
background-color: var(--vh-color-warning-01);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
147
149
|
}
|
|
148
150
|
}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
// This module is responsible for checking
|
|
2
2
|
// keyboard events and determining whether
|
|
3
3
|
// a run should be triggered or not.
|
|
4
|
-
//
|
|
5
|
-
// The most common case is when the us
|
|
6
4
|
export const shouldTriggerRun = (event: KeyboardEvent) => {
|
|
7
5
|
const isMac = /Mac|iMac|MacBook/i.test(
|
|
8
6
|
navigator.userAgent,
|