vzcode 1.19.0 → 1.21.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.
@@ -1,4 +1,4 @@
1
- import React, {
1
+ import {
2
2
  useCallback,
3
3
  useContext,
4
4
  useEffect,
@@ -8,17 +8,68 @@ import React, {
8
8
  import { Button, Modal, Form } from './bootstrap';
9
9
  import { ThemeLabel, themes } from './themes';
10
10
  import { VZCodeContext } from './VZCodeContext';
11
- import { fonts } from './Fonts/fonts';
12
- import { toggleRainbowBrackets } from './CodeEditor/rainbowBrackets';
13
11
 
14
- const fontSizes = ['10px','12px','14px','16px', '18px', '20px', '24px'];
12
+ const DEBUG = false;
13
+
14
+ // Font size options for the editor
15
+ const fontSizes = [
16
+ '10px',
17
+ '12px',
18
+ '14px',
19
+ '16px',
20
+ '18px',
21
+ '20px',
22
+ '24px',
23
+ ];
24
+
25
+ // List of system fonts to be detected for availability
26
+ const systemFonts = [
27
+ '-apple-system',
28
+ 'BlinkMacSystemFont',
29
+ 'Segoe UI',
30
+ 'Roboto',
31
+ 'Helvetica Neue',
32
+ 'Arial',
33
+ 'sans-serif',
34
+ 'Courier New',
35
+ 'Georgia',
36
+ 'Tahoma',
37
+ 'Verdana',
38
+ 'Times New Roman',
39
+ 'Trebuchet MS',
40
+ 'Comic Sans MS',
41
+ ];
42
+
43
+ // Utility function to detect if a given font is available
44
+ const isFontAvailable = (font: string): boolean => {
45
+ const testString = 'abcdefghijklmnopqrstuvwxyz0123456789';
46
+ const testSize = '72px';
47
+
48
+ const span = document.createElement('span');
49
+ span.style.fontSize = testSize;
50
+ span.style.visibility = 'hidden';
51
+ span.style.position = 'absolute';
52
+ span.innerHTML = testString;
53
+ document.body.appendChild(span);
54
+
55
+ const defaultFont = 'monospace';
56
+ span.style.fontFamily = defaultFont;
57
+ const defaultWidth = span.offsetWidth;
58
+
59
+ span.style.fontFamily = `${font}, ${defaultFont}`;
60
+ const newWidth = span.offsetWidth;
61
+
62
+ document.body.removeChild(span);
63
+
64
+ return newWidth !== defaultWidth;
65
+ };
15
66
 
16
67
  export const VZSettings = ({
17
68
  enableUsernameField = true,
18
69
  }: {
19
- // Feature flag to enable/disable username field
20
70
  enableUsernameField?: boolean;
21
71
  }) => {
72
+ // Extracting context values for managing settings state
22
73
  const {
23
74
  isSettingsOpen,
24
75
  closeSettings,
@@ -28,58 +79,24 @@ export const VZSettings = ({
28
79
  setUsername,
29
80
  } = useContext(VZCodeContext);
30
81
 
31
- const handleThemeChange = useCallback(
32
- (event: React.ChangeEvent<HTMLSelectElement>) => {
33
- const selectedTheme = event.target.value as ThemeLabel;
34
- setTheme(selectedTheme);
35
- localStorage.setItem('vzcodeSelectedTheme', selectedTheme);
36
- },
37
- [],
38
- );
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]);
48
- // Initialize font and size from localStorage or defaults
49
- // const [selectedFont, setSelectedFont] = useState(
50
- // localStorage.getItem('vzcodeSelectedFont') ||
51
- // 'Roboto Mono',
52
- // );
53
- // const [selectedFontSize, setSelectedFontSize] = useState(
54
- // localStorage.getItem('vzcodeSelectedFontSize') ||
55
- // '16px',
56
- // );
82
+ // State variables for managing font and font size
57
83
  const [selectedFont, setSelectedFont] =
58
84
  useState('Roboto Mono');
59
85
  const [selectedFontSize, setSelectedFontSize] =
60
86
  useState('16px');
87
+ const [availableFonts, setAvailableFonts] = useState<
88
+ string[]
89
+ >([]);
61
90
 
62
- // Initialize rainbowBrackets setting from localStorage or default to 'on'
63
- const [rainbowBrackets, setRainbowBrackets] =
64
- useState('on');
65
-
91
+ // Load saved settings from local storage on initial render
66
92
  useEffect(() => {
67
- // If we're in the browser,
68
93
  if (typeof window !== 'undefined') {
69
- const selectedFontFromLocalStorage: string | null =
94
+ const selectedFontFromLocalStorage =
70
95
  window.localStorage.getItem('vzcodeSelectedFont');
71
-
72
- const selectedFontSizeFromLocalStorage:
73
- | string
74
- | null = window.localStorage.getItem(
75
- 'vzcodeSelectedFontSize',
76
- );
77
-
78
- const rainbowBracketsFromLocalStorage:
79
- | string
80
- | null = window.localStorage.getItem(
81
- 'vzcodeRainbowBrackets',
82
- );
96
+ const selectedFontSizeFromLocalStorage =
97
+ window.localStorage.getItem(
98
+ 'vzcodeSelectedFontSize',
99
+ );
83
100
 
84
101
  if (selectedFontFromLocalStorage !== null) {
85
102
  setSelectedFont(selectedFontFromLocalStorage);
@@ -89,48 +106,42 @@ export const VZSettings = ({
89
106
  selectedFontSizeFromLocalStorage,
90
107
  );
91
108
  }
92
- if (rainbowBracketsFromLocalStorage !== null) {
93
- setRainbowBrackets(rainbowBracketsFromLocalStorage);
94
- }
95
- } else {
96
- // If we're not in the browser, use the default initial width.
97
109
  }
98
110
  }, []);
99
111
 
100
- // Called when the user selects a different font
101
- const handleFontChange = useCallback(
102
- (event: React.ChangeEvent<HTMLSelectElement>) => {
103
- const newFont = event.target.value;
104
- localStorage.setItem('vzcodeSelectedFont', newFont);
105
- setSelectedFont(newFont);
106
- },
107
- [],
108
- );
112
+ // Detect available system fonts and update the state
113
+ useEffect(() => {
114
+ const detectFonts = () => {
115
+ const detectedFonts: string[] = [];
116
+ for (const font of systemFonts) {
117
+ if (isFontAvailable(font)) {
118
+ detectedFonts.push(font);
119
+ if (DEBUG) {
120
+ console.log(`${font} is available`);
121
+ }
122
+ } else if (DEBUG) {
123
+ console.log(`${font} is not available`);
124
+ }
125
+ }
126
+ setAvailableFonts(detectedFonts);
127
+ };
109
128
 
110
- // Called when the user selects a different font size
111
- const handleFontSizeChange = useCallback(
112
- (event: React.ChangeEvent<HTMLSelectElement>) => {
113
- const newSize = event.target.value;
114
- localStorage.setItem(
115
- 'vzcodeSelectedFontSize',
116
- newSize,
117
- );
118
- setSelectedFontSize(newSize);
119
- },
120
- [],
121
- );
129
+ detectFonts();
130
+ }, []);
122
131
 
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
- );
132
+ // Reset all settings to default values
133
+ const resetSettings = useCallback(() => {
134
+ setSelectedFont('Roboto Mono');
135
+ setSelectedFontSize('16px');
136
+ setTheme(themes[0].label);
137
+ if (enableUsernameField) {
138
+ setUsername('');
139
+ }
140
+ localStorage.removeItem('vzcodeSelectedFont');
141
+ localStorage.removeItem('vzcodeSelectedFontSize');
142
+ }, [enableUsernameField, setTheme, setUsername]);
133
143
 
144
+ // Update font family in the document's style
134
145
  useEffect(() => {
135
146
  document.body.style.setProperty(
136
147
  '--vzcode-font-family',
@@ -138,6 +149,7 @@ export const VZSettings = ({
138
149
  );
139
150
  }, [selectedFont]);
140
151
 
152
+ // Update font size in the document's style
141
153
  useEffect(() => {
142
154
  document.body.style.setProperty(
143
155
  '--vzcode-font-size',
@@ -147,11 +159,12 @@ export const VZSettings = ({
147
159
 
148
160
  const usernameRef = useRef<HTMLInputElement>(null);
149
161
 
162
+ // Handle username input change
150
163
  const handleUsernameChange = useCallback(() => {
151
164
  setUsername(usernameRef.current?.value || '');
152
165
  }, [setUsername]);
153
166
 
154
- // Function to handle pressing Enter key
167
+ // Close settings modal on Enter key press
155
168
  useEffect(() => {
156
169
  if (isSettingsOpen) {
157
170
  const handleEnterKey = (event: KeyboardEvent) => {
@@ -203,7 +216,9 @@ export const VZSettings = ({
203
216
  <select
204
217
  className="form-select"
205
218
  value={theme}
206
- onChange={handleThemeChange}
219
+ onChange={(e) =>
220
+ setTheme(e.target.value as ThemeLabel)
221
+ }
207
222
  >
208
223
  {themes.map(({ label }) => (
209
224
  <option key={label} value={label}>
@@ -211,37 +226,32 @@ export const VZSettings = ({
211
226
  </option>
212
227
  ))}
213
228
  </select>
214
- <Form.Text className="text-muted">
215
- Select a color theme for the editor
216
- </Form.Text>
217
229
  </Form.Group>
218
230
 
219
231
  <Form.Group className="mb-3" controlId="formFork">
220
232
  <Form.Label>Font</Form.Label>
221
-
222
233
  <select
223
234
  className="form-select"
224
- onChange={handleFontChange}
235
+ onChange={(e) =>
236
+ setSelectedFont(e.target.value)
237
+ }
225
238
  value={selectedFont}
226
239
  >
227
- {fonts.map((font) => (
240
+ {availableFonts.map((font) => (
228
241
  <option key={font} value={font}>
229
242
  {font}
230
243
  </option>
231
244
  ))}
232
245
  </select>
233
-
234
- <Form.Text className="text-muted">
235
- Select font for the editor
236
- </Form.Text>
237
246
  </Form.Group>
238
247
 
239
248
  <Form.Group className="mb-3" controlId="formFork">
240
249
  <Form.Label>Font Size</Form.Label>
241
-
242
250
  <select
243
251
  className="form-select"
244
- onChange={handleFontSizeChange}
252
+ onChange={(e) =>
253
+ setSelectedFontSize(e.target.value)
254
+ }
245
255
  value={selectedFontSize}
246
256
  >
247
257
  {fontSizes.map((size) => (
@@ -250,29 +260,12 @@ export const VZSettings = ({
250
260
  </option>
251
261
  ))}
252
262
  </select>
253
-
254
- <Form.Text className="text-muted">
255
- Select a font size for the editor
256
- </Form.Text>
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
263
  </Form.Group>
273
-
274
264
  </Modal.Body>
275
265
  <Modal.Footer>
266
+ <Button variant="secondary" onClick={resetSettings}>
267
+ Reset to Default
268
+ </Button>
276
269
  <Button variant="primary" onClick={closeSettings}>
277
270
  Done
278
271
  </Button>
@@ -38,8 +38,8 @@ if (isCopilotEnabled) {
38
38
  openai = new OpenAI(openAIOptions);
39
39
  }
40
40
 
41
- export const handleAICopilot =
42
- (/*TODO shareDBDoc*/) => async (req, res) => {
41
+ export const handleAICopilot = (/*TODO shareDBDoc*/) =>
42
+ async (req, res) => {
43
43
  // Don't break if the AI is not enabled.
44
44
  // This is useful for local development.
45
45
  if (!isCopilotEnabled) {