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.
Files changed (34) hide show
  1. package/README.md +1 -1
  2. package/dist/assets/{index-Bfl2hCW9.js → index-BfS1mzJK.js} +47 -47
  3. package/dist/assets/index-CpIQ8AoQ.css +1 -0
  4. package/dist/assets/{worker-D0nKlL79.js → worker-CH5jA9Si.js} +44 -44
  5. package/dist/index.html +2 -2
  6. package/package.json +20 -20
  7. package/src/client/AIAssist/AIAssistWidget/index.tsx +10 -3
  8. package/src/client/AIAssist/AIAssistWidget/style.scss +4 -2
  9. package/src/client/AIAssist/index.ts +0 -1
  10. package/src/client/App/index.tsx +2 -0
  11. package/src/client/App/style.scss +6 -0
  12. package/src/client/App/useShareDB.ts +12 -0
  13. package/src/client/CodeEditor/index.tsx +6 -5
  14. package/src/client/CodeEditor/style.scss +4 -0
  15. package/src/client/Fonts/fonts.ts +8 -0
  16. package/src/client/Icons/PlaySVG.tsx +16 -0
  17. package/src/client/Icons/index.tsx +1 -0
  18. package/src/client/RunCodeWidget/index.tsx +53 -0
  19. package/src/client/RunCodeWidget/style.scss +7 -0
  20. package/src/client/TabList/style.scss +4 -4
  21. package/src/client/VZCodeContext.tsx +20 -8
  22. package/src/client/VZMiddle.tsx +2 -0
  23. package/src/client/VZSettings.tsx +96 -7
  24. package/src/client/VZSidebar/index.tsx +8 -4
  25. package/src/client/VZSidebar/styles.scss +13 -11
  26. package/src/client/shouldTriggerRun.ts +0 -2
  27. package/src/client/useKeyboardShortcuts.ts +54 -16
  28. package/src/client/usePrettier/index.ts +34 -102
  29. package/src/client/useRunCode.tsx +28 -0
  30. package/src/client/useTypeScript/worker.ts +8 -1
  31. package/src/server/computeInitialDocument.js +2 -1
  32. package/src/server/index.js +1 -49
  33. package/src/types.ts +10 -0
  34. 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-Bfl2hCW9.js"></script>
24
- <link rel="stylesheet" crossorigin href="/assets/index-DOd2vdTJ.css">
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.70.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.1",
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.0",
72
+ "@codemirror/state": "^6.4.1",
73
73
  "@codemirror/theme-one-dark": "^6.1.2",
74
- "@codemirror/view": "^6.24.0",
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.21",
83
- "@uiw/codemirror-theme-dracula": "^4.21.21",
84
- "@uiw/codemirror-theme-eclipse": "^4.21.21",
85
- "@uiw/codemirror-theme-github": "^4.21.21",
86
- "@uiw/codemirror-theme-material": "^4.21.21",
87
- "@uiw/codemirror-theme-nord": "^4.21.21",
88
- "@uiw/codemirror-theme-okaidia": "^4.21.21",
89
- "@uiw/codemirror-theme-xcode": "^4.21.21",
90
- "@uiw/codemirror-themes": "^4.21.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.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.3",
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.19.0",
111
+ "vizhub-ui": "^3.21.0",
112
112
  "ws": "^8.16.0"
113
113
  },
114
114
  "devDependencies": {
115
- "@types/react": "^18.2.55",
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.0",
120
+ "sass": "^1.71.1",
121
121
  "typescript": "^5.3.3",
122
- "vite": "^5.1.3",
123
- "vitest": "^1.3.0"
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, StopSVG } from '../../Icons';
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 } = useContext(VZCodeContext);
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
@@ -1,7 +1,9 @@
1
1
  .vz-code-ai-assist-widget {
2
2
  position: absolute;
3
- bottom: 32px;
4
- right: 32px;
3
+ // bottom: 32px;
4
+ // right: 32px;
5
+ bottom: 16px;
6
+ right: 16px;
5
7
  color: var(--vh-color-caution-01);
6
8
  }
7
9
 
@@ -1,3 +1,2 @@
1
1
  export { AIAssistWidget } from './AIAssistWidget';
2
2
  export { AIAssistCodeMirrorKeyMap } from './AIAssistCodeMirrorKeyMap';
3
- export type { AIAssistState } from './AIAssistState';
@@ -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: false` after a delay.
83
+ // Set `isInteracting: undefined` after a delay.
84
84
  interactTimeoutRef.current = setTimeout(() => {
85
85
  interactTimeoutRef.current = null;
86
- submitOperation((document) => ({
87
- ...document,
88
- isInteracting: false,
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
 
@@ -43,4 +43,8 @@
43
43
  background-color: #0077cc;
44
44
  color: white;
45
45
  }
46
+
47
+ .cm-line {
48
+ font-family: var(--vzcode-font-family);
49
+ }
46
50
  }
@@ -0,0 +1,8 @@
1
+ export const fonts = [
2
+ 'Roboto Mono',
3
+ 'Inconsolata',
4
+ 'Source Code Pro',
5
+ 'Ubuntu Mono',
6
+ 'JetBrains Mono',
7
+ 'Fira Code',
8
+ ];
@@ -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
+ );
@@ -8,3 +8,4 @@ export { TrashSVG } from './TrashSVG';
8
8
  export { BugSVG } from './BugSVG';
9
9
  export { FileSVG } from './FileSVG';
10
10
  export { DirectoryArrowSVG } from './DirectoryArrowSVG';
11
+ export { PlaySVG } from './PlaySVG';
@@ -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
+ };
@@ -0,0 +1,7 @@
1
+ .vz-code-run-code-widget {
2
+ position: absolute;
3
+ right: 16px;
4
+ top: 9px;
5
+ // color: var(--vh-color-caution-01);
6
+ color: var(--vh-color-neutral-04);
7
+ }
@@ -12,10 +12,10 @@
12
12
  align-items: center;
13
13
  display: flex;
14
14
  gap: 8px;
15
- padding: 8px 8px 8px 16px;
16
- border-top-left-radius: 4px;
17
- border-top-right-radius: 4px;
18
- margin-top: 5px;
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 (
@@ -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 { useCallback, useContext, useRef } from 'react';
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((event) => {
22
- const selectedValue = event.target.value;
23
- console.log(selectedValue);
24
- setTheme(selectedValue);
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 = false;
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 Status
178
+ {connected ? 'Connected' : 'Connection Lost'}
178
179
  <div className="connection">
179
- Saved
180
- <div className="saved" />
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
- .connection {
137
- display: flex;
138
- gap: 6px;
139
- align-items: center;
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
- .saved {
143
- width: 16px;
144
- height: 16px;
145
- border-radius: 99px;
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,