vzcode 1.14.0 → 1.15.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-DGNI0PAo.js → index-DbFdL1A1.js} +55 -53
- package/dist/assets/{index-Wxh-Jaj6.css → index-Yz-ZHc0O.css} +1 -1
- package/dist/index.html +2 -2
- package/package.json +1 -1
- package/src/client/CodeEditor/index.tsx +1 -1
- package/src/client/VZCodeContext.tsx +14 -0
- package/src/client/VZSidebar/FileListing.tsx +20 -56
- package/src/client/VZSidebar/FileTypeIcon.tsx +49 -0
- package/src/client/VZSidebar/Item.tsx +5 -9
- package/src/client/VZSidebar/Search.tsx +412 -108
- package/src/client/VZSidebar/index.tsx +1 -1
- package/src/client/VZSidebar/styles.scss +36 -21
- package/src/client/useActions.ts +31 -0
- package/src/client/useKeyboardShortcuts.ts +13 -3
- package/src/client/vzReducer/createInitialState.ts +7 -1
- package/src/client/vzReducer/index.ts +21 -0
- package/src/client/vzReducer/openTabReducer.ts +4 -3
- package/src/client/vzReducer/searchReducer.ts +46 -1
- package/src/types.ts +2 -0
|
@@ -3,13 +3,15 @@ import {
|
|
|
3
3
|
useEffect,
|
|
4
4
|
useContext,
|
|
5
5
|
useState,
|
|
6
|
+
useCallback,
|
|
6
7
|
} from 'react';
|
|
7
8
|
import { Form } from '../bootstrap';
|
|
8
9
|
import { VZCodeContext } from '../VZCodeContext';
|
|
9
|
-
import { SearchFile } from '../../types';
|
|
10
|
+
import { FileId, SearchFile } from '../../types';
|
|
10
11
|
import { EditorView } from 'codemirror';
|
|
11
|
-
import { getExtensionIcon } from './FileListing';
|
|
12
12
|
import { CloseSVG, DirectoryArrowSVG } from '../Icons';
|
|
13
|
+
import { FileTypeIcon } from './FileTypeIcon';
|
|
14
|
+
import { editorCacheKey } from '../useEditorCache';
|
|
13
15
|
|
|
14
16
|
function jumpToPattern(
|
|
15
17
|
editor: EditorView,
|
|
@@ -32,21 +34,47 @@ function jumpToPattern(
|
|
|
32
34
|
});
|
|
33
35
|
}
|
|
34
36
|
|
|
37
|
+
function isResultElementWithinView(container, element) {
|
|
38
|
+
const containerTop = container.scrollTop;
|
|
39
|
+
const containerBottom =
|
|
40
|
+
containerTop + container.clientHeight;
|
|
41
|
+
|
|
42
|
+
const elementTop =
|
|
43
|
+
element.offsetTop - container.offsetTop;
|
|
44
|
+
const elementBottom = elementTop + element.clientHeight;
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
elementTop >= containerTop + 100 &&
|
|
48
|
+
elementBottom <= containerBottom - 100
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
35
52
|
export const Search = () => {
|
|
36
|
-
const inputRef = useRef(null);
|
|
37
53
|
const [isMounted, setIsMounted] = useState(false);
|
|
38
54
|
const [isSearching, setIsSearching] = useState(false);
|
|
39
55
|
const {
|
|
40
56
|
search,
|
|
41
57
|
setSearch,
|
|
58
|
+
activePaneId,
|
|
42
59
|
setActiveFileId,
|
|
43
|
-
openTab,
|
|
44
60
|
setSearchResults,
|
|
45
61
|
setSearchFileVisibility,
|
|
62
|
+
setSearchLineVisibility,
|
|
63
|
+
setSearchFocusedIndex,
|
|
46
64
|
shareDBDoc,
|
|
47
65
|
editorCache,
|
|
48
66
|
} = useContext(VZCodeContext);
|
|
49
|
-
const {
|
|
67
|
+
const {
|
|
68
|
+
pattern,
|
|
69
|
+
results,
|
|
70
|
+
focusedIndex,
|
|
71
|
+
focusedChildIndex,
|
|
72
|
+
focused,
|
|
73
|
+
} = search;
|
|
74
|
+
const inputRef = useRef(null);
|
|
75
|
+
const files: [string, SearchFile][] = Object.entries(
|
|
76
|
+
results,
|
|
77
|
+
).filter(([_, file]) => file.visibility !== 'closed');
|
|
50
78
|
|
|
51
79
|
useEffect(() => {
|
|
52
80
|
if (isMounted) {
|
|
@@ -70,7 +98,199 @@ export const Search = () => {
|
|
|
70
98
|
}
|
|
71
99
|
}, [pattern]);
|
|
72
100
|
|
|
101
|
+
const flattenResult = useCallback(
|
|
102
|
+
(fileId: string, file: SearchFile) => {
|
|
103
|
+
setSearchFileVisibility(
|
|
104
|
+
shareDBDoc,
|
|
105
|
+
fileId,
|
|
106
|
+
file.visibility === 'open' &&
|
|
107
|
+
focusedChildIndex === null
|
|
108
|
+
? 'flattened'
|
|
109
|
+
: 'open',
|
|
110
|
+
);
|
|
111
|
+
},
|
|
112
|
+
[focusedIndex, focusedChildIndex],
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
const closeResult = useCallback((fileId: FileId) => {
|
|
116
|
+
setSearchFileVisibility(shareDBDoc, fileId, 'closed');
|
|
117
|
+
}, []);
|
|
118
|
+
|
|
119
|
+
const focusFileElement = useCallback(
|
|
120
|
+
(fileId: FileId, index: number) => {
|
|
121
|
+
setActiveFileId(fileId);
|
|
122
|
+
setSearchFocusedIndex(index, null);
|
|
123
|
+
},
|
|
124
|
+
[],
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
const handleKeyDown = (event) => {
|
|
128
|
+
event.preventDefault();
|
|
129
|
+
|
|
130
|
+
if (files.length === 0) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const matchingLines: number =
|
|
135
|
+
files[focusedIndex][1].matches.length;
|
|
136
|
+
|
|
137
|
+
switch (event.key) {
|
|
138
|
+
case 'Tab':
|
|
139
|
+
// Focus the file heading
|
|
140
|
+
setSearchFocusedIndex(focusedIndex, null);
|
|
141
|
+
break;
|
|
142
|
+
case 'ArrowUp':
|
|
143
|
+
if (
|
|
144
|
+
focusedIndex == 0 &&
|
|
145
|
+
focusedChildIndex == null
|
|
146
|
+
) {
|
|
147
|
+
// No effect on first search listing
|
|
148
|
+
break;
|
|
149
|
+
} else if (
|
|
150
|
+
focusedChildIndex === null ||
|
|
151
|
+
matchingLines == 0
|
|
152
|
+
) {
|
|
153
|
+
// Toggle the previous file last child, if any
|
|
154
|
+
const previousMatchingLines: number =
|
|
155
|
+
files[focusedIndex - 1][1].matches.length;
|
|
156
|
+
setSearchFocusedIndex(
|
|
157
|
+
focusedIndex - 1,
|
|
158
|
+
previousMatchingLines > 0
|
|
159
|
+
? previousMatchingLines - 1
|
|
160
|
+
: null,
|
|
161
|
+
);
|
|
162
|
+
} else if (focusedChildIndex === 0) {
|
|
163
|
+
// Toggle the file
|
|
164
|
+
setSearchFocusedIndex(focusedIndex, null);
|
|
165
|
+
} else {
|
|
166
|
+
// Toggle the previous matching line
|
|
167
|
+
setSearchFocusedIndex(
|
|
168
|
+
focusedIndex,
|
|
169
|
+
focusedChildIndex - 1,
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
break;
|
|
174
|
+
case 'ArrowDown':
|
|
175
|
+
if (
|
|
176
|
+
focusedIndex == files.length - 1 &&
|
|
177
|
+
focusedChildIndex == matchingLines - 1
|
|
178
|
+
) {
|
|
179
|
+
// Last matching line should have no effect
|
|
180
|
+
break;
|
|
181
|
+
} else if (
|
|
182
|
+
focusedChildIndex === null &&
|
|
183
|
+
matchingLines > 0
|
|
184
|
+
) {
|
|
185
|
+
// Toggle the first matching line
|
|
186
|
+
setSearchFocusedIndex(focusedIndex, 0);
|
|
187
|
+
} else if (
|
|
188
|
+
focusedChildIndex == matchingLines - 1 ||
|
|
189
|
+
matchingLines == 0
|
|
190
|
+
) {
|
|
191
|
+
// Toggle the next file
|
|
192
|
+
setSearchFocusedIndex(focusedIndex + 1, null);
|
|
193
|
+
} else {
|
|
194
|
+
// Toggle the next matching line
|
|
195
|
+
setSearchFocusedIndex(
|
|
196
|
+
focusedIndex,
|
|
197
|
+
focusedChildIndex + 1,
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
break;
|
|
202
|
+
case 'ArrowLeft':
|
|
203
|
+
if (focusedChildIndex !== null) {
|
|
204
|
+
setSearchFocusedIndex(focusedIndex, null);
|
|
205
|
+
} else {
|
|
206
|
+
flattenResult(
|
|
207
|
+
files[focusedIndex][0],
|
|
208
|
+
files[focusedIndex][1],
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
break;
|
|
212
|
+
case 'ArrowRight':
|
|
213
|
+
if (files[focusedIndex][1].visibility !== 'open') {
|
|
214
|
+
flattenResult(
|
|
215
|
+
files[focusedIndex][0],
|
|
216
|
+
files[focusedIndex][1],
|
|
217
|
+
);
|
|
218
|
+
} else if (
|
|
219
|
+
focusedChildIndex === null &&
|
|
220
|
+
matchingLines !== 0
|
|
221
|
+
) {
|
|
222
|
+
setSearchFocusedIndex(focusedIndex, 0);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
break;
|
|
226
|
+
case 'Enter':
|
|
227
|
+
case ' ':
|
|
228
|
+
const fileId: string = files[focusedIndex][0];
|
|
229
|
+
setActiveFileId(fileId);
|
|
230
|
+
|
|
231
|
+
if (focusedChildIndex !== null) {
|
|
232
|
+
// Jump to matching line
|
|
233
|
+
const line: number =
|
|
234
|
+
files[focusedIndex][1].matches[
|
|
235
|
+
focusedChildIndex
|
|
236
|
+
].line;
|
|
237
|
+
const index: number =
|
|
238
|
+
files[focusedIndex][1].matches[
|
|
239
|
+
focusedChildIndex
|
|
240
|
+
].index;
|
|
241
|
+
|
|
242
|
+
const cacheKey = editorCacheKey(
|
|
243
|
+
fileId,
|
|
244
|
+
activePaneId,
|
|
245
|
+
);
|
|
246
|
+
if (editorCache.has(cacheKey)) {
|
|
247
|
+
jumpToPattern(
|
|
248
|
+
editorCache.get(cacheKey).editor,
|
|
249
|
+
pattern,
|
|
250
|
+
line,
|
|
251
|
+
index,
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
break;
|
|
256
|
+
default:
|
|
257
|
+
break;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Ensure keyboard navigation keeps results within the current view
|
|
261
|
+
const file: string = files[focusedIndex][0];
|
|
262
|
+
const container = document.getElementById(
|
|
263
|
+
'sidebar-view-container',
|
|
264
|
+
);
|
|
265
|
+
|
|
266
|
+
if (container) {
|
|
267
|
+
if (focusedChildIndex === null) {
|
|
268
|
+
const fileElement = document.getElementById(file);
|
|
269
|
+
|
|
270
|
+
if (
|
|
271
|
+
!isResultElementWithinView(container, fileElement)
|
|
272
|
+
) {
|
|
273
|
+
fileElement.scrollIntoView({ block: 'center' });
|
|
274
|
+
}
|
|
275
|
+
} else {
|
|
276
|
+
const line =
|
|
277
|
+
files[focusedIndex][1].matches[focusedChildIndex]
|
|
278
|
+
.line;
|
|
279
|
+
const lineElement = document.getElementById(
|
|
280
|
+
file + '-' + line,
|
|
281
|
+
);
|
|
282
|
+
|
|
283
|
+
if (
|
|
284
|
+
!isResultElementWithinView(container, lineElement)
|
|
285
|
+
) {
|
|
286
|
+
lineElement.scrollIntoView({ block: 'center' });
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
|
|
73
292
|
useEffect(() => {
|
|
293
|
+
// Focus the search input on mount and keyboard shortcut invocation
|
|
74
294
|
if (inputRef.current) {
|
|
75
295
|
inputRef.current.focus();
|
|
76
296
|
}
|
|
@@ -85,122 +305,206 @@ export const Search = () => {
|
|
|
85
305
|
<Form.Control
|
|
86
306
|
type="text"
|
|
87
307
|
value={pattern}
|
|
88
|
-
onChange={(
|
|
308
|
+
onChange={(event) =>
|
|
309
|
+
setSearch(event.target.value)
|
|
310
|
+
}
|
|
89
311
|
ref={inputRef}
|
|
90
312
|
spellCheck="false"
|
|
91
313
|
/>
|
|
92
314
|
</Form.Group>
|
|
93
315
|
{Object.keys(results).length >= 1 &&
|
|
94
316
|
pattern.trim().length >= 1 ? (
|
|
95
|
-
<div
|
|
96
|
-
{
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
317
|
+
<div
|
|
318
|
+
onKeyDown={handleKeyDown}
|
|
319
|
+
tabIndex={0}
|
|
320
|
+
className="search-results"
|
|
321
|
+
>
|
|
322
|
+
{files.map(
|
|
323
|
+
(
|
|
324
|
+
[fileId, file]: [string, SearchFile],
|
|
325
|
+
index,
|
|
326
|
+
) => {
|
|
327
|
+
const matches = file.matches;
|
|
328
|
+
return (
|
|
329
|
+
<div
|
|
330
|
+
className="search-result"
|
|
331
|
+
key={file.name}
|
|
332
|
+
>
|
|
333
|
+
<div
|
|
334
|
+
onClick={() =>
|
|
335
|
+
focusFileElement(fileId, index)
|
|
336
|
+
}
|
|
337
|
+
id={fileId}
|
|
338
|
+
className={`search-file-heading
|
|
339
|
+
${
|
|
340
|
+
focusedIndex == index &&
|
|
341
|
+
focusedChildIndex == null
|
|
342
|
+
? 'active'
|
|
343
|
+
: ''
|
|
344
|
+
}`}
|
|
345
|
+
>
|
|
346
|
+
<div className="search-file-title">
|
|
347
|
+
<div
|
|
348
|
+
className="arrow-wrapper"
|
|
349
|
+
onClick={() =>
|
|
350
|
+
flattenResult(fileId, file)
|
|
351
|
+
}
|
|
352
|
+
style={{
|
|
353
|
+
transform: `rotate(${file.visibility === 'open' ? 90 : 0}deg)`,
|
|
354
|
+
}}
|
|
355
|
+
>
|
|
356
|
+
<DirectoryArrowSVG />
|
|
357
|
+
</div>
|
|
358
|
+
<div className="search-file-name">
|
|
359
|
+
<FileTypeIcon name={file.name} />
|
|
360
|
+
<h5>{file.name}</h5>
|
|
361
|
+
</div>
|
|
123
362
|
</div>
|
|
124
|
-
<div className="search-file-
|
|
125
|
-
{
|
|
126
|
-
|
|
363
|
+
<div className="search-file-info">
|
|
364
|
+
{index == focusedIndex &&
|
|
365
|
+
focusedChildIndex == null ? (
|
|
366
|
+
<span
|
|
367
|
+
className="search-file-close"
|
|
368
|
+
onClick={(event) => {
|
|
369
|
+
event.stopPropagation();
|
|
370
|
+
closeResult(fileId);
|
|
371
|
+
// Focus the previous search file, if possible
|
|
372
|
+
setSearchFocusedIndex(
|
|
373
|
+
Math.max(0, index - 1),
|
|
374
|
+
null,
|
|
375
|
+
);
|
|
376
|
+
}}
|
|
377
|
+
>
|
|
378
|
+
<CloseSVG />
|
|
379
|
+
</span>
|
|
380
|
+
) : (
|
|
381
|
+
<h6 className="search-file-count">
|
|
382
|
+
{matches.length}
|
|
383
|
+
</h6>
|
|
384
|
+
)}
|
|
127
385
|
</div>
|
|
128
386
|
</div>
|
|
129
|
-
<div className="search-file-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
387
|
+
<div className="search-file-lines">
|
|
388
|
+
{(file.visibility === 'open' ||
|
|
389
|
+
(file.visibility === 'flattened' &&
|
|
390
|
+
index == focusedIndex &&
|
|
391
|
+
focusedChildIndex !== null)) &&
|
|
392
|
+
file.matches.map(
|
|
393
|
+
(match, childIndex) => {
|
|
394
|
+
const before =
|
|
395
|
+
match.text.substring(
|
|
396
|
+
0,
|
|
397
|
+
match.index,
|
|
398
|
+
);
|
|
399
|
+
const hit = match.text.substring(
|
|
400
|
+
match.index,
|
|
401
|
+
match.index + pattern.length,
|
|
402
|
+
);
|
|
403
|
+
const after =
|
|
404
|
+
match.text.substring(
|
|
405
|
+
match.index + pattern.length,
|
|
406
|
+
);
|
|
407
|
+
|
|
408
|
+
const identifier =
|
|
409
|
+
file.name + '-' + match.line;
|
|
410
|
+
|
|
411
|
+
return (
|
|
412
|
+
<div
|
|
413
|
+
key={identifier}
|
|
414
|
+
tabIndex={
|
|
415
|
+
index == focusedIndex
|
|
416
|
+
? 0
|
|
417
|
+
: -1
|
|
418
|
+
}
|
|
419
|
+
id={fileId + '-' + match.line}
|
|
420
|
+
className={`search-line
|
|
421
|
+
${
|
|
422
|
+
focusedIndex == index &&
|
|
423
|
+
focusedChildIndex ==
|
|
424
|
+
childIndex
|
|
425
|
+
? 'active'
|
|
426
|
+
: ''
|
|
427
|
+
}`}
|
|
428
|
+
>
|
|
429
|
+
<p
|
|
430
|
+
key={
|
|
431
|
+
file.name +
|
|
432
|
+
' - ' +
|
|
433
|
+
match.line +
|
|
434
|
+
' - ' +
|
|
435
|
+
match.index
|
|
436
|
+
}
|
|
437
|
+
onClick={() => {
|
|
438
|
+
setSearchFocusedIndex(
|
|
439
|
+
index,
|
|
440
|
+
childIndex,
|
|
441
|
+
);
|
|
442
|
+
|
|
443
|
+
const cacheKey =
|
|
444
|
+
editorCacheKey(
|
|
445
|
+
fileId,
|
|
446
|
+
activePaneId,
|
|
447
|
+
);
|
|
448
|
+
|
|
449
|
+
if (
|
|
450
|
+
editorCache.has(
|
|
451
|
+
cacheKey,
|
|
452
|
+
)
|
|
453
|
+
) {
|
|
454
|
+
jumpToPattern(
|
|
455
|
+
editorCache.get(
|
|
456
|
+
cacheKey,
|
|
457
|
+
).editor,
|
|
458
|
+
pattern,
|
|
459
|
+
match.line,
|
|
460
|
+
match.index,
|
|
461
|
+
);
|
|
462
|
+
}
|
|
463
|
+
}}
|
|
464
|
+
>
|
|
465
|
+
{before}
|
|
466
|
+
<span className="search-pattern">
|
|
467
|
+
{hit}
|
|
468
|
+
</span>
|
|
469
|
+
{after}
|
|
470
|
+
</p>
|
|
471
|
+
{focusedIndex == index &&
|
|
472
|
+
focusedChildIndex ===
|
|
473
|
+
childIndex && (
|
|
474
|
+
<span
|
|
475
|
+
className="search-file-close"
|
|
476
|
+
onClick={(event) => {
|
|
477
|
+
event.stopPropagation();
|
|
478
|
+
setSearchLineVisibility(
|
|
479
|
+
shareDBDoc,
|
|
480
|
+
fileId,
|
|
481
|
+
match.line,
|
|
482
|
+
);
|
|
483
|
+
|
|
484
|
+
if (childIndex == 0) {
|
|
485
|
+
// Removing remaining single line
|
|
486
|
+
setSearchFocusedIndex(
|
|
487
|
+
index,
|
|
488
|
+
null,
|
|
489
|
+
);
|
|
490
|
+
}
|
|
491
|
+
}}
|
|
492
|
+
>
|
|
493
|
+
<CloseSVG />
|
|
494
|
+
</span>
|
|
495
|
+
)}
|
|
496
|
+
</div>
|
|
497
|
+
);
|
|
498
|
+
},
|
|
499
|
+
)}
|
|
145
500
|
</div>
|
|
146
501
|
</div>
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
const before = match.text.substring(
|
|
151
|
-
0,
|
|
152
|
-
match.index,
|
|
153
|
-
);
|
|
154
|
-
const hit = match.text.substring(
|
|
155
|
-
match.index,
|
|
156
|
-
match.index + pattern.length,
|
|
157
|
-
);
|
|
158
|
-
const after = match.text.substring(
|
|
159
|
-
match.index + pattern.length,
|
|
160
|
-
);
|
|
161
|
-
|
|
162
|
-
return (
|
|
163
|
-
<p
|
|
164
|
-
className="search-line"
|
|
165
|
-
key={
|
|
166
|
-
file.name +
|
|
167
|
-
' - ' +
|
|
168
|
-
match.line +
|
|
169
|
-
' - ' +
|
|
170
|
-
match.index
|
|
171
|
-
}
|
|
172
|
-
onClick={() => {
|
|
173
|
-
setActiveFileId(fileId);
|
|
174
|
-
openTab({
|
|
175
|
-
fileId: fileId,
|
|
176
|
-
isTransient: false,
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
if (editorCache.get(fileId)) {
|
|
180
|
-
jumpToPattern(
|
|
181
|
-
editorCache.get(fileId)
|
|
182
|
-
.editor,
|
|
183
|
-
pattern,
|
|
184
|
-
match.line,
|
|
185
|
-
match.index,
|
|
186
|
-
);
|
|
187
|
-
}
|
|
188
|
-
}}
|
|
189
|
-
>
|
|
190
|
-
{before}
|
|
191
|
-
<span className="search-pattern">
|
|
192
|
-
{hit}
|
|
193
|
-
</span>
|
|
194
|
-
{after}
|
|
195
|
-
</p>
|
|
196
|
-
);
|
|
197
|
-
})}
|
|
198
|
-
</div>
|
|
199
|
-
</div>
|
|
200
|
-
))}
|
|
502
|
+
);
|
|
503
|
+
},
|
|
504
|
+
)}
|
|
201
505
|
</div>
|
|
202
506
|
) : (
|
|
203
|
-
<div className="search-
|
|
507
|
+
<div className="search-state">
|
|
204
508
|
<h6>
|
|
205
509
|
{isSearching ? 'Searching...' : 'No Results'}
|
|
206
510
|
</h6>
|
|
@@ -71,22 +71,25 @@
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
.sidebar-search {
|
|
74
|
-
padding: 10px;
|
|
75
|
-
|
|
76
74
|
* {
|
|
77
75
|
color: inherit;
|
|
78
76
|
}
|
|
79
77
|
}
|
|
80
78
|
|
|
81
|
-
.search-
|
|
82
|
-
|
|
83
|
-
|
|
79
|
+
.sidebar-search .arrow-wrapper {
|
|
80
|
+
cursor: pointer;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.sidebar-search-form {
|
|
84
|
+
padding: 10px;
|
|
84
85
|
}
|
|
85
86
|
|
|
86
87
|
.search-file-heading {
|
|
87
88
|
display: flex;
|
|
88
89
|
justify-content: space-between;
|
|
89
90
|
align-items: center;
|
|
91
|
+
padding: 10px;
|
|
92
|
+
cursor: pointer;
|
|
90
93
|
|
|
91
94
|
* {
|
|
92
95
|
margin: 0px;
|
|
@@ -121,22 +124,32 @@
|
|
|
121
124
|
border-radius: 100%;
|
|
122
125
|
}
|
|
123
126
|
|
|
124
|
-
.search-
|
|
125
|
-
|
|
127
|
+
.search-state {
|
|
128
|
+
margin: 10px;
|
|
126
129
|
}
|
|
127
130
|
|
|
128
|
-
.search-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
+
.search-results .active {
|
|
132
|
+
border: 1px solid var(--vh-color-neutral-04);
|
|
133
|
+
background-color: var(--vh-color-neutral-02);
|
|
134
|
+
cursor: pointer;
|
|
131
135
|
}
|
|
132
136
|
|
|
133
|
-
.search-line
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
137
|
+
.search-line {
|
|
138
|
+
display: flex;
|
|
139
|
+
justify-content: space-between;
|
|
140
|
+
align-items: center;
|
|
141
|
+
padding-right: 10px;
|
|
142
|
+
cursor: pointer;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.search-line p {
|
|
146
|
+
padding-left: 30px;
|
|
147
|
+
margin: 10px 0px;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.search-file-lines {
|
|
151
|
+
font-size: inherit;
|
|
152
|
+
margin-top: 10px;
|
|
140
153
|
}
|
|
141
154
|
|
|
142
155
|
.search-file-lines .search-pattern {
|
|
@@ -259,22 +272,24 @@
|
|
|
259
272
|
white-space: nowrap;
|
|
260
273
|
overflow: hidden;
|
|
261
274
|
gap: 6px;
|
|
275
|
+
position: relative;
|
|
262
276
|
}
|
|
263
277
|
|
|
264
278
|
.presence-indicators {
|
|
279
|
+
position: absolute;
|
|
280
|
+
top: 0;
|
|
265
281
|
display: flex;
|
|
266
282
|
gap: 4px;
|
|
267
|
-
margin-right: 6px; /* Space between the indicators and the file name */
|
|
268
283
|
}
|
|
269
284
|
|
|
270
285
|
.presence-indicator {
|
|
271
|
-
width:
|
|
272
|
-
height:
|
|
286
|
+
width: 10px;
|
|
287
|
+
height: 10px;
|
|
273
288
|
border-radius: 50%;
|
|
274
289
|
display: flex;
|
|
275
290
|
align-items: center;
|
|
276
291
|
justify-content: center;
|
|
277
|
-
font-size:
|
|
292
|
+
font-size: 8px;
|
|
278
293
|
background-color: #ff5733;
|
|
279
294
|
color: #ffffff;
|
|
280
295
|
}
|