vzcode 1.16.0 → 1.18.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-CSSpCKM0.js +447 -0
- package/dist/assets/index-eifYAxsF.js +181 -0
- package/dist/assets/index-zzK6rRiK.css +1 -0
- package/dist/assets/worker-8af7bTHW.js +293 -0
- package/dist/index.html +2 -2
- package/package.json +40 -34
- package/src/client/App/index.tsx +52 -20
- package/src/client/App/usePending.ts +50 -0
- package/src/client/App/useShareDB.ts +40 -1
- package/src/client/CodeEditor/Copilot/index.ts +28 -0
- package/src/client/CodeEditor/InteractiveWidgets/colorPicker.ts +129 -33
- package/src/client/CodeEditor/InteractiveWidgets/colorsInTextPlugin.ts +36 -1
- package/src/client/CodeEditor/getOrCreateEditor.ts +43 -6
- package/src/client/CodeEditor/index.tsx +4 -1
- package/src/client/CodeEditor/rainbowBrackets.ts +14 -2
- package/src/client/CodeEditor/style.scss +106 -1
- package/src/client/Icons/MicSVG.tsx +25 -0
- package/src/client/RunCodeWidget/index.tsx +20 -3
- package/src/client/VZCodeContext.tsx +52 -14
- package/src/client/VZKeyboardShortcutsDoc.tsx +8 -8
- package/src/client/VZLeft.tsx +5 -2
- package/src/client/VZMiddle.tsx +5 -0
- package/src/client/VZSettings.tsx +54 -3
- package/src/client/VZSidebar/VoiceChatModal.tsx +121 -0
- package/src/client/VZSidebar/index.tsx +93 -14
- package/src/client/VZSidebar/styles.scss +6 -1
- package/src/client/featureFlags.ts +2 -0
- package/src/client/useTypeScript/worker/constants.ts +6 -0
- package/src/server/generateAIResponse.js +79 -13
- package/src/server/handleAICopilot.js +77 -0
- package/src/server/index.js +23 -8
- package/src/server/livekit.js +24 -0
- package/src/server/setupEnv.js +1 -1
- package/src/types.ts +1 -0
- package/src/vite-env.d.ts +10 -0
- package/dist/assets/index-B6yTvvah.css +0 -1
- package/dist/assets/index-BlwLvENZ.js +0 -159
- package/dist/assets/index-Bm65AzMP.js +0 -425
- package/dist/assets/worker-CJWrLBN2.js +0 -286
|
@@ -10,11 +10,13 @@ import { markdown } from '@codemirror/lang-markdown';
|
|
|
10
10
|
import { html } from '@codemirror/lang-html';
|
|
11
11
|
import { css } from '@codemirror/lang-css';
|
|
12
12
|
import { json1Sync } from 'codemirror-ot';
|
|
13
|
+
|
|
13
14
|
import { autocompletion } from '@codemirror/autocomplete';
|
|
14
15
|
import { indentationMarkers } from '@replit/codemirror-indentation-markers';
|
|
15
16
|
// import { showMinimap } from '@replit/codemirror-minimap';
|
|
16
17
|
import { vscodeKeymap } from '@replit/codemirror-vscode-keymap';
|
|
17
18
|
import { Diagnostic, linter } from '@codemirror/lint';
|
|
19
|
+
|
|
18
20
|
import { json1Presence, textUnicode } from '../../ot';
|
|
19
21
|
import {
|
|
20
22
|
FileId,
|
|
@@ -45,11 +47,14 @@ import { InteractRule } from '@replit/codemirror-interact';
|
|
|
45
47
|
import rainbowBrackets from '../CodeEditor/rainbowBrackets';
|
|
46
48
|
import { cssLanguage } from '@codemirror/lang-css';
|
|
47
49
|
import { javascriptLanguage } from '@codemirror/lang-javascript';
|
|
50
|
+
import { copilot } from './Copilot';
|
|
48
51
|
|
|
49
52
|
// Feature flag to enable TypeScript completions & TypeScript Linter.
|
|
50
|
-
const enableTypeScriptCompletions = true;
|
|
51
53
|
const enableTypeScriptLinter = true;
|
|
52
54
|
|
|
55
|
+
// Feature flag to enable AI copilot
|
|
56
|
+
const enableCopilot = true;
|
|
57
|
+
|
|
53
58
|
// Enables TypeScript +JSX support in CodeMirror.
|
|
54
59
|
const tsx = () =>
|
|
55
60
|
javascript({ jsx: true, typescript: true });
|
|
@@ -74,6 +79,7 @@ const htmlConfig = {
|
|
|
74
79
|
],
|
|
75
80
|
nestedAttributes: [],
|
|
76
81
|
};
|
|
82
|
+
|
|
77
83
|
// Language extensions for CodeMirror.
|
|
78
84
|
// Keys are file extensions.
|
|
79
85
|
// Values are CodeMirror extensions.
|
|
@@ -101,6 +107,13 @@ const getAtPath = (obj, path) => {
|
|
|
101
107
|
return current;
|
|
102
108
|
};
|
|
103
109
|
|
|
110
|
+
// Extend the EditorCacheValue type to include the compartments and the updateRainbowBrackets method
|
|
111
|
+
interface ExtendedEditorCacheValue extends EditorCacheValue {
|
|
112
|
+
themeCompartment: Compartment;
|
|
113
|
+
rainbowBracketsCompartment: Compartment;
|
|
114
|
+
updateRainbowBrackets: (enabled: boolean) => void;
|
|
115
|
+
}
|
|
116
|
+
|
|
104
117
|
// Gets or creates an `editorCache` entry for the given file id.
|
|
105
118
|
// Looks in `editorCache` first, and if not found, creates a new editor.
|
|
106
119
|
export const getOrCreateEditor = ({
|
|
@@ -120,6 +133,8 @@ export const getOrCreateEditor = ({
|
|
|
120
133
|
allowGlobals,
|
|
121
134
|
enableAutoFollowRef,
|
|
122
135
|
openTab,
|
|
136
|
+
aiCopilotEndpoint,
|
|
137
|
+
rainbowBracketsEnabled = true, // New parameter to enable or disable Rainbow Brackets
|
|
123
138
|
}: {
|
|
124
139
|
// TODO pass this in from the outside
|
|
125
140
|
paneId?: PaneId;
|
|
@@ -156,13 +171,15 @@ export const getOrCreateEditor = ({
|
|
|
156
171
|
// enable auto-following the cursors of remote users.
|
|
157
172
|
enableAutoFollowRef: React.MutableRefObject<boolean>;
|
|
158
173
|
openTab: (tabState: TabState) => void;
|
|
159
|
-
|
|
174
|
+
aiCopilotEndpoint: string;
|
|
175
|
+
rainbowBracketsEnabled?: boolean; // New parameter type
|
|
176
|
+
}): ExtendedEditorCacheValue => {
|
|
160
177
|
// Cache hit
|
|
161
178
|
|
|
162
179
|
const cacheKey = editorCacheKey(fileId, paneId);
|
|
163
180
|
|
|
164
181
|
if (editorCache.has(cacheKey)) {
|
|
165
|
-
return editorCache.get(cacheKey);
|
|
182
|
+
return editorCache.get(cacheKey) as ExtendedEditorCacheValue;
|
|
166
183
|
}
|
|
167
184
|
|
|
168
185
|
// Cache miss
|
|
@@ -177,6 +194,9 @@ export const getOrCreateEditor = ({
|
|
|
177
194
|
// Create a compartment for the theme so that it can be changed dynamically.
|
|
178
195
|
// Inspired by: https://github.com/craftzdog/cm6-themes/blob/main/example/index.ts
|
|
179
196
|
let themeCompartment = new Compartment();
|
|
197
|
+
|
|
198
|
+
// Create a compartment for rainbow brackets so that it can be enabled/disabled dynamically.
|
|
199
|
+
let rainbowBracketsCompartment = new Compartment();
|
|
180
200
|
|
|
181
201
|
// The CodeMirror extensions to use.
|
|
182
202
|
// const extensions = [autocompletion(), html(htmlConfig)]
|
|
@@ -237,6 +257,13 @@ export const getOrCreateEditor = ({
|
|
|
237
257
|
themeCompartment.of(themeOptionsByLabel[theme].value),
|
|
238
258
|
);
|
|
239
259
|
|
|
260
|
+
// Adds compartment for rainbow brackets with initial toggle state.
|
|
261
|
+
extensions.push(
|
|
262
|
+
rainbowBracketsCompartment.of(
|
|
263
|
+
rainbowBracketsEnabled ? rainbowBrackets() : []
|
|
264
|
+
),
|
|
265
|
+
);
|
|
266
|
+
|
|
240
267
|
// TODO handle dynamic changing of the file extension.
|
|
241
268
|
// TODO handle dynamic file extensions by making
|
|
242
269
|
// the CodeMirror language extension dynamic
|
|
@@ -380,8 +407,11 @@ export const getOrCreateEditor = ({
|
|
|
380
407
|
}),
|
|
381
408
|
),
|
|
382
409
|
);
|
|
383
|
-
|
|
384
|
-
|
|
410
|
+
|
|
411
|
+
// adds copilot
|
|
412
|
+
if (enableCopilot) {
|
|
413
|
+
extensions.push(copilot({ aiCopilotEndpoint }));
|
|
414
|
+
}
|
|
385
415
|
|
|
386
416
|
const editor = new EditorView({
|
|
387
417
|
state: EditorState.create({
|
|
@@ -390,10 +420,17 @@ export const getOrCreateEditor = ({
|
|
|
390
420
|
}),
|
|
391
421
|
});
|
|
392
422
|
|
|
393
|
-
const editorCacheValue = { editor, themeCompartment
|
|
423
|
+
const editorCacheValue: ExtendedEditorCacheValue = { editor, themeCompartment, rainbowBracketsCompartment, updateRainbowBrackets: (enabled) => {
|
|
424
|
+
editor.dispatch({
|
|
425
|
+
effects: rainbowBracketsCompartment.reconfigure(enabled ? rainbowBrackets() : []),
|
|
426
|
+
});
|
|
427
|
+
}};
|
|
394
428
|
|
|
395
429
|
// Populate the cache.
|
|
396
430
|
editorCache.set(cacheKey, editorCacheValue);
|
|
397
431
|
|
|
432
|
+
// Initialize rainbow brackets based on the toggle state
|
|
433
|
+
editorCacheValue.updateRainbowBrackets(rainbowBracketsEnabled);
|
|
434
|
+
|
|
398
435
|
return editorCacheValue;
|
|
399
436
|
};
|
|
@@ -19,9 +19,11 @@ const filesPath = ['files'];
|
|
|
19
19
|
export const CodeEditor = ({
|
|
20
20
|
customInteractRules,
|
|
21
21
|
allowGlobals,
|
|
22
|
+
aiCopilotEndpoint,
|
|
22
23
|
}: {
|
|
23
24
|
customInteractRules?: Array<InteractRule>;
|
|
24
25
|
allowGlobals: boolean;
|
|
26
|
+
aiCopilotEndpoint: string;
|
|
25
27
|
}) => {
|
|
26
28
|
const {
|
|
27
29
|
activePane,
|
|
@@ -99,7 +101,7 @@ export const CodeEditor = ({
|
|
|
99
101
|
allowGlobals,
|
|
100
102
|
enableAutoFollowRef,
|
|
101
103
|
openTab,
|
|
102
|
-
|
|
104
|
+
aiCopilotEndpoint,
|
|
103
105
|
}),
|
|
104
106
|
[
|
|
105
107
|
activePane,
|
|
@@ -112,6 +114,7 @@ export const CodeEditor = ({
|
|
|
112
114
|
editorCache,
|
|
113
115
|
usernameRef,
|
|
114
116
|
typeScriptWorker,
|
|
117
|
+
aiCopilotEndpoint,
|
|
115
118
|
],
|
|
116
119
|
);
|
|
117
120
|
|
|
@@ -8,6 +8,12 @@ function generateColors() {
|
|
|
8
8
|
return ['red', 'orange', 'yellow', 'green'];
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
+
let isRainbowEnabled = true;
|
|
12
|
+
|
|
13
|
+
export const toggleRainbowBrackets = (enabled: boolean) => {
|
|
14
|
+
isRainbowEnabled = enabled;
|
|
15
|
+
};
|
|
16
|
+
|
|
11
17
|
const rainbowBracketsPlugin = ViewPlugin.fromClass(
|
|
12
18
|
class {
|
|
13
19
|
decorations;
|
|
@@ -50,12 +56,16 @@ const rainbowBracketsPlugin = ViewPlugin.fromClass(
|
|
|
50
56
|
) {
|
|
51
57
|
const color =
|
|
52
58
|
colors[stack.length % colors.length];
|
|
59
|
+
const bracketClass = isRainbowEnabled
|
|
60
|
+
? `rainbow-bracket-${color}`
|
|
61
|
+
: `default-bracket`;
|
|
62
|
+
|
|
53
63
|
decorations.push(
|
|
54
64
|
Decoration.mark({
|
|
55
|
-
class:
|
|
65
|
+
class: bracketClass,
|
|
56
66
|
}).range(open.from, open.from + 1),
|
|
57
67
|
Decoration.mark({
|
|
58
|
-
class:
|
|
68
|
+
class: bracketClass,
|
|
59
69
|
}).range(pos, pos + 1),
|
|
60
70
|
);
|
|
61
71
|
}
|
|
@@ -105,6 +115,8 @@ export default function rainbowBrackets() {
|
|
|
105
115
|
},
|
|
106
116
|
'.rainbow-bracket-green': { color: '#B2FFB2' },
|
|
107
117
|
'.rainbow-bracket-green > span': { color: '#B2FFB2' },
|
|
118
|
+
'.default-bracket': { color: 'currentColor' },
|
|
119
|
+
'.default-bracket > span': { color: 'currentColor' },
|
|
108
120
|
}),
|
|
109
121
|
];
|
|
110
122
|
}
|
|
@@ -48,4 +48,109 @@
|
|
|
48
48
|
.cm-line {
|
|
49
49
|
font-family: var(--vzcode-font-family);
|
|
50
50
|
}
|
|
51
|
-
|
|
51
|
+
|
|
52
|
+
.tooltip_hover_circle {
|
|
53
|
+
color: white;
|
|
54
|
+
text-align: center;
|
|
55
|
+
position: fixed;
|
|
56
|
+
background-color: black;
|
|
57
|
+
padding: 5px;
|
|
58
|
+
border-radius: 5px;
|
|
59
|
+
white-space: nowrap;
|
|
60
|
+
opacity: 0;
|
|
61
|
+
transition: opacity 0.3s ease;
|
|
62
|
+
z-index: 1000;
|
|
63
|
+
pointer-events: none;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.tooltip_hover_circle strong {
|
|
67
|
+
font-size: 14px;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.tooltip_hover_circle div {
|
|
71
|
+
font-size: 12px;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.cm-panel.cm-search {
|
|
75
|
+
padding: 5px;
|
|
76
|
+
position: relative;
|
|
77
|
+
background-color: var(--vh-color-neutral-01);
|
|
78
|
+
border-radius: 6px;
|
|
79
|
+
color: var(--vh-color-neutral-04);
|
|
80
|
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.4);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.cm-panels {
|
|
84
|
+
background-color: #333338;
|
|
85
|
+
color: var(--vh-color-neutral-04);
|
|
86
|
+
border: 2px solid var(--vh-color-neutral-02);
|
|
87
|
+
border-radius: 6px;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.cm-textfield {
|
|
91
|
+
background-color: var(--vh-color-neutral-01);
|
|
92
|
+
color: #efe7dc;
|
|
93
|
+
border: 1px solid var(--vh-color-neutral-04);
|
|
94
|
+
padding: 8px;
|
|
95
|
+
border-radius: 6px;
|
|
96
|
+
font-size: 14px;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.cm-button {
|
|
100
|
+
background-color: var(--vh-color-neutral-01);
|
|
101
|
+
border: 1px solid #193350;
|
|
102
|
+
color: var(--vh-color-neutral-04);
|
|
103
|
+
border: 1px solid var(--vh-color-neutral-04);
|
|
104
|
+
border-radius: 5px;
|
|
105
|
+
padding: 6px 12px;
|
|
106
|
+
font-weight: bold;
|
|
107
|
+
cursor: pointer;
|
|
108
|
+
transition: all 0.3s ease-in-out;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.cm-button:hover {
|
|
112
|
+
background-color: #50c878;
|
|
113
|
+
color: #ffffff;
|
|
114
|
+
transform: scale(1.1);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.cm-button:active {
|
|
118
|
+
background-color: #202e46;
|
|
119
|
+
transform: scale(0.95);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.cm-searchMatch {
|
|
123
|
+
background-color: rgba(255, 255, 0, 0.5);
|
|
124
|
+
border-radius: 2px;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.cm-searchMatch-selected {
|
|
128
|
+
background-color: rgba(255, 140, 0, 0.5);
|
|
129
|
+
border: 2px solid #ff8800;
|
|
130
|
+
border-radius: 2px;
|
|
131
|
+
}
|
|
132
|
+
.cm-panel.cm-search [name="close"] {
|
|
133
|
+
position: absolute;
|
|
134
|
+
top: 0;
|
|
135
|
+
right: 4px;
|
|
136
|
+
background-color: var(--vh-color-neutral-01);
|
|
137
|
+
color: var(--vh-color-neutral-04);
|
|
138
|
+
border: none;
|
|
139
|
+
font: inherit;
|
|
140
|
+
padding: 4px 8px;
|
|
141
|
+
margin: 4px;
|
|
142
|
+
border-radius: 4px;
|
|
143
|
+
cursor: pointer;
|
|
144
|
+
transition: all 0.3s ease-in-out;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.cm-panel.cm-search [name="close"]:hover {
|
|
148
|
+
background-color: var(--vh-color-caution-01);
|
|
149
|
+
color: #ffffff;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.cm-panel.cm-search [name="close"]:active {
|
|
153
|
+
background-color: var(--vh-color-caution-02);
|
|
154
|
+
transform: scale(0.95);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export const MicSVG = () => (
|
|
2
|
+
<svg
|
|
3
|
+
fill="#000000"
|
|
4
|
+
height="24"
|
|
5
|
+
width="24"
|
|
6
|
+
stroke="currentColor"
|
|
7
|
+
version="1.1"
|
|
8
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
9
|
+
viewBox="0 0 512 512"
|
|
10
|
+
enable-background="new 0 0 512 512"
|
|
11
|
+
>
|
|
12
|
+
<g>
|
|
13
|
+
<g>
|
|
14
|
+
<path
|
|
15
|
+
fill="currentColor"
|
|
16
|
+
d="m439.5,236c0-11.3-9.1-20.4-20.4-20.4s-20.4,9.1-20.4,20.4c0,70-64,126.9-142.7,126.9-78.7,0-142.7-56.9-142.7-126.9 0-11.3-9.1-20.4-20.4-20.4s-20.4,9.1-20.4,20.4c0,86.2 71.5,157.4 163.1,166.7v57.5h-23.6c-11.3,0-20.4,9.1-20.4,20.4 0,11.3 9.1,20.4 20.4,20.4h88c11.3,0 20.4-9.1 20.4-20.4 0-11.3-9.1-20.4-20.4-20.4h-23.6v-57.5c91.6-9.3 163.1-80.5 163.1-166.7z"
|
|
17
|
+
/>
|
|
18
|
+
<path
|
|
19
|
+
fill="currentColor"
|
|
20
|
+
d="m256,323.5c51,0 92.3-41.3 92.3-92.3v-127.9c0-51-41.3-92.3-92.3-92.3s-92.3,41.3-92.3,92.3v127.9c0,51 41.3,92.3 92.3,92.3zm-52.3-220.2c0-28.8 23.5-52.3 52.3-52.3s52.3,23.5 52.3,52.3v127.9c0,28.8-23.5,52.3-52.3,52.3s-52.3-23.5-52.3-52.3v-127.9z"
|
|
21
|
+
/>
|
|
22
|
+
</g>
|
|
23
|
+
</g>
|
|
24
|
+
</svg>
|
|
25
|
+
);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useCallback, useContext, useState } from 'react';
|
|
1
|
+
import { useCallback, useContext, useEffect, useState } from 'react';
|
|
2
2
|
import { PlaySVG } from '../Icons';
|
|
3
3
|
import { SplitEditorSVG } from '../Icons/SplitEditorSVG';
|
|
4
4
|
import { VZCodeContext } from '../VZCodeContext';
|
|
@@ -17,7 +17,7 @@ export const RunCodeWidget = ({
|
|
|
17
17
|
</>
|
|
18
18
|
),
|
|
19
19
|
}: {
|
|
20
|
-
|
|
20
|
+
runCodeWidgetTooltipText?: JSX.Element;
|
|
21
21
|
}) => {
|
|
22
22
|
const { runCodeRef, runPrettierRef, splitCurrentPane } =
|
|
23
23
|
useContext(VZCodeContext);
|
|
@@ -40,7 +40,7 @@ export const RunCodeWidget = ({
|
|
|
40
40
|
|
|
41
41
|
// Optional: reset the icon state after animation completes (e.g., 1 second)
|
|
42
42
|
setTimeout(() => setIsRunning(false), 1000);
|
|
43
|
-
}, []);
|
|
43
|
+
}, [runCodeRef, runPrettierRef]);
|
|
44
44
|
|
|
45
45
|
const handleSplitEditor = useCallback(() => {
|
|
46
46
|
console.log('Split Editor');
|
|
@@ -48,6 +48,23 @@ export const RunCodeWidget = ({
|
|
|
48
48
|
splitCurrentPane();
|
|
49
49
|
}, [splitCurrentPane]);
|
|
50
50
|
|
|
51
|
+
// Add the keyboard event listener for Ctrl+S and Shift+Enter
|
|
52
|
+
useEffect(() => {
|
|
53
|
+
const handleKeyDown = (event: KeyboardEvent) => {
|
|
54
|
+
if ((event.ctrlKey && event.key === 's') || (event.shiftKey && event.key === 'Enter')) {
|
|
55
|
+
event.preventDefault();
|
|
56
|
+
handleClick();
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
window.addEventListener('keydown', handleKeyDown);
|
|
61
|
+
|
|
62
|
+
// Cleanup the event listener on component unmount
|
|
63
|
+
return () => {
|
|
64
|
+
window.removeEventListener('keydown', handleKeyDown);
|
|
65
|
+
};
|
|
66
|
+
}, [handleClick]);
|
|
67
|
+
|
|
51
68
|
return (
|
|
52
69
|
<div>
|
|
53
70
|
<div className="vz-code-split-view-widget">
|
|
@@ -2,42 +2,42 @@ import {
|
|
|
2
2
|
createContext,
|
|
3
3
|
useCallback,
|
|
4
4
|
useReducer,
|
|
5
|
-
useState,
|
|
6
5
|
useRef,
|
|
6
|
+
useState,
|
|
7
7
|
} from 'react';
|
|
8
8
|
import {
|
|
9
9
|
Files,
|
|
10
10
|
ItemId,
|
|
11
|
+
LeafPane,
|
|
12
|
+
Pane,
|
|
13
|
+
PaneId,
|
|
14
|
+
PresenceIndicator,
|
|
15
|
+
SearchFileVisibility,
|
|
16
|
+
SearchResults,
|
|
11
17
|
ShareDBDoc,
|
|
12
18
|
SubmitOperation,
|
|
19
|
+
TabState,
|
|
13
20
|
Username,
|
|
14
21
|
VZCodeContent,
|
|
15
|
-
SearchResults,
|
|
16
|
-
SearchFileVisibility,
|
|
17
|
-
TabState,
|
|
18
|
-
PresenceIndicator,
|
|
19
|
-
Pane,
|
|
20
|
-
PaneId,
|
|
21
|
-
LeafPane,
|
|
22
22
|
} from '../types';
|
|
23
|
-
import { usePrettier } from './usePrettier';
|
|
24
|
-
import { useTypeScript } from './useTypeScript';
|
|
25
|
-
import { createInitialState, vzReducer } from './vzReducer';
|
|
26
23
|
import {
|
|
27
24
|
ThemeLabel,
|
|
28
25
|
defaultTheme,
|
|
29
26
|
useDynamicTheme,
|
|
30
27
|
} from './themes';
|
|
31
28
|
import { useActions } from './useActions';
|
|
32
|
-
import { useOpenDirectories } from './useOpenDirectories';
|
|
33
|
-
import { useFileCRUD } from './useFileCRUD';
|
|
34
29
|
import {
|
|
35
30
|
EditorCache,
|
|
36
31
|
useEditorCache,
|
|
37
32
|
} from './useEditorCache';
|
|
38
|
-
import {
|
|
33
|
+
import { useFileCRUD } from './useFileCRUD';
|
|
39
34
|
import { useKeyboardShortcuts } from './useKeyboardShortcuts';
|
|
35
|
+
import { useOpenDirectories } from './useOpenDirectories';
|
|
36
|
+
import { usePrettier } from './usePrettier';
|
|
40
37
|
import { useRunCode } from './useRunCode';
|
|
38
|
+
import { useTypeScript } from './useTypeScript';
|
|
39
|
+
import { useURLSync } from './useURLSync';
|
|
40
|
+
import { createInitialState, vzReducer } from './vzReducer';
|
|
41
41
|
import { findPane } from './vzReducer/findPane';
|
|
42
42
|
|
|
43
43
|
// This context centralizes all the "smart" logic
|
|
@@ -156,6 +156,7 @@ export type VZCodeContextValue = {
|
|
|
156
156
|
codeEditorRef: React.RefObject<HTMLDivElement>;
|
|
157
157
|
|
|
158
158
|
connected: boolean;
|
|
159
|
+
pending: boolean;
|
|
159
160
|
|
|
160
161
|
hoveredItemId: ItemId | null;
|
|
161
162
|
setHoveredItemId: (itemId: ItemId | null) => void;
|
|
@@ -169,6 +170,15 @@ export type VZCodeContextValue = {
|
|
|
169
170
|
|
|
170
171
|
sidebarPresenceIndicators: Array<PresenceIndicator>;
|
|
171
172
|
splitCurrentPane: () => void;
|
|
173
|
+
|
|
174
|
+
liveKitToken: string;
|
|
175
|
+
setLiveKitToken: (state: string) => void;
|
|
176
|
+
liveKitRoomName: string;
|
|
177
|
+
setLiveKitRoom: (state: string) => void;
|
|
178
|
+
liveKitConnection: boolean;
|
|
179
|
+
setLiveKitConnection: (state: boolean) => void;
|
|
180
|
+
voiceChatModalOpen: boolean;
|
|
181
|
+
setVoiceChatModalOpen: (state: boolean) => void;
|
|
172
182
|
};
|
|
173
183
|
|
|
174
184
|
export const VZCodeProvider = ({
|
|
@@ -183,6 +193,13 @@ export const VZCodeProvider = ({
|
|
|
183
193
|
children,
|
|
184
194
|
codeError = null,
|
|
185
195
|
connected,
|
|
196
|
+
pending,
|
|
197
|
+
liveKitToken,
|
|
198
|
+
setLiveKitToken,
|
|
199
|
+
liveKitRoomName,
|
|
200
|
+
setLiveKitRoom,
|
|
201
|
+
liveKitConnection,
|
|
202
|
+
setLiveKitConnection,
|
|
186
203
|
}: {
|
|
187
204
|
content: VZCodeContent;
|
|
188
205
|
shareDBDoc: ShareDBDoc<VZCodeContent>;
|
|
@@ -195,6 +212,13 @@ export const VZCodeProvider = ({
|
|
|
195
212
|
children: React.ReactNode;
|
|
196
213
|
codeError?: string | null;
|
|
197
214
|
connected: boolean;
|
|
215
|
+
pending: boolean;
|
|
216
|
+
liveKitToken: string | undefined;
|
|
217
|
+
setLiveKitToken: (state: string) => void;
|
|
218
|
+
liveKitRoomName: string | undefined;
|
|
219
|
+
setLiveKitRoom: (state: string) => void;
|
|
220
|
+
liveKitConnection: boolean;
|
|
221
|
+
setLiveKitConnection: (state: boolean) => void;
|
|
198
222
|
}) => {
|
|
199
223
|
// Auto-run Pretter after local changes.
|
|
200
224
|
const {
|
|
@@ -393,6 +417,11 @@ export const VZCodeProvider = ({
|
|
|
393
417
|
const [hoveredItemId, setHoveredItemId] =
|
|
394
418
|
useState<ItemId | null>(null);
|
|
395
419
|
|
|
420
|
+
// Livekit Voice Chat Modal
|
|
421
|
+
|
|
422
|
+
const [voiceChatModalOpen, setVoiceChatModalOpen] =
|
|
423
|
+
useState(false);
|
|
424
|
+
|
|
396
425
|
// The value provided by this context.
|
|
397
426
|
const value: VZCodeContextValue = {
|
|
398
427
|
content,
|
|
@@ -471,6 +500,7 @@ export const VZCodeProvider = ({
|
|
|
471
500
|
codeEditorRef,
|
|
472
501
|
|
|
473
502
|
connected,
|
|
503
|
+
pending,
|
|
474
504
|
|
|
475
505
|
hoveredItemId,
|
|
476
506
|
setHoveredItemId,
|
|
@@ -480,6 +510,14 @@ export const VZCodeProvider = ({
|
|
|
480
510
|
updatePresenceIndicator,
|
|
481
511
|
sidebarPresenceIndicators,
|
|
482
512
|
splitCurrentPane,
|
|
513
|
+
liveKitRoomName,
|
|
514
|
+
setLiveKitRoom,
|
|
515
|
+
liveKitToken,
|
|
516
|
+
setLiveKitToken,
|
|
517
|
+
liveKitConnection,
|
|
518
|
+
setLiveKitConnection,
|
|
519
|
+
voiceChatModalOpen,
|
|
520
|
+
setVoiceChatModalOpen,
|
|
483
521
|
};
|
|
484
522
|
|
|
485
523
|
return (
|
|
@@ -46,41 +46,41 @@ export const VZKeyboardShortcutsDoc = ({
|
|
|
46
46
|
{/* <Form.Label>WINDOWS</Form.Label> */}
|
|
47
47
|
<ul>
|
|
48
48
|
<li>
|
|
49
|
-
<strong>Ctrl +
|
|
50
|
-
<strong>Shift + Enter
|
|
49
|
+
<strong><kbd>Ctrl</kbd> + <kbd>S</kbd></strong> or{' '}
|
|
50
|
+
<strong><kbd>Shift↑</kbd> + <kbd>Enter←</kbd></strong> <br />
|
|
51
51
|
<span>Run and format code</span>
|
|
52
52
|
</li>
|
|
53
53
|
<li>
|
|
54
|
-
<strong>Alt +
|
|
54
|
+
<strong><kbd>Alt</kbd> + Drag on a number</strong>
|
|
55
55
|
<br />
|
|
56
56
|
<span>
|
|
57
57
|
Modify the number by dragging left or right
|
|
58
58
|
</span>
|
|
59
59
|
</li>
|
|
60
60
|
<li>
|
|
61
|
-
<strong>Alt +
|
|
61
|
+
<strong><kbd>Alt</kbd> + Click on a hex color</strong>
|
|
62
62
|
<br />
|
|
63
63
|
<span>
|
|
64
64
|
Open a color picker to modify the color
|
|
65
65
|
</span>
|
|
66
66
|
</li>
|
|
67
67
|
<li>
|
|
68
|
-
<strong>Alt +
|
|
68
|
+
<strong><kbd>Alt</kbd> + <kbd>W</kbd></strong> <br />
|
|
69
69
|
<span>Close the current tab</span>
|
|
70
70
|
</li>
|
|
71
71
|
<li>
|
|
72
|
-
<strong>Alt +
|
|
72
|
+
<strong><kbd>Alt</kbd> + <kbd>N</kbd></strong> or{' '} <strong><kbd>Ctrl</kbd> + <kbd>Shift↑</kbd> + <kbd>N</kbd></strong>{' '}
|
|
73
73
|
<br />
|
|
74
74
|
<span>Open the create file modal</span>
|
|
75
75
|
</li>
|
|
76
76
|
<li>
|
|
77
|
-
<strong>Alt +
|
|
77
|
+
<strong><kbd>Alt</kbd> + <kbd>PgUp↑</kbd></strong> <br />
|
|
78
78
|
<span>
|
|
79
79
|
Change the active tab to the previous one
|
|
80
80
|
</span>
|
|
81
81
|
</li>
|
|
82
82
|
<li>
|
|
83
|
-
<strong>Alt +
|
|
83
|
+
<strong><kbd>Alt</kbd> + <kbd>PgDn↓</kbd></strong> <br />
|
|
84
84
|
<span>
|
|
85
85
|
Change the active tab to the next one
|
|
86
86
|
</span>
|
package/src/client/VZLeft.tsx
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { enableLiveKit } from './featureFlags';
|
|
2
2
|
import { VZKeyboardShortcutsDoc } from './VZKeyboardShortcutsDoc';
|
|
3
|
+
import { VZSettings } from './VZSettings';
|
|
3
4
|
import { VZSidebar } from './VZSidebar';
|
|
4
|
-
import { CreateFileModal } from './VZSidebar/CreateFileModal';
|
|
5
5
|
import { CreateDirModal } from './VZSidebar/CreateDirModal';
|
|
6
|
+
import { CreateFileModal } from './VZSidebar/CreateFileModal';
|
|
7
|
+
import { VoiceChatModal } from './VZSidebar/VoiceChatModal';
|
|
6
8
|
|
|
7
9
|
// The middle portion of the VZCode environment, containing:
|
|
8
10
|
// * The sidebar
|
|
@@ -20,6 +22,7 @@ export const VZLeft = ({ enableUsernameField = true }) => {
|
|
|
20
22
|
/>
|
|
21
23
|
<CreateFileModal />
|
|
22
24
|
<CreateDirModal />
|
|
25
|
+
{enableLiveKit && <VoiceChatModal />}
|
|
23
26
|
</div>
|
|
24
27
|
);
|
|
25
28
|
};
|
package/src/client/VZMiddle.tsx
CHANGED
|
@@ -23,6 +23,7 @@ const PaneView = ({
|
|
|
23
23
|
aiAssistOptions,
|
|
24
24
|
aiAssistTooltipText,
|
|
25
25
|
aiAssistClickOverride,
|
|
26
|
+
aiCopilotEndpoint,
|
|
26
27
|
}) => {
|
|
27
28
|
// This prevents the CodeEditor from rendering
|
|
28
29
|
// during SSR.
|
|
@@ -49,6 +50,7 @@ const PaneView = ({
|
|
|
49
50
|
<CodeEditor
|
|
50
51
|
customInteractRules={customInteractRules}
|
|
51
52
|
allowGlobals={allowGlobals}
|
|
53
|
+
aiCopilotEndpoint={aiCopilotEndpoint}
|
|
52
54
|
/>
|
|
53
55
|
)}
|
|
54
56
|
{isClient &&
|
|
@@ -82,6 +84,7 @@ export const VZMiddle = ({
|
|
|
82
84
|
aiAssistOptions,
|
|
83
85
|
aiAssistTooltipText,
|
|
84
86
|
aiAssistClickOverride,
|
|
87
|
+
aiCopilotEndpoint,
|
|
85
88
|
customInteractRules,
|
|
86
89
|
allowGlobals = false,
|
|
87
90
|
}: {
|
|
@@ -90,6 +93,7 @@ export const VZMiddle = ({
|
|
|
90
93
|
aiAssistOptions?: { [key: string]: string };
|
|
91
94
|
aiAssistTooltipText?: string;
|
|
92
95
|
aiAssistClickOverride?: () => void;
|
|
96
|
+
aiCopilotEndpoint?: string;
|
|
93
97
|
customInteractRules?: Array<InteractRule>;
|
|
94
98
|
allowGlobals?: boolean;
|
|
95
99
|
}) => {
|
|
@@ -128,6 +132,7 @@ export const VZMiddle = ({
|
|
|
128
132
|
aiAssistOptions={aiAssistOptions}
|
|
129
133
|
aiAssistTooltipText={aiAssistTooltipText}
|
|
130
134
|
aiAssistClickOverride={aiAssistClickOverride}
|
|
135
|
+
aiCopilotEndpoint={aiCopilotEndpoint}
|
|
131
136
|
/>
|
|
132
137
|
<CodeErrorOverlay
|
|
133
138
|
errorMessage={errorMessage}
|