vzcode 1.5.0 → 1.7.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 (36) hide show
  1. package/dist/assets/{index-ClPo_hzs.css → index-BKRpkJER.css} +1 -1
  2. package/dist/assets/index-BwUWRAvf.js +425 -0
  3. package/dist/assets/index-Cq7BgKMs.js +157 -0
  4. package/dist/assets/{worker-DqNV0IYq.js → worker-Cs0ZU3m1.js} +193 -193
  5. package/dist/index.html +2 -2
  6. package/package.json +24 -20
  7. package/src/client/CodeEditor/getOrCreateEditor.ts +6 -0
  8. package/src/client/CodeEditor/index.tsx +19 -7
  9. package/src/client/CodeEditor/json1PresenceDisplay.ts +6 -5
  10. package/src/client/Icons/CssSVG.tsx +16 -0
  11. package/src/client/Icons/FolderSVG.tsx +20 -0
  12. package/src/client/Icons/HtmlSVG.tsx +16 -0
  13. package/src/client/Icons/JavaScriptSVG.tsx +16 -0
  14. package/src/client/Icons/JsonSVG.tsx +16 -0
  15. package/src/client/Icons/MarkdownSVG.tsx +16 -0
  16. package/src/client/Icons/PinSVG.tsx +14 -0
  17. package/src/client/Icons/ReactSVG.tsx +16 -0
  18. package/src/client/Icons/SearchFileSVG.tsx +19 -0
  19. package/src/client/Icons/SearchSVG.tsx +20 -0
  20. package/src/client/Icons/SvelteSVG.tsx +16 -0
  21. package/src/client/Icons/TypeScriptSVG.tsx +16 -0
  22. package/src/client/Icons/index.tsx +12 -0
  23. package/src/client/TabList/style.scss +2 -2
  24. package/src/client/VZCodeContext.tsx +36 -1
  25. package/src/client/VZSidebar/Search.tsx +242 -0
  26. package/src/client/VZSidebar/index.tsx +196 -112
  27. package/src/client/VZSidebar/styles.scss +101 -9
  28. package/src/client/useActions.ts +68 -1
  29. package/src/client/useFileCRUD.ts +1 -1
  30. package/src/client/vzReducer/createInitialState.ts +2 -0
  31. package/src/client/vzReducer/index.ts +60 -3
  32. package/src/client/vzReducer/searchReducer.ts +114 -0
  33. package/src/client/vzReducer/toggleAutoFollowReducer.ts +12 -0
  34. package/src/types.ts +20 -0
  35. package/dist/assets/index-Bx5B6Xgl.js +0 -400
  36. package/dist/assets/index-D6aZiqme.js +0 -156
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-D6aZiqme.js"></script>
24
- <link rel="stylesheet" crossorigin href="/assets/index-ClPo_hzs.css">
23
+ <script type="module" crossorigin src="/assets/index-Cq7BgKMs.js"></script>
24
+ <link rel="stylesheet" crossorigin href="/assets/index-BKRpkJER.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": "1.5.0",
3
+ "version": "1.7.0",
4
4
  "description": "Multiplayer code editor system",
5
5
  "main": "src/index.ts",
6
6
  "type": "module",
@@ -91,6 +91,10 @@
91
91
  {
92
92
  "name": "Philip Park",
93
93
  "url": "https://github.com/philippark"
94
+ },
95
+ {
96
+ "name": "Jeffrey Cordero",
97
+ "url": "https://github.com/jeffrey-asm"
94
98
  }
95
99
  ],
96
100
  "license": "MIT",
@@ -99,7 +103,7 @@
99
103
  },
100
104
  "homepage": "https://github.com/vizhub-core/vzcode#readme",
101
105
  "dependencies": {
102
- "@codemirror/autocomplete": "^6.16.2",
106
+ "@codemirror/autocomplete": "^6.17.0",
103
107
  "@codemirror/lang-css": "^6.2.1",
104
108
  "@codemirror/lang-html": "^6.4.9",
105
109
  "@codemirror/lang-javascript": "^6.2.2",
@@ -107,7 +111,7 @@
107
111
  "@codemirror/lang-markdown": "^6.2.5",
108
112
  "@codemirror/state": "^6.4.1",
109
113
  "@codemirror/theme-one-dark": "^6.1.2",
110
- "@codemirror/view": "^6.28.1",
114
+ "@codemirror/view": "^6.28.4",
111
115
  "@lezer/highlight": "^1.2.0",
112
116
  "@replit/codemirror-indentation-markers": "^6.5.2",
113
117
  "@replit/codemirror-interact": "^6.3.1",
@@ -115,15 +119,15 @@
115
119
  "@replit/codemirror-vscode-keymap": "^6.0.2",
116
120
  "@teamwork/websocket-json-stream": "^2.0.0",
117
121
  "@typescript/vfs": "^1.5.3",
118
- "@uiw/codemirror-theme-abcdef": "^4.22.2",
119
- "@uiw/codemirror-theme-dracula": "^4.22.2",
120
- "@uiw/codemirror-theme-eclipse": "^4.22.2",
121
- "@uiw/codemirror-theme-github": "^4.22.2",
122
- "@uiw/codemirror-theme-material": "^4.22.2",
123
- "@uiw/codemirror-theme-nord": "^4.22.2",
124
- "@uiw/codemirror-theme-okaidia": "^4.22.2",
125
- "@uiw/codemirror-theme-xcode": "^4.22.2",
126
- "@uiw/codemirror-themes": "^4.22.2",
122
+ "@uiw/codemirror-theme-abcdef": "^4.23.0",
123
+ "@uiw/codemirror-theme-dracula": "^4.23.0",
124
+ "@uiw/codemirror-theme-eclipse": "^4.23.0",
125
+ "@uiw/codemirror-theme-github": "^4.23.0",
126
+ "@uiw/codemirror-theme-material": "^4.23.0",
127
+ "@uiw/codemirror-theme-nord": "^4.23.0",
128
+ "@uiw/codemirror-theme-okaidia": "^4.23.0",
129
+ "@uiw/codemirror-theme-xcode": "^4.23.0",
130
+ "@uiw/codemirror-themes": "^4.23.0",
127
131
  "body-parser": "^1.20.2",
128
132
  "codemirror": "^6.0.1",
129
133
  "codemirror-ot": "^4.4.0",
@@ -136,16 +140,16 @@
136
140
  "json0-ot-diff": "^1.1.2",
137
141
  "ngrok": "^4.3.3",
138
142
  "open": "^10.1.0",
139
- "openai": "^4.51.0",
140
- "prettier-plugin-svelte": "^3.2.4",
143
+ "openai": "^4.52.3",
144
+ "prettier-plugin-svelte": "^3.2.5",
141
145
  "react": "^18.3.1",
142
- "react-bootstrap": "^2.10.2",
146
+ "react-bootstrap": "^2.10.4",
143
147
  "react-dom": "^18.3.1",
144
- "react-router-dom": "^6.23.1",
148
+ "react-router-dom": "^6.24.1",
145
149
  "sharedb": "^5.0.2",
146
150
  "sharedb-client-browser": "^5.0.1",
147
151
  "vizhub-ui": "^3.23.0",
148
- "ws": "^8.17.0"
152
+ "ws": "^8.18.0"
149
153
  },
150
154
  "devDependencies": {
151
155
  "@types/react": "^18.3.3",
@@ -153,9 +157,9 @@
153
157
  "@vitejs/plugin-react": "^4.3.1",
154
158
  "concurrently": "^8.2.2",
155
159
  "prettier": "^3.3.2",
156
- "sass": "^1.77.5",
157
- "typescript": "^5.4.5",
158
- "vite": "^5.3.1",
160
+ "sass": "^1.77.6",
161
+ "typescript": "^5.5.3",
162
+ "vite": "^5.3.3",
159
163
  "vitest": "^1.6.0"
160
164
  },
161
165
  "optionalDependencies": {
@@ -92,6 +92,7 @@ export const getOrCreateEditor = ({
92
92
  typeScriptWorker,
93
93
  customInteractRules,
94
94
  allowGlobals,
95
+ enableAutoFollowRef,
95
96
  }: {
96
97
  fileId: FileId;
97
98
 
@@ -121,6 +122,10 @@ export const getOrCreateEditor = ({
121
122
  typeScriptWorker: Worker;
122
123
  customInteractRules?: Array<InteractRule>;
123
124
  allowGlobals: boolean;
125
+
126
+ // Ref to a boolean that determines whether to
127
+ // enable auto-following the cursors of remote users.
128
+ enableAutoFollowRef: React.MutableRefObject<boolean>;
124
129
  }): EditorCacheValue => {
125
130
  // Cache hit
126
131
  if (editorCache.has(fileId)) {
@@ -173,6 +178,7 @@ export const getOrCreateEditor = ({
173
178
  json1PresenceDisplay({
174
179
  path: textPath,
175
180
  docPresence,
181
+ enableAutoFollowRef,
176
182
  }),
177
183
  );
178
184
  }
@@ -4,6 +4,7 @@ import {
4
4
  useCallback,
5
5
  useMemo,
6
6
  useContext,
7
+ useEffect,
7
8
  } from 'react';
8
9
  import { Username } from '../../types';
9
10
  import { EditorCacheValue } from '../useEditorCache';
@@ -36,10 +37,9 @@ export const CodeEditor = ({
36
37
  typeScriptWorker,
37
38
  theme,
38
39
  codeEditorRef,
40
+ enableAutoFollow,
39
41
  } = useContext(VZCodeContext);
40
42
 
41
- const ref = codeEditorRef;
42
-
43
43
  // Set `doc.data.isInteracting` to `true` when the user is interacting
44
44
  // via interactive code widgets (e.g. Alt+drag), and `false` when they are not.
45
45
  const interactTimeoutRef = useRef(null);
@@ -71,6 +71,13 @@ export const CodeEditor = ({
71
71
  const usernameRef = useRef<Username>(username);
72
72
  usernameRef.current = username;
73
73
 
74
+ // Track enableAutoFollow on a ref, so that we can use it in the
75
+ // CodeMirror extension.
76
+ const enableAutoFollowRef = useRef(enableAutoFollow);
77
+ useEffect(() => {
78
+ enableAutoFollowRef.current = enableAutoFollow;
79
+ }, [enableAutoFollow]);
80
+
74
81
  // Get the editor corresponding to the active file.
75
82
  // Looks in `editorCache` first, and if not found, creates a new editor.
76
83
  const editorCacheValue: EditorCacheValue = useMemo(
@@ -89,6 +96,7 @@ export const CodeEditor = ({
89
96
  typeScriptWorker,
90
97
  customInteractRules,
91
98
  allowGlobals,
99
+ enableAutoFollowRef,
92
100
  }),
93
101
  [
94
102
  activeFileId,
@@ -109,11 +117,13 @@ export const CodeEditor = ({
109
117
  // and the editor corresponding to the new file is added to the DOM.
110
118
  useLayoutEffect(() => {
111
119
  // Guard against cases where page is still loading.
112
- if (!ref.current) return;
120
+ if (!codeEditorRef.current) return;
113
121
  if (!content) return;
114
122
 
115
123
  // Add the editor and apply the prior scroll position to the DOM.
116
- ref.current.appendChild(editorCacheValue.editor.dom);
124
+ codeEditorRef.current.appendChild(
125
+ editorCacheValue.editor.dom,
126
+ );
117
127
  editorCacheValue.editor.scrollDOM.scrollTo({
118
128
  top: editorCacheValue.scrollPosition ?? 0,
119
129
  });
@@ -123,7 +133,9 @@ export const CodeEditor = ({
123
133
  // This happens every time `activeFileId` changes.
124
134
  editorCacheValue.scrollPosition =
125
135
  editorCacheValue.editor.scrollDOM.scrollTop;
126
- ref.current.removeChild(editorCacheValue.editor.dom);
136
+ codeEditorRef.current.removeChild(
137
+ editorCacheValue.editor.dom,
138
+ );
127
139
  };
128
140
  }, [shareDBDoc, editorCacheValue]);
129
141
 
@@ -142,8 +154,8 @@ export const CodeEditor = ({
142
154
  return (
143
155
  <div
144
156
  className="vz-code-editor"
145
- ref={ref}
157
+ ref={codeEditorRef}
146
158
  tabIndex={-1}
147
- ></div>
159
+ />
148
160
  );
149
161
  };
@@ -10,10 +10,10 @@ import { Username } from '../../types';
10
10
 
11
11
  const debug = false;
12
12
 
13
- // TODO: Make this a setting in the UI.
14
- // See https://github.com/vizhub-core/vzcode/issues/739
15
- const enableAutoFollow = false;
16
-
13
+ // export let enableAutoFollow = false;
14
+ // export const toggleAutoFollowButton = () => {
15
+ // enableAutoFollow = !enableAutoFollow;
16
+ // };
17
17
  // Deals with receiving the broadcasted presence cursor locations
18
18
  // from other clients and displaying them.
19
19
  //
@@ -25,6 +25,7 @@ const enableAutoFollow = false;
25
25
  export const json1PresenceDisplay = ({
26
26
  path,
27
27
  docPresence,
28
+ enableAutoFollowRef,
28
29
  }) => [
29
30
  ViewPlugin.fromClass(
30
31
  class {
@@ -146,7 +147,7 @@ export const json1PresenceDisplay = ({
146
147
 
147
148
  // Auto-follow all users when their presence is broadcast
148
149
  // by scrolling them into view.
149
- if (enableAutoFollow) {
150
+ if (enableAutoFollowRef.current) {
150
151
  this.scrollToCursor(view);
151
152
  }
152
153
  });
@@ -0,0 +1,16 @@
1
+ // https://reactsvgicons.com/
2
+ export const CssSVG = () => {
3
+ return (
4
+ <svg
5
+ width="24"
6
+ height="24"
7
+ xmlns="http://www.w3.org/2000/svg"
8
+ fill="currentColor"
9
+ viewBox="0 0 24 24"
10
+ strokeWidth="1.5"
11
+ stroke="none"
12
+ >
13
+ <path d="M4.192 3.143h15.615l-1.42 16.034-6.404 1.812-6.369-1.813L4.192 3.143zM16.9 6.424l-9.8-.002.158 1.949 7.529.002-.189 2.02H9.66l.179 1.913h4.597l-.272 2.62-2.164.598-2.197-.603-.141-1.569h-1.94l.216 2.867L12 17.484l3.995-1.137.905-9.923z" />
14
+ </svg>
15
+ );
16
+ };
@@ -0,0 +1,20 @@
1
+ // From Heroicons
2
+ export const FolderSVG = () => {
3
+ return (
4
+ <svg
5
+ width="24"
6
+ height="24"
7
+ xmlns="http://www.w3.org/2000/svg"
8
+ fill="none"
9
+ viewBox="0 0 24 24"
10
+ strokeWidth="1.5"
11
+ stroke="currentColor"
12
+ >
13
+ <path
14
+ strokeLinecap="round"
15
+ strokeLinejoin="round"
16
+ d="M2.25 12.75V12A2.25 2.25 0 0 1 4.5 9.75h15A2.25 2.25 0 0 1 21.75 12v.75m-8.69-6.44-2.12-2.12a1.5 1.5 0 0 0-1.061-.44H4.5A2.25 2.25 0 0 0 2.25 6v12a2.25 2.25 0 0 0 2.25 2.25h15A2.25 2.25 0 0 0 21.75 18V9a2.25 2.25 0 0 0-2.25-2.25h-5.379a1.5 1.5 0 0 1-1.06-.44Z"
17
+ />
18
+ </svg>
19
+ );
20
+ };
@@ -0,0 +1,16 @@
1
+ // https://reactsvgicons.com/
2
+ export const HtmlSVG = () => {
3
+ return (
4
+ <svg
5
+ width="24"
6
+ height="24"
7
+ xmlns="http://www.w3.org/2000/svg"
8
+ fill="currentColor"
9
+ viewBox="0 0 24 24"
10
+ strokeWidth="1.5"
11
+ stroke="none"
12
+ >
13
+ <path d="M4.136 3.012h15.729l-1.431 16.15-6.451 1.826-6.414-1.826-1.433-16.15zm5.266 7.302l-.173-2.035 7.533.002.173-1.963-9.87-.002.522 5.998h6.835l-.243 2.566-2.179.602-2.214-.605-.141-1.58H7.691l.247 3.123L12 17.506l4.028-1.08.558-6.111H9.402v-.001z" />
14
+ </svg>
15
+ );
16
+ };
@@ -0,0 +1,16 @@
1
+ // https://reactsvgicons.com/
2
+ export const JavaScriptSVG = () => {
3
+ return (
4
+ <svg
5
+ width="24"
6
+ height="24"
7
+ xmlns="http://www.w3.org/2000/svg"
8
+ fill="currentColor"
9
+ viewBox="0 0 24 24"
10
+ strokeWidth="1.5"
11
+ stroke="none"
12
+ >
13
+ <path d="M3 3h18v18H3V3zm16.525 13.707c-.131-.821-.666-1.511-2.252-2.155-.552-.259-1.165-.438-1.349-.854-.068-.248-.078-.382-.034-.529.113-.484.687-.629 1.137-.495.293.09.563.315.732.676.775-.507.775-.507 1.316-.844-.203-.314-.304-.451-.439-.586-.473-.528-1.103-.798-2.126-.775l-.528.067c-.507.124-.991.395-1.283.754-.855.968-.608 2.655.427 3.354 1.023.765 2.521.933 2.712 1.653.18.878-.652 1.159-1.475 1.058-.607-.136-.945-.439-1.316-1.002l-1.372.788c.157.359.337.517.607.832 1.305 1.316 4.568 1.249 5.153-.754.021-.067.18-.528.056-1.237l.034.049zm-6.737-5.434h-1.686c0 1.453-.007 2.898-.007 4.354 0 .924.047 1.772-.104 2.033-.247.517-.886.451-1.175.359-.297-.146-.448-.349-.623-.641-.047-.078-.082-.146-.095-.146l-1.368.844c.229.473.563.879.994 1.137.641.383 1.502.507 2.404.305.588-.17 1.095-.519 1.358-1.059.384-.697.302-1.553.299-2.509.008-1.541 0-3.083 0-4.635l.003-.042z" />
14
+ </svg>
15
+ );
16
+ };
@@ -0,0 +1,16 @@
1
+ // https://reactsvgicons.com/
2
+ export const JsonSVG = () => {
3
+ return (
4
+ <svg
5
+ width="24"
6
+ height="24"
7
+ xmlns="http://www.w3.org/2000/svg"
8
+ fill="currentColor"
9
+ viewBox="0 0 24 24"
10
+ strokeWidth="1.5"
11
+ stroke="none"
12
+ >
13
+ <path d="M5 3h2v2H5v5a2 2 0 01-2 2 2 2 0 012 2v5h2v2H5c-1.07-.27-2-.9-2-2v-4a2 2 0 00-2-2H0v-2h1a2 2 0 002-2V5a2 2 0 012-2m14 0a2 2 0 012 2v4a2 2 0 002 2h1v2h-1a2 2 0 00-2 2v4a2 2 0 01-2 2h-2v-2h2v-5a2 2 0 012-2 2 2 0 01-2-2V5h-2V3h2m-7 12a1 1 0 011 1 1 1 0 01-1 1 1 1 0 01-1-1 1 1 0 011-1m-4 0a1 1 0 011 1 1 1 0 01-1 1 1 1 0 01-1-1 1 1 0 011-1m8 0a1 1 0 011 1 1 1 0 01-1 1 1 1 0 01-1-1 1 1 0 011-1z" />
14
+ </svg>
15
+ );
16
+ };
@@ -0,0 +1,16 @@
1
+ // https://reactsvgicons.com/
2
+ export const MarkdownSVG = () => {
3
+ return (
4
+ <svg
5
+ width="24"
6
+ height="24"
7
+ xmlns="http://www.w3.org/2000/svg"
8
+ fill="currentColor"
9
+ viewBox="0 0 24 24"
10
+ strokeWidth="1.5"
11
+ stroke="none"
12
+ >
13
+ <path d="M20.56 18H3.44C2.65 18 2 17.37 2 16.59V7.41C2 6.63 2.65 6 3.44 6h17.12c.79 0 1.44.63 1.44 1.41v9.18c0 .78-.65 1.41-1.44 1.41M6.81 15.19v-3.66l1.92 2.35 1.92-2.35v3.66h1.93V8.81h-1.93l-1.92 2.35-1.92-2.35H4.89v6.38h1.92M19.69 12h-1.92V8.81h-1.92V12h-1.93l2.89 3.28L19.69 12z" />
14
+ </svg>
15
+ );
16
+ };
@@ -0,0 +1,14 @@
1
+ // From https://primer.style/foundations/icons/pin-24
2
+ export const PinSVG = () => (
3
+ <svg
4
+ xmlns="http://www.w3.org/2000/svg"
5
+ viewBox="0 0 24 24"
6
+ width="24"
7
+ height="24"
8
+ >
9
+ <path
10
+ fill="currentColor"
11
+ d="m16.114 1.553 6.333 6.333a1.75 1.75 0 0 1-.603 2.869l-1.63.633a5.67 5.67 0 0 0-3.395 3.725l-1.131 3.959a1.75 1.75 0 0 1-2.92.757L9 16.061l-5.595 5.594a.749.749 0 1 1-1.06-1.06L7.939 15l-3.768-3.768a1.75 1.75 0 0 1 .757-2.92l3.959-1.131a5.666 5.666 0 0 0 3.725-3.395l.633-1.63a1.75 1.75 0 0 1 2.869-.603ZM5.232 10.171l8.597 8.597a.25.25 0 0 0 .417-.108l1.131-3.959A7.17 7.17 0 0 1 19.67 9.99l1.63-.634a.25.25 0 0 0 .086-.409l-6.333-6.333a.25.25 0 0 0-.409.086l-.634 1.63a7.17 7.17 0 0 1-4.711 4.293L5.34 9.754a.25.25 0 0 0-.108.417Z"
12
+ ></path>
13
+ </svg>
14
+ );
@@ -0,0 +1,16 @@
1
+ // https://reactsvgicons.com/
2
+ export const ReactSVG = () => {
3
+ return (
4
+ <svg
5
+ width="24"
6
+ height="24"
7
+ xmlns="http://www.w3.org/2000/svg"
8
+ fill="currentColor"
9
+ viewBox="0 0 24 24"
10
+ strokeWidth="1.5"
11
+ stroke="none"
12
+ >
13
+ <path d="M14.23 12.004a2.236 2.236 0 01-2.235 2.236 2.236 2.236 0 01-2.236-2.236 2.236 2.236 0 012.235-2.236 2.236 2.236 0 012.236 2.236zm2.648-10.69c-1.346 0-3.107.96-4.888 2.622-1.78-1.653-3.542-2.602-4.887-2.602-.41 0-.783.093-1.106.278-1.375.793-1.683 3.264-.973 6.365C1.98 8.917 0 10.42 0 12.004c0 1.59 1.99 3.097 5.043 4.03-.704 3.113-.39 5.588.988 6.38.32.187.69.275 1.102.275 1.345 0 3.107-.96 4.888-2.624 1.78 1.654 3.542 2.603 4.887 2.603.41 0 .783-.09 1.106-.275 1.374-.792 1.683-3.263.973-6.365C22.02 15.096 24 13.59 24 12.004c0-1.59-1.99-3.097-5.043-4.032.704-3.11.39-5.587-.988-6.38a2.167 2.167 0 00-1.092-.278zm-.005 1.09v.006c.225 0 .406.044.558.127.666.382.955 1.835.73 3.704-.054.46-.142.945-.25 1.44a23.476 23.476 0 00-3.107-.534A23.892 23.892 0 0012.769 4.7c1.592-1.48 3.087-2.292 4.105-2.295zm-9.77.02c1.012 0 2.514.808 4.11 2.28-.686.72-1.37 1.537-2.02 2.442a22.73 22.73 0 00-3.113.538 15.02 15.02 0 01-.254-1.42c-.23-1.868.054-3.32.714-3.707.19-.09.4-.127.563-.132zm4.882 3.05c.455.468.91.992 1.36 1.564-.44-.02-.89-.034-1.345-.034-.46 0-.915.01-1.36.034.44-.572.895-1.096 1.345-1.565zM12 8.1c.74 0 1.477.034 2.202.093.406.582.802 1.203 1.183 1.86.372.64.71 1.29 1.018 1.946-.308.655-.646 1.31-1.013 1.95-.38.66-.773 1.288-1.18 1.87a25.64 25.64 0 01-4.412.005 26.64 26.64 0 01-1.183-1.86c-.372-.64-.71-1.29-1.018-1.946a25.17 25.17 0 011.013-1.954c.38-.66.773-1.286 1.18-1.868A25.245 25.245 0 0112 8.098zm-3.635.254c-.24.377-.48.763-.704 1.16-.225.39-.435.782-.635 1.174-.265-.656-.49-1.31-.676-1.947.64-.15 1.315-.283 2.015-.386zm7.26 0c.695.103 1.365.23 2.006.387-.18.632-.405 1.282-.66 1.933a25.952 25.952 0 00-1.345-2.32zm3.063.675c.484.15.944.317 1.375.498 1.732.74 2.852 1.708 2.852 2.476-.005.768-1.125 1.74-2.857 2.475-.42.18-.88.342-1.355.493a23.966 23.966 0 00-1.1-2.98c.45-1.017.81-2.01 1.085-2.964zm-13.395.004c.278.96.645 1.957 1.1 2.98a23.142 23.142 0 00-1.086 2.964c-.484-.15-.944-.318-1.37-.5-1.732-.737-2.852-1.706-2.852-2.474 0-.768 1.12-1.742 2.852-2.476.42-.18.88-.342 1.356-.494zm11.678 4.28c.265.657.49 1.312.676 1.948-.64.157-1.316.29-2.016.39a25.819 25.819 0 001.341-2.338zm-9.945.02c.2.392.41.783.64 1.175.23.39.465.772.705 1.143a22.005 22.005 0 01-2.006-.386c.18-.63.406-1.282.66-1.933zM17.92 16.32c.112.493.2.968.254 1.423.23 1.868-.054 3.32-.714 3.708-.147.09-.338.128-.563.128-1.012 0-2.514-.807-4.11-2.28.686-.72 1.37-1.536 2.02-2.44 1.107-.118 2.154-.3 3.113-.54zm-11.83.01c.96.234 2.006.415 3.107.532.66.905 1.345 1.727 2.035 2.446-1.595 1.483-3.092 2.295-4.11 2.295a1.185 1.185 0 01-.553-.132c-.666-.38-.955-1.834-.73-3.703.054-.46.142-.944.25-1.438zm4.56.64c.44.02.89.034 1.345.034.46 0 .915-.01 1.36-.034-.44.572-.895 1.095-1.345 1.565-.455-.47-.91-.993-1.36-1.565z" />
14
+ </svg>
15
+ );
16
+ };
@@ -0,0 +1,19 @@
1
+ export const SearchFileSVG = () => {
2
+ return (
3
+ <svg
4
+ xmlns="http://www.w3.org/2000/svg"
5
+ width="24"
6
+ height="24"
7
+ fill="none"
8
+ viewBox="0 0 24 24"
9
+ >
10
+ <path
11
+ stroke="currentColor"
12
+ strokeLinecap="round"
13
+ strokeLinejoin="round"
14
+ strokeWidth="1.5"
15
+ d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H8.25m0 12.75h7.5m-7.5 3H12M10.5 2.25H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z"
16
+ />
17
+ </svg>
18
+ );
19
+ };
@@ -0,0 +1,20 @@
1
+ // From Heroicons
2
+ export const SearchSVG = () => {
3
+ return (
4
+ <svg
5
+ width="24"
6
+ height="24"
7
+ xmlns="http://www.w3.org/2000/svg"
8
+ fill="none"
9
+ viewBox="0 0 24 24"
10
+ strokeWidth="1.5"
11
+ stroke="currentColor"
12
+ >
13
+ <path
14
+ strokeLinecap="round"
15
+ strokeLinejoin="round"
16
+ d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z"
17
+ />
18
+ </svg>
19
+ );
20
+ };
@@ -0,0 +1,16 @@
1
+ // https://reactsvgicons.com/
2
+ export const SvelteSVG = () => {
3
+ return (
4
+ <svg
5
+ width="24"
6
+ height="24"
7
+ xmlns="http://www.w3.org/2000/svg"
8
+ fill="currentColor"
9
+ viewBox="0 0 24 24"
10
+ strokeWidth="1.5"
11
+ stroke="none"
12
+ >
13
+ <path d="M10.354 21.125a4.44 4.44 0 01-4.765-1.767 4.109 4.109 0 01-.703-3.107 3.898 3.898 0 01.134-.522l.105-.321.287.21a7.21 7.21 0 002.186 1.092l.208.063-.02.208a1.253 1.253 0 00.226.83 1.337 1.337 0 001.435.533 1.231 1.231 0 00.343-.15l5.59-3.562a1.164 1.164 0 00.524-.778 1.242 1.242 0 00-.211-.937 1.338 1.338 0 00-1.435-.533 1.23 1.23 0 00-.343.15l-2.133 1.36a4.078 4.078 0 01-1.135.499 4.44 4.44 0 01-4.765-1.766 4.108 4.108 0 01-.702-3.108 3.855 3.855 0 011.742-2.582l5.589-3.563a4.072 4.072 0 011.135-.499 4.44 4.44 0 014.765 1.767 4.109 4.109 0 01.703 3.107 3.943 3.943 0 01-.134.522l-.105.321-.286-.21a7.204 7.204 0 00-2.187-1.093l-.208-.063.02-.207a1.255 1.255 0 00-.226-.831 1.337 1.337 0 00-1.435-.532 1.231 1.231 0 00-.343.15L8.62 9.368a1.162 1.162 0 00-.524.778 1.24 1.24 0 00.211.937 1.338 1.338 0 001.435.533 1.235 1.235 0 00.344-.151l2.132-1.36a4.067 4.067 0 011.135-.498 4.44 4.44 0 014.765 1.766 4.108 4.108 0 01.702 3.108 3.857 3.857 0 01-1.742 2.583l-5.589 3.562a4.072 4.072 0 01-1.135.499m10.358-17.95C18.484-.015 14.082-.96 10.9 1.068L5.31 4.63a6.412 6.412 0 00-2.896 4.295 6.753 6.753 0 00.666 4.336 6.43 6.43 0 00-.96 2.396 6.833 6.833 0 001.168 5.167c2.229 3.19 6.63 4.135 9.812 2.108l5.59-3.562a6.41 6.41 0 002.896-4.295 6.756 6.756 0 00-.665-4.336 6.429 6.429 0 00.958-2.396 6.831 6.831 0 00-1.167-5.168z" />
14
+ </svg>
15
+ );
16
+ };
@@ -0,0 +1,16 @@
1
+ // https://reactsvgicons.com/
2
+ export const TypeScriptSVG = () => {
3
+ return (
4
+ <svg
5
+ width="24"
6
+ height="24"
7
+ xmlns="http://www.w3.org/2000/svg"
8
+ fill="currentColor"
9
+ viewBox="0 0 24 24"
10
+ strokeWidth="1.5"
11
+ stroke="none"
12
+ >
13
+ <path d="M3 3h18v18H3V3m10.71 14.86c.5.98 1.51 1.73 3.09 1.73 1.6 0 2.8-.83 2.8-2.36 0-1.41-.81-2.04-2.25-2.66l-.42-.18c-.73-.31-1.04-.52-1.04-1.02 0-.41.31-.73.81-.73.48 0 .8.21 1.09.73l1.31-.87c-.55-.96-1.33-1.33-2.4-1.33-1.51 0-2.48.96-2.48 2.23 0 1.38.81 2.03 2.03 2.55l.42.18c.78.34 1.24.55 1.24 1.13 0 .48-.45.83-1.15.83-.83 0-1.31-.43-1.67-1.03l-1.38.8M13 11.25H8v1.5h1.5V20h1.75v-7.25H13v-1.5z" />
14
+ </svg>
15
+ );
16
+ };
@@ -10,3 +10,15 @@ export { FileSVG } from './FileSVG';
10
10
  export { DirectoryArrowSVG } from './DirectoryArrowSVG';
11
11
  export { PlaySVG } from './PlaySVG';
12
12
  export { QuestionMarkSVG } from './QuestionMarkSVG';
13
+ export { PinSVG } from './PinSVG';
14
+ export { FolderSVG } from './FolderSVG';
15
+ export { SearchSVG } from './SearchSVG';
16
+ export { SearchFileSVG } from './SearchFileSVG';
17
+ export { JavaScriptSVG } from './JavaScriptSVG';
18
+ export { TypeScriptSVG } from './TypeScriptSVG';
19
+ export { ReactSVG } from './ReactSVG';
20
+ export { SvelteSVG } from './SvelteSVG';
21
+ export { HtmlSVG } from './HtmlSVG';
22
+ export { CssSVG } from './CssSVG';
23
+ export { JsonSVG } from './JsonSVG';
24
+ export { MarkdownSVG } from './MarkdownSVG';
@@ -11,8 +11,8 @@
11
11
  font-weight: 500;
12
12
  align-items: center;
13
13
  display: flex;
14
- gap: 8px;
15
- padding: 6px 6px 6px 16px;
14
+ gap: 6px;
15
+ padding: 4px 4px 4px 14px;
16
16
  border-top-left-radius: 8px;
17
17
  border-top-right-radius: 8px;
18
18
  margin-top: 6px;
@@ -6,13 +6,14 @@ import {
6
6
  useRef,
7
7
  } from 'react';
8
8
  import {
9
- FileId,
10
9
  Files,
11
10
  ItemId,
12
11
  ShareDBDoc,
13
12
  SubmitOperation,
14
13
  Username,
15
14
  VZCodeContent,
15
+ SearchResults,
16
+ SearchFileVisibility,
16
17
  } from '../types';
17
18
  import { usePrettier } from './usePrettier';
18
19
  import { useTypeScript } from './useTypeScript';
@@ -112,6 +113,19 @@ export type VZCodeContextValue = {
112
113
 
113
114
  typeScriptWorker: Worker | null;
114
115
 
116
+ search: SearchResults;
117
+ isSearchOpen: boolean;
118
+ setIsSearchOpen: (isSearchOpen: boolean) => void;
119
+ setSearch: (pattern: string) => void;
120
+ setSearchResults: (
121
+ files: ShareDBDoc<VZCodeContent>,
122
+ ) => void;
123
+ setSearchFileVisibility: (
124
+ files: ShareDBDoc<VZCodeContent>,
125
+ id: string,
126
+ visibility: SearchFileVisibility,
127
+ ) => void;
128
+
115
129
  isCreateFileModalOpen: boolean;
116
130
  handleOpenCreateFileModal: () => void;
117
131
  handleCloseCreateFileModal: () => void;
@@ -135,6 +149,9 @@ export type VZCodeContextValue = {
135
149
 
136
150
  hoveredItemId: ItemId | null;
137
151
  setHoveredItemId: (itemId: ItemId | null) => void;
152
+
153
+ enableAutoFollow: boolean;
154
+ toggleAutoFollow: () => void;
138
155
  };
139
156
 
140
157
  export const VZCodeProvider = ({
@@ -216,10 +233,13 @@ export const VZCodeProvider = ({
216
233
  tabList,
217
234
  activeFileId,
218
235
  theme,
236
+ search,
237
+ isSearchOpen,
219
238
  isSettingsOpen,
220
239
  isDocOpen,
221
240
  editorWantsFocus,
222
241
  username,
242
+ enableAutoFollow,
223
243
  } = state;
224
244
 
225
245
  // Functions for dispatching actions to the reducer.
@@ -230,12 +250,17 @@ export const VZCodeProvider = ({
230
250
  openTab,
231
251
  closeTabs,
232
252
  setTheme,
253
+ setIsSearchOpen,
254
+ setSearch,
255
+ setSearchResults,
256
+ setSearchFileVisibility,
233
257
  setIsSettingsOpen,
234
258
  setIsDocOpen,
235
259
  closeSettings,
236
260
  closeDoc,
237
261
  editorNoLongerWantsFocus,
238
262
  setUsername,
263
+ toggleAutoFollow,
239
264
  } = useActions(dispatch);
240
265
 
241
266
  // Sync tab state to the URL.
@@ -359,6 +384,13 @@ export const VZCodeProvider = ({
359
384
  openTab,
360
385
  closeTabs,
361
386
 
387
+ search,
388
+ isSearchOpen,
389
+ setIsSearchOpen,
390
+ setSearch,
391
+ setSearchResults,
392
+ setSearchFileVisibility,
393
+
362
394
  isSettingsOpen,
363
395
  setIsSettingsOpen,
364
396
  closeSettings,
@@ -401,6 +433,9 @@ export const VZCodeProvider = ({
401
433
 
402
434
  hoveredItemId,
403
435
  setHoveredItemId,
436
+
437
+ enableAutoFollow,
438
+ toggleAutoFollow,
404
439
  };
405
440
 
406
441
  return (