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
@@ -7,20 +7,26 @@
7
7
  justify-content: space-between;
8
8
 
9
9
  .full-box {
10
- padding: 4px;
10
+ width: 100%;
11
+ height: 100%;
11
12
  display: flex;
12
13
  flex-direction: row;
13
- align-items: center;
14
- justify-content: space-between;
14
+ justify-content: start;
15
+ align-items: start;
15
16
  border-bottom: 2px solid var(--vh-color-neutral-02);
17
+ overflow: hidden;
16
18
  }
17
19
 
18
20
  .files {
19
- overflow: auto;
21
+ margin-top: 6px;
20
22
  display: flex;
21
- flex-direction: column;
23
+ flex-direction: row;
24
+ justify-content: start;
25
+ align-items: start;
22
26
  flex: 1;
23
27
  outline: none;
28
+ overflow: auto;
29
+ height: 100%;
24
30
  }
25
31
 
26
32
  .file-or-directory {
@@ -30,9 +36,9 @@
30
36
  align-items: center;
31
37
  justify-content: space-between;
32
38
  cursor: pointer;
33
- margin: 0 10px;
39
+ margin: 0 6px;
34
40
  padding: 0 4px 0 8px;
35
- border-radius: 4px;
41
+ border-radius: 8px;
36
42
  font-family: var(--vzcode-font-family);
37
43
  font-weight: 500;
38
44
  }
@@ -46,14 +52,100 @@
46
52
  }
47
53
 
48
54
  .sidebar-section-buttons {
55
+ border-right: 2px solid var(--vh-color-neutral-02);
56
+ height: 100%;
49
57
  display: flex;
50
- flex-direction: row;
58
+ flex-direction: column;
51
59
  align-items: center;
60
+ gap: 6px;
61
+ padding: 6px;
62
+
52
63
  a {
53
64
  color: inherit;
54
65
  }
55
66
  }
56
67
 
68
+ .sidebar-files,
69
+ .sidebar-search {
70
+ width: 100%;
71
+ }
72
+
73
+ .sidebar-search {
74
+ padding: 10px;
75
+
76
+ * {
77
+ color: inherit;
78
+ }
79
+ }
80
+
81
+ .search-result-lines {
82
+ margin-top: 10px;
83
+ margin-left: 20px;
84
+ }
85
+
86
+ .search-file-heading {
87
+ display: flex;
88
+ justify-content: space-between;
89
+ align-items: center;
90
+
91
+ * {
92
+ margin: 0px;
93
+ }
94
+ }
95
+
96
+ .search-file-title,
97
+ .search-file-name,
98
+ .search-file-info {
99
+ display: flex;
100
+ justify-content: center;
101
+ align-items: center;
102
+ gap: 10px;
103
+ }
104
+
105
+ .search-file-name {
106
+ font-size: inherit;
107
+ }
108
+
109
+ .search-file-count {
110
+ width: 18px;
111
+ height: 18px;
112
+ display: flex;
113
+ align-items: center;
114
+ justify-content: center;
115
+ margin: 0px;
116
+ font-size: 12px;
117
+ font-weight: bold;
118
+ text-align: center;
119
+ background: var(--vh-color-neutral-04);
120
+ color: var(--vh-color-neutral-01);
121
+ border-radius: 100%;
122
+ }
123
+
124
+ .search-results {
125
+ padding: 10px;
126
+ }
127
+
128
+ .search-file-lines {
129
+ font-size: inherit;
130
+ margin: 15px 0px 0px 30px;
131
+ }
132
+
133
+ .search-line,
134
+ .arrow-wrapper,
135
+ .search-file-close {
136
+ &:hover {
137
+ opacity: 0.7;
138
+ cursor: pointer;
139
+ }
140
+ }
141
+
142
+ .search-file-lines .search-pattern {
143
+ background: var(--vh-color-neutral-04);
144
+ color: var(--vh-color-neutral-01);
145
+ margin: 0.5px;
146
+ padding: 1px;
147
+ }
148
+
57
149
  .new-btn {
58
150
  justify-content: right;
59
151
  margin-right: 10px;
@@ -82,7 +174,7 @@
82
174
  align-items: center;
83
175
  white-space: nowrap;
84
176
  overflow: hidden;
85
- gap: 8px;
177
+ gap: 6px;
86
178
  .file-icon,
87
179
  .arrow-wrapper {
88
180
  opacity: 0.5;
@@ -1,6 +1,12 @@
1
1
  import { useCallback } from 'react';
2
2
  import { ThemeLabel } from './themes';
3
- import { FileId, Username } from '../types';
3
+ import {
4
+ FileId,
5
+ SearchFileVisibility,
6
+ ShareDBDoc,
7
+ Username,
8
+ VZCodeContent,
9
+ } from '../types';
4
10
  import { TabState, VZAction } from './vzReducer';
5
11
 
6
12
  // This is a custom hook that returns a set of functions
@@ -57,6 +63,56 @@ export const useActions = (
57
63
  [dispatch],
58
64
  );
59
65
 
66
+ // True to show the settings modal.
67
+ const setIsSearchOpen = useCallback(
68
+ (value: boolean) => {
69
+ dispatch({
70
+ type: 'set_is_search_open',
71
+ value: value,
72
+ });
73
+ },
74
+ [dispatch],
75
+ );
76
+
77
+ // Update search pattern
78
+ const setSearch = useCallback(
79
+ (pattern: string) => {
80
+ dispatch({
81
+ type: 'set_search',
82
+ value: pattern,
83
+ });
84
+ },
85
+ [dispatch],
86
+ );
87
+
88
+ // Update search results based on current pattern
89
+ const setSearchResults = useCallback(
90
+ (files: ShareDBDoc<VZCodeContent>) => {
91
+ dispatch({
92
+ type: 'set_search_results',
93
+ files: files,
94
+ });
95
+ },
96
+ [dispatch],
97
+ );
98
+
99
+ // Update search results file visibility based on current pattern
100
+ const setSearchFileVisibility = useCallback(
101
+ (
102
+ files: ShareDBDoc<VZCodeContent>,
103
+ id: string,
104
+ visibility: SearchFileVisibility,
105
+ ) => {
106
+ dispatch({
107
+ type: 'set_search_file_visibility',
108
+ files: files,
109
+ id: id,
110
+ visibility: visibility,
111
+ });
112
+ },
113
+ [dispatch],
114
+ );
115
+
60
116
  // True to show the settings modal.
61
117
  const setIsSettingsOpen = useCallback(
62
118
  (value: boolean) => {
@@ -102,6 +158,12 @@ export const useActions = (
102
158
  [dispatch],
103
159
  );
104
160
 
161
+ const toggleAutoFollow = useCallback(() => {
162
+ dispatch({
163
+ type: 'toggle_auto_follow',
164
+ });
165
+ }, [dispatch]);
166
+
105
167
  return {
106
168
  setActiveFileId,
107
169
  setActiveFileLeft,
@@ -109,11 +171,16 @@ export const useActions = (
109
171
  openTab,
110
172
  closeTabs,
111
173
  setTheme,
174
+ setIsSearchOpen,
175
+ setSearch,
176
+ setSearchResults,
177
+ setSearchFileVisibility,
112
178
  setIsSettingsOpen,
113
179
  setIsDocOpen,
114
180
  closeSettings,
115
181
  closeDoc,
116
182
  editorNoLongerWantsFocus,
117
183
  setUsername,
184
+ toggleAutoFollow,
118
185
  };
119
186
  };
@@ -1,4 +1,4 @@
1
- import { useCallback, useState } from 'react';
1
+ import { useCallback } from 'react';
2
2
  import {
3
3
  FileId,
4
4
  FileTreePath,
@@ -12,6 +12,8 @@ export const createInitialState = ({
12
12
  tabList: [],
13
13
  activeFileId: null,
14
14
  theme: defaultTheme,
15
+ search: { pattern: '', results: {} },
16
+ isSearchOpen: false,
15
17
  isSettingsOpen: false,
16
18
  isDocOpen: false,
17
19
  editorWantsFocus: false,
@@ -1,4 +1,11 @@
1
- import { FileId, Username } from '../../types';
1
+ import {
2
+ FileId,
3
+ SearchFileVisibility,
4
+ SearchResults,
5
+ ShareDBDoc,
6
+ Username,
7
+ VZCodeContent,
8
+ } from '../../types';
2
9
  import { ThemeLabel } from '../themes';
3
10
  import { closeTabsReducer } from './closeTabsReducer';
4
11
  import { openTabReducer } from './openTabReducer';
@@ -12,7 +19,13 @@ import { setIsDocOpenReducer } from './setIsDocOpenReducer';
12
19
  import { setThemeReducer } from './setThemeReducer';
13
20
  import { editorNoLongerWantsFocusReducer } from './editorNoLongerWantsFocusReducer';
14
21
  import { setUsernameReducer } from './setUsernameReducer';
15
-
22
+ import {
23
+ setIsSearchOpenReducer,
24
+ setSearchReducer,
25
+ setSearchResultsReducer,
26
+ setSearchFileVisibilityReducer,
27
+ } from './searchReducer';
28
+ import { toggleAutoFollowReducer } from './toggleAutoFollowReducer';
16
29
  export { createInitialState } from './createInitialState';
17
30
 
18
31
  // The shape of the state managed by the reducer.
@@ -27,6 +40,12 @@ export type VZState = {
27
40
  // The theme that is currently active.
28
41
  theme: ThemeLabel;
29
42
 
43
+ // Search pattern and most recent results based on the current pattern
44
+ search: SearchResults;
45
+
46
+ // True to show the search instead of files
47
+ isSearchOpen: boolean;
48
+
30
49
  // True to show the settings modal.
31
50
  isSettingsOpen: boolean;
32
51
 
@@ -37,6 +56,11 @@ export type VZState = {
37
56
 
38
57
  // The username of the current user.
39
58
  username: Username;
59
+
60
+ // True if "auto-follow" is enabled.
61
+ // This is a feature that automatically scrolls the editor to the
62
+ // currently active remote user's cursor position.
63
+ enableAutoFollow: boolean;
40
64
  };
41
65
 
42
66
  // The shape of the actions that can be dispatched to the reducer.
@@ -73,13 +97,41 @@ export type VZAction =
73
97
  | { type: 'set_is_settings_open'; value: boolean }
74
98
  | { type: 'set_is_doc_open'; value: boolean }
75
99
 
100
+ // `set_is_search_open`
101
+ // * Sets whether the search tab is open.
102
+ | { type: 'set_is_search_open'; value: boolean }
103
+
104
+ // `set_search`
105
+ // * Sets the current search pattern
106
+ | { type: 'set_search'; value: string }
107
+
108
+ // `set_search_results`
109
+ // * Sets the current search pattern
110
+ | {
111
+ type: 'set_search_results';
112
+ files: ShareDBDoc<VZCodeContent>;
113
+ }
114
+
115
+ // `set_search_results_visibility`
116
+ // * Sets the visibility of a current search pattern file
117
+ | {
118
+ type: 'set_search_file_visibility';
119
+ files: ShareDBDoc<VZCodeContent>;
120
+ id: string;
121
+ visibility: SearchFileVisibility;
122
+ }
123
+
76
124
  // `editor_no_longer_wants_focus`
77
125
  // * Sets `editorWantsFocus` to `false`.
78
126
  | { type: 'editor_no_longer_wants_focus' }
79
127
 
80
128
  // `set_username`
81
129
  // * Sets the username.
82
- | { type: 'set_username'; username: Username };
130
+ | { type: 'set_username'; username: Username }
131
+
132
+ // `toggle_auto_follow
133
+ // * Toggles the auto-follow feature.
134
+ | { type: 'toggle_auto_follow' };
83
135
 
84
136
  // Representation of an open tab.
85
137
  export type TabState = {
@@ -107,10 +159,15 @@ const reducers = [
107
159
  openTabReducer,
108
160
  closeTabsReducer,
109
161
  setThemeReducer,
162
+ setSearchReducer,
163
+ setSearchResultsReducer,
164
+ setSearchFileVisibilityReducer,
165
+ setIsSearchOpenReducer,
110
166
  setIsSettingsOpenReducer,
111
167
  setIsDocOpenReducer,
112
168
  editorNoLongerWantsFocusReducer,
113
169
  setUsernameReducer,
170
+ toggleAutoFollowReducer,
114
171
  ];
115
172
 
116
173
  export const vzReducer = (
@@ -0,0 +1,114 @@
1
+ import { VZAction, VZState } from '.';
2
+ import {
3
+ SearchFile,
4
+ SearchFileVisibility,
5
+ SearchResult,
6
+ ShareDBDoc,
7
+ VZCodeContent,
8
+ } from '../../types';
9
+
10
+ function searchPattern(
11
+ shareDBDoc: ShareDBDoc<VZCodeContent>,
12
+ pattern: string,
13
+ ): SearchResult {
14
+ const files = shareDBDoc.data.files;
15
+ const fileIds = Object.keys(shareDBDoc.data.files);
16
+ let results: { [id: string]: SearchFile } = {};
17
+
18
+ for (let i = 0; i < fileIds.length; i++) {
19
+ const file = files[fileIds[i]];
20
+
21
+ if (files[fileIds[i]].text) {
22
+ const fileName = file.name;
23
+ const lines = file.text.split('\n');
24
+ const matches = [];
25
+
26
+ for (let j = 0; j < lines.length; j++) {
27
+ const index = lines[j].indexOf(pattern);
28
+
29
+ if (index !== -1) {
30
+ matches.push({
31
+ line: j + 1,
32
+ index: index,
33
+ text: lines[j],
34
+ });
35
+ }
36
+ }
37
+
38
+ if (matches.length > 0) {
39
+ results[fileIds[i]] = {
40
+ name: fileName,
41
+ matches: matches,
42
+ visibility: 'open',
43
+ };
44
+ }
45
+ }
46
+ }
47
+
48
+ return results;
49
+ }
50
+
51
+ function updateSearchFileVisibility(
52
+ results: SearchResult,
53
+ id: string,
54
+ visibility: SearchFileVisibility,
55
+ ): SearchResult {
56
+ return {
57
+ ...results,
58
+ [id]: { ...results[id], visibility: visibility },
59
+ };
60
+ }
61
+
62
+ export const setIsSearchOpenReducer = (
63
+ state: VZState,
64
+ action: VZAction,
65
+ ): VZState =>
66
+ action.type === 'set_is_search_open'
67
+ ? { ...state, isSearchOpen: action.value }
68
+ : state;
69
+
70
+ export const setSearchReducer = (
71
+ state: VZState,
72
+ action: VZAction,
73
+ ): VZState =>
74
+ action.type === 'set_search'
75
+ ? {
76
+ ...state,
77
+ search: { pattern: action.value, results: {} },
78
+ }
79
+ : state;
80
+
81
+ export const setSearchResultsReducer = (
82
+ state: VZState,
83
+ action: VZAction,
84
+ ): VZState =>
85
+ action.type === 'set_search_results'
86
+ ? {
87
+ ...state,
88
+ search: {
89
+ pattern: state.search.pattern,
90
+ results: searchPattern(
91
+ action.files,
92
+ state.search.pattern,
93
+ ),
94
+ },
95
+ }
96
+ : state;
97
+
98
+ export const setSearchFileVisibilityReducer = (
99
+ state: VZState,
100
+ action: VZAction,
101
+ ): VZState =>
102
+ action.type === 'set_search_file_visibility'
103
+ ? {
104
+ ...state,
105
+ search: {
106
+ pattern: state.search.pattern,
107
+ results: updateSearchFileVisibility(
108
+ state.search.results,
109
+ action.id,
110
+ action.visibility,
111
+ ),
112
+ },
113
+ }
114
+ : state;
@@ -0,0 +1,12 @@
1
+ import { VZAction, VZState } from '.';
2
+
3
+ export const toggleAutoFollowReducer = (
4
+ state: VZState,
5
+ action: VZAction,
6
+ ): VZState =>
7
+ action.type === 'toggle_auto_follow'
8
+ ? {
9
+ ...state,
10
+ enableAutoFollow: !state.enableAutoFollow,
11
+ }
12
+ : state;
package/src/types.ts CHANGED
@@ -61,6 +61,26 @@ export interface FileTreeFile {
61
61
  file: File;
62
62
  fileId: FileId;
63
63
  }
64
+ export type SearchMatch = Array<{
65
+ line: number;
66
+ index: number;
67
+ text: string;
68
+ }>;
69
+ export type SearchFileVisibility =
70
+ | 'open'
71
+ | 'flattened'
72
+ | 'closed';
73
+ export type SearchResult = { [id: string]: SearchFile };
74
+
75
+ export interface SearchFile {
76
+ name: string;
77
+ matches: SearchMatch;
78
+ visibility: SearchFileVisibility;
79
+ }
80
+ export interface SearchResults {
81
+ pattern: string;
82
+ results: SearchResult;
83
+ }
64
84
 
65
85
  export type JSONOp = any;
66
86