gloomberb 0.7.0 → 0.7.2
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/package.json +1 -1
- package/src/app.tsx +149 -51
- package/src/capabilities/factories.ts +3 -0
- package/src/components/chart/chart-renderer.ts +24 -12
- package/src/components/chart/chart.test.ts +43 -0
- package/src/components/chart/comparison-chart-renderer.test.ts +26 -0
- package/src/components/chart/comparison-chart-renderer.ts +13 -6
- package/src/components/chart/comparison-stock-chart.tsx +15 -12
- package/src/components/chart/price-axis-labels.tsx +114 -0
- package/src/components/chart/static-chart-surface.tsx +2 -0
- package/src/components/chart/stock-chart.tsx +31 -20
- package/src/components/chart/time-axis-label.tsx +78 -1
- package/src/components/command-bar/__snapshots__/command-bar.test.tsx.snap +0 -28
- package/src/components/command-bar/command-bar.test.tsx +114 -31
- package/src/components/command-bar/command-bar.tsx +587 -335
- package/src/components/command-bar/command-registry.ts +0 -10
- package/src/components/command-bar/helpers.ts +2 -5
- package/src/components/command-bar/list-model.ts +1 -2
- package/src/components/command-bar/theme-picker.tsx +254 -0
- package/src/components/command-bar/view-model.test.ts +4 -4
- package/src/components/command-bar/view-model.ts +1 -1
- package/src/components/command-bar/workflow-types.ts +1 -2
- package/src/components/layout/detached-pane-shell.tsx +29 -10
- package/src/components/layout/floating-pane.tsx +5 -2
- package/src/components/layout/header.tsx +2 -0
- package/src/components/layout/pane-content.test.tsx +64 -0
- package/src/components/layout/pane-content.tsx +2 -0
- package/src/components/layout/pane-sizing.ts +9 -2
- package/src/components/layout/pane-title.ts +4 -1
- package/src/components/layout/pane.tsx +11 -5
- package/src/components/layout/shell.test.tsx +198 -0
- package/src/components/layout/shell.tsx +33 -2
- package/src/components/layout/status-bar.tsx +2 -0
- package/src/components/speedometer-gauge.tsx +29 -25
- package/src/components/table-view-shared.tsx +85 -3
- package/src/components/ticker-list-table-view.tsx +16 -2
- package/src/components/ticker-list-table.test.tsx +82 -1
- package/src/components/ticker-list-table.tsx +22 -9
- package/src/components/ui/data-table.tsx +12 -9
- package/src/components/ui/frame.tsx +2 -0
- package/src/components/ui/table-layout.test.ts +27 -1
- package/src/components/ui/table-layout.ts +39 -1
- package/src/components/ui/tabs.tsx +34 -1
- package/src/components/ui/ui.test.tsx +68 -1
- package/src/core/state/app-state.ts +4 -14
- package/src/market-data/coordinator.test.ts +75 -0
- package/src/market-data/coordinator.ts +218 -48
- package/src/news/aggregator.test.ts +49 -1
- package/src/news/aggregator.ts +48 -0
- package/src/news/hooks.ts +6 -2
- package/src/plugins/builtin/ai/screener-pane.tsx +3 -2
- package/src/plugins/builtin/analytics/index.tsx +1 -18
- package/src/plugins/builtin/chat-controller.test.ts +83 -1
- package/src/plugins/builtin/chat-controller.ts +491 -243
- package/src/plugins/builtin/chat.test.tsx +425 -7
- package/src/plugins/builtin/chat.tsx +1109 -211
- package/src/plugins/builtin/cloud-tweets.tsx +1 -0
- package/src/plugins/builtin/fear-greed/index.tsx +148 -39
- package/src/plugins/builtin/holders/index.test.ts +13 -1
- package/src/plugins/builtin/holders/index.tsx +54 -14
- package/src/plugins/builtin/market-movers/index.tsx +12 -18
- package/src/plugins/builtin/market-movers/screener.test.ts +39 -1
- package/src/plugins/builtin/market-movers/screener.ts +70 -17
- package/src/plugins/builtin/news-wire/breaking-pane.tsx +3 -2
- package/src/plugins/builtin/news-wire/industry-pane.tsx +4 -18
- package/src/plugins/builtin/news-wire/news-detail-view.tsx +46 -4
- package/src/plugins/builtin/news-wire/news-preset-pane.tsx +3 -2
- package/src/plugins/builtin/notes.tsx +1 -0
- package/src/plugins/builtin/options.tsx +2 -16
- package/src/plugins/builtin/portfolio-list/pane.tsx +16 -39
- package/src/plugins/builtin/research/index.test.ts +94 -0
- package/src/plugins/builtin/research/index.tsx +159 -12
- package/src/plugins/builtin/ticker-detail/pane.tsx +28 -22
- package/src/plugins/builtin/ticker-detail.test.tsx +38 -0
- package/src/plugins/plugin-runtime.test.tsx +34 -0
- package/src/plugins/plugin-runtime.tsx +7 -2
- package/src/plugins/prediction-markets/controller.ts +0 -15
- package/src/plugins/prediction-markets/detail/pane.tsx +1 -0
- package/src/plugins/registry.ts +3 -3
- package/src/plugins/ticker-navigation.test.ts +66 -0
- package/src/plugins/ticker-navigation.ts +44 -0
- package/src/react/input.ts +1 -1
- package/src/renderers/electrobun/bun/index.ts +32 -11
- package/src/renderers/electrobun/bun/window-focus.ts +37 -0
- package/src/renderers/electrobun/shared/protocol.ts +7 -1
- package/src/renderers/electrobun/view/app-services.ts +88 -31
- package/src/renderers/electrobun/view/backend-rpc.ts +15 -0
- package/src/renderers/electrobun/view/data-table.tsx +111 -96
- package/src/renderers/electrobun/view/desktop-controls.tsx +8 -0
- package/src/renderers/electrobun/view/desktop-window-bridge.ts +12 -1
- package/src/renderers/electrobun/view/dialog-host.tsx +2 -0
- package/src/renderers/electrobun/view/input-host.tsx +1 -1
- package/src/renderers/electrobun/view/main.tsx +18 -1
- package/src/renderers/electrobun/view/styles.css +6 -8
- package/src/renderers/electrobun/view/toast-host.tsx +29 -3
- package/src/renderers/electrobun/view/ui-host.tsx +101 -5
- package/src/renderers/opentui/input-host.tsx +1 -1
- package/src/sources/gloomberb-cloud.test.ts +86 -1
- package/src/sources/gloomberb-cloud.ts +117 -21
- package/src/sources/provider-router.test.ts +122 -0
- package/src/sources/provider-router.ts +198 -11
- package/src/sources/yahoo-finance.test.ts +44 -0
- package/src/sources/yahoo-finance.ts +6 -0
- package/src/state/app-bootstrap.ts +20 -7
- package/src/state/app-context-selector.test.tsx +189 -4
- package/src/state/app-context.test.ts +20 -0
- package/src/state/app-context.tsx +48 -16
- package/src/state/use-inline-tickers.ts +13 -10
- package/src/theme/colors.test.ts +75 -0
- package/src/theme/colors.ts +64 -3
- package/src/theme/theme-context.tsx +26 -0
- package/src/types/capability-route-source.ts +1 -0
- package/src/types/data-provider.ts +15 -1
- package/src/types/desktop-window.ts +6 -0
- package/src/types/financials.ts +2 -0
- package/src/types/plugin.ts +1 -1
- package/src/ui/host.tsx +14 -2
- package/src/ui/index.tsx +1 -0
- package/src/utils/api-client.test.ts +32 -0
- package/src/utils/api-client.ts +119 -18
- package/src/utils/double-escape-close.test.ts +33 -0
- package/src/utils/double-escape-close.ts +40 -0
- package/src/utils/throttled-fetch.test.ts +22 -0
- package/src/utils/throttled-fetch.ts +3 -1
- package/src/utils/ticker-search.ts +53 -9
- package/src/version.ts +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Box, Input, ScrollBox, Text, Textarea, useUiCapabilities } from "../../ui";
|
|
2
|
-
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
2
|
+
import { memo, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
3
3
|
import type { RefObject } from "react";
|
|
4
4
|
import { TextAttributes, type InputRenderable, type ScrollBoxRenderable, type TextareaRenderable } from "../../ui";
|
|
5
5
|
import { useNativeRenderer } from "../../ui";
|
|
@@ -8,7 +8,8 @@ import { Button, NumberField, Spinner, TextField } from "../ui";
|
|
|
8
8
|
import { NativeSelect, openNativeSelect, type NativeSelectElement } from "../ui/native-select";
|
|
9
9
|
import { ToggleList } from "../toggle-list";
|
|
10
10
|
import {
|
|
11
|
-
|
|
11
|
+
applyTheme,
|
|
12
|
+
clearTransientThemePreview,
|
|
12
13
|
commandBarBg,
|
|
13
14
|
commandBarHeadingText,
|
|
14
15
|
commandBarHoverBg,
|
|
@@ -18,9 +19,10 @@ import {
|
|
|
18
19
|
commandBarSelectedText,
|
|
19
20
|
commandBarSubtleText,
|
|
20
21
|
commandBarText,
|
|
22
|
+
getCurrentThemeId,
|
|
23
|
+
previewTheme,
|
|
21
24
|
} from "../../theme/colors";
|
|
22
25
|
import {
|
|
23
|
-
getEffectiveThemeId,
|
|
24
26
|
getFocusedCollectionId,
|
|
25
27
|
useAppDispatch,
|
|
26
28
|
useAppSelector,
|
|
@@ -28,8 +30,9 @@ import {
|
|
|
28
30
|
type AppState,
|
|
29
31
|
} from "../../state/app-context";
|
|
30
32
|
import { fuzzyFilter } from "../../utils/fuzzy-search";
|
|
31
|
-
import { commands,
|
|
32
|
-
import {
|
|
33
|
+
import { commands, matchPrefix, type Command } from "./command-registry";
|
|
34
|
+
import { useThemeColors } from "../../theme/theme-context";
|
|
35
|
+
import { ThemePicker, type ThemePickerHandle } from "./theme-picker";
|
|
33
36
|
import { exportConfig, importConfig, resetAllData, saveConfig } from "../../data/config-store";
|
|
34
37
|
import type { DataProvider } from "../../types/data-provider";
|
|
35
38
|
import type { TickerRepository } from "../../data/ticker-repository";
|
|
@@ -180,6 +183,7 @@ const COMMAND_BAR_OVERLAY_Z_INDEX = 2_147_483_646;
|
|
|
180
183
|
const COMMAND_BAR_PANEL_Z_INDEX = 2_147_483_647;
|
|
181
184
|
const NATIVE_COMMAND_BAR_PADDING_X_PX = 14;
|
|
182
185
|
const NATIVE_COMMAND_BAR_PADDING_Y_PX = 14;
|
|
186
|
+
const QUICK_LOOK_TICKER_SEARCH_OPTIONS = { includeOptionContracts: false } as const;
|
|
183
187
|
|
|
184
188
|
function getDefaultConfigBackupPath(): string {
|
|
185
189
|
const home = typeof process !== "undefined" ? process.env.HOME : undefined;
|
|
@@ -297,6 +301,309 @@ function getVisibleMultiSelectPickerOptions(
|
|
|
297
301
|
});
|
|
298
302
|
}
|
|
299
303
|
|
|
304
|
+
type CommandBarListScrollEvent = {
|
|
305
|
+
stopPropagation: () => void;
|
|
306
|
+
preventDefault: () => void;
|
|
307
|
+
scroll?: { direction?: string; delta?: number };
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
interface CommandBarListHeaderProps {
|
|
311
|
+
kind: ListScreenState["kind"];
|
|
312
|
+
query: string;
|
|
313
|
+
queryDisplayWidth: number;
|
|
314
|
+
nativePaneChrome: boolean;
|
|
315
|
+
inputBg: string;
|
|
316
|
+
paletteBg: string;
|
|
317
|
+
paletteText: string;
|
|
318
|
+
paletteSubtleText: string;
|
|
319
|
+
cursorColor: string;
|
|
320
|
+
contentPadding: number;
|
|
321
|
+
rootGhostSuffix: string | null;
|
|
322
|
+
rootQueryLength: number;
|
|
323
|
+
rootShortcutFeedback: string | null;
|
|
324
|
+
onQueryChange: (query: string) => void;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
const CommandBarListHeader = memo(function CommandBarListHeader({
|
|
328
|
+
kind,
|
|
329
|
+
query,
|
|
330
|
+
queryDisplayWidth,
|
|
331
|
+
nativePaneChrome,
|
|
332
|
+
inputBg,
|
|
333
|
+
paletteBg,
|
|
334
|
+
paletteText,
|
|
335
|
+
paletteSubtleText,
|
|
336
|
+
cursorColor,
|
|
337
|
+
contentPadding,
|
|
338
|
+
rootGhostSuffix,
|
|
339
|
+
rootQueryLength,
|
|
340
|
+
rootShortcutFeedback,
|
|
341
|
+
onQueryChange,
|
|
342
|
+
}: CommandBarListHeaderProps) {
|
|
343
|
+
return (
|
|
344
|
+
<>
|
|
345
|
+
<Box height={1} paddingX={contentPadding}>
|
|
346
|
+
<Box
|
|
347
|
+
width={queryDisplayWidth}
|
|
348
|
+
height={1}
|
|
349
|
+
position="relative"
|
|
350
|
+
backgroundColor={nativePaneChrome ? undefined : inputBg}
|
|
351
|
+
style={nativePaneChrome ? undefined : {
|
|
352
|
+
overflow: "hidden",
|
|
353
|
+
}}
|
|
354
|
+
>
|
|
355
|
+
<Input
|
|
356
|
+
value={query}
|
|
357
|
+
onInput={onQueryChange}
|
|
358
|
+
onChange={onQueryChange}
|
|
359
|
+
placeholder={kind === "root" ? "Search" : "Filter"}
|
|
360
|
+
focused
|
|
361
|
+
width={nativePaneChrome ? "100%" : queryDisplayWidth}
|
|
362
|
+
backgroundColor={nativePaneChrome ? "transparent" : paletteBg}
|
|
363
|
+
focusedBackgroundColor={nativePaneChrome ? "transparent" : paletteBg}
|
|
364
|
+
textColor={paletteText}
|
|
365
|
+
focusedTextColor={paletteText}
|
|
366
|
+
placeholderColor={paletteSubtleText}
|
|
367
|
+
cursorColor={cursorColor}
|
|
368
|
+
/>
|
|
369
|
+
{kind === "root" && rootGhostSuffix && (
|
|
370
|
+
<Box
|
|
371
|
+
position="absolute"
|
|
372
|
+
top={0}
|
|
373
|
+
left={Math.max(0, Math.min(rootQueryLength, queryDisplayWidth - 1))}
|
|
374
|
+
width={Math.max(0, queryDisplayWidth - Math.min(rootQueryLength, queryDisplayWidth - 1))}
|
|
375
|
+
height={1}
|
|
376
|
+
>
|
|
377
|
+
<Text fg={paletteSubtleText}>
|
|
378
|
+
{truncateText(
|
|
379
|
+
rootGhostSuffix,
|
|
380
|
+
Math.max(0, queryDisplayWidth - Math.min(rootQueryLength, queryDisplayWidth - 1)),
|
|
381
|
+
)}
|
|
382
|
+
</Text>
|
|
383
|
+
</Box>
|
|
384
|
+
)}
|
|
385
|
+
</Box>
|
|
386
|
+
</Box>
|
|
387
|
+
<Box height={1} paddingX={contentPadding}>
|
|
388
|
+
{kind === "root" && rootShortcutFeedback
|
|
389
|
+
? (
|
|
390
|
+
<Text fg={paletteSubtleText}>
|
|
391
|
+
{truncateText(rootShortcutFeedback, queryDisplayWidth)}
|
|
392
|
+
</Text>
|
|
393
|
+
)
|
|
394
|
+
: null}
|
|
395
|
+
</Box>
|
|
396
|
+
</>
|
|
397
|
+
);
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
interface CommandBarListItemRowProps {
|
|
401
|
+
item: ResultItem;
|
|
402
|
+
globalIdx: number;
|
|
403
|
+
isSelected: boolean;
|
|
404
|
+
isHovered: boolean;
|
|
405
|
+
contentPadding: number;
|
|
406
|
+
labelWidth: number;
|
|
407
|
+
trailingWidth: number;
|
|
408
|
+
nativePaneChrome: boolean;
|
|
409
|
+
paletteBg: string;
|
|
410
|
+
paletteHoverBg: string;
|
|
411
|
+
paletteSelectedBg: string;
|
|
412
|
+
paletteSelectedText: string;
|
|
413
|
+
paletteSubtleText: string;
|
|
414
|
+
paletteText: string;
|
|
415
|
+
panelBg: string;
|
|
416
|
+
onHoverIndex: (index: number | null) => void;
|
|
417
|
+
onListScroll: (event: CommandBarListScrollEvent) => void;
|
|
418
|
+
onRowMouseDown: (event: any, item: ResultItem, globalIdx: number) => void;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
const CommandBarListItemRow = memo(function CommandBarListItemRow({
|
|
422
|
+
item,
|
|
423
|
+
globalIdx,
|
|
424
|
+
isSelected,
|
|
425
|
+
isHovered,
|
|
426
|
+
contentPadding,
|
|
427
|
+
labelWidth,
|
|
428
|
+
trailingWidth,
|
|
429
|
+
nativePaneChrome,
|
|
430
|
+
paletteBg,
|
|
431
|
+
paletteHoverBg,
|
|
432
|
+
paletteSelectedBg,
|
|
433
|
+
paletteSelectedText,
|
|
434
|
+
paletteSubtleText,
|
|
435
|
+
paletteText,
|
|
436
|
+
panelBg,
|
|
437
|
+
onHoverIndex,
|
|
438
|
+
onListScroll,
|
|
439
|
+
onRowMouseDown,
|
|
440
|
+
}: CommandBarListItemRowProps) {
|
|
441
|
+
const presentation = getRowPresentation(item, isSelected, trailingWidth > 0);
|
|
442
|
+
const label = truncateText(presentation.label, labelWidth);
|
|
443
|
+
const trailing = truncateText(presentation.trailing, trailingWidth);
|
|
444
|
+
|
|
445
|
+
return (
|
|
446
|
+
<Box
|
|
447
|
+
key={item.id}
|
|
448
|
+
flexDirection="row"
|
|
449
|
+
height={1}
|
|
450
|
+
paddingX={contentPadding}
|
|
451
|
+
backgroundColor={isSelected
|
|
452
|
+
? paletteSelectedBg
|
|
453
|
+
: isHovered
|
|
454
|
+
? paletteHoverBg
|
|
455
|
+
: (nativePaneChrome ? panelBg : paletteBg)}
|
|
456
|
+
onMouseMove={() => onHoverIndex(globalIdx)}
|
|
457
|
+
onMouseOut={() => onHoverIndex(null)}
|
|
458
|
+
{...(!nativePaneChrome ? { onMouseScroll: onListScroll } : {})}
|
|
459
|
+
onMouseDown={(event: any) => onRowMouseDown(event, item, globalIdx)}
|
|
460
|
+
data-command-bar-row-selected={nativePaneChrome && isSelected ? "true" : undefined}
|
|
461
|
+
style={nativePaneChrome ? { borderRadius: 6 } : undefined}
|
|
462
|
+
>
|
|
463
|
+
<Box width={labelWidth}>
|
|
464
|
+
<Text fg={isSelected ? paletteSelectedText : presentation.primaryMuted ? paletteSubtleText : paletteText}>
|
|
465
|
+
{label}
|
|
466
|
+
</Text>
|
|
467
|
+
</Box>
|
|
468
|
+
<Box width={trailingWidth}>
|
|
469
|
+
<Text fg={isSelected ? paletteSelectedText : paletteSubtleText}>{trailing}</Text>
|
|
470
|
+
</Box>
|
|
471
|
+
</Box>
|
|
472
|
+
);
|
|
473
|
+
});
|
|
474
|
+
|
|
475
|
+
interface CommandBarListBodyProps {
|
|
476
|
+
visibleListState: ListScreenState;
|
|
477
|
+
nativeListRows: CommandBarListRow[];
|
|
478
|
+
listBodyHeight: number;
|
|
479
|
+
contentPadding: number;
|
|
480
|
+
labelWidth: number;
|
|
481
|
+
nativePaneChrome: boolean;
|
|
482
|
+
nativeListScrollRef: RefObject<ScrollBoxRenderable | null>;
|
|
483
|
+
paletteBg: string;
|
|
484
|
+
paletteHeadingText: string;
|
|
485
|
+
paletteHoverBg: string;
|
|
486
|
+
paletteSelectedBg: string;
|
|
487
|
+
paletteSelectedText: string;
|
|
488
|
+
paletteSubtleText: string;
|
|
489
|
+
paletteText: string;
|
|
490
|
+
panelBg: string;
|
|
491
|
+
queryDisplayWidth: number;
|
|
492
|
+
trailingWidth: number;
|
|
493
|
+
onHoverIndex: (index: number | null) => void;
|
|
494
|
+
onListScroll: (event: CommandBarListScrollEvent) => void;
|
|
495
|
+
onRowMouseDown: (event: any, item: ResultItem, globalIdx: number) => void;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
const CommandBarListBody = memo(function CommandBarListBody({
|
|
499
|
+
visibleListState,
|
|
500
|
+
nativeListRows,
|
|
501
|
+
listBodyHeight,
|
|
502
|
+
contentPadding,
|
|
503
|
+
labelWidth,
|
|
504
|
+
nativePaneChrome,
|
|
505
|
+
nativeListScrollRef,
|
|
506
|
+
paletteBg,
|
|
507
|
+
paletteHeadingText,
|
|
508
|
+
paletteHoverBg,
|
|
509
|
+
paletteSelectedBg,
|
|
510
|
+
paletteSelectedText,
|
|
511
|
+
paletteSubtleText,
|
|
512
|
+
paletteText,
|
|
513
|
+
panelBg,
|
|
514
|
+
queryDisplayWidth,
|
|
515
|
+
trailingWidth,
|
|
516
|
+
onHoverIndex,
|
|
517
|
+
onListScroll,
|
|
518
|
+
onRowMouseDown,
|
|
519
|
+
}: CommandBarListBodyProps) {
|
|
520
|
+
const visibleRows = useMemo(() => {
|
|
521
|
+
const rows = nativeListRows;
|
|
522
|
+
if (nativePaneChrome) return rows;
|
|
523
|
+
const paddedRows = [...rows];
|
|
524
|
+
while (paddedRows.length < listBodyHeight) {
|
|
525
|
+
paddedRows.push({ kind: "filler", id: `filler:${paddedRows.length}` });
|
|
526
|
+
}
|
|
527
|
+
return paddedRows;
|
|
528
|
+
}, [
|
|
529
|
+
listBodyHeight,
|
|
530
|
+
nativeListRows,
|
|
531
|
+
nativePaneChrome,
|
|
532
|
+
]);
|
|
533
|
+
|
|
534
|
+
const renderedRows = (
|
|
535
|
+
<>
|
|
536
|
+
{visibleRows.map((row) => {
|
|
537
|
+
if (row.kind === "filler" || row.kind === "spacer") {
|
|
538
|
+
return <Box key={row.id} height={1} />;
|
|
539
|
+
}
|
|
540
|
+
if (row.kind === "spinner") {
|
|
541
|
+
return (
|
|
542
|
+
<Box key={row.id} height={1} paddingX={contentPadding} {...(!nativePaneChrome ? { onMouseScroll: onListScroll } : {})}>
|
|
543
|
+
<Spinner label={row.label} />
|
|
544
|
+
</Box>
|
|
545
|
+
);
|
|
546
|
+
}
|
|
547
|
+
if (row.kind === "message") {
|
|
548
|
+
return (
|
|
549
|
+
<Box key={row.id} height={1} paddingX={contentPadding} {...(!nativePaneChrome ? { onMouseScroll: onListScroll } : {})}>
|
|
550
|
+
<Text fg={paletteText}>{truncateText(row.label, queryDisplayWidth)}</Text>
|
|
551
|
+
</Box>
|
|
552
|
+
);
|
|
553
|
+
}
|
|
554
|
+
if (row.kind === "heading") {
|
|
555
|
+
return (
|
|
556
|
+
<Box key={row.id} height={1} paddingX={contentPadding} {...(!nativePaneChrome ? { onMouseScroll: onListScroll } : {})}>
|
|
557
|
+
<Text attributes={TextAttributes.BOLD} fg={paletteHeadingText}>
|
|
558
|
+
{truncateText(row.label, queryDisplayWidth)}
|
|
559
|
+
</Text>
|
|
560
|
+
</Box>
|
|
561
|
+
);
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
const isSelected = row.globalIdx === visibleListState.selectedIdx;
|
|
565
|
+
const isHovered = row.globalIdx === visibleListState.hoveredIdx && !isSelected;
|
|
566
|
+
return (
|
|
567
|
+
<CommandBarListItemRow
|
|
568
|
+
key={row.item.id}
|
|
569
|
+
item={row.item}
|
|
570
|
+
globalIdx={row.globalIdx}
|
|
571
|
+
isSelected={isSelected}
|
|
572
|
+
isHovered={isHovered}
|
|
573
|
+
contentPadding={contentPadding}
|
|
574
|
+
labelWidth={labelWidth}
|
|
575
|
+
trailingWidth={trailingWidth}
|
|
576
|
+
nativePaneChrome={nativePaneChrome}
|
|
577
|
+
paletteBg={paletteBg}
|
|
578
|
+
paletteHoverBg={paletteHoverBg}
|
|
579
|
+
paletteSelectedBg={paletteSelectedBg}
|
|
580
|
+
paletteSelectedText={paletteSelectedText}
|
|
581
|
+
paletteSubtleText={paletteSubtleText}
|
|
582
|
+
paletteText={paletteText}
|
|
583
|
+
panelBg={panelBg}
|
|
584
|
+
onHoverIndex={onHoverIndex}
|
|
585
|
+
onListScroll={onListScroll}
|
|
586
|
+
onRowMouseDown={onRowMouseDown}
|
|
587
|
+
/>
|
|
588
|
+
);
|
|
589
|
+
})}
|
|
590
|
+
</>
|
|
591
|
+
);
|
|
592
|
+
|
|
593
|
+
return (
|
|
594
|
+
<ScrollBox
|
|
595
|
+
ref={nativeListScrollRef}
|
|
596
|
+
flexDirection="column"
|
|
597
|
+
height={listBodyHeight}
|
|
598
|
+
scrollY
|
|
599
|
+
focusable={false}
|
|
600
|
+
{...(!nativePaneChrome ? { onMouseScroll: onListScroll } : {})}
|
|
601
|
+
>
|
|
602
|
+
{renderedRows}
|
|
603
|
+
</ScrollBox>
|
|
604
|
+
);
|
|
605
|
+
});
|
|
606
|
+
|
|
300
607
|
export function CommandBar({
|
|
301
608
|
dataProvider,
|
|
302
609
|
tickerRepository,
|
|
@@ -305,6 +612,7 @@ export function CommandBar({
|
|
|
305
612
|
onCheckForUpdates,
|
|
306
613
|
}: CommandBarProps) {
|
|
307
614
|
const dispatch = useAppDispatch();
|
|
615
|
+
const themeColors = useThemeColors();
|
|
308
616
|
const config = useAppSelector((state) => state.config);
|
|
309
617
|
const paneState = useAppSelector((state) => state.paneState);
|
|
310
618
|
const tickers = useAppSelector((state) => state.tickers);
|
|
@@ -366,6 +674,8 @@ export function CommandBar({
|
|
|
366
674
|
const rootQueryRef = useRef(rootQuery);
|
|
367
675
|
rootQueryRef.current = rootQuery;
|
|
368
676
|
const rootModeInfo = resolveCommandBarMode(rootQuery, availableCommands);
|
|
677
|
+
const rootModeKindRef = useRef(rootModeInfo.kind);
|
|
678
|
+
rootModeKindRef.current = rootModeInfo.kind;
|
|
369
679
|
const [rootSelectedIdx, setRootSelectedIdx] = useState(0);
|
|
370
680
|
const [rootHoveredIdx, setRootHoveredIdx] = useState<number | null>(null);
|
|
371
681
|
const [rootSearching, setRootSearching] = useState(false);
|
|
@@ -390,32 +700,50 @@ export function CommandBar({
|
|
|
390
700
|
const workflowNativeSelectRefs = useRef(new Map<string, NativeSelectElement>());
|
|
391
701
|
const workflowScrollRef = useRef<ScrollBoxRenderable | null>(null);
|
|
392
702
|
const nativeListScrollRef = useRef<ScrollBoxRenderable | null>(null);
|
|
703
|
+
const themePickerRef = useRef<ThemePickerHandle | null>(null);
|
|
393
704
|
const visibleListStateRef = useRef<ListScreenState | null>(null);
|
|
394
705
|
const processedLaunchSequenceRef = useRef<number | null>(null);
|
|
706
|
+
const currentThemePreviewRef = useRef<string | null>(null);
|
|
395
707
|
const currentRoute = routeStack[routeStack.length - 1] ?? null;
|
|
396
708
|
const currentRouteRef = useRef<CommandBarRoute | null>(currentRoute);
|
|
397
709
|
currentRouteRef.current = currentRoute;
|
|
398
710
|
const activeCollectionId = getFocusedCollectionId(state);
|
|
399
711
|
const activePortfolio = state.config.portfolios.find((portfolio) => portfolio.id === activeCollectionId);
|
|
400
712
|
|
|
713
|
+
const applyThemePreview = useCallback((themeId: string | null) => {
|
|
714
|
+
const committedThemeId = stateRef.current.config.theme;
|
|
715
|
+
const preview = themeId && themeId !== committedThemeId ? themeId : null;
|
|
716
|
+
if (preview) {
|
|
717
|
+
previewTheme(preview);
|
|
718
|
+
} else {
|
|
719
|
+
clearTransientThemePreview();
|
|
720
|
+
if (getCurrentThemeId() !== committedThemeId) {
|
|
721
|
+
applyTheme(committedThemeId);
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
if (currentThemePreviewRef.current !== preview) {
|
|
725
|
+
currentThemePreviewRef.current = preview;
|
|
726
|
+
dispatch({ type: "PREVIEW_THEME", theme: preview });
|
|
727
|
+
}
|
|
728
|
+
}, [dispatch]);
|
|
729
|
+
|
|
401
730
|
const clearThemePreview = useCallback((themeId: string | null | undefined) => {
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
731
|
+
themePickerRef.current?.cancelPreview();
|
|
732
|
+
const targetThemeId = themeId ?? stateRef.current.config.theme;
|
|
733
|
+
if (!targetThemeId) return;
|
|
734
|
+
clearTransientThemePreview();
|
|
735
|
+
if (getCurrentThemeId() !== targetThemeId) {
|
|
736
|
+
applyTheme(targetThemeId);
|
|
737
|
+
}
|
|
738
|
+
if (currentThemePreviewRef.current !== null) {
|
|
739
|
+
currentThemePreviewRef.current = null;
|
|
740
|
+
dispatch({ type: "PREVIEW_THEME", theme: null });
|
|
405
741
|
}
|
|
406
|
-
dispatch({ type: "PREVIEW_THEME", theme: null });
|
|
407
742
|
}, [dispatch]);
|
|
408
743
|
|
|
409
744
|
const restoreThemePreview = useCallback(() => {
|
|
410
|
-
const themeRoute = [...routeStack].reverse().find((route) => (
|
|
411
|
-
route.kind === "mode" && route.screen === "themes"
|
|
412
|
-
));
|
|
413
|
-
if (themeRoute?.kind === "mode" && themeRoute.themeBaseId) {
|
|
414
|
-
clearThemePreview(themeRoute.themeBaseId);
|
|
415
|
-
return;
|
|
416
|
-
}
|
|
417
745
|
clearThemePreview(rootThemeBaseIdRef.current);
|
|
418
|
-
}, [clearThemePreview
|
|
746
|
+
}, [clearThemePreview]);
|
|
419
747
|
|
|
420
748
|
const closeAll = useCallback((options?: { revertThemePreview?: boolean }) => {
|
|
421
749
|
if (options?.revertThemePreview !== false) {
|
|
@@ -462,10 +790,6 @@ export function CommandBar({
|
|
|
462
790
|
return;
|
|
463
791
|
}
|
|
464
792
|
|
|
465
|
-
if (currentRoute.kind === "mode" && currentRoute.screen === "themes" && currentRoute.themeBaseId) {
|
|
466
|
-
clearThemePreview(currentRoute.themeBaseId);
|
|
467
|
-
}
|
|
468
|
-
|
|
469
793
|
if (routeStack.length === 1 && currentRoute.restoreMain) {
|
|
470
794
|
setRootQuery(currentRoute.restoreMain.query);
|
|
471
795
|
setRootSelectedIdx(currentRoute.restoreMain.selectedIdx);
|
|
@@ -525,20 +849,22 @@ export function CommandBar({
|
|
|
525
849
|
pluginRegistry.pinTicker(symbol, { floating: true, paneType: "ticker-detail" });
|
|
526
850
|
}, [pluginRegistry]);
|
|
527
851
|
|
|
528
|
-
const
|
|
529
|
-
|
|
852
|
+
const commitTheme = useCallback((themeId: string) => {
|
|
853
|
+
themePickerRef.current?.cancelPreview();
|
|
854
|
+
clearTransientThemePreview();
|
|
530
855
|
if (getCurrentThemeId() !== themeId) {
|
|
531
856
|
applyTheme(themeId);
|
|
532
857
|
}
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
dispatch({ type: "PREVIEW_THEME", theme: previewTheme });
|
|
536
|
-
}
|
|
858
|
+
currentThemePreviewRef.current = null;
|
|
859
|
+
dispatch({ type: "SET_THEME", theme: themeId });
|
|
537
860
|
}, [dispatch]);
|
|
538
861
|
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
862
|
+
useEffect(() => {
|
|
863
|
+
return () => {
|
|
864
|
+
themePickerRef.current?.cancelPreview();
|
|
865
|
+
clearTransientThemePreview();
|
|
866
|
+
};
|
|
867
|
+
}, []);
|
|
542
868
|
|
|
543
869
|
const focusTicker = useCallback((symbol: string, options?: { forceNewPane?: boolean }) => {
|
|
544
870
|
const currentState = stateRef.current;
|
|
@@ -591,7 +917,7 @@ export function CommandBar({
|
|
|
591
917
|
}, [dispatch, persistLayoutChange, pluginRegistry]);
|
|
592
918
|
|
|
593
919
|
const openModeRoute = useCallback((
|
|
594
|
-
screen: "ticker-search" | "
|
|
920
|
+
screen: "ticker-search" | "plugins" | "layout",
|
|
595
921
|
initialQuery = "",
|
|
596
922
|
payload?: Record<string, unknown>,
|
|
597
923
|
) => {
|
|
@@ -604,7 +930,6 @@ export function CommandBar({
|
|
|
604
930
|
query: initialQuery,
|
|
605
931
|
selectedIdx: 0,
|
|
606
932
|
hoveredIdx: null,
|
|
607
|
-
themeBaseId: screen === "themes" ? stateRef.current.config.theme : undefined,
|
|
608
933
|
payload,
|
|
609
934
|
});
|
|
610
935
|
}, [pushRoute]);
|
|
@@ -1161,44 +1486,6 @@ export function CommandBar({
|
|
|
1161
1486
|
});
|
|
1162
1487
|
}, [openConfirmRoute]);
|
|
1163
1488
|
|
|
1164
|
-
const buildThemeItems = useCallback((
|
|
1165
|
-
query: string,
|
|
1166
|
-
currentThemeId: string | null | undefined,
|
|
1167
|
-
options?: { onSelectTheme?: (themeId: string) => void },
|
|
1168
|
-
): { items: ResultItem[]; selectedIdx: number } => {
|
|
1169
|
-
let selectedIdx = 0;
|
|
1170
|
-
const filtered = query
|
|
1171
|
-
? getThemeOptions().filter((theme) => (
|
|
1172
|
-
theme.name.toLowerCase().includes(query.toLowerCase())
|
|
1173
|
-
|| theme.id.includes(query.toLowerCase())
|
|
1174
|
-
))
|
|
1175
|
-
: getThemeOptions();
|
|
1176
|
-
const items = filtered.map((theme, index): ResultItem => {
|
|
1177
|
-
const current = theme.id === currentThemeId;
|
|
1178
|
-
if (current) selectedIdx = index;
|
|
1179
|
-
return {
|
|
1180
|
-
id: `theme:${theme.id}`,
|
|
1181
|
-
label: theme.name,
|
|
1182
|
-
detail: theme.description,
|
|
1183
|
-
category: "Themes",
|
|
1184
|
-
kind: "theme",
|
|
1185
|
-
current,
|
|
1186
|
-
themeId: theme.id,
|
|
1187
|
-
action: () => {
|
|
1188
|
-
options?.onSelectTheme?.(theme.id);
|
|
1189
|
-
const nextConfig = {
|
|
1190
|
-
...state.config,
|
|
1191
|
-
theme: theme.id,
|
|
1192
|
-
};
|
|
1193
|
-
dispatch({ type: "SET_THEME", theme: theme.id });
|
|
1194
|
-
void saveConfig(nextConfig);
|
|
1195
|
-
closeAll({ revertThemePreview: false });
|
|
1196
|
-
},
|
|
1197
|
-
};
|
|
1198
|
-
});
|
|
1199
|
-
return { items, selectedIdx };
|
|
1200
|
-
}, [closeAll, dispatch, state.config]);
|
|
1201
|
-
|
|
1202
1489
|
const buildPluginItems = useCallback((query: string): ResultItem[] => {
|
|
1203
1490
|
const disabledPlugins = state.config.disabledPlugins || [];
|
|
1204
1491
|
const toggleable = [...pluginRegistry.allPlugins.values()].filter((plugin) => plugin.toggleable);
|
|
@@ -2379,20 +2666,24 @@ export function CommandBar({
|
|
|
2379
2666
|
tickerSearchCacheRef.current.clear();
|
|
2380
2667
|
}, [state.tickers]);
|
|
2381
2668
|
|
|
2669
|
+
const createQuickLookLocalTickerCandidates = useCallback((tickers: Iterable<TickerRecord>) => (
|
|
2670
|
+
createLocalTickerSearchCandidates(tickers, new Map(), QUICK_LOOK_TICKER_SEARCH_OPTIONS)
|
|
2671
|
+
), []);
|
|
2672
|
+
|
|
2382
2673
|
const localTickerSearchResultItems = useCallback((query?: string, options?: {
|
|
2383
2674
|
category?: string;
|
|
2384
2675
|
limit?: number;
|
|
2385
2676
|
}): ResultItem[] => {
|
|
2386
2677
|
const items = query
|
|
2387
|
-
? rankTickerSearchItems(
|
|
2388
|
-
:
|
|
2678
|
+
? rankTickerSearchItems(createQuickLookLocalTickerCandidates(state.tickers.values()), query)
|
|
2679
|
+
: createQuickLookLocalTickerCandidates(state.tickers.values());
|
|
2389
2680
|
return items
|
|
2390
2681
|
.slice(0, options?.limit)
|
|
2391
2682
|
.map((candidate) => ({
|
|
2392
2683
|
...mapTickerSearchCandidateToResultItem(candidate),
|
|
2393
2684
|
category: options?.category ?? candidate.category,
|
|
2394
2685
|
}));
|
|
2395
|
-
}, [mapTickerSearchCandidateToResultItem, state.tickers]);
|
|
2686
|
+
}, [createQuickLookLocalTickerCandidates, mapTickerSearchCandidateToResultItem, state.tickers]);
|
|
2396
2687
|
|
|
2397
2688
|
const adaptTickerSearchRouteResult = useCallback((
|
|
2398
2689
|
item: ResultItem,
|
|
@@ -2812,6 +3103,8 @@ export function CommandBar({
|
|
|
2812
3103
|
const importPath = getDefaultConfigBackupPath();
|
|
2813
3104
|
void importConfig(state.config.dataDir, importPath)
|
|
2814
3105
|
.then((imported) => {
|
|
3106
|
+
themePickerRef.current?.cancelPreview();
|
|
3107
|
+
clearTransientThemePreview();
|
|
2815
3108
|
dispatch({ type: "SET_CONFIG", config: imported });
|
|
2816
3109
|
applyTheme(imported.theme);
|
|
2817
3110
|
dispatch({ type: "SET_THEME", theme: imported.theme });
|
|
@@ -2843,6 +3136,10 @@ export function CommandBar({
|
|
|
2843
3136
|
void onCheckForUpdates?.();
|
|
2844
3137
|
closeAll({ revertThemePreview: false });
|
|
2845
3138
|
return;
|
|
3139
|
+
case "theme":
|
|
3140
|
+
rootThemeBaseIdRef.current = stateRef.current.config.theme;
|
|
3141
|
+
setRootQuery(arg ? `TH ${arg}` : "TH ");
|
|
3142
|
+
return;
|
|
2846
3143
|
case "security-description":
|
|
2847
3144
|
void runSecurityDescriptionShortcut(arg);
|
|
2848
3145
|
return;
|
|
@@ -2879,9 +3176,12 @@ export function CommandBar({
|
|
|
2879
3176
|
quitApp,
|
|
2880
3177
|
runSecurityDescriptionShortcut,
|
|
2881
3178
|
executeCollectionCommand,
|
|
3179
|
+
setRootQuery,
|
|
2882
3180
|
]);
|
|
2883
3181
|
|
|
2884
3182
|
const activeMatch = matchPrefix(rootQuery, availableCommands);
|
|
3183
|
+
const themePickerActive = !currentRoute && activeMatch?.command.id === "theme";
|
|
3184
|
+
const themePickerFilter = themePickerActive ? activeMatch.arg : "";
|
|
2885
3185
|
const rootSecurityDescriptionArg = activeMatch?.command.id === "security-description" && activeMatch.arg.length >= 1
|
|
2886
3186
|
? activeMatch.arg
|
|
2887
3187
|
: null;
|
|
@@ -2903,13 +3203,13 @@ export function CommandBar({
|
|
|
2903
3203
|
rootThemeBaseIdRef.current = state.config.theme;
|
|
2904
3204
|
} else if (rootModeInfo.kind !== "themes" && previousMode === "themes") {
|
|
2905
3205
|
const rootThemeBaseId = rootThemeBaseIdRef.current;
|
|
2906
|
-
if (rootThemeBaseId
|
|
3206
|
+
if (rootThemeBaseId) {
|
|
2907
3207
|
clearThemePreview(rootThemeBaseId);
|
|
2908
3208
|
}
|
|
2909
3209
|
rootThemeBaseIdRef.current = null;
|
|
2910
3210
|
}
|
|
2911
3211
|
previousRootModeRef.current = rootModeInfo.kind;
|
|
2912
|
-
}, [clearThemePreview, currentRoute, rootModeInfo.kind, state.config.theme
|
|
3212
|
+
}, [clearThemePreview, currentRoute, rootModeInfo.kind, state.config.theme]);
|
|
2913
3213
|
|
|
2914
3214
|
const tickerSearchRouteQuery = currentRoute?.kind === "mode" && currentRoute.screen === "ticker-search"
|
|
2915
3215
|
? currentRoute.query
|
|
@@ -2957,6 +3257,7 @@ export function CommandBar({
|
|
|
2957
3257
|
brokerId: activePortfolio?.brokerId,
|
|
2958
3258
|
brokerInstanceId: activePortfolio?.brokerInstanceId,
|
|
2959
3259
|
},
|
|
3260
|
+
...QUICK_LOOK_TICKER_SEARCH_OPTIONS,
|
|
2960
3261
|
});
|
|
2961
3262
|
if (requestId !== searchRequestIdRef.current) return;
|
|
2962
3263
|
writeTickerSearchCache(
|
|
@@ -3247,14 +3548,7 @@ export function CommandBar({
|
|
|
3247
3548
|
} else if (match && match.command.id === "layout") {
|
|
3248
3549
|
items.push(...buildLayoutItems(match.arg, { confirmDangerousActions: true }));
|
|
3249
3550
|
} else if (match && match.command.id === "theme") {
|
|
3250
|
-
|
|
3251
|
-
const themeResult = buildThemeItems(match.arg, savedThemeId, {
|
|
3252
|
-
onSelectTheme: (themeId) => {
|
|
3253
|
-
rootThemeBaseIdRef.current = themeId;
|
|
3254
|
-
},
|
|
3255
|
-
});
|
|
3256
|
-
initialIdx = themeResult.selectedIdx;
|
|
3257
|
-
items.push(...themeResult.items);
|
|
3551
|
+
initialIdx = 0;
|
|
3258
3552
|
} else if (match && match.command.id === "security-description") {
|
|
3259
3553
|
if (shortcutItem) {
|
|
3260
3554
|
items.push(shortcutItem);
|
|
@@ -3281,18 +3575,26 @@ export function CommandBar({
|
|
|
3281
3575
|
const recentSymbols = state.recentTickers.slice(0, maxDefaultTickers);
|
|
3282
3576
|
const recentTickers = recentSymbols
|
|
3283
3577
|
.map((symbol) => state.tickers.get(symbol))
|
|
3284
|
-
.filter((ticker): ticker is NonNullable<typeof ticker> =>
|
|
3578
|
+
.filter((ticker): ticker is NonNullable<typeof ticker> => (
|
|
3579
|
+
ticker != null && createQuickLookLocalTickerCandidates([ticker]).length > 0
|
|
3580
|
+
));
|
|
3285
3581
|
if (recentTickers.length < maxDefaultTickers) {
|
|
3286
3582
|
const seen = new Set(recentSymbols);
|
|
3287
3583
|
for (const ticker of state.tickers.values()) {
|
|
3288
3584
|
if (recentTickers.length >= maxDefaultTickers) break;
|
|
3585
|
+
if (createQuickLookLocalTickerCandidates([ticker]).length === 0) continue;
|
|
3289
3586
|
if (!seen.has(ticker.metadata.ticker)) recentTickers.push(ticker);
|
|
3290
3587
|
}
|
|
3291
3588
|
}
|
|
3292
|
-
items.push(...recentTickers.
|
|
3293
|
-
|
|
3294
|
-
|
|
3295
|
-
|
|
3589
|
+
items.push(...recentTickers.flatMap((ticker) => {
|
|
3590
|
+
const candidate = createQuickLookLocalTickerCandidates([ticker])[0];
|
|
3591
|
+
return candidate
|
|
3592
|
+
? [{
|
|
3593
|
+
...mapTickerSearchCandidateToResultItem(candidate),
|
|
3594
|
+
category: "Tickers",
|
|
3595
|
+
}]
|
|
3596
|
+
: [];
|
|
3597
|
+
}));
|
|
3296
3598
|
items.push(...paneShortcutItems());
|
|
3297
3599
|
for (const command of availableCommands) {
|
|
3298
3600
|
const item = commandToItem(command);
|
|
@@ -3324,7 +3626,7 @@ export function CommandBar({
|
|
|
3324
3626
|
availableCommands,
|
|
3325
3627
|
buildLayoutItems,
|
|
3326
3628
|
buildPluginItems,
|
|
3327
|
-
|
|
3629
|
+
createQuickLookLocalTickerCandidates,
|
|
3328
3630
|
createPluginCommandItem,
|
|
3329
3631
|
currentRoute,
|
|
3330
3632
|
executeCollectionCommand,
|
|
@@ -3412,6 +3714,7 @@ export function CommandBar({
|
|
|
3412
3714
|
brokerId: activeSearchPortfolio?.brokerId,
|
|
3413
3715
|
brokerInstanceId: activeSearchPortfolio?.brokerInstanceId,
|
|
3414
3716
|
},
|
|
3717
|
+
...QUICK_LOOK_TICKER_SEARCH_OPTIONS,
|
|
3415
3718
|
});
|
|
3416
3719
|
if (requestId !== rootSearchRequestIdRef.current) return;
|
|
3417
3720
|
writeTickerSearchCache(
|
|
@@ -3461,6 +3764,7 @@ export function CommandBar({
|
|
|
3461
3764
|
}
|
|
3462
3765
|
return rootResultModel.items;
|
|
3463
3766
|
}, [rootProviderResults, rootProviderResultsQuery, rootResultModel.items, rootSecurityDescriptionArg]);
|
|
3767
|
+
const orderedRootResults = useMemo(() => orderListResults(rootResults), [rootResults]);
|
|
3464
3768
|
|
|
3465
3769
|
const rootGhostCompletion = !currentRoute && rootShortcutIntent.kind === "inferred-complete"
|
|
3466
3770
|
? rootShortcutIntent.completionQuery
|
|
@@ -3666,12 +3970,15 @@ export function CommandBar({
|
|
|
3666
3970
|
|
|
3667
3971
|
if (match.command.id === "theme") {
|
|
3668
3972
|
return {
|
|
3669
|
-
id: "theme-
|
|
3973
|
+
id: "theme-picker",
|
|
3670
3974
|
label: "Change Theme",
|
|
3671
3975
|
detail: "Preview and apply themes",
|
|
3672
3976
|
category: "Themes",
|
|
3673
3977
|
kind: "command",
|
|
3674
|
-
action: () =>
|
|
3978
|
+
action: () => {
|
|
3979
|
+
rootThemeBaseIdRef.current = stateRef.current.config.theme;
|
|
3980
|
+
setRootQuery(match.arg ? `TH ${match.arg}` : "TH ");
|
|
3981
|
+
},
|
|
3675
3982
|
};
|
|
3676
3983
|
}
|
|
3677
3984
|
|
|
@@ -3737,6 +4044,7 @@ export function CommandBar({
|
|
|
3737
4044
|
openModeRoute,
|
|
3738
4045
|
runDirectCommand,
|
|
3739
4046
|
runSecurityDescriptionShortcut,
|
|
4047
|
+
setRootQuery,
|
|
3740
4048
|
]);
|
|
3741
4049
|
|
|
3742
4050
|
const routeListState = useMemo<ListScreenState | null>(() => {
|
|
@@ -3752,7 +4060,7 @@ export function CommandBar({
|
|
|
3752
4060
|
query: rootQuery,
|
|
3753
4061
|
selectedIdx: rootSelectedIdx,
|
|
3754
4062
|
hoveredIdx: rootHoveredIdx,
|
|
3755
|
-
results:
|
|
4063
|
+
results: orderedRootResults,
|
|
3756
4064
|
searching: rootSearching,
|
|
3757
4065
|
emptyLabel: emptyState.label,
|
|
3758
4066
|
emptyDetail: emptyState.detail,
|
|
@@ -3763,23 +4071,6 @@ export function CommandBar({
|
|
|
3763
4071
|
|
|
3764
4072
|
if (currentRoute.kind === "mode") {
|
|
3765
4073
|
switch (currentRoute.screen) {
|
|
3766
|
-
case "themes": {
|
|
3767
|
-
const results = buildThemeItems(currentRoute.query, currentRoute.themeBaseId).items;
|
|
3768
|
-
return {
|
|
3769
|
-
kind: "mode",
|
|
3770
|
-
title: "Change Theme",
|
|
3771
|
-
subtitle: "Preview themes with the keyboard, then save.",
|
|
3772
|
-
query: currentRoute.query,
|
|
3773
|
-
selectedIdx: currentRoute.selectedIdx,
|
|
3774
|
-
hoveredIdx: currentRoute.hoveredIdx,
|
|
3775
|
-
results: orderListResults(results),
|
|
3776
|
-
searching: false,
|
|
3777
|
-
emptyLabel: getEmptyState("themes", currentRoute.query).label,
|
|
3778
|
-
emptyDetail: getEmptyState("themes", currentRoute.query).detail,
|
|
3779
|
-
footerLeft: getScreenFooterLeft(currentRoute),
|
|
3780
|
-
footerRight: getScreenFooterRight(currentRoute),
|
|
3781
|
-
};
|
|
3782
|
-
}
|
|
3783
4074
|
case "plugins": {
|
|
3784
4075
|
const results = buildPluginItems(currentRoute.query);
|
|
3785
4076
|
return {
|
|
@@ -3911,7 +4202,6 @@ export function CommandBar({
|
|
|
3911
4202
|
activeTickerSymbol,
|
|
3912
4203
|
buildLayoutItems,
|
|
3913
4204
|
buildPluginItems,
|
|
3914
|
-
buildThemeItems,
|
|
3915
4205
|
closeAll,
|
|
3916
4206
|
createPaneTemplateItem,
|
|
3917
4207
|
currentRoute,
|
|
@@ -3935,7 +4225,7 @@ export function CommandBar({
|
|
|
3935
4225
|
rootHoveredIdx,
|
|
3936
4226
|
rootModeInfo.kind,
|
|
3937
4227
|
rootQuery,
|
|
3938
|
-
|
|
4228
|
+
orderedRootResults,
|
|
3939
4229
|
rootSearching,
|
|
3940
4230
|
rootSelectedIdx,
|
|
3941
4231
|
rootShortcutIntent,
|
|
@@ -3972,8 +4262,9 @@ export function CommandBar({
|
|
|
3972
4262
|
}, [currentRoute, routeListState, updateTopRoute]);
|
|
3973
4263
|
|
|
3974
4264
|
const setActiveListQuery = useCallback((nextQuery: string) => {
|
|
3975
|
-
|
|
3976
|
-
|
|
4265
|
+
const route = currentRouteRef.current;
|
|
4266
|
+
if (!route) {
|
|
4267
|
+
if (rootModeKindRef.current === "themes" && resolveCommandBarMode(nextQuery, availableCommands).kind !== "themes") {
|
|
3977
4268
|
clearThemePreview(rootThemeBaseIdRef.current ?? stateRef.current.config.theme);
|
|
3978
4269
|
rootThemeBaseIdRef.current = null;
|
|
3979
4270
|
}
|
|
@@ -3981,7 +4272,7 @@ export function CommandBar({
|
|
|
3981
4272
|
return;
|
|
3982
4273
|
}
|
|
3983
4274
|
|
|
3984
|
-
if (
|
|
4275
|
+
if (route.kind === "mode" || route.kind === "picker" || route.kind === "pane-settings") {
|
|
3985
4276
|
updateTopRoute((route) => {
|
|
3986
4277
|
if (route.kind === "mode" || route.kind === "picker" || route.kind === "pane-settings") {
|
|
3987
4278
|
return { ...route, query: nextQuery, selectedIdx: 0, hoveredIdx: null };
|
|
@@ -3989,19 +4280,21 @@ export function CommandBar({
|
|
|
3989
4280
|
return route;
|
|
3990
4281
|
});
|
|
3991
4282
|
}
|
|
3992
|
-
}, [availableCommands, clearThemePreview,
|
|
4283
|
+
}, [availableCommands, clearThemePreview, setRootQuery, updateTopRoute]);
|
|
3993
4284
|
|
|
3994
|
-
const
|
|
4285
|
+
const applyListSelectionDelta = useCallback((delta: number) => {
|
|
3995
4286
|
const listState = visibleListStateRef.current;
|
|
3996
4287
|
if (!listState || listState.results.length === 0 || delta === 0) return;
|
|
3997
4288
|
const nextIndex = clampListIndex(listState.selectedIdx + delta, listState.results.length);
|
|
4289
|
+
const selectionChanged = nextIndex !== listState.selectedIdx;
|
|
4290
|
+
const hoverChanged = listState.hoveredIdx !== null;
|
|
4291
|
+
if (!selectionChanged && !hoverChanged) return;
|
|
3998
4292
|
const nextListState = { ...listState, selectedIdx: nextIndex, hoveredIdx: null };
|
|
3999
4293
|
visibleListStateRef.current = nextListState;
|
|
4000
|
-
previewThemeSelection(nextListState, nextIndex);
|
|
4001
4294
|
|
|
4002
4295
|
if (!currentRouteRef.current) {
|
|
4003
|
-
setRootSelectedIdx(nextIndex);
|
|
4004
|
-
setRootHoveredIdx(null);
|
|
4296
|
+
setRootSelectedIdx((current) => (current === nextIndex ? current : nextIndex));
|
|
4297
|
+
setRootHoveredIdx((current) => (current === null ? current : null));
|
|
4005
4298
|
return;
|
|
4006
4299
|
}
|
|
4007
4300
|
setRouteStack((current) => {
|
|
@@ -4011,24 +4304,34 @@ export function CommandBar({
|
|
|
4011
4304
|
if (!top || (top.kind !== "mode" && top.kind !== "picker" && top.kind !== "pane-settings")) {
|
|
4012
4305
|
return current;
|
|
4013
4306
|
}
|
|
4307
|
+
if (top.selectedIdx === nextIndex && top.hoveredIdx === null) return current;
|
|
4014
4308
|
next[next.length - 1] = { ...top, selectedIdx: nextIndex, hoveredIdx: null };
|
|
4015
4309
|
return next;
|
|
4016
4310
|
});
|
|
4017
|
-
}, [
|
|
4311
|
+
}, []);
|
|
4312
|
+
|
|
4313
|
+
const moveListSelection = useCallback((delta: number) => {
|
|
4314
|
+
applyListSelectionDelta(delta);
|
|
4315
|
+
}, [applyListSelectionDelta]);
|
|
4018
4316
|
|
|
4019
4317
|
const setHoveredIndex = useCallback((index: number | null) => {
|
|
4020
|
-
if (!
|
|
4318
|
+
if (!currentRouteRef.current) {
|
|
4021
4319
|
setRootHoveredIdx((current) => (current === index ? current : index));
|
|
4022
4320
|
return;
|
|
4023
4321
|
}
|
|
4024
|
-
|
|
4322
|
+
setRouteStack((current) => {
|
|
4323
|
+
if (current.length === 0) return current;
|
|
4324
|
+
const next = [...current];
|
|
4325
|
+
const route = next[next.length - 1];
|
|
4326
|
+
if (!route) return current;
|
|
4025
4327
|
if (route.kind === "mode" || route.kind === "picker" || route.kind === "pane-settings") {
|
|
4026
|
-
if (route.hoveredIdx === index) return
|
|
4027
|
-
|
|
4328
|
+
if (route.hoveredIdx === index) return current;
|
|
4329
|
+
next[next.length - 1] = { ...route, hoveredIdx: index };
|
|
4330
|
+
return next;
|
|
4028
4331
|
}
|
|
4029
|
-
return
|
|
4332
|
+
return current;
|
|
4030
4333
|
});
|
|
4031
|
-
}, [
|
|
4334
|
+
}, []);
|
|
4032
4335
|
|
|
4033
4336
|
const handleListScroll = useCallback((event: {
|
|
4034
4337
|
stopPropagation: () => void;
|
|
@@ -4402,6 +4705,29 @@ export function CommandBar({
|
|
|
4402
4705
|
disconnectBrokerInstance,
|
|
4403
4706
|
executeCollectionCommand,
|
|
4404
4707
|
]);
|
|
4708
|
+
const activateListSelectionRef = useRef(activateListSelection);
|
|
4709
|
+
activateListSelectionRef.current = activateListSelection;
|
|
4710
|
+
|
|
4711
|
+
const handleListRowMouseDown = useCallback((event: any, item: ResultItem, globalIdx: number) => {
|
|
4712
|
+
event.stopPropagation?.();
|
|
4713
|
+
event.preventDefault?.();
|
|
4714
|
+
if (!currentRouteRef.current) {
|
|
4715
|
+
setRootSelectedIdx((current) => (current === globalIdx ? current : globalIdx));
|
|
4716
|
+
} else {
|
|
4717
|
+
setRouteStack((current) => {
|
|
4718
|
+
if (current.length === 0) return current;
|
|
4719
|
+
const next = [...current];
|
|
4720
|
+
const route = next[next.length - 1];
|
|
4721
|
+
if (!route || (route.kind !== "mode" && route.kind !== "picker" && route.kind !== "pane-settings")) {
|
|
4722
|
+
return current;
|
|
4723
|
+
}
|
|
4724
|
+
if (route.selectedIdx === globalIdx && route.hoveredIdx === globalIdx) return current;
|
|
4725
|
+
next[next.length - 1] = { ...route, selectedIdx: globalIdx, hoveredIdx: globalIdx };
|
|
4726
|
+
return next;
|
|
4727
|
+
});
|
|
4728
|
+
}
|
|
4729
|
+
activateListSelectionRef.current({ item });
|
|
4730
|
+
}, []);
|
|
4405
4731
|
|
|
4406
4732
|
const confirmCurrentRoute = useCallback(async () => {
|
|
4407
4733
|
if (currentRoute?.kind !== "confirm") return;
|
|
@@ -4539,6 +4865,7 @@ export function CommandBar({
|
|
|
4539
4865
|
preventDefault: () => void;
|
|
4540
4866
|
}) => void) => void;
|
|
4541
4867
|
};
|
|
4868
|
+
if (!keyInput) return undefined;
|
|
4542
4869
|
const handleKeyPress = (event: {
|
|
4543
4870
|
name: string;
|
|
4544
4871
|
sequence?: string;
|
|
@@ -4735,6 +5062,27 @@ export function CommandBar({
|
|
|
4735
5062
|
return;
|
|
4736
5063
|
}
|
|
4737
5064
|
|
|
5065
|
+
if (themePickerActive) {
|
|
5066
|
+
if (event.name === "up" || (event.ctrl && event.name === "p")) {
|
|
5067
|
+
event.stopPropagation();
|
|
5068
|
+
event.preventDefault();
|
|
5069
|
+
themePickerRef.current?.move(-1);
|
|
5070
|
+
return;
|
|
5071
|
+
}
|
|
5072
|
+
if (event.name === "down" || (event.ctrl && event.name === "n")) {
|
|
5073
|
+
event.stopPropagation();
|
|
5074
|
+
event.preventDefault();
|
|
5075
|
+
themePickerRef.current?.move(1);
|
|
5076
|
+
return;
|
|
5077
|
+
}
|
|
5078
|
+
if (event.name === "return" || event.name === "enter") {
|
|
5079
|
+
event.stopPropagation();
|
|
5080
|
+
event.preventDefault();
|
|
5081
|
+
themePickerRef.current?.commit();
|
|
5082
|
+
return;
|
|
5083
|
+
}
|
|
5084
|
+
}
|
|
5085
|
+
|
|
4738
5086
|
const activeListState = visibleListStateRef.current;
|
|
4739
5087
|
if (!activeListState) return;
|
|
4740
5088
|
|
|
@@ -4802,13 +5150,13 @@ export function CommandBar({
|
|
|
4802
5150
|
if (keyInput.onInternal) {
|
|
4803
5151
|
keyInput.onInternal("keypress", handleKeyPress);
|
|
4804
5152
|
} else {
|
|
4805
|
-
|
|
5153
|
+
keyInput.on("keypress", handleKeyPress);
|
|
4806
5154
|
}
|
|
4807
5155
|
return () => {
|
|
4808
5156
|
if (keyInput.offInternal) {
|
|
4809
5157
|
keyInput.offInternal("keypress", handleKeyPress);
|
|
4810
5158
|
} else {
|
|
4811
|
-
|
|
5159
|
+
keyInput.off("keypress", handleKeyPress);
|
|
4812
5160
|
}
|
|
4813
5161
|
};
|
|
4814
5162
|
}, [
|
|
@@ -4828,6 +5176,7 @@ export function CommandBar({
|
|
|
4828
5176
|
renderer,
|
|
4829
5177
|
rootModeInfo.kind,
|
|
4830
5178
|
setActiveListQuery,
|
|
5179
|
+
themePickerActive,
|
|
4831
5180
|
updateWorkflowValue,
|
|
4832
5181
|
]);
|
|
4833
5182
|
|
|
@@ -4849,8 +5198,23 @@ export function CommandBar({
|
|
|
4849
5198
|
? routeListState
|
|
4850
5199
|
: null;
|
|
4851
5200
|
const showCustomMultiSelectPicker = currentRoute?.kind === "picker" && currentRoute.pickerId === "field-multi-select";
|
|
4852
|
-
const listRows =
|
|
4853
|
-
|
|
5201
|
+
const listRows = useMemo(
|
|
5202
|
+
() => (visibleListState ? buildListRows(visibleListState) : []),
|
|
5203
|
+
[visibleListState?.results],
|
|
5204
|
+
);
|
|
5205
|
+
const nativeListRows = useMemo(
|
|
5206
|
+
() => (visibleListState ? buildNativeListRows(visibleListState, listRows) : []),
|
|
5207
|
+
[listRows, visibleListState?.emptyLabel, visibleListState?.searching],
|
|
5208
|
+
);
|
|
5209
|
+
const listRowIndexByGlobalIndex = useMemo(() => {
|
|
5210
|
+
const indexByGlobalIndex = new Map<number, number>();
|
|
5211
|
+
listRows.forEach((row, index) => {
|
|
5212
|
+
if (row.kind === "item") {
|
|
5213
|
+
indexByGlobalIndex.set(row.globalIdx, index);
|
|
5214
|
+
}
|
|
5215
|
+
});
|
|
5216
|
+
return indexByGlobalIndex;
|
|
5217
|
+
}, [listRows]);
|
|
4854
5218
|
const workflowBodyHeight = currentRoute?.kind === "workflow"
|
|
4855
5219
|
? Math.min(
|
|
4856
5220
|
Math.max(9, termHeight - (nativePaneChrome ? 7 : 9)),
|
|
@@ -4879,26 +5243,30 @@ export function CommandBar({
|
|
|
4879
5243
|
const trailingWidth = Math.max(8, Math.min(12, Math.floor(resultsInnerWidth * 0.18)));
|
|
4880
5244
|
const labelWidth = Math.max(10, resultsInnerWidth - trailingWidth);
|
|
4881
5245
|
const queryDisplayWidth = Math.max(8, resultsInnerWidth);
|
|
4882
|
-
const
|
|
4883
|
-
?
|
|
5246
|
+
const selectedListRowIndex = visibleListState
|
|
5247
|
+
? listRowIndexByGlobalIndex.get(visibleListState.selectedIdx) ?? -1
|
|
4884
5248
|
: -1;
|
|
5249
|
+
const selectedScrollRowIndex = selectedListRowIndex;
|
|
4885
5250
|
const bodySlotKey = showCustomMultiSelectPicker
|
|
4886
5251
|
? "picker:field-multi-select"
|
|
4887
|
-
:
|
|
4888
|
-
?
|
|
4889
|
-
: currentRoute?.kind
|
|
5252
|
+
: themePickerActive
|
|
5253
|
+
? "theme-picker"
|
|
5254
|
+
: currentRoute?.kind === "picker"
|
|
5255
|
+
? `picker:${currentRoute.pickerId}`
|
|
5256
|
+
: currentRoute?.kind ?? "root";
|
|
4890
5257
|
|
|
4891
|
-
|
|
4892
|
-
if (!nativePaneChrome || nativeSelectedRowIndex < 0) return;
|
|
5258
|
+
useLayoutEffect(() => {
|
|
4893
5259
|
const scrollBox = nativeListScrollRef.current;
|
|
4894
5260
|
if (!scrollBox) return;
|
|
5261
|
+
if (scrollBox.verticalScrollBar) scrollBox.verticalScrollBar.visible = false;
|
|
5262
|
+
if (selectedScrollRowIndex < 0) return;
|
|
4895
5263
|
const viewportHeight = Math.max(1, scrollBox.viewport?.height ?? listBodyHeight);
|
|
4896
|
-
if (
|
|
4897
|
-
scrollBox.scrollTo(
|
|
4898
|
-
} else if (
|
|
4899
|
-
scrollBox.scrollTo(
|
|
5264
|
+
if (selectedScrollRowIndex < scrollBox.scrollTop) {
|
|
5265
|
+
scrollBox.scrollTo(selectedScrollRowIndex);
|
|
5266
|
+
} else if (selectedScrollRowIndex >= scrollBox.scrollTop + viewportHeight) {
|
|
5267
|
+
scrollBox.scrollTo(selectedScrollRowIndex - viewportHeight + 1);
|
|
4900
5268
|
}
|
|
4901
|
-
}, [listBodyHeight,
|
|
5269
|
+
}, [listBodyHeight, selectedScrollRowIndex, visibleListState?.kind, visibleListState?.query]);
|
|
4902
5270
|
|
|
4903
5271
|
useEffect(() => {
|
|
4904
5272
|
if (!nativePaneChrome || currentRoute?.kind !== "workflow") return;
|
|
@@ -4919,140 +5287,6 @@ export function CommandBar({
|
|
|
4919
5287
|
}
|
|
4920
5288
|
}, [bodyHeight, currentRoute, nativePaneChrome]);
|
|
4921
5289
|
|
|
4922
|
-
const renderListBody = () => {
|
|
4923
|
-
if (!visibleListState) return null;
|
|
4924
|
-
|
|
4925
|
-
const allRows = listRows;
|
|
4926
|
-
let visibleRows: CommandBarListRow[];
|
|
4927
|
-
if (nativePaneChrome) {
|
|
4928
|
-
visibleRows = nativeListRows;
|
|
4929
|
-
} else if (visibleListState.searching && allRows.length === 0) {
|
|
4930
|
-
visibleRows = [{ kind: "spinner", id: "searching", label: "Searching…" }];
|
|
4931
|
-
} else if (allRows.length === 0) {
|
|
4932
|
-
visibleRows = [{ kind: "message", id: "empty", label: visibleListState.emptyLabel }];
|
|
4933
|
-
} else {
|
|
4934
|
-
const selectedRowIdx = allRows.findIndex((row) => row.kind === "item" && row.globalIdx === visibleListState.selectedIdx);
|
|
4935
|
-
const halfWindow = Math.floor(listBodyHeight / 2);
|
|
4936
|
-
let windowStart = Math.max(0, Math.min(selectedRowIdx - halfWindow, allRows.length - listBodyHeight));
|
|
4937
|
-
if (windowStart < 0) windowStart = 0;
|
|
4938
|
-
visibleRows = allRows.slice(windowStart, windowStart + listBodyHeight);
|
|
4939
|
-
if (visibleListState.searching) {
|
|
4940
|
-
if (visibleRows.length >= listBodyHeight) {
|
|
4941
|
-
visibleRows = visibleRows.slice(0, listBodyHeight - 1);
|
|
4942
|
-
}
|
|
4943
|
-
visibleRows.push({ kind: "spinner", id: "searching", label: "Searching…" });
|
|
4944
|
-
}
|
|
4945
|
-
}
|
|
4946
|
-
|
|
4947
|
-
while (!nativePaneChrome && visibleRows.length < listBodyHeight) {
|
|
4948
|
-
visibleRows.push({ kind: "filler", id: `filler:${visibleRows.length}` });
|
|
4949
|
-
}
|
|
4950
|
-
|
|
4951
|
-
const renderedRows = (
|
|
4952
|
-
<>
|
|
4953
|
-
{visibleRows.map((row) => {
|
|
4954
|
-
if (row.kind === "filler" || row.kind === "spacer") {
|
|
4955
|
-
return <Box key={row.id} height={1} />;
|
|
4956
|
-
}
|
|
4957
|
-
if (row.kind === "spinner") {
|
|
4958
|
-
return (
|
|
4959
|
-
<Box key={row.id} height={1} paddingX={contentPadding} {...(!nativePaneChrome ? { onMouseScroll: handleListScroll } : {})}>
|
|
4960
|
-
<Spinner label={row.label} />
|
|
4961
|
-
</Box>
|
|
4962
|
-
);
|
|
4963
|
-
}
|
|
4964
|
-
if (row.kind === "message") {
|
|
4965
|
-
return (
|
|
4966
|
-
<Box key={row.id} height={1} paddingX={contentPadding} {...(!nativePaneChrome ? { onMouseScroll: handleListScroll } : {})}>
|
|
4967
|
-
<Text fg={paletteText}>{truncateText(row.label, queryDisplayWidth)}</Text>
|
|
4968
|
-
</Box>
|
|
4969
|
-
);
|
|
4970
|
-
}
|
|
4971
|
-
if (row.kind === "heading") {
|
|
4972
|
-
return (
|
|
4973
|
-
<Box key={row.id} height={1} paddingX={contentPadding} {...(!nativePaneChrome ? { onMouseScroll: handleListScroll } : {})}>
|
|
4974
|
-
<Text attributes={TextAttributes.BOLD} fg={paletteHeadingText}>
|
|
4975
|
-
{truncateText(row.label, queryDisplayWidth)}
|
|
4976
|
-
</Text>
|
|
4977
|
-
</Box>
|
|
4978
|
-
);
|
|
4979
|
-
}
|
|
4980
|
-
|
|
4981
|
-
const isSelected = row.globalIdx === visibleListState.selectedIdx;
|
|
4982
|
-
const isHovered = row.globalIdx === visibleListState.hoveredIdx && !isSelected;
|
|
4983
|
-
const presentation = getRowPresentation(row.item, isSelected, trailingWidth > 0);
|
|
4984
|
-
const label = truncateText(presentation.label, labelWidth);
|
|
4985
|
-
const trailing = truncateText(presentation.trailing, trailingWidth);
|
|
4986
|
-
return (
|
|
4987
|
-
<Box
|
|
4988
|
-
key={row.item.id}
|
|
4989
|
-
flexDirection="row"
|
|
4990
|
-
height={1}
|
|
4991
|
-
paddingX={contentPadding}
|
|
4992
|
-
backgroundColor={isSelected
|
|
4993
|
-
? paletteSelectedBg
|
|
4994
|
-
: isHovered
|
|
4995
|
-
? paletteHoverBg
|
|
4996
|
-
: (nativePaneChrome ? panelBg : paletteBg)}
|
|
4997
|
-
onMouseMove={() => setHoveredIndex(row.globalIdx)}
|
|
4998
|
-
onMouseOut={() => setHoveredIndex(null)}
|
|
4999
|
-
{...(!nativePaneChrome ? { onMouseScroll: handleListScroll } : {})}
|
|
5000
|
-
onMouseDown={(event: any) => {
|
|
5001
|
-
event.stopPropagation?.();
|
|
5002
|
-
event.preventDefault?.();
|
|
5003
|
-
if (!currentRoute) {
|
|
5004
|
-
setRootSelectedIdx(row.globalIdx);
|
|
5005
|
-
} else {
|
|
5006
|
-
updateTopRoute((route) => {
|
|
5007
|
-
if (route.kind === "mode" || route.kind === "picker" || route.kind === "pane-settings") {
|
|
5008
|
-
return { ...route, selectedIdx: row.globalIdx, hoveredIdx: row.globalIdx };
|
|
5009
|
-
}
|
|
5010
|
-
return route;
|
|
5011
|
-
});
|
|
5012
|
-
}
|
|
5013
|
-
activateListSelection({ item: row.item });
|
|
5014
|
-
}}
|
|
5015
|
-
data-command-bar-row-selected={nativePaneChrome && isSelected ? "true" : undefined}
|
|
5016
|
-
style={nativePaneChrome ? { borderRadius: 6 } : undefined}
|
|
5017
|
-
>
|
|
5018
|
-
<Box width={labelWidth}>
|
|
5019
|
-
<Text fg={isSelected ? paletteSelectedText : presentation.primaryMuted ? paletteSubtleText : paletteText}>
|
|
5020
|
-
{label}
|
|
5021
|
-
</Text>
|
|
5022
|
-
</Box>
|
|
5023
|
-
<Box width={trailingWidth}>
|
|
5024
|
-
<Text fg={isSelected ? paletteSelectedText : paletteSubtleText}>{trailing}</Text>
|
|
5025
|
-
</Box>
|
|
5026
|
-
</Box>
|
|
5027
|
-
);
|
|
5028
|
-
})}
|
|
5029
|
-
</>
|
|
5030
|
-
);
|
|
5031
|
-
|
|
5032
|
-
if (nativePaneChrome) {
|
|
5033
|
-
return (
|
|
5034
|
-
<ScrollBox
|
|
5035
|
-
ref={nativeListScrollRef}
|
|
5036
|
-
flexDirection="column"
|
|
5037
|
-
height={listBodyHeight}
|
|
5038
|
-
scrollY
|
|
5039
|
-
>
|
|
5040
|
-
{renderedRows}
|
|
5041
|
-
</ScrollBox>
|
|
5042
|
-
);
|
|
5043
|
-
}
|
|
5044
|
-
|
|
5045
|
-
return (
|
|
5046
|
-
<Box
|
|
5047
|
-
flexDirection="column"
|
|
5048
|
-
height={listBodyHeight}
|
|
5049
|
-
onMouseScroll={handleListScroll}
|
|
5050
|
-
>
|
|
5051
|
-
{renderedRows}
|
|
5052
|
-
</Box>
|
|
5053
|
-
);
|
|
5054
|
-
};
|
|
5055
|
-
|
|
5056
5290
|
const renderWorkflowBody = () => {
|
|
5057
5291
|
if (currentRoute?.kind !== "workflow") return null;
|
|
5058
5292
|
const visibleFields = getVisibleWorkflowFields(currentRoute.fields, currentRoute.values);
|
|
@@ -5130,7 +5364,7 @@ export function CommandBar({
|
|
|
5130
5364
|
borderColor={active ? paletteSelectedBg : paletteBg}
|
|
5131
5365
|
backgroundColor={nativePaneChrome ? inputBg : fieldBg}
|
|
5132
5366
|
style={nativePaneChrome ? {
|
|
5133
|
-
border: `1px solid ${active ?
|
|
5367
|
+
border: `1px solid ${active ? themeColors.borderFocused : themeColors.border}`,
|
|
5134
5368
|
borderRadius: 6,
|
|
5135
5369
|
overflow: "hidden",
|
|
5136
5370
|
} : undefined}
|
|
@@ -5144,7 +5378,7 @@ export function CommandBar({
|
|
|
5144
5378
|
focused={!currentRoute.pending}
|
|
5145
5379
|
textColor={paletteText}
|
|
5146
5380
|
placeholderColor={paletteSubtleText}
|
|
5147
|
-
backgroundColor={nativePaneChrome ? inputBg :
|
|
5381
|
+
backgroundColor={nativePaneChrome ? inputBg : themeColors.panel}
|
|
5148
5382
|
flexGrow={1}
|
|
5149
5383
|
wrapText
|
|
5150
5384
|
/>
|
|
@@ -5225,7 +5459,7 @@ export function CommandBar({
|
|
|
5225
5459
|
})}
|
|
5226
5460
|
{currentRoute.error && (
|
|
5227
5461
|
<Box height={1}>
|
|
5228
|
-
<Text fg={
|
|
5462
|
+
<Text fg={themeColors.negative}>{truncateText(currentRoute.error, queryDisplayWidth)}</Text>
|
|
5229
5463
|
</Box>
|
|
5230
5464
|
)}
|
|
5231
5465
|
{currentRoute.pendingLabel && currentRoute.pending && (
|
|
@@ -5366,10 +5600,9 @@ export function CommandBar({
|
|
|
5366
5600
|
<Box flexGrow={1}>
|
|
5367
5601
|
<Text fg={paletteText} attributes={TextAttributes.BOLD}>
|
|
5368
5602
|
{currentRoute?.kind === "mode"
|
|
5369
|
-
? currentRoute.screen === "
|
|
5370
|
-
: currentRoute.screen === "
|
|
5371
|
-
:
|
|
5372
|
-
: "Security Description"
|
|
5603
|
+
? currentRoute.screen === "plugins" ? "Manage Plugins"
|
|
5604
|
+
: currentRoute.screen === "layout" ? "Layout Actions"
|
|
5605
|
+
: "Security Description"
|
|
5373
5606
|
: currentRoute?.kind === "picker" ? currentRoute.title
|
|
5374
5607
|
: currentRoute?.kind === "pane-settings" ? "Pane Settings"
|
|
5375
5608
|
: currentRoute?.kind === "workflow" ? currentRoute.title
|
|
@@ -5398,61 +5631,80 @@ export function CommandBar({
|
|
|
5398
5631
|
)}
|
|
5399
5632
|
{(visibleListState || currentRoute?.kind === "picker") && visibleListState && (
|
|
5400
5633
|
<>
|
|
5401
|
-
<
|
|
5402
|
-
|
|
5403
|
-
|
|
5404
|
-
|
|
5405
|
-
|
|
5406
|
-
|
|
5407
|
-
|
|
5408
|
-
|
|
5409
|
-
|
|
5410
|
-
|
|
5411
|
-
|
|
5412
|
-
|
|
5413
|
-
|
|
5414
|
-
|
|
5415
|
-
|
|
5416
|
-
|
|
5417
|
-
width={nativePaneChrome ? "100%" : queryDisplayWidth}
|
|
5418
|
-
backgroundColor={nativePaneChrome ? "transparent" : paletteBg}
|
|
5419
|
-
focusedBackgroundColor={nativePaneChrome ? "transparent" : paletteBg}
|
|
5420
|
-
textColor={paletteText}
|
|
5421
|
-
focusedTextColor={paletteText}
|
|
5422
|
-
placeholderColor={paletteSubtleText}
|
|
5423
|
-
cursorColor={colors.textBright}
|
|
5424
|
-
/>
|
|
5425
|
-
{visibleListState.kind === "root" && rootGhostSuffix && (
|
|
5426
|
-
<Box
|
|
5427
|
-
position="absolute"
|
|
5428
|
-
top={0}
|
|
5429
|
-
left={Math.max(0, Math.min(rootQuery.length, queryDisplayWidth - 1))}
|
|
5430
|
-
width={Math.max(0, queryDisplayWidth - Math.min(rootQuery.length, queryDisplayWidth - 1))}
|
|
5431
|
-
height={1}
|
|
5432
|
-
>
|
|
5433
|
-
<Text fg={paletteSubtleText}>
|
|
5434
|
-
{truncateText(
|
|
5435
|
-
rootGhostSuffix,
|
|
5436
|
-
Math.max(0, queryDisplayWidth - Math.min(rootQuery.length, queryDisplayWidth - 1)),
|
|
5437
|
-
)}
|
|
5438
|
-
</Text>
|
|
5439
|
-
</Box>
|
|
5440
|
-
)}
|
|
5441
|
-
</Box>
|
|
5442
|
-
</Box>
|
|
5443
|
-
<Box height={1} paddingX={contentPadding}>
|
|
5444
|
-
{visibleListState.kind === "root" && rootShortcutFeedback
|
|
5445
|
-
? (
|
|
5446
|
-
<Text fg={paletteSubtleText}>
|
|
5447
|
-
{truncateText(rootShortcutFeedback, queryDisplayWidth)}
|
|
5448
|
-
</Text>
|
|
5449
|
-
)
|
|
5450
|
-
: null}
|
|
5451
|
-
</Box>
|
|
5634
|
+
<CommandBarListHeader
|
|
5635
|
+
kind={visibleListState.kind}
|
|
5636
|
+
query={visibleListState.query}
|
|
5637
|
+
queryDisplayWidth={queryDisplayWidth}
|
|
5638
|
+
nativePaneChrome={nativePaneChrome}
|
|
5639
|
+
inputBg={inputBg}
|
|
5640
|
+
paletteBg={paletteBg}
|
|
5641
|
+
paletteText={paletteText}
|
|
5642
|
+
paletteSubtleText={paletteSubtleText}
|
|
5643
|
+
cursorColor={themeColors.textBright}
|
|
5644
|
+
contentPadding={contentPadding}
|
|
5645
|
+
rootGhostSuffix={rootGhostSuffix}
|
|
5646
|
+
rootQueryLength={rootQuery.length}
|
|
5647
|
+
rootShortcutFeedback={rootShortcutFeedback}
|
|
5648
|
+
onQueryChange={setActiveListQuery}
|
|
5649
|
+
/>
|
|
5452
5650
|
</>
|
|
5453
5651
|
)}
|
|
5454
5652
|
|
|
5455
|
-
{
|
|
5653
|
+
{themePickerActive && (
|
|
5654
|
+
<ThemePicker
|
|
5655
|
+
ref={themePickerRef}
|
|
5656
|
+
filter={themePickerFilter}
|
|
5657
|
+
committedThemeId={state.config.theme}
|
|
5658
|
+
height={listBodyHeight}
|
|
5659
|
+
contentPadding={contentPadding}
|
|
5660
|
+
labelWidth={labelWidth}
|
|
5661
|
+
trailingWidth={trailingWidth}
|
|
5662
|
+
queryDisplayWidth={queryDisplayWidth}
|
|
5663
|
+
nativePaneChrome={nativePaneChrome}
|
|
5664
|
+
paletteBg={paletteBg}
|
|
5665
|
+
paletteHoverBg={paletteHoverBg}
|
|
5666
|
+
paletteSelectedBg={paletteSelectedBg}
|
|
5667
|
+
paletteSelectedText={paletteSelectedText}
|
|
5668
|
+
paletteSubtleText={paletteSubtleText}
|
|
5669
|
+
paletteText={paletteText}
|
|
5670
|
+
panelBg={panelBg}
|
|
5671
|
+
onPreview={applyThemePreview}
|
|
5672
|
+
onCommit={(themeId) => {
|
|
5673
|
+
const nextConfig = {
|
|
5674
|
+
...stateRef.current.config,
|
|
5675
|
+
theme: themeId,
|
|
5676
|
+
};
|
|
5677
|
+
commitTheme(themeId);
|
|
5678
|
+
void saveConfig(nextConfig);
|
|
5679
|
+
closeAll({ revertThemePreview: false });
|
|
5680
|
+
}}
|
|
5681
|
+
/>
|
|
5682
|
+
)}
|
|
5683
|
+
|
|
5684
|
+
{visibleListState && !themePickerActive && !showCustomMultiSelectPicker && (
|
|
5685
|
+
<CommandBarListBody
|
|
5686
|
+
visibleListState={visibleListState}
|
|
5687
|
+
nativeListRows={nativeListRows}
|
|
5688
|
+
listBodyHeight={listBodyHeight}
|
|
5689
|
+
contentPadding={contentPadding}
|
|
5690
|
+
labelWidth={labelWidth}
|
|
5691
|
+
nativePaneChrome={nativePaneChrome}
|
|
5692
|
+
nativeListScrollRef={nativeListScrollRef}
|
|
5693
|
+
paletteBg={paletteBg}
|
|
5694
|
+
paletteHeadingText={paletteHeadingText}
|
|
5695
|
+
paletteHoverBg={paletteHoverBg}
|
|
5696
|
+
paletteSelectedBg={paletteSelectedBg}
|
|
5697
|
+
paletteSelectedText={paletteSelectedText}
|
|
5698
|
+
paletteSubtleText={paletteSubtleText}
|
|
5699
|
+
paletteText={paletteText}
|
|
5700
|
+
panelBg={panelBg}
|
|
5701
|
+
queryDisplayWidth={queryDisplayWidth}
|
|
5702
|
+
trailingWidth={trailingWidth}
|
|
5703
|
+
onHoverIndex={setHoveredIndex}
|
|
5704
|
+
onListScroll={handleListScroll}
|
|
5705
|
+
onRowMouseDown={handleListRowMouseDown}
|
|
5706
|
+
/>
|
|
5707
|
+
)}
|
|
5456
5708
|
{currentRoute?.kind === "workflow" && renderWorkflowBody()}
|
|
5457
5709
|
{currentRoute?.kind === "confirm" && renderConfirmBody()}
|
|
5458
5710
|
{showCustomMultiSelectPicker && renderMultiSelectBody()}
|