vzcode 0.25.0 → 0.27.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-5f9f376e.css +1 -0
- package/dist/assets/index-70b6d947.js +111 -0
- package/dist/index.html +2 -6
- package/package.json +7 -7
- package/src/client/App.tsx +110 -247
- package/src/client/CodeEditor/getOrCreateEditor.ts +6 -1
- package/src/client/CodeEditor/index.tsx +94 -16
- package/src/client/CodeEditor/{json1PresenceBroadcast.js → json1PresenceBroadcast.ts} +9 -3
- package/src/client/CodeEditor/{json1PresenceDisplay.js → json1PresenceDisplay.ts} +9 -48
- package/src/client/CodeEditor/style.scss +5 -1
- package/src/client/CodeErrorOverlay/index.tsx +27 -0
- package/src/client/CodeErrorOverlay/style.scss +30 -0
- package/src/client/PresenceNotifications/PresenceNotifications.test.ts +134 -0
- package/src/client/PresenceNotifications/index.tsx +119 -106
- package/src/client/SplitPaneResizeContext.tsx +12 -7
- package/src/client/TabList/Tab.tsx +70 -0
- package/src/client/TabList/index.tsx +28 -69
- package/src/client/TabList/style.scss +26 -9
- package/src/client/{Settings.tsx → VZSettings.tsx} +34 -21
- package/src/client/{Sidebar/ConfirmationBox.tsx → VZSidebar/DeleteConfirmationModal.tsx} +17 -14
- package/src/client/{Sidebar → VZSidebar}/DirectoryListing.tsx +27 -26
- package/src/client/{Sidebar → VZSidebar}/FileListing.tsx +19 -19
- package/src/client/VZSidebar/Item.tsx +179 -0
- package/src/client/{Sidebar → VZSidebar}/Listing.tsx +20 -14
- package/src/client/{Sidebar → VZSidebar}/index.tsx +48 -30
- package/src/client/{Sidebar → VZSidebar}/styles.scss +17 -12
- package/src/client/bootstrap.ts +3 -0
- package/src/client/style.scss +8 -2
- package/src/client/useActions.ts +93 -0
- package/src/client/useEditorCache.ts +2 -1
- package/src/client/useFileCRUD.ts +103 -0
- package/src/client/useOpenDirectories.ts +25 -7
- package/src/client/useSubmitOperation.ts +25 -0
- package/src/client/usernameLocalStorage.ts +43 -0
- package/src/client/vzReducer/closeTabReducer.test.ts +177 -0
- package/src/client/vzReducer/closeTabsReducer.ts +68 -0
- package/src/client/vzReducer/createInitialState.ts +19 -0
- package/src/client/vzReducer/editorNoLongerWantsFocusReducer.ts +9 -0
- package/src/client/vzReducer/index.ts +107 -0
- package/src/client/vzReducer/openTabReducer.test.ts +110 -0
- package/src/client/vzReducer/openTabReducer.ts +57 -0
- package/src/client/vzReducer/setActiveFileIdReducer.ts +9 -0
- package/src/client/vzReducer/setIsSettingsOpenReducer.ts +9 -0
- package/src/client/vzReducer/setThemeReducer.ts +9 -0
- package/src/client/vzReducer/setUsernameReducer.ts +9 -0
- package/src/index.ts +40 -0
- package/src/server/index.js +13 -2
- package/src/types.ts +12 -5
- package/dist/assets/index-8628ebab.js +0 -111
- package/dist/assets/index-cf19de3b.css +0 -1
- package/src/client/PrettierErrorOverlay/index.tsx +0 -9
- package/src/client/PrettierErrorOverlay/style.scss +0 -9
- package/src/client/Sidebar/Item.tsx +0 -130
- package/src/client/reducer.ts +0 -119
- /package/src/client/{Sidebar → VZSidebar}/DirectoryArrowSVG.jsx +0 -0
package/dist/index.html
CHANGED
|
@@ -24,12 +24,8 @@
|
|
|
24
24
|
href="https://unpkg.com/boxicons@2.0.7/css/boxicons.min.css"
|
|
25
25
|
rel="stylesheet"
|
|
26
26
|
/>
|
|
27
|
-
<
|
|
28
|
-
|
|
29
|
-
rel="stylesheet"
|
|
30
|
-
/>
|
|
31
|
-
<script type="module" crossorigin src="/assets/index-8628ebab.js"></script>
|
|
32
|
-
<link rel="stylesheet" href="/assets/index-cf19de3b.css">
|
|
27
|
+
<script type="module" crossorigin src="/assets/index-70b6d947.js"></script>
|
|
28
|
+
<link rel="stylesheet" href="/assets/index-5f9f376e.css">
|
|
33
29
|
</head>
|
|
34
30
|
<body>
|
|
35
31
|
<div id="root"></div>
|
package/package.json
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vzcode",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.27.0",
|
|
4
4
|
"description": "Multiplayer code editor system",
|
|
5
|
-
"main": "index.
|
|
5
|
+
"main": "src/index.ts",
|
|
6
6
|
"type": "module",
|
|
7
|
-
"types": "src/types.ts",
|
|
8
7
|
"bin": "src/server/index.js",
|
|
9
8
|
"files": [
|
|
10
9
|
"dist/**",
|
|
@@ -52,7 +51,7 @@
|
|
|
52
51
|
"@codemirror/lang-markdown": "^6.2.2",
|
|
53
52
|
"@codemirror/state": "^6.3.1",
|
|
54
53
|
"@codemirror/theme-one-dark": "^6.1.2",
|
|
55
|
-
"@codemirror/view": "^6.21.
|
|
54
|
+
"@codemirror/view": "^6.21.4",
|
|
56
55
|
"@lezer/highlight": "^1.1.6",
|
|
57
56
|
"@replit/codemirror-interact": "^6.3.0",
|
|
58
57
|
"@teamwork/websocket-json-stream": "^2.0.0",
|
|
@@ -76,18 +75,19 @@
|
|
|
76
75
|
"open": "^9.1.0",
|
|
77
76
|
"ot-json1": "^1.0.2",
|
|
78
77
|
"react": "^18.2.0",
|
|
79
|
-
"react-bootstrap": "^2.9.
|
|
78
|
+
"react-bootstrap": "^2.9.1",
|
|
80
79
|
"react-dom": "^18.2.0",
|
|
81
80
|
"sharedb": "^4.1.1",
|
|
82
81
|
"sharedb-client-browser": "^4.3.1",
|
|
82
|
+
"vizhub-ui": "^3.5.0",
|
|
83
83
|
"ws": "^8.14.2"
|
|
84
84
|
},
|
|
85
85
|
"devDependencies": {
|
|
86
|
-
"@types/react": "^18.2.
|
|
86
|
+
"@types/react": "^18.2.33",
|
|
87
87
|
"@types/react-dom": "^18.2.14",
|
|
88
88
|
"@vitejs/plugin-react": "^4.1.0",
|
|
89
89
|
"prettier": "^3.0.3",
|
|
90
|
-
"sass": "^1.69.
|
|
90
|
+
"sass": "^1.69.5",
|
|
91
91
|
"typescript": "^5.2.2",
|
|
92
92
|
"vite": "^4.5.0",
|
|
93
93
|
"vitest": "^0.34.6"
|
package/src/client/App.tsx
CHANGED
|
@@ -1,40 +1,39 @@
|
|
|
1
|
-
import {
|
|
2
|
-
useState,
|
|
3
|
-
useEffect,
|
|
4
|
-
useCallback,
|
|
5
|
-
useRef,
|
|
6
|
-
useReducer,
|
|
7
|
-
} from 'react';
|
|
1
|
+
import { useState, useEffect, useReducer } from 'react';
|
|
8
2
|
import ShareDBClient from 'sharedb-client-browser/dist/sharedb-client-umd.cjs';
|
|
9
3
|
import { json1Presence } from '../ot';
|
|
10
4
|
import { randomId } from '../randomId';
|
|
11
5
|
import { CodeEditor } from './CodeEditor';
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import { Sidebar } from './Sidebar';
|
|
6
|
+
import { VZSettings } from './VZSettings';
|
|
7
|
+
import { VZSidebar } from './VZSidebar';
|
|
15
8
|
import {
|
|
16
|
-
FileId,
|
|
17
9
|
Files,
|
|
18
10
|
ShareDBDoc,
|
|
11
|
+
Username,
|
|
19
12
|
VZCodeContent,
|
|
20
13
|
} from '../types';
|
|
21
14
|
import { TabList } from './TabList';
|
|
22
15
|
import { useOpenDirectories } from './useOpenDirectories';
|
|
16
|
+
import { defaultTheme, useDynamicTheme } from './themes';
|
|
23
17
|
import {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
} from './themes';
|
|
28
|
-
import { useEditorCache } from './useEditorCache';
|
|
18
|
+
EditorCache,
|
|
19
|
+
useEditorCache,
|
|
20
|
+
} from './useEditorCache';
|
|
29
21
|
import { usePrettier } from './usePrettier';
|
|
30
22
|
// @ts-ignore
|
|
31
23
|
import PrettierWorker from './usePrettier/worker?worker';
|
|
32
24
|
import { SplitPaneResizeProvider } from './SplitPaneResizeContext';
|
|
33
25
|
import { Resizer } from './Resizer';
|
|
34
26
|
import { PresenceNotifications } from './PresenceNotifications';
|
|
35
|
-
import {
|
|
27
|
+
import { CodeErrorOverlay } from './CodeErrorOverlay';
|
|
28
|
+
import { vzReducer, createInitialState } from './vzReducer';
|
|
29
|
+
import { useActions } from './useActions';
|
|
30
|
+
import { useFileCRUD } from './useFileCRUD';
|
|
31
|
+
import { useSubmitOperation } from './useSubmitOperation';
|
|
32
|
+
import {
|
|
33
|
+
useInitialUsername,
|
|
34
|
+
usePersistUsername,
|
|
35
|
+
} from './usernameLocalStorage';
|
|
36
36
|
import './style.scss';
|
|
37
|
-
import { PrettierErrorOverlay } from './PrettierErrorOverlay';
|
|
38
37
|
|
|
39
38
|
// Instantiate the Prettier worker.
|
|
40
39
|
const prettierWorker = new PrettierWorker();
|
|
@@ -60,30 +59,6 @@ function App() {
|
|
|
60
59
|
const [shareDBDoc, setShareDBDoc] =
|
|
61
60
|
useState<ShareDBDoc<VZCodeContent> | null>(null);
|
|
62
61
|
|
|
63
|
-
// A helper function to submit operations to the ShareDB document
|
|
64
|
-
|
|
65
|
-
const submitOperation: (
|
|
66
|
-
next: (content: VZCodeContent) => VZCodeContent,
|
|
67
|
-
) => void = useCallback(
|
|
68
|
-
(next) => {
|
|
69
|
-
const content: VZCodeContent = shareDBDoc.data;
|
|
70
|
-
const op = diff(content, next(content));
|
|
71
|
-
if (op && shareDBDoc) {
|
|
72
|
-
shareDBDoc.submitOp(op);
|
|
73
|
-
}
|
|
74
|
-
},
|
|
75
|
-
[shareDBDoc],
|
|
76
|
-
);
|
|
77
|
-
|
|
78
|
-
// Auto-run Pretter after local changes.
|
|
79
|
-
const { prettierError } = usePrettier(
|
|
80
|
-
shareDBDoc,
|
|
81
|
-
submitOperation,
|
|
82
|
-
prettierWorker,
|
|
83
|
-
);
|
|
84
|
-
|
|
85
|
-
console.log('prettierError', prettierError);
|
|
86
|
-
|
|
87
62
|
// Local ShareDB presence, for broadcasting our cursor position
|
|
88
63
|
// so other clients can see it.
|
|
89
64
|
// See https://share.github.io/sharedb/api/local-presence
|
|
@@ -125,6 +100,12 @@ function App() {
|
|
|
125
100
|
// This decouples rendering logic from ShareDB.
|
|
126
101
|
// This callback gets called on each change.
|
|
127
102
|
shareDBDoc.on('op', () => {
|
|
103
|
+
// TODO consider excluding file contents from this,
|
|
104
|
+
// because currently we are re-rendering the entire
|
|
105
|
+
// document on each file change (each keystroke while editing).
|
|
106
|
+
// This is not required, because no part of the app outside
|
|
107
|
+
// of the CodeMirror integration uses those file contents.
|
|
108
|
+
// The Sidebar only needs to know file names, not contents.
|
|
128
109
|
setContent(shareDBDoc.data);
|
|
129
110
|
});
|
|
130
111
|
|
|
@@ -141,7 +122,14 @@ function App() {
|
|
|
141
122
|
});
|
|
142
123
|
|
|
143
124
|
// Set up our local presence for broadcasting this client's presence.
|
|
144
|
-
|
|
125
|
+
const generateTimestampedId = () => {
|
|
126
|
+
const timestamp = Date.now().toString(36);
|
|
127
|
+
const randomPart = randomId();
|
|
128
|
+
return `${timestamp}-${randomPart}`;
|
|
129
|
+
};
|
|
130
|
+
setLocalPresence(
|
|
131
|
+
docPresence.create(generateTimestampedId()),
|
|
132
|
+
);
|
|
145
133
|
|
|
146
134
|
// Store docPresence so child components can listen for changes.
|
|
147
135
|
setDocPresence(docPresence);
|
|
@@ -155,212 +143,77 @@ function App() {
|
|
|
155
143
|
};
|
|
156
144
|
}, []);
|
|
157
145
|
|
|
158
|
-
//
|
|
159
|
-
const
|
|
160
|
-
tabList: [],
|
|
161
|
-
activeFileId: null,
|
|
162
|
-
theme: defaultTheme,
|
|
163
|
-
isSettingsOpen: false,
|
|
164
|
-
});
|
|
146
|
+
// Get the initial username from localStorage.
|
|
147
|
+
const initialUsername: Username = useInitialUsername();
|
|
165
148
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
const theme = state.theme;
|
|
170
|
-
const isSettingsOpen = state.isSettingsOpen;
|
|
171
|
-
// TODO phase this out as we complete the refactoring
|
|
172
|
-
// It's here now for backwards compatibility
|
|
173
|
-
|
|
174
|
-
const setTabList = useCallback(
|
|
175
|
-
(tabList) => {
|
|
176
|
-
dispatch({
|
|
177
|
-
type: 'set_tab_list',
|
|
178
|
-
tabList,
|
|
179
|
-
});
|
|
180
|
-
},
|
|
181
|
-
[dispatch],
|
|
182
|
-
);
|
|
183
|
-
|
|
184
|
-
const setActiveFileId = useCallback(
|
|
185
|
-
(activeFileId) => {
|
|
186
|
-
dispatch({
|
|
187
|
-
type: 'set_active_fileId',
|
|
188
|
-
activeFileId,
|
|
189
|
-
});
|
|
190
|
-
},
|
|
191
|
-
[dispatch],
|
|
192
|
-
);
|
|
193
|
-
|
|
194
|
-
const openTab = useCallback(
|
|
195
|
-
(fileId: FileId) => {
|
|
196
|
-
dispatch({
|
|
197
|
-
type: 'open_tab',
|
|
198
|
-
fileId,
|
|
199
|
-
});
|
|
200
|
-
},
|
|
201
|
-
[dispatch],
|
|
202
|
-
);
|
|
203
|
-
|
|
204
|
-
const closeTab = useCallback(
|
|
205
|
-
(fileIdToRemove: FileId) => {
|
|
206
|
-
dispatch({
|
|
207
|
-
type: 'close_tab',
|
|
208
|
-
fileIdToRemove,
|
|
209
|
-
});
|
|
210
|
-
},
|
|
211
|
-
[dispatch],
|
|
212
|
-
);
|
|
213
|
-
|
|
214
|
-
const multiCloseTab = useCallback(
|
|
215
|
-
(idsToDelete: Array<FileId>) => {
|
|
216
|
-
dispatch({
|
|
217
|
-
type: 'multi_close_tab',
|
|
218
|
-
idsToDelete,
|
|
219
|
-
});
|
|
220
|
-
},
|
|
221
|
-
[dispatch],
|
|
222
|
-
);
|
|
149
|
+
const submitOperation: (
|
|
150
|
+
next: (content: VZCodeContent) => VZCodeContent,
|
|
151
|
+
) => void = useSubmitOperation(shareDBDoc);
|
|
223
152
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
153
|
+
// Auto-run Pretter after local changes.
|
|
154
|
+
const {
|
|
155
|
+
prettierError,
|
|
156
|
+
}: {
|
|
157
|
+
prettierError: string | null;
|
|
158
|
+
} = usePrettier(
|
|
159
|
+
shareDBDoc,
|
|
160
|
+
submitOperation,
|
|
161
|
+
prettierWorker,
|
|
232
162
|
);
|
|
233
163
|
|
|
234
|
-
//
|
|
235
|
-
const
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
value: value,
|
|
240
|
-
});
|
|
241
|
-
},
|
|
242
|
-
[dispatch],
|
|
164
|
+
// https://react.dev/reference/react/useReducer
|
|
165
|
+
const [state, dispatch] = useReducer(
|
|
166
|
+
vzReducer,
|
|
167
|
+
{ defaultTheme, initialUsername },
|
|
168
|
+
createInitialState,
|
|
243
169
|
);
|
|
244
170
|
|
|
245
|
-
//
|
|
246
|
-
const
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
171
|
+
// Unpack state.
|
|
172
|
+
const {
|
|
173
|
+
tabList,
|
|
174
|
+
activeFileId,
|
|
175
|
+
theme,
|
|
176
|
+
isSettingsOpen,
|
|
177
|
+
editorWantsFocus,
|
|
178
|
+
username,
|
|
179
|
+
} = state;
|
|
180
|
+
|
|
181
|
+
// Functions for dispatching actions to the reducer.
|
|
182
|
+
const {
|
|
183
|
+
setActiveFileId,
|
|
184
|
+
openTab,
|
|
185
|
+
closeTabs,
|
|
186
|
+
setTheme,
|
|
187
|
+
setIsSettingsOpen,
|
|
188
|
+
closeSettings,
|
|
189
|
+
editorNoLongerWantsFocus,
|
|
190
|
+
setUsername,
|
|
191
|
+
} = useActions(dispatch);
|
|
250
192
|
|
|
251
193
|
// The set of open directories.
|
|
194
|
+
// TODO move this into reducer/useActions
|
|
252
195
|
const { isDirectoryOpen, toggleDirectory } =
|
|
253
196
|
useOpenDirectories();
|
|
254
197
|
|
|
255
|
-
|
|
256
|
-
// Include
|
|
257
|
-
// - `createFile`
|
|
258
|
-
// - `handleRenameFileClick`
|
|
259
|
-
// - `deleteFile`
|
|
260
|
-
// - `handleDeleteFileClick`
|
|
261
|
-
const createFile = useCallback(() => {
|
|
262
|
-
const name = prompt('Enter new file name');
|
|
263
|
-
if (name) {
|
|
264
|
-
submitOperation((document) => ({
|
|
265
|
-
...document,
|
|
266
|
-
files: {
|
|
267
|
-
...document.files,
|
|
268
|
-
[randomId()]: { name, text: '' },
|
|
269
|
-
},
|
|
270
|
-
}));
|
|
271
|
-
}
|
|
272
|
-
}, [submitOperation]);
|
|
273
|
-
|
|
274
|
-
// Called when a file in the sidebar is renamed.
|
|
275
|
-
const handleRenameFileClick = useCallback(
|
|
276
|
-
(fileId: FileId, newName: string) => {
|
|
277
|
-
submitOperation((document) => ({
|
|
278
|
-
...document,
|
|
279
|
-
files: {
|
|
280
|
-
...document.files,
|
|
281
|
-
[fileId]: {
|
|
282
|
-
...document.files[fileId],
|
|
283
|
-
name: newName,
|
|
284
|
-
},
|
|
285
|
-
},
|
|
286
|
-
}));
|
|
287
|
-
},
|
|
288
|
-
[submitOperation],
|
|
289
|
-
);
|
|
290
|
-
|
|
291
|
-
const deleteFile = useCallback(
|
|
292
|
-
(fileId: FileId) => {
|
|
293
|
-
submitOperation((document) => {
|
|
294
|
-
const updatedFiles = { ...document.files };
|
|
295
|
-
delete updatedFiles[fileId];
|
|
296
|
-
return { ...document, files: updatedFiles };
|
|
297
|
-
});
|
|
298
|
-
closeTab(fileId);
|
|
299
|
-
},
|
|
300
|
-
[submitOperation, closeTab],
|
|
301
|
-
);
|
|
198
|
+
usePersistUsername(username);
|
|
302
199
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
let tabsToDelete: Array<FileId> = [];
|
|
306
|
-
submitOperation((document) => {
|
|
307
|
-
const updatedFiles = { ...document.files };
|
|
308
|
-
for (const key in updatedFiles) {
|
|
309
|
-
if (updatedFiles[key].name.includes(path)) {
|
|
310
|
-
tabsToDelete.push(key);
|
|
311
|
-
delete updatedFiles[key];
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
return { ...document, files: updatedFiles };
|
|
315
|
-
});
|
|
316
|
-
multiCloseTab(tabsToDelete);
|
|
317
|
-
},
|
|
318
|
-
[submitOperation, multiCloseTab],
|
|
319
|
-
);
|
|
320
|
-
|
|
321
|
-
const handleDeleteClick = useCallback(
|
|
322
|
-
(key: string) => {
|
|
323
|
-
//Regex to identify if the key is a file path or a file id.
|
|
324
|
-
if (/^[0-9]*$/.test(key)) {
|
|
325
|
-
if (key.length == 8) {
|
|
326
|
-
deleteFile(key);
|
|
327
|
-
} else {
|
|
328
|
-
deleteDirectory(key);
|
|
329
|
-
}
|
|
330
|
-
} else {
|
|
331
|
-
deleteDirectory(key);
|
|
332
|
-
}
|
|
333
|
-
},
|
|
334
|
-
[deleteFile, deleteDirectory],
|
|
335
|
-
);
|
|
336
|
-
|
|
337
|
-
const handleSettingsClose = useCallback(() => {
|
|
338
|
-
setIsSettingsOpen(false);
|
|
339
|
-
}, []);
|
|
200
|
+
// Cache of CodeMirror editors by file id.
|
|
201
|
+
const editorCache: EditorCache = useEditorCache();
|
|
340
202
|
|
|
341
|
-
//
|
|
342
|
-
|
|
343
|
-
const interactTimeoutRef = useRef(null);
|
|
344
|
-
const handleInteract = useCallback(() => {
|
|
345
|
-
// Set `isInteracting: true` if not already set.
|
|
346
|
-
if (!interactTimeoutRef.current) {
|
|
347
|
-
submitOperation((document) => ({
|
|
348
|
-
...document,
|
|
349
|
-
isInteracting: true,
|
|
350
|
-
}));
|
|
351
|
-
} else {
|
|
352
|
-
clearTimeout(interactTimeoutRef.current);
|
|
353
|
-
}
|
|
203
|
+
// Handle dynamic theme changes.
|
|
204
|
+
useDynamicTheme(editorCache, theme);
|
|
354
205
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
206
|
+
// Handle file CRUD operations.
|
|
207
|
+
const {
|
|
208
|
+
createFile,
|
|
209
|
+
renameFile,
|
|
210
|
+
deleteFile,
|
|
211
|
+
deleteDirectory,
|
|
212
|
+
} = useFileCRUD({
|
|
213
|
+
submitOperation,
|
|
214
|
+
closeTabs,
|
|
215
|
+
openTab,
|
|
216
|
+
});
|
|
364
217
|
|
|
365
218
|
// Isolate the files object from the document.
|
|
366
219
|
const files: Files | null = content
|
|
@@ -371,21 +224,25 @@ function App() {
|
|
|
371
224
|
<SplitPaneResizeProvider>
|
|
372
225
|
<div className="app">
|
|
373
226
|
<div className="left">
|
|
374
|
-
<
|
|
375
|
-
createFile={createFile}
|
|
227
|
+
<VZSidebar
|
|
376
228
|
files={files}
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
229
|
+
createFile={createFile}
|
|
230
|
+
renameFile={renameFile}
|
|
231
|
+
deleteFile={deleteFile}
|
|
232
|
+
deleteDirectory={deleteDirectory}
|
|
233
|
+
openTab={openTab}
|
|
380
234
|
setIsSettingsOpen={setIsSettingsOpen}
|
|
381
235
|
isDirectoryOpen={isDirectoryOpen}
|
|
382
236
|
toggleDirectory={toggleDirectory}
|
|
237
|
+
activeFileId={activeFileId}
|
|
383
238
|
/>
|
|
384
|
-
<
|
|
239
|
+
<VZSettings
|
|
385
240
|
show={isSettingsOpen}
|
|
386
|
-
onClose={
|
|
241
|
+
onClose={closeSettings}
|
|
387
242
|
theme={theme}
|
|
388
243
|
setTheme={setTheme}
|
|
244
|
+
username={username}
|
|
245
|
+
setUsername={setUsername}
|
|
389
246
|
/>
|
|
390
247
|
</div>
|
|
391
248
|
<div className="right">
|
|
@@ -394,24 +251,30 @@ function App() {
|
|
|
394
251
|
tabList={tabList}
|
|
395
252
|
activeFileId={activeFileId}
|
|
396
253
|
setActiveFileId={setActiveFileId}
|
|
397
|
-
|
|
254
|
+
openTab={openTab}
|
|
255
|
+
closeTabs={closeTabs}
|
|
256
|
+
createFile={createFile}
|
|
398
257
|
/>
|
|
399
258
|
{content && activeFileId ? (
|
|
400
259
|
<CodeEditor
|
|
401
260
|
shareDBDoc={shareDBDoc}
|
|
261
|
+
submitOperation={submitOperation}
|
|
402
262
|
localPresence={localPresence}
|
|
403
263
|
docPresence={docPresence}
|
|
404
264
|
activeFileId={activeFileId}
|
|
405
265
|
theme={theme}
|
|
406
|
-
onInteract={handleInteract}
|
|
407
266
|
editorCache={editorCache}
|
|
267
|
+
editorWantsFocus={editorWantsFocus}
|
|
268
|
+
editorNoLongerWantsFocus={
|
|
269
|
+
editorNoLongerWantsFocus
|
|
270
|
+
}
|
|
271
|
+
username={username}
|
|
408
272
|
/>
|
|
409
273
|
) : null}
|
|
410
|
-
<
|
|
411
|
-
prettierError={prettierError}
|
|
412
|
-
/>
|
|
274
|
+
<CodeErrorOverlay errorMessage={prettierError} />
|
|
413
275
|
<PresenceNotifications
|
|
414
276
|
docPresence={docPresence}
|
|
277
|
+
localPresence={localPresence}
|
|
415
278
|
/>
|
|
416
279
|
</div>
|
|
417
280
|
<Resizer />
|
|
@@ -12,6 +12,7 @@ import { json1Presence, textUnicode } from '../../ot';
|
|
|
12
12
|
import {
|
|
13
13
|
FileId,
|
|
14
14
|
ShareDBDoc,
|
|
15
|
+
Username,
|
|
15
16
|
VZCodeContent,
|
|
16
17
|
} from '../../types';
|
|
17
18
|
import { json1PresenceBroadcast } from './json1PresenceBroadcast';
|
|
@@ -64,6 +65,7 @@ export const getOrCreateEditor = ({
|
|
|
64
65
|
theme,
|
|
65
66
|
onInteract,
|
|
66
67
|
editorCache,
|
|
68
|
+
usernameRef,
|
|
67
69
|
}: {
|
|
68
70
|
fileId: FileId;
|
|
69
71
|
|
|
@@ -82,6 +84,7 @@ export const getOrCreateEditor = ({
|
|
|
82
84
|
theme: ThemeLabel;
|
|
83
85
|
onInteract?: () => void;
|
|
84
86
|
editorCache: EditorCache;
|
|
87
|
+
usernameRef: React.MutableRefObject<Username>;
|
|
85
88
|
}): EditorCacheValue => {
|
|
86
89
|
// Cache hit
|
|
87
90
|
if (editorCache.has(fileId)) {
|
|
@@ -118,13 +121,15 @@ export const getOrCreateEditor = ({
|
|
|
118
121
|
);
|
|
119
122
|
|
|
120
123
|
// Deals with broadcasting changes in cursor location and selection.
|
|
121
|
-
if (localPresence)
|
|
124
|
+
if (localPresence) {
|
|
122
125
|
extensions.push(
|
|
123
126
|
json1PresenceBroadcast({
|
|
124
127
|
path: textPath,
|
|
125
128
|
localPresence,
|
|
129
|
+
usernameRef,
|
|
126
130
|
}),
|
|
127
131
|
);
|
|
132
|
+
}
|
|
128
133
|
|
|
129
134
|
// Deals with receiving the broadcas from other clients and displaying them.
|
|
130
135
|
if (docPresence)
|