vzcode 1.15.0 → 1.17.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 (44) hide show
  1. package/dist/assets/index-BQgRA0SD.js +181 -0
  2. package/dist/assets/index-CSSpCKM0.js +447 -0
  3. package/dist/assets/index-zzK6rRiK.css +1 -0
  4. package/dist/assets/worker-8af7bTHW.js +293 -0
  5. package/dist/index.html +2 -2
  6. package/package.json +40 -34
  7. package/src/client/AIAssist/AIAssistWidget/index.tsx +10 -6
  8. package/src/client/App/index.tsx +52 -20
  9. package/src/client/App/usePending.ts +50 -0
  10. package/src/client/App/useShareDB.ts +40 -1
  11. package/src/client/CodeEditor/Copilot/index.ts +28 -0
  12. package/src/client/CodeEditor/InteractiveWidgets/colorPicker.ts +129 -33
  13. package/src/client/CodeEditor/InteractiveWidgets/colorsInTextPlugin.ts +36 -1
  14. package/src/client/CodeEditor/getOrCreateEditor.ts +43 -6
  15. package/src/client/CodeEditor/index.tsx +7 -4
  16. package/src/client/CodeEditor/json1PresenceDisplay.ts +5 -5
  17. package/src/client/CodeEditor/rainbowBrackets.ts +14 -2
  18. package/src/client/CodeEditor/style.scss +106 -1
  19. package/src/client/Icons/MicSVG.tsx +25 -0
  20. package/src/client/RunCodeWidget/index.tsx +20 -3
  21. package/src/client/TabList/index.tsx +8 -11
  22. package/src/client/VZCodeContext.tsx +66 -24
  23. package/src/client/VZKeyboardShortcutsDoc.tsx +8 -8
  24. package/src/client/VZLeft.tsx +4 -2
  25. package/src/client/VZMiddle.tsx +86 -27
  26. package/src/client/VZResizer/index.tsx +3 -3
  27. package/src/client/VZSettings.tsx +54 -3
  28. package/src/client/VZSidebar/FileListing.tsx +20 -6
  29. package/src/client/VZSidebar/Listing.tsx +2 -2
  30. package/src/client/VZSidebar/VoiceChatModal.tsx +121 -0
  31. package/src/client/VZSidebar/index.tsx +80 -15
  32. package/src/client/VZSidebar/styles.scss +6 -2
  33. package/src/client/presenceColor.ts +8 -0
  34. package/src/client/useTypeScript/worker/constants.ts +6 -0
  35. package/src/server/generateAIResponse.js +79 -13
  36. package/src/server/handleAICopilot.js +77 -0
  37. package/src/server/index.js +23 -8
  38. package/src/server/livekit.js +24 -0
  39. package/src/server/setupEnv.js +1 -1
  40. package/src/types.ts +1 -0
  41. package/dist/assets/index-Bm65AzMP.js +0 -425
  42. package/dist/assets/index-DbFdL1A1.js +0 -159
  43. package/dist/assets/index-Yz-ZHc0O.css +0 -1
  44. package/dist/assets/worker-CJWrLBN2.js +0 -286
@@ -2,41 +2,43 @@ 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
22
  } from '../types';
22
- import { usePrettier } from './usePrettier';
23
- import { useTypeScript } from './useTypeScript';
24
- import { createInitialState, vzReducer } from './vzReducer';
25
23
  import {
26
24
  ThemeLabel,
27
25
  defaultTheme,
28
26
  useDynamicTheme,
29
27
  } from './themes';
30
28
  import { useActions } from './useActions';
31
- import { useOpenDirectories } from './useOpenDirectories';
32
- import { useFileCRUD } from './useFileCRUD';
33
29
  import {
34
30
  EditorCache,
35
31
  useEditorCache,
36
32
  } from './useEditorCache';
37
- import { useURLSync } from './useURLSync';
33
+ import { useFileCRUD } from './useFileCRUD';
38
34
  import { useKeyboardShortcuts } from './useKeyboardShortcuts';
35
+ import { useOpenDirectories } from './useOpenDirectories';
36
+ import { usePrettier } from './usePrettier';
39
37
  import { useRunCode } from './useRunCode';
38
+ import { useTypeScript } from './useTypeScript';
39
+ import { useURLSync } from './useURLSync';
40
+ import { createInitialState, vzReducer } from './vzReducer';
41
+ import { findPane } from './vzReducer/findPane';
40
42
 
41
43
  // This context centralizes all the "smart" logic
42
44
  // to do with the application state. This includes
@@ -72,14 +74,14 @@ export type VZCodeContextValue = {
72
74
  ) => void;
73
75
  deleteDirectory: (directoryId: string) => void;
74
76
 
75
- activeFileId: string | null;
76
77
  setActiveFileId: (fileId: string | null) => void;
77
78
  setActiveFileLeft: () => void;
78
79
  setActiveFileRight: () => void;
79
80
 
80
81
  activePaneId: PaneId;
82
+ pane: Pane;
83
+ activePane: LeafPane;
81
84
 
82
- tabList: Array<TabState>;
83
85
  openTab: (tabState: TabState) => void;
84
86
  closeTabs: (fileIds: string[]) => void;
85
87
 
@@ -154,6 +156,7 @@ export type VZCodeContextValue = {
154
156
  codeEditorRef: React.RefObject<HTMLDivElement>;
155
157
 
156
158
  connected: boolean;
159
+ pending: boolean;
157
160
 
158
161
  hoveredItemId: ItemId | null;
159
162
  setHoveredItemId: (itemId: ItemId | null) => void;
@@ -167,6 +170,15 @@ export type VZCodeContextValue = {
167
170
 
168
171
  sidebarPresenceIndicators: Array<PresenceIndicator>;
169
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;
170
182
  };
171
183
 
172
184
  export const VZCodeProvider = ({
@@ -181,6 +193,13 @@ export const VZCodeProvider = ({
181
193
  children,
182
194
  codeError = null,
183
195
  connected,
196
+ pending,
197
+ liveKitToken,
198
+ setLiveKitToken,
199
+ liveKitRoomName,
200
+ setLiveKitRoom,
201
+ liveKitConnection,
202
+ setLiveKitConnection,
184
203
  }: {
185
204
  content: VZCodeContent;
186
205
  shareDBDoc: ShareDBDoc<VZCodeContent>;
@@ -193,6 +212,13 @@ export const VZCodeProvider = ({
193
212
  children: React.ReactNode;
194
213
  codeError?: string | null;
195
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;
196
222
  }) => {
197
223
  // Auto-run Pretter after local changes.
198
224
  const {
@@ -260,12 +286,11 @@ export const VZCodeProvider = ({
260
286
  sidebarPresenceIndicators,
261
287
  } = state;
262
288
 
263
- // TODO support splitPane type
264
- if (pane.type !== 'leafPane') {
289
+ const activePane = findPane(pane, activePaneId);
290
+ if (activePane.type !== 'leafPane') {
291
+ // Should never happen
265
292
  throw new Error('Expected leafPane');
266
293
  }
267
- const tabList = pane.tabList;
268
- const activeFileId = pane.activeFileId;
269
294
 
270
295
  // Functions for dispatching actions to the reducer.
271
296
  const {
@@ -298,8 +323,8 @@ export const VZCodeProvider = ({
298
323
  content,
299
324
  openTab,
300
325
  setActiveFileId,
301
- tabList,
302
- activeFileId,
326
+ tabList: activePane.tabList,
327
+ activeFileId: activePane.activeFileId,
303
328
  });
304
329
 
305
330
  // The set of open directories.
@@ -374,7 +399,8 @@ export const VZCodeProvider = ({
374
399
 
375
400
  useKeyboardShortcuts({
376
401
  closeTabs,
377
- activeFileId,
402
+ // TODO verify that this makes sense
403
+ activeFileId: activePane.activeFileId,
378
404
  activePaneId,
379
405
  handleOpenCreateFileModal,
380
406
  setActiveFileLeft,
@@ -391,6 +417,11 @@ export const VZCodeProvider = ({
391
417
  const [hoveredItemId, setHoveredItemId] =
392
418
  useState<ItemId | null>(null);
393
419
 
420
+ // Livekit Voice Chat Modal
421
+
422
+ const [voiceChatModalOpen, setVoiceChatModalOpen] =
423
+ useState(false);
424
+
394
425
  // The value provided by this context.
395
426
  const value: VZCodeContextValue = {
396
427
  content,
@@ -407,14 +438,16 @@ export const VZCodeProvider = ({
407
438
  renameDirectory,
408
439
  deleteDirectory,
409
440
 
410
- activeFileId,
411
441
  setActiveFileId,
412
442
  setActiveFileLeft,
413
443
  setActiveFileRight,
414
444
 
415
445
  activePaneId,
446
+ // Root pane
447
+ pane,
448
+ // Active leaf pane
449
+ activePane,
416
450
 
417
- tabList,
418
451
  openTab,
419
452
  closeTabs,
420
453
 
@@ -467,6 +500,7 @@ export const VZCodeProvider = ({
467
500
  codeEditorRef,
468
501
 
469
502
  connected,
503
+ pending,
470
504
 
471
505
  hoveredItemId,
472
506
  setHoveredItemId,
@@ -476,6 +510,14 @@ export const VZCodeProvider = ({
476
510
  updatePresenceIndicator,
477
511
  sidebarPresenceIndicators,
478
512
  splitCurrentPane,
513
+ liveKitRoomName,
514
+ setLiveKitRoom,
515
+ liveKitToken,
516
+ setLiveKitToken,
517
+ liveKitConnection,
518
+ setLiveKitConnection,
519
+ voiceChatModalOpen,
520
+ setVoiceChatModalOpen,
479
521
  };
480
522
 
481
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 + s</strong> or{' '}
50
- <strong>Shift + Enter</strong> <br />
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 + drag on a number</strong>
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 + click on a hex color</strong>
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 + w</strong> <br />
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 + n or Ctrl + Shift + n</strong>{' '}
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 + Page Up</strong> <br />
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 + Page Down</strong> <br />
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>
@@ -1,8 +1,9 @@
1
- import { VZSettings } from './VZSettings';
2
1
  import { VZKeyboardShortcutsDoc } from './VZKeyboardShortcutsDoc';
2
+ import { VZSettings } from './VZSettings';
3
3
  import { VZSidebar } from './VZSidebar';
4
- import { CreateFileModal } from './VZSidebar/CreateFileModal';
5
4
  import { CreateDirModal } from './VZSidebar/CreateDirModal';
5
+ import { CreateFileModal } from './VZSidebar/CreateFileModal';
6
+ import { VoiceChatModal } from './VZSidebar/VoiceChatModal';
6
7
 
7
8
  // The middle portion of the VZCode environment, containing:
8
9
  // * The sidebar
@@ -20,6 +21,7 @@ export const VZLeft = ({ enableUsernameField = true }) => {
20
21
  />
21
22
  <CreateFileModal />
22
23
  <CreateDirModal />
24
+ <VoiceChatModal />
23
25
  </div>
24
26
  );
25
27
  };
@@ -9,6 +9,69 @@ import { VZCodeContext } from './VZCodeContext';
9
9
  import { RunCodeWidget } from './RunCodeWidget';
10
10
  import { InteractRule } from '@replit/codemirror-interact';
11
11
 
12
+ // TODO modify this to handle the SplitPane type
13
+ // Recursive structure?
14
+ // SplitPaneView
15
+ // LeafPaneView
16
+ const PaneView = ({
17
+ pane,
18
+ content,
19
+ customInteractRules,
20
+ allowGlobals,
21
+ enableAIAssist,
22
+ aiAssistEndpoint,
23
+ aiAssistOptions,
24
+ aiAssistTooltipText,
25
+ aiAssistClickOverride,
26
+ aiCopilotEndpoint,
27
+ }) => {
28
+ // This prevents the CodeEditor from rendering
29
+ // during SSR.
30
+ const [isClient, setIsClient] = useState(false);
31
+ useEffect(() => {
32
+ setIsClient(true);
33
+ }, []);
34
+
35
+ // TODO something like
36
+ // return pane.type === 'leafPane' ? (
37
+ // <LeafPaneView />
38
+ // ) : (
39
+ // <SplitPaneView />
40
+ // );
41
+
42
+ // This should go in LeafPaneView
43
+ return (
44
+ <>
45
+ <TabList
46
+ activeFileId={pane.activeFileId}
47
+ tabList={pane.tabList}
48
+ />
49
+ {isClient && content && pane.activeFileId && (
50
+ <CodeEditor
51
+ customInteractRules={customInteractRules}
52
+ allowGlobals={allowGlobals}
53
+ aiCopilotEndpoint={aiCopilotEndpoint}
54
+ />
55
+ )}
56
+ {isClient &&
57
+ enableAIAssist &&
58
+ content &&
59
+ pane.activeFileId ? (
60
+ <AIAssistWidget
61
+ aiAssistEndpoint={aiAssistEndpoint}
62
+ aiAssistOptions={aiAssistOptions}
63
+ aiAssistTooltipText={aiAssistTooltipText}
64
+ aiAssistClickOverride={aiAssistClickOverride}
65
+ paneId={pane.id}
66
+ activeFileId={pane.activeFileId}
67
+ tabList={pane.tabList}
68
+ />
69
+ ) : null}
70
+ <RunCodeWidget />
71
+ </>
72
+ );
73
+ };
74
+
12
75
  // The middle portion of the VZCode environment, containing:
13
76
  // * The list of tabs at the top
14
77
  // * The code editor itself
@@ -21,6 +84,7 @@ export const VZMiddle = ({
21
84
  aiAssistOptions,
22
85
  aiAssistTooltipText,
23
86
  aiAssistClickOverride,
87
+ aiCopilotEndpoint,
24
88
  customInteractRules,
25
89
  allowGlobals = false,
26
90
  }: {
@@ -29,6 +93,7 @@ export const VZMiddle = ({
29
93
  aiAssistOptions?: { [key: string]: string };
30
94
  aiAssistTooltipText?: string;
31
95
  aiAssistClickOverride?: () => void;
96
+ aiCopilotEndpoint?: string;
32
97
  customInteractRules?: Array<InteractRule>;
33
98
  allowGlobals?: boolean;
34
99
  }) => {
@@ -40,41 +105,35 @@ export const VZMiddle = ({
40
105
  content,
41
106
  localPresence,
42
107
  docPresence,
43
- activeFileId,
108
+ pane,
109
+ activePane,
44
110
  errorMessage,
45
111
  } = useContext(VZCodeContext);
46
112
 
47
- // This prevents the CodeEditor from rendering
48
- // during SSR.
49
- const [isClient, setIsClient] = useState(false);
50
- useEffect(() => {
51
- setIsClient(true);
52
- }, []);
113
+ if (activePane.type !== 'leafPane') {
114
+ throw new Error('Expected leafPane');
115
+ }
116
+ // True if the editor panes should be shown.
117
+ const shouldShowEditorPanes: boolean =
118
+ activePane.activeFileId !== null;
53
119
 
54
- return activeFileId !== null ? (
120
+ return shouldShowEditorPanes ? (
55
121
  <div
56
122
  className="middle"
57
123
  style={{ width: codeEditorWidth + 'px' }}
58
124
  >
59
- <TabList />
60
- {isClient && content && activeFileId && (
61
- <CodeEditor
62
- customInteractRules={customInteractRules}
63
- allowGlobals={allowGlobals}
64
- />
65
- )}
66
- {isClient &&
67
- enableAIAssist &&
68
- content &&
69
- activeFileId ? (
70
- <AIAssistWidget
71
- aiAssistEndpoint={aiAssistEndpoint}
72
- aiAssistOptions={aiAssistOptions}
73
- aiAssistTooltipText={aiAssistTooltipText}
74
- aiAssistClickOverride={aiAssistClickOverride}
75
- />
76
- ) : null}
77
- <RunCodeWidget />
125
+ <PaneView
126
+ pane={pane}
127
+ content={content}
128
+ customInteractRules={customInteractRules}
129
+ allowGlobals={allowGlobals}
130
+ enableAIAssist={enableAIAssist}
131
+ aiAssistEndpoint={aiAssistEndpoint}
132
+ aiAssistOptions={aiAssistOptions}
133
+ aiAssistTooltipText={aiAssistTooltipText}
134
+ aiAssistClickOverride={aiAssistClickOverride}
135
+ aiCopilotEndpoint={aiCopilotEndpoint}
136
+ />
78
137
  <CodeErrorOverlay
79
138
  errorMessage={errorMessage}
80
139
  content={content}
@@ -6,7 +6,6 @@ import {
6
6
  useCallback,
7
7
  useRef,
8
8
  } from 'react';
9
-
10
9
  import {
11
10
  Side,
12
11
  SplitPaneResizeContext,
@@ -44,9 +43,10 @@ export const VZResizer = ({
44
43
 
45
44
  // If there is no active file, don't render the resizer
46
45
  // for the right side.
47
- const { activeFileId } = useContext(VZCodeContext);
46
+ const { activePane } = useContext(VZCodeContext);
47
+
48
48
  const shouldRenderResizer =
49
- side === 'left' || activeFileId;
49
+ side === 'left' || activePane.activeFileId;
50
50
 
51
51
  const previousClientX = useRef<number>(0);
52
52
 
@@ -9,8 +9,9 @@ import { Button, Modal, Form } from './bootstrap';
9
9
  import { ThemeLabel, themes } from './themes';
10
10
  import { VZCodeContext } from './VZCodeContext';
11
11
  import { fonts } from './Fonts/fonts';
12
+ import { toggleRainbowBrackets } from './CodeEditor/rainbowBrackets';
12
13
 
13
- const fontSizes = ['16px', '18px', '20px', '24px'];
14
+ const fontSizes = ['10px','12px','14px','16px', '18px', '20px', '24px'];
14
15
 
15
16
  export const VZSettings = ({
16
17
  enableUsernameField = true,
@@ -29,11 +30,21 @@ export const VZSettings = ({
29
30
 
30
31
  const handleThemeChange = useCallback(
31
32
  (event: React.ChangeEvent<HTMLSelectElement>) => {
32
- setTheme(event.target.value as ThemeLabel);
33
+ const selectedTheme = event.target.value as ThemeLabel;
34
+ setTheme(selectedTheme);
35
+ localStorage.setItem('vzcodeSelectedTheme', selectedTheme);
33
36
  },
34
37
  [],
35
38
  );
36
-
39
+
40
+ useEffect(() => {
41
+ const savedTheme = localStorage.getItem('vzcodeSelectedTheme') as ThemeLabel | null;
42
+ if (savedTheme) {
43
+ setTheme(savedTheme);
44
+ } else {
45
+ setTheme('vizhub');
46
+ }
47
+ }, [setTheme]);
37
48
  // Initialize font and size from localStorage or defaults
38
49
  // const [selectedFont, setSelectedFont] = useState(
39
50
  // localStorage.getItem('vzcodeSelectedFont') ||
@@ -48,6 +59,10 @@ export const VZSettings = ({
48
59
  const [selectedFontSize, setSelectedFontSize] =
49
60
  useState('16px');
50
61
 
62
+ // Initialize rainbowBrackets setting from localStorage or default to 'on'
63
+ const [rainbowBrackets, setRainbowBrackets] =
64
+ useState('on');
65
+
51
66
  useEffect(() => {
52
67
  // If we're in the browser,
53
68
  if (typeof window !== 'undefined') {
@@ -60,6 +75,12 @@ export const VZSettings = ({
60
75
  'vzcodeSelectedFontSize',
61
76
  );
62
77
 
78
+ const rainbowBracketsFromLocalStorage:
79
+ | string
80
+ | null = window.localStorage.getItem(
81
+ 'vzcodeRainbowBrackets',
82
+ );
83
+
63
84
  if (selectedFontFromLocalStorage !== null) {
64
85
  setSelectedFont(selectedFontFromLocalStorage);
65
86
  }
@@ -68,6 +89,9 @@ export const VZSettings = ({
68
89
  selectedFontSizeFromLocalStorage,
69
90
  );
70
91
  }
92
+ if (rainbowBracketsFromLocalStorage !== null) {
93
+ setRainbowBrackets(rainbowBracketsFromLocalStorage);
94
+ }
71
95
  } else {
72
96
  // If we're not in the browser, use the default initial width.
73
97
  }
@@ -96,6 +120,17 @@ export const VZSettings = ({
96
120
  [],
97
121
  );
98
122
 
123
+ // Called when the user changes the Rainbow Brackets setting
124
+ const handleRainbowBracketsChange = useCallback(
125
+ (event: React.ChangeEvent<HTMLSelectElement>) => {
126
+ const newSetting = event.target.value;
127
+ localStorage.setItem('vzcodeRainbowBrackets', newSetting);
128
+ setRainbowBrackets(newSetting);
129
+ toggleRainbowBrackets(newSetting === 'on');
130
+ },
131
+ [],
132
+ );
133
+
99
134
  useEffect(() => {
100
135
  document.body.style.setProperty(
101
136
  '--vzcode-font-family',
@@ -220,6 +255,22 @@ export const VZSettings = ({
220
255
  Select a font size for the editor
221
256
  </Form.Text>
222
257
  </Form.Group>
258
+
259
+ <Form.Group className="mb-3" controlId="formFork">
260
+ <Form.Label>Rainbow Brackets</Form.Label>
261
+ <select
262
+ className="form-select"
263
+ onChange={handleRainbowBracketsChange}
264
+ value={rainbowBrackets}
265
+ >
266
+ <option value="on">On</option>
267
+ <option value="off">Off</option>
268
+ </select>
269
+ <Form.Text className="text-muted">
270
+ Toggle Rainbow Brackets
271
+ </Form.Text>
272
+ </Form.Group>
273
+
223
274
  </Modal.Body>
224
275
  <Modal.Footer>
225
276
  <Button variant="primary" onClick={closeSettings}>
@@ -3,6 +3,7 @@ import { Item } from './Item';
3
3
  import { FileId, PresenceIndicator } from '../../types';
4
4
  import { VZCodeContext } from '../VZCodeContext';
5
5
  import { FileTypeIcon } from './FileTypeIcon';
6
+ import { assignUserColor } from '../presenceColor';
6
7
 
7
8
  const PresenceIndicators = ({
8
9
  presence,
@@ -11,12 +12,25 @@ const PresenceIndicators = ({
11
12
  }) => {
12
13
  return (
13
14
  <div className="presence-indicators">
14
- {presence.map((indicator, index) => (
15
- <div key={index} className="presence-indicator">
16
- {indicator.username[0]}{' '}
17
- {/* Display the first letter of the username */}
18
- </div>
19
- ))}
15
+ {presence.map((indicator, index) => {
16
+ // Get the raw RGB values from assignUserColor
17
+ const color = assignUserColor(indicator.username);
18
+
19
+ // Format it as `rgb()` directly in the component
20
+ const formattedColor = `rgb(${color})`;
21
+
22
+ //console.log(`Username: ${indicator.username}, Assigned Color: ${formattedColor}`);
23
+
24
+ return (
25
+ <div
26
+ key={index}
27
+ className="presence-indicator"
28
+ style={{ backgroundColor: formattedColor }}
29
+ >
30
+ {indicator.username[0]}
31
+ </div>
32
+ );
33
+ })}
20
34
  </div>
21
35
  );
22
36
  };
@@ -19,7 +19,7 @@ export const Listing = ({
19
19
  handleFileClick: (fileId: FileId) => void;
20
20
  handleFileDoubleClick: (fileId: FileId) => void;
21
21
  }) => {
22
- const { activeFileId, sidebarPresenceIndicators } =
22
+ const { activePane, sidebarPresenceIndicators } =
23
23
  useContext(VZCodeContext);
24
24
  const { name, file, fileId } = entity as FileTreeFile;
25
25
  const { path, children } = entity as FileTree;
@@ -35,7 +35,7 @@ export const Listing = ({
35
35
  name={name}
36
36
  handleFileClick={handleFileClick}
37
37
  handleFileDoubleClick={handleFileDoubleClick}
38
- isActive={fileId === activeFileId}
38
+ isActive={fileId === activePane.activeFileId}
39
39
  presence={presence}
40
40
  />
41
41
  ) : (