gloomberb 0.10.0 → 0.10.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 +8 -1
- package/src/api-client/auth.ts +1 -0
- package/src/api-client/index.test.ts +359 -108
- package/src/api-client/index.ts +24 -13
- package/src/api-client/socket.ts +70 -35
- package/src/api-client/types.ts +1 -1
- package/src/app/language-observer.test.tsx +82 -0
- package/src/app/language-observer.tsx +13 -0
- package/src/app/pane-runtime/index.tsx +2 -2
- package/src/app/pane-runtime/pane-settings-runtime.tsx +2 -2
- package/src/app/pane-runtime/pane-template-runtime.ts +2 -2
- package/src/app/pane-runtime/plugin-bindings.ts +2 -2
- package/src/app/pane-runtime/ticker-open-runtime.ts +2 -2
- package/src/app/runtime/broker-import.ts +2 -2
- package/src/app/runtime/plugin-bindings.ts +2 -2
- package/src/app/runtime/startup.ts +2 -2
- package/src/app.tsx +16 -7
- package/src/brokers/account-cache.ts +6 -6
- package/src/brokers/broker-ticker-sync.ts +3 -3
- package/src/brokers/remote-broker-adapter.ts +2 -2
- package/src/brokers/sync-broker-instance.ts +5 -6
- package/src/cli/commands/api.ts +3 -6
- package/src/cli/commands/automation.ts +7 -15
- package/src/cli/commands/market.ts +26 -61
- package/src/cli/commands/overview.ts +34 -45
- package/src/cli/commands/search.ts +25 -27
- package/src/cli/commands/system.ts +27 -57
- package/src/cli/commands/ticker.ts +62 -63
- package/src/cli/context.test.ts +63 -0
- package/src/cli/context.ts +15 -1
- package/src/cli/index.ts +1 -1
- package/src/cli/pane-functions/data.ts +2 -19
- package/src/cli/pane-functions/index.ts +26 -25
- package/src/cli/pane-functions/report.ts +1 -1
- package/src/cli/pane-functions/screenshot.ts +3 -3
- package/src/cli/scoped-context.ts +41 -0
- package/src/components/chart/composite/composite-chart.test.tsx +615 -18
- package/src/components/chart/composite/composite-chart.tsx +179 -79
- package/src/components/chart/composite/format.test.ts +20 -7
- package/src/components/chart/composite/index.ts +0 -21
- package/src/components/chart/composite/interactions.test.ts +90 -3
- package/src/components/chart/composite/interactions.ts +189 -24
- package/src/components/chart/composite/price-series.ts +0 -2
- package/src/components/chart/composite/rasterizer.ts +10 -9
- package/src/components/chart/composite/renderers.test.ts +108 -2
- package/src/components/chart/composite/scene.test.ts +36 -0
- package/src/components/chart/composite/scene.ts +5 -2
- package/src/components/chart/composite/text-renderer.ts +37 -25
- package/src/components/chart/composite/time-axis.test.ts +243 -0
- package/src/components/chart/composite/time-axis.ts +608 -0
- package/src/components/chart/composite/types.ts +12 -1
- package/src/components/chart/core/data.ts +2 -159
- package/src/components/chart/core/date-window.ts +6 -225
- package/src/components/chart/core/palette.ts +1 -12
- package/src/components/chart/core/pointer.ts +0 -142
- package/src/components/chart/core/types.ts +1 -58
- package/src/components/chart/cursor-motion.ts +2 -4
- package/src/components/chart/indicators/types.ts +0 -9
- package/src/components/chart/market-session.ts +0 -11
- package/src/components/chart/native/kitty/protocol.ts +1 -1
- package/src/components/chart/native/raster/layout.ts +3 -10
- package/src/components/chart/static/chart/axis-overlays.test.tsx +64 -0
- package/src/components/chart/static/chart/axis-overlays.tsx +59 -14
- package/src/components/chart/static/chart/surface.tsx +1 -2
- package/src/components/command-bar/action-runtime.ts +2 -2
- package/src/components/command-bar/commands/direct/index.ts +1 -1
- package/src/components/command-bar/panel/body.tsx +2 -2
- package/src/components/command-bar/panel/index.tsx +11 -9
- package/src/components/command-bar/routes/ticker-search/actions.ts +2 -2
- package/src/components/command-bar/surface/index.tsx +2 -2
- package/src/components/command-bar/workflow/body.tsx +3 -3
- package/src/components/command-bar/workflow/collection-actions.ts +2 -2
- package/src/components/command-bar/workflow/coordinator.ts +2 -2
- package/src/components/command-bar/workflow/field-row.tsx +25 -11
- package/src/components/command-bar/workflow/tickers.ts +2 -2
- package/src/components/feed-data-table/stack-view.test.tsx +28 -36
- package/src/components/feed-data-table/stack-view.tsx +3 -1
- package/src/components/layout/detached-pane-shell.tsx +6 -6
- package/src/components/layout/header.tsx +13 -9
- package/src/components/layout/pane/content.test.tsx +42 -3
- package/src/components/layout/pane/content.tsx +3 -1
- package/src/components/layout/pane/footer/index.test.tsx +45 -2
- package/src/components/layout/pane/footer/registration.tsx +3 -1
- package/src/components/layout/shell/index.tsx +1 -2
- package/src/components/layout/shell/native/surfaces.ts +1 -1
- package/src/components/layout/shell/native/window-state.ts +1 -1
- package/src/components/layout/status-bar.tsx +12 -8
- package/src/components/layout/window-controls.tsx +8 -6
- package/src/components/onboarding/onboarding-wizard.tsx +3 -1
- package/src/components/pane-settings-dialog/desktop.tsx +0 -2
- package/src/components/pane-settings-dialog.tsx +0 -2
- package/src/components/pane-template-wizard.tsx +10 -9
- package/src/components/price-performance.tsx +2 -113
- package/src/components/price-sparkline/model.ts +15 -17
- package/src/components/price-sparkline/view.tsx +8 -7
- package/src/components/speedometer-gauge/desktop.tsx +2 -1
- package/src/components/speedometer-gauge/index.tsx +0 -2
- package/src/components/speedometer-gauge/terminal.tsx +24 -5
- package/src/components/ticker/badge/index.tsx +1 -18
- package/src/components/ui/data-table/opentui/index.tsx +3 -3
- package/src/components/ui/frame.tsx +1 -2
- package/src/components/ui/page-stack-view.test.tsx +126 -0
- package/src/components/ui/page-stack-view.tsx +24 -12
- package/src/components/ui/tabs.tsx +7 -3
- package/src/components/ui/ui.test.tsx +23 -2
- package/src/components/use-external-link-footer.ts +4 -2
- package/src/core/app-service-ports.ts +46 -0
- package/src/core/app-services.test.ts +66 -0
- package/src/core/app-services.ts +17 -15
- package/src/data/config/chart-settings.ts +3 -10
- package/src/data/config/store/index.test.ts +99 -2
- package/src/data/config/store/migrations.ts +278 -0
- package/src/data/config/store/normalize.ts +44 -186
- package/src/data/resource-store.ts +73 -12
- package/src/data/sqlite/cache.test.ts +104 -15
- package/src/i18n/index.test.ts +17 -0
- package/src/i18n/index.ts +23 -6
- package/src/i18n/ja.ts +13 -0
- package/src/i18n/ko.ts +13 -0
- package/src/i18n/react.ts +6 -0
- package/src/i18n/zh-cn.ts +13 -0
- package/src/i18n/zh-tw.ts +13 -0
- package/src/market-data/coordinator/auxiliary.ts +7 -3
- package/src/market-data/coordinator/chart.ts +1 -1
- package/src/market-data/coordinator/index.test.ts +26 -0
- package/src/market-data/coordinator/index.ts +11 -5
- package/src/market-data/coordinator/quotes.ts +4 -40
- package/src/market-data/coordinator/subscriptions.test.ts +89 -1
- package/src/market-data/hooks.tsx +47 -1
- package/src/market-data/market/status.ts +6 -6
- package/src/market-data/performance.ts +1 -1
- package/src/market-data/quote-subscription-target.test.ts +37 -0
- package/src/market-data/quote-subscription-target.ts +60 -0
- package/src/market-data/quotes/freshness.ts +1 -0
- package/src/market-data/quotes/resolution.ts +4 -0
- package/src/market-data/request-types.ts +3 -3
- package/src/news/aggregator.test.ts +97 -1
- package/src/news/aggregator.ts +100 -57
- package/src/news/hooks.test.tsx +64 -0
- package/src/news/hooks.ts +18 -25
- package/src/plugins/builtin/account-management/footer.ts +4 -2
- package/src/plugins/builtin/account-management/pane.tsx +9 -4
- package/src/plugins/builtin/ai/agent-history.ts +11 -7
- package/src/plugins/builtin/ai/ask-ai-detail-tab.tsx +0 -5
- package/src/plugins/builtin/ai/ask-ai.test.tsx +3 -4
- package/src/plugins/builtin/ai/index.test.ts +2 -2
- package/src/plugins/builtin/ai/index.tsx +10 -11
- package/src/plugins/builtin/ai/pane-settings.ts +1 -1
- package/src/plugins/builtin/ai/pi/runtime.ts +6 -5
- package/src/plugins/builtin/ai/providers.ts +1 -9
- package/src/plugins/builtin/ai/runner.ts +0 -6
- package/src/plugins/builtin/ai/screener/footer.ts +4 -1
- package/src/plugins/builtin/ai/screener/pane.test.tsx +9 -9
- package/src/plugins/builtin/ai/workspace/model.ts +2 -27
- package/src/plugins/builtin/ai/workspace/pane.tsx +2 -2
- package/src/plugins/builtin/analytics/metrics.ts +1 -7
- package/src/plugins/builtin/broker-manager/detail.tsx +3 -2
- package/src/plugins/builtin/broker-manager/index.tsx +4 -2
- package/src/plugins/builtin/chart-composer/editor/controller.ts +643 -0
- package/src/plugins/builtin/chart-composer/editor/desktop-view.tsx +134 -0
- package/src/plugins/builtin/chart-composer/editor/model.test.ts +85 -0
- package/src/plugins/builtin/chart-composer/editor/model.ts +292 -0
- package/src/plugins/builtin/chart-composer/editor/opentui-view.tsx +108 -0
- package/src/plugins/builtin/chart-composer/editor.tsx +65 -947
- package/src/plugins/builtin/chart-composer/index.tsx +0 -6
- package/src/plugins/builtin/chart-composer/pane.tsx +69 -36
- package/src/plugins/builtin/chart-composer/presets.ts +1 -19
- package/src/plugins/builtin/chart-composer/settings.ts +1 -1
- package/src/plugins/builtin/chat/content/composer-runtime.ts +1 -1
- package/src/plugins/builtin/chat/content/shortcuts.ts +0 -1
- package/src/plugins/builtin/chat/controller/fetch.ts +8 -2
- package/src/plugins/builtin/chat/controller/persistence.ts +2 -0
- package/src/plugins/builtin/chat/controller/session.test.ts +25 -0
- package/src/plugins/builtin/chat/controller/session.ts +2 -0
- package/src/plugins/builtin/chat/controller/state.ts +7 -0
- package/src/plugins/builtin/chat/controller.test.ts +73 -20
- package/src/plugins/builtin/chat/message/desktop.tsx +2 -0
- package/src/plugins/builtin/cloud-tweets/footer.ts +9 -28
- package/src/plugins/builtin/cloud-tweets/pane.tsx +0 -5
- package/src/plugins/builtin/cloud-tweets/table.tsx +12 -17
- package/src/plugins/builtin/correlation/compute.ts +4 -10
- package/src/plugins/builtin/econ/index.tsx +17 -19
- package/src/plugins/builtin/holders/types.ts +0 -1
- package/src/plugins/builtin/insider/index.tsx +6 -31
- package/src/plugins/builtin/news/index.tsx +5 -7
- package/src/plugins/builtin/news/wire/breaking/pane.test.tsx +6 -8
- package/src/plugins/builtin/news/wire/news/footer.ts +10 -11
- package/src/plugins/builtin/news/wire/read-state.test.ts +7 -0
- package/src/plugins/builtin/news/wire/read-state.ts +18 -28
- package/src/plugins/builtin/news/wire/rss/parser.ts +1 -11
- package/src/plugins/builtin/options/footer.test.ts +115 -0
- package/src/plugins/builtin/options/footer.ts +110 -0
- package/src/plugins/builtin/options/live-quotes.test.ts +238 -0
- package/src/plugins/builtin/options/live-quotes.ts +147 -0
- package/src/plugins/builtin/options/view.test.tsx +71 -1
- package/src/plugins/builtin/options/view.tsx +39 -24
- package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +103 -117
- package/src/plugins/builtin/portfolio-list/cli/render.ts +11 -5
- package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +120 -135
- package/src/plugins/builtin/portfolio-list/header.tsx +9 -4
- package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +6 -1
- package/src/plugins/builtin/portfolio-list/quick-add/resolution.ts +4 -2
- package/src/plugins/builtin/research/corporate-actions-pane.tsx +24 -52
- package/src/plugins/builtin/sec/filing-content.test.ts +41 -0
- package/src/plugins/builtin/sec/filing-content.ts +94 -0
- package/src/plugins/builtin/sec/index.tsx +21 -104
- package/src/plugins/builtin/sectors/sector-model.ts +1 -7
- package/src/plugins/builtin/shared/cloud-upgrade.ts +1 -0
- package/src/plugins/builtin/shared/pane-footer.ts +82 -0
- package/src/plugins/builtin/shared/read-state.ts +64 -3
- package/src/plugins/builtin/substack/read-state.ts +16 -41
- package/src/plugins/builtin/thirteenf/pane.tsx +24 -73
- package/src/plugins/builtin/ticker-detail/quote-monitor/index.tsx +10 -10
- package/src/plugins/builtin/yield-curve/index.tsx +11 -9
- package/src/plugins/ibkr/dialogs.tsx +3 -3
- package/src/plugins/ibkr/gateway/fundamentals.ts +1 -1
- package/src/plugins/ibkr/gateway/history-requests.ts +2 -2
- package/src/plugins/ibkr/gateway/history.ts +2 -2
- package/src/plugins/ibkr/gateway/selection.ts +2 -2
- package/src/plugins/ibkr/gateway/service/index.ts +2 -2
- package/src/plugins/ibkr/gateway/service/native.ts +2 -2
- package/src/plugins/plugin-persistence.ts +3 -4
- package/src/plugins/prediction-markets/controller/keyboard.ts +1 -1
- package/src/plugins/prediction-markets/controller/live-updates.ts +6 -5
- package/src/plugins/prediction-markets/detail/book.tsx +2 -2
- package/src/plugins/prediction-markets/detail/outcomes.tsx +3 -1
- package/src/plugins/prediction-markets/detail/pane.tsx +3 -1
- package/src/plugins/prediction-markets/detail/trades.tsx +3 -3
- package/src/plugins/registry/context.ts +3 -4
- package/src/plugins/registry/index.ts +5 -6
- package/src/react/input.test.ts +126 -3
- package/src/react/input.ts +120 -1
- package/src/remote/app-host.tsx +2 -13
- package/src/renderers/electrobun/bun/desktop/backend-requests.ts +44 -60
- package/src/renderers/electrobun/bun/desktop/capability-bridge.ts +15 -13
- package/src/renderers/electrobun/bun/desktop/host-requests.ts +26 -22
- package/src/renderers/electrobun/bun/desktop/http-fetch.ts +5 -1
- package/src/renderers/electrobun/bun/desktop/initialization.ts +11 -6
- package/src/renderers/electrobun/bun/desktop/media.ts +5 -3
- package/src/renderers/electrobun/bun/desktop/plugin-state.ts +21 -22
- package/src/renderers/electrobun/bun/desktop/window-controls.ts +3 -1
- package/src/renderers/electrobun/bun/desktop/workspace/requests.ts +18 -18
- package/src/renderers/electrobun/bun/index.ts +123 -83
- package/src/renderers/electrobun/shared/protocol.ts +146 -7
- package/src/renderers/electrobun/view/app-services.ts +5 -8
- package/src/renderers/electrobun/view/backend-rpc.ts +18 -8
- package/src/renderers/electrobun/view/broker-remote-client.ts +2 -2
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +5 -22
- package/src/renderers/electrobun/view/config-host.ts +1 -1
- package/src/renderers/electrobun/view/context-menu.ts +1 -17
- package/src/renderers/electrobun/view/data-table/index.tsx +0 -1
- package/src/renderers/electrobun/view/data-table/row.tsx +0 -4
- package/src/renderers/electrobun/view/desktop/control-styles.ts +37 -34
- package/src/renderers/electrobun/view/desktop/controls.tsx +36 -33
- package/src/renderers/electrobun/view/desktop/list-view.tsx +15 -12
- package/src/renderers/electrobun/view/desktop/popover.tsx +2 -3
- package/src/renderers/electrobun/view/dialog-host.tsx +2 -3
- package/src/renderers/electrobun/view/fatal-screen.tsx +0 -1
- package/src/renderers/electrobun/view/host/box.tsx +0 -1
- package/src/renderers/electrobun/view/host/chart-surface.tsx +0 -1
- package/src/renderers/electrobun/view/host/input.tsx +0 -1
- package/src/renderers/electrobun/view/host/media-surface.tsx +0 -1
- package/src/renderers/electrobun/view/host/native.ts +0 -1
- package/src/renderers/electrobun/view/host/scroll-box.tsx +0 -1
- package/src/renderers/electrobun/view/host/tabs.tsx +0 -1
- package/src/renderers/electrobun/view/host/text.tsx +0 -1
- package/src/renderers/electrobun/view/http-fetch.ts +3 -11
- package/src/renderers/electrobun/view/input-host.tsx +10 -53
- package/src/renderers/electrobun/view/key-event.ts +0 -1
- package/src/renderers/electrobun/view/main.tsx +3 -3
- package/src/renderers/electrobun/view/native-renderer.ts +0 -1
- package/src/renderers/electrobun/view/native-stubs/backend-rpc.ts +13 -1
- package/src/renderers/electrobun/view/native-stubs/chart/surface-manager.ts +11 -0
- package/src/renderers/electrobun/view/native-stubs/native-stubs.test.ts +47 -0
- package/src/renderers/electrobun/view/remote/asset-data-client.ts +6 -44
- package/src/renderers/electrobun/view/remote/persistence.ts +6 -2
- package/src/renderers/electrobun/view/remote/quote-subscription-registry.test.ts +86 -0
- package/src/renderers/electrobun/view/remote/quote-subscription-registry.ts +72 -0
- package/src/renderers/electrobun/view/remote/ticker-repository.ts +2 -2
- package/src/renderers/electrobun/view/toast-host.tsx +0 -1
- package/src/renderers/electrobun/view/ui-host.tsx +1 -2
- package/src/renderers/electrobun/view/update-host.ts +1 -1
- package/src/renderers/opentui/chart-surface.tsx +2 -1
- package/src/renderers/opentui/dialog-host.tsx +20 -4
- package/src/renderers/opentui/image/loader.ts +12 -2
- package/src/renderers/opentui/input-host.tsx +7 -49
- package/src/renderers/opentui/start.tsx +2 -0
- package/src/sources/gloomberb-cloud/history-quality.ts +44 -0
- package/src/sources/gloomberb-cloud/index.test.ts +173 -0
- package/src/sources/gloomberb-cloud/index.ts +42 -20
- package/src/sources/gloomberb-cloud/normalizers.ts +9 -3
- package/src/sources/provider-router/cache.ts +1 -1
- package/src/sources/provider-router/document-routes.ts +10 -5
- package/src/sources/provider-router/financials.test.ts +14 -0
- package/src/sources/provider-router/financials.ts +6 -1
- package/src/sources/provider-router/history.test.ts +163 -1
- package/src/sources/provider-router/history.ts +278 -347
- package/src/sources/provider-router/index.ts +2 -2
- package/src/sources/provider-router/routing.test.ts +39 -0
- package/src/sources/provider-router/routing.ts +24 -11
- package/src/sources/provider-router/supplemental.ts +37 -17
- package/src/sources/sec-edgar/content.ts +2 -12
- package/src/sources/sec-edgar.ts +2 -13
- package/src/sources/yahoo-finance/history.ts +2 -2
- package/src/sources/yahoo-finance/options.ts +5 -0
- package/src/sources/yahoo-finance.ts +2 -2
- package/src/state/app/bootstrap.ts +2 -2
- package/src/state/app/context/index.tsx +2 -2
- package/src/state/hooks/quote-streaming.ts +66 -1
- package/src/state/hooks/session-snapshot.ts +2 -2
- package/src/state/selectors.ts +0 -9
- package/src/sync/controller.test.ts +98 -0
- package/src/sync/controller.ts +29 -5
- package/src/sync/react.ts +2 -2
- package/src/sync/types.ts +2 -2
- package/src/theme/colors.test.ts +10 -0
- package/src/theme/colors.ts +75 -78
- package/src/theme/theme-context.test.tsx +67 -0
- package/src/theme/theme-context.tsx +9 -5
- package/src/tickers/open-target.ts +2 -2
- package/src/tickers/search/upsert.ts +2 -2
- package/src/time-series/alignment.ts +0 -7
- package/src/time-series/chart-data.ts +145 -0
- package/src/time-series/date-window.ts +44 -0
- package/src/time-series/history-window.ts +21 -0
- package/src/time-series/hooks.test.ts +59 -0
- package/src/time-series/hooks.ts +33 -12
- package/src/time-series/market-resolution.ts +2 -2
- package/src/time-series/market.ts +1 -1
- package/src/time-series/range.ts +9 -0
- package/src/{components/chart/core → time-series}/resolution.ts +3 -102
- package/src/time-series/resolve.test.ts +203 -1
- package/src/time-series/resolve.ts +96 -18
- package/src/time-series/spec-studies.test.ts +15 -0
- package/src/time-series/spec.ts +2 -2
- package/src/time-series/studies.ts +5 -2
- package/src/time-series/types.ts +3 -1
- package/src/time-series/use-chart-resolution.test.tsx +358 -0
- package/src/time-series/use-chart-resolution.ts +46 -4
- package/src/types/broker.ts +2 -2
- package/src/types/data-provider.ts +3 -3
- package/src/types/financials.ts +12 -0
- package/src/types/plugin.ts +2 -2
- package/src/ui/context-menu.tsx +3 -2
- package/src/ui/dialog.tsx +2 -2
- package/src/utils/html-entities.ts +3 -5
- package/src/utils/main-thread-monitor.ts +1 -1
- package/src/utils/price-history.ts +5 -5
- package/src/version.ts +3 -1
- package/src/components/chart/core/viewport.test.ts +0 -8
- package/src/components/chart/core/viewport.ts +0 -24
- package/src/time-series/index.ts +0 -14
- /package/src/{components/chart/core → time-series}/resolution.test.ts +0 -0
|
@@ -6,6 +6,7 @@ import type { WizardStep } from "../types/plugin";
|
|
|
6
6
|
import { colors } from "../theme/colors";
|
|
7
7
|
import { isPlainKey } from "../utils/keyboard";
|
|
8
8
|
import { DialogFrame, ListView, TextField } from "./ui";
|
|
9
|
+
import { t } from "../i18n";
|
|
9
10
|
|
|
10
11
|
export function PaneTemplateInfoStep({
|
|
11
12
|
dismiss,
|
|
@@ -24,7 +25,7 @@ export function PaneTemplateInfoStep({
|
|
|
24
25
|
<Box flexDirection="column">
|
|
25
26
|
{step.body?.map((line, index) => (
|
|
26
27
|
<Box key={`${step.key}:${index}`} height={1}>
|
|
27
|
-
<Text fg={colors.textDim}>{line
|
|
28
|
+
<Text fg={colors.textDim}>{line ? t(line) : " "}</Text>
|
|
28
29
|
</Box>
|
|
29
30
|
))}
|
|
30
31
|
</Box>
|
|
@@ -55,14 +56,14 @@ export function PaneTemplateInputStep({
|
|
|
55
56
|
<Box flexDirection="column">
|
|
56
57
|
{step.body?.map((line, index) => (
|
|
57
58
|
<Box key={`${step.key}:${index}`} height={1}>
|
|
58
|
-
<Text fg={colors.textDim}>{line
|
|
59
|
+
<Text fg={colors.textDim}>{line ? t(line) : " "}</Text>
|
|
59
60
|
</Box>
|
|
60
61
|
))}
|
|
61
62
|
<Box height={1} />
|
|
62
63
|
<TextField
|
|
63
64
|
inputRef={inputRef}
|
|
64
65
|
value={value}
|
|
65
|
-
placeholder={step.placeholder
|
|
66
|
+
placeholder={step.placeholder ? t(step.placeholder) : ""}
|
|
66
67
|
type={step.type === "password" ? "password" : "text"}
|
|
67
68
|
focused
|
|
68
69
|
onChange={setValue}
|
|
@@ -112,7 +113,7 @@ export function PaneTemplateTextareaStep({
|
|
|
112
113
|
<Box flexDirection="column" flexGrow={1}>
|
|
113
114
|
{step.body?.map((line, index) => (
|
|
114
115
|
<Box key={`${step.key}:${index}`} height={1}>
|
|
115
|
-
<Text fg={colors.textDim}>{line
|
|
116
|
+
<Text fg={colors.textDim}>{line ? t(line) : " "}</Text>
|
|
116
117
|
</Box>
|
|
117
118
|
))}
|
|
118
119
|
<Box height={1} />
|
|
@@ -126,7 +127,7 @@ export function PaneTemplateTextareaStep({
|
|
|
126
127
|
<Textarea
|
|
127
128
|
ref={textareaRef}
|
|
128
129
|
initialValue={step.defaultValue ?? ""}
|
|
129
|
-
placeholder={step.placeholder
|
|
130
|
+
placeholder={step.placeholder ? t(step.placeholder) : ""}
|
|
130
131
|
focused
|
|
131
132
|
textColor={colors.text}
|
|
132
133
|
placeholderColor={colors.textDim}
|
|
@@ -141,13 +142,13 @@ export function PaneTemplateTextareaStep({
|
|
|
141
142
|
backgroundColor={colors.selected}
|
|
142
143
|
onMouseDown={commit}
|
|
143
144
|
>
|
|
144
|
-
<Text fg={colors.selectedText}>{` Save `}</Text>
|
|
145
|
+
<Text fg={colors.selectedText}>{` ${t("Save")} `}</Text>
|
|
145
146
|
</Box>
|
|
146
147
|
<Box
|
|
147
148
|
backgroundColor={colors.panel}
|
|
148
149
|
onMouseDown={() => resolve("")}
|
|
149
150
|
>
|
|
150
|
-
<Text fg={colors.text}>{` Cancel `}</Text>
|
|
151
|
+
<Text fg={colors.text}>{` ${t("Cancel")} `}</Text>
|
|
151
152
|
</Box>
|
|
152
153
|
</Box>
|
|
153
154
|
</Box>
|
|
@@ -186,14 +187,14 @@ export function PaneTemplateSelectStep({
|
|
|
186
187
|
<Box flexDirection="column">
|
|
187
188
|
{step.body?.map((line, index) => (
|
|
188
189
|
<Box key={`${step.key}:${index}`} height={1}>
|
|
189
|
-
<Text fg={colors.textDim}>{line
|
|
190
|
+
<Text fg={colors.textDim}>{line ? t(line) : " "}</Text>
|
|
190
191
|
</Box>
|
|
191
192
|
))}
|
|
192
193
|
<Box height={1} />
|
|
193
194
|
<ListView
|
|
194
195
|
items={options.map((option) => ({
|
|
195
196
|
id: option.value,
|
|
196
|
-
label: option.label,
|
|
197
|
+
label: t(option.label),
|
|
197
198
|
}))}
|
|
198
199
|
selectedIndex={selectedIndex}
|
|
199
200
|
bgColor={colors.commandBg}
|
|
@@ -1,24 +1,10 @@
|
|
|
1
|
-
import { Box,
|
|
2
|
-
import {
|
|
1
|
+
import { Box, Text } from "../ui";
|
|
2
|
+
import { colors, priceColor } from "../theme/colors";
|
|
3
3
|
import { displayWidth, formatPercent, padTo } from "../utils/format";
|
|
4
4
|
import type { PriceReturnField } from "../market-data/performance";
|
|
5
5
|
|
|
6
|
-
type MouseInteractionEvent = {
|
|
7
|
-
stopPropagation?: () => void;
|
|
8
|
-
preventDefault?: () => void;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
6
|
const STRIP_COLUMN_GAP = 1;
|
|
12
7
|
const RETURN_CELL_MIN_WIDTH = 7;
|
|
13
|
-
const SYMBOL_COLUMN_MIN_WIDTH = 6;
|
|
14
|
-
const SYMBOL_COLUMN_MAX_WIDTH = 12;
|
|
15
|
-
|
|
16
|
-
export interface PriceReturnTableRow {
|
|
17
|
-
symbol: string;
|
|
18
|
-
color: string;
|
|
19
|
-
fields: PriceReturnField[];
|
|
20
|
-
selected: boolean;
|
|
21
|
-
}
|
|
22
8
|
|
|
23
9
|
function formatReturnValue(value: number | null): string {
|
|
24
10
|
return value == null ? "-" : formatPercent(value);
|
|
@@ -84,100 +70,3 @@ export function PriceReturnStrip({
|
|
|
84
70
|
</Box>
|
|
85
71
|
);
|
|
86
72
|
}
|
|
87
|
-
|
|
88
|
-
function getFieldById(fields: readonly PriceReturnField[], id: string): PriceReturnField | null {
|
|
89
|
-
return fields.find((field) => field.id === id) ?? null;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
function chooseComparisonFieldIds(width: number, availableIds: readonly string[]): string[] {
|
|
93
|
-
const preferred = width >= 86
|
|
94
|
-
? ["RNG", "1M", "3M", "6M", "1Y", "3Y", "5Y"]
|
|
95
|
-
: width >= 72
|
|
96
|
-
? ["RNG", "1M", "3M", "1Y", "3Y", "5Y"]
|
|
97
|
-
: width >= 58
|
|
98
|
-
? ["RNG", "1M", "1Y", "3Y", "5Y"]
|
|
99
|
-
: width >= 44
|
|
100
|
-
? ["RNG", "1M", "1Y", "5Y"]
|
|
101
|
-
: ["1Y", "5Y"];
|
|
102
|
-
const available = new Set(availableIds);
|
|
103
|
-
return preferred.filter((id) => available.has(id));
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
export function PriceReturnTable({
|
|
107
|
-
height,
|
|
108
|
-
onFocusInteraction,
|
|
109
|
-
onOpenSymbol,
|
|
110
|
-
onSelectSymbol,
|
|
111
|
-
rows,
|
|
112
|
-
width,
|
|
113
|
-
}: {
|
|
114
|
-
height: number;
|
|
115
|
-
onFocusInteraction?: (event: MouseInteractionEvent | null | undefined) => void;
|
|
116
|
-
onOpenSymbol: (symbol: string) => void;
|
|
117
|
-
onSelectSymbol: (symbol: string) => void;
|
|
118
|
-
rows: PriceReturnTableRow[];
|
|
119
|
-
width: number;
|
|
120
|
-
}) {
|
|
121
|
-
if (height <= 0 || rows.length === 0) return null;
|
|
122
|
-
|
|
123
|
-
const availableIds = rows[0]?.fields.map((field) => field.id) ?? [];
|
|
124
|
-
const fieldIds = chooseComparisonFieldIds(width, availableIds);
|
|
125
|
-
if (fieldIds.length === 0) return null;
|
|
126
|
-
|
|
127
|
-
const valueWidth = Math.max(
|
|
128
|
-
RETURN_CELL_MIN_WIDTH,
|
|
129
|
-
Math.floor((width - SYMBOL_COLUMN_MIN_WIDTH - fieldIds.length) / Math.max(fieldIds.length, 1)),
|
|
130
|
-
);
|
|
131
|
-
const symbolWidth = Math.min(
|
|
132
|
-
SYMBOL_COLUMN_MAX_WIDTH,
|
|
133
|
-
Math.max(SYMBOL_COLUMN_MIN_WIDTH, width - fieldIds.length * (valueWidth + 1)),
|
|
134
|
-
);
|
|
135
|
-
const fieldsById = rows[0]?.fields ?? [];
|
|
136
|
-
|
|
137
|
-
return (
|
|
138
|
-
<ScrollBox height={height} scrollY>
|
|
139
|
-
<Box flexDirection="column" width={width}>
|
|
140
|
-
<Box flexDirection="row" height={1}>
|
|
141
|
-
<Text fg={colors.textDim}>{padTo("Sym", symbolWidth)}</Text>
|
|
142
|
-
{fieldIds.map((fieldId) => {
|
|
143
|
-
const field = getFieldById(fieldsById, fieldId);
|
|
144
|
-
return (
|
|
145
|
-
<Box key={fieldId} flexDirection="row">
|
|
146
|
-
<Text fg={colors.textDim}>{" "}</Text>
|
|
147
|
-
<Text fg={colors.textDim}>{padTo(field?.label ?? fieldId, valueWidth, "right")}</Text>
|
|
148
|
-
</Box>
|
|
149
|
-
);
|
|
150
|
-
})}
|
|
151
|
-
</Box>
|
|
152
|
-
|
|
153
|
-
{rows.map((row) => (
|
|
154
|
-
<Box
|
|
155
|
-
key={row.symbol}
|
|
156
|
-
flexDirection="row"
|
|
157
|
-
height={1}
|
|
158
|
-
width={width}
|
|
159
|
-
backgroundColor={row.selected ? blendHex(colors.panel, colors.borderFocused, 0.18) : colors.panel}
|
|
160
|
-
onMouseOver={() => onSelectSymbol(row.symbol)}
|
|
161
|
-
onMouseDown={(event: any) => {
|
|
162
|
-
onFocusInteraction?.(event);
|
|
163
|
-
onSelectSymbol(row.symbol);
|
|
164
|
-
onOpenSymbol(row.symbol);
|
|
165
|
-
}}
|
|
166
|
-
>
|
|
167
|
-
<Text fg={row.color}>{padTo(`${row.selected ? ">" : " "} ${row.symbol}`, symbolWidth)}</Text>
|
|
168
|
-
{fieldIds.map((fieldId) => {
|
|
169
|
-
const field = getFieldById(row.fields, fieldId);
|
|
170
|
-
const value = field?.value ?? null;
|
|
171
|
-
return (
|
|
172
|
-
<Box key={fieldId} flexDirection="row">
|
|
173
|
-
<Text fg={colors.textDim}>{" "}</Text>
|
|
174
|
-
<Text fg={returnValueColor(value)}>{padTo(formatReturnValue(value), valueWidth, "right")}</Text>
|
|
175
|
-
</Box>
|
|
176
|
-
);
|
|
177
|
-
})}
|
|
178
|
-
</Box>
|
|
179
|
-
))}
|
|
180
|
-
</Box>
|
|
181
|
-
</ScrollBox>
|
|
182
|
-
);
|
|
183
|
-
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { colors } from "../../theme/colors";
|
|
1
|
+
import { colors, type ThemeColors } from "../../theme/colors";
|
|
2
2
|
import type { PricePoint } from "../../types/financials";
|
|
3
|
+
import { getPricePointTimestamp } from "../../utils/price-history";
|
|
3
4
|
|
|
4
5
|
const SPARKLINE_FALLBACK_POINTS = 22;
|
|
5
6
|
|
|
@@ -29,22 +30,15 @@ function closeValue(point: PricePoint): number | null {
|
|
|
29
30
|
return Number.isFinite(point.close) ? point.close : null;
|
|
30
31
|
}
|
|
31
32
|
|
|
32
|
-
function getPointTime(point: PricePoint): number {
|
|
33
|
-
const value = point.date as Date | string | number | null | undefined;
|
|
34
|
-
if (value instanceof Date) return value.getTime();
|
|
35
|
-
if (value == null) return Number.NaN;
|
|
36
|
-
return new Date(value).getTime();
|
|
37
|
-
}
|
|
38
|
-
|
|
39
33
|
export function resolveSparklineHistory(priceHistory: PricePoint[], period: PriceSparklinePeriod = "1M"): PricePoint[] {
|
|
40
|
-
const validHistory = priceHistory.filter((point) => Number.isFinite(
|
|
34
|
+
const validHistory = priceHistory.filter((point) => Number.isFinite(getPricePointTimestamp(point)));
|
|
41
35
|
const latest = validHistory.at(-1);
|
|
42
36
|
if (!latest) return [];
|
|
43
37
|
|
|
44
|
-
const latestTime =
|
|
38
|
+
const latestTime = getPricePointTimestamp(latest);
|
|
45
39
|
if (Number.isFinite(latestTime)) {
|
|
46
40
|
const cutoffTime = latestTime - PERIOD_WINDOW_DAYS[period] * 86_400_000;
|
|
47
|
-
const windowHistory = validHistory.filter((point) =>
|
|
41
|
+
const windowHistory = validHistory.filter((point) => getPricePointTimestamp(point) >= cutoffTime);
|
|
48
42
|
if (windowHistory.length >= 2) return windowHistory;
|
|
49
43
|
}
|
|
50
44
|
|
|
@@ -57,15 +51,19 @@ export function sparklineValues(priceHistory: PricePoint[]): number[] {
|
|
|
57
51
|
.filter((value): value is number => value != null);
|
|
58
52
|
}
|
|
59
53
|
|
|
60
|
-
export function sparklineColor(
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
54
|
+
export function sparklineColor(
|
|
55
|
+
values: number[],
|
|
56
|
+
trend?: PriceSparklineTrend,
|
|
57
|
+
palette: ThemeColors = colors,
|
|
58
|
+
): string {
|
|
59
|
+
if (trend === "positive") return palette.positive;
|
|
60
|
+
if (trend === "negative") return palette.negative;
|
|
61
|
+
if (trend === "neutral") return palette.textMuted;
|
|
64
62
|
|
|
65
63
|
const first = values[0];
|
|
66
64
|
const last = values.at(-1);
|
|
67
|
-
if (first == null || last == null) return
|
|
68
|
-
return last >= first ?
|
|
65
|
+
if (first == null || last == null) return palette.textMuted;
|
|
66
|
+
return last >= first ? palette.positive : palette.negative;
|
|
69
67
|
}
|
|
70
68
|
|
|
71
69
|
export function buildSamples(values: number[], width: number, height: number, padding: number): SparklineSample[] {
|
|
@@ -7,7 +7,6 @@ import {
|
|
|
7
7
|
useUiCapabilities,
|
|
8
8
|
useUiHost,
|
|
9
9
|
} from "../../ui";
|
|
10
|
-
import { colors } from "../../theme/colors";
|
|
11
10
|
import { useThemeColors } from "../../theme/theme-context";
|
|
12
11
|
import type { PricePoint } from "../../types/financials";
|
|
13
12
|
import { resolveNativeBitmapSize, shouldRenderNativeBitmap } from "../chart/native/bitmap-support";
|
|
@@ -37,16 +36,18 @@ function DesktopPriceSparkline({
|
|
|
37
36
|
width,
|
|
38
37
|
height,
|
|
39
38
|
color,
|
|
39
|
+
emptyColor,
|
|
40
40
|
}: {
|
|
41
41
|
values: number[];
|
|
42
42
|
width: number;
|
|
43
43
|
height: number;
|
|
44
44
|
color: string;
|
|
45
|
+
emptyColor: string;
|
|
45
46
|
}) {
|
|
46
47
|
const svgWidth = Math.max(24, width * 8);
|
|
47
48
|
const svgHeight = Math.max(18, height * 18);
|
|
48
49
|
const path = svgPath(buildSamples(values, svgWidth, svgHeight, 2));
|
|
49
|
-
if (!path) return <Text fg={
|
|
50
|
+
if (!path) return <Text fg={emptyColor}>{" "}</Text>;
|
|
50
51
|
|
|
51
52
|
return (
|
|
52
53
|
<Box width={width} height={height} justifyContent="center" overflow="hidden">
|
|
@@ -149,7 +150,7 @@ export function PriceSparkline({
|
|
|
149
150
|
height?: number;
|
|
150
151
|
area?: boolean;
|
|
151
152
|
}) {
|
|
152
|
-
useThemeColors();
|
|
153
|
+
const colors = useThemeColors();
|
|
153
154
|
const uiHost = useUiHost();
|
|
154
155
|
const sparklineHistory = useMemo(() => resolveSparklineHistory(priceHistory ?? [], period), [period, priceHistory]);
|
|
155
156
|
const values = useMemo(() => sparklineValues(sparklineHistory), [sparklineHistory]);
|
|
@@ -157,9 +158,9 @@ export function PriceSparkline({
|
|
|
157
158
|
return <Text fg={colors.textMuted}>{" "}</Text>;
|
|
158
159
|
}
|
|
159
160
|
|
|
160
|
-
const color = sparklineColor(values, trend);
|
|
161
|
+
const color = sparklineColor(values, trend, colors);
|
|
161
162
|
return uiHost.kind === "desktop-web"
|
|
162
|
-
? <DesktopPriceSparkline values={values} width={width} height={height} color={color} />
|
|
163
|
+
? <DesktopPriceSparkline values={values} width={width} height={height} color={color} emptyColor={colors.textMuted} />
|
|
163
164
|
: <TerminalPriceSparkline priceHistory={sparklineHistory} values={values} width={width} height={height} color={color} area={area} />;
|
|
164
165
|
}
|
|
165
166
|
|
|
@@ -172,13 +173,13 @@ export function PriceAreaSparklineBackground({
|
|
|
172
173
|
trend?: PriceSparklineTrend;
|
|
173
174
|
period?: PriceSparklinePeriod;
|
|
174
175
|
}) {
|
|
175
|
-
useThemeColors();
|
|
176
|
+
const colors = useThemeColors();
|
|
176
177
|
const uiHost = useUiHost();
|
|
177
178
|
const sparklineHistory = useMemo(() => resolveSparklineHistory(priceHistory ?? [], period), [period, priceHistory]);
|
|
178
179
|
const values = useMemo(() => sparklineValues(sparklineHistory), [sparklineHistory]);
|
|
179
180
|
if (uiHost.kind !== "desktop-web" || values.length < 2) return null;
|
|
180
181
|
|
|
181
|
-
const color = sparklineColor(values, trend);
|
|
182
|
+
const color = sparklineColor(values, trend, colors);
|
|
182
183
|
const baseline = 100;
|
|
183
184
|
const samples = buildSamples(values, 100, baseline, 0);
|
|
184
185
|
const linePath = svgPath(samples);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createElement, type SVGProps } from "react";
|
|
2
2
|
import { Box } from "../../ui";
|
|
3
|
-
import {
|
|
3
|
+
import { useThemeColors } from "../../theme/theme-context";
|
|
4
4
|
import {
|
|
5
5
|
compactSegmentLabel,
|
|
6
6
|
formatGaugeValue,
|
|
@@ -54,6 +54,7 @@ export function DesktopSpeedometerGauge({
|
|
|
54
54
|
maxWidth,
|
|
55
55
|
compact,
|
|
56
56
|
}: Required<SpeedometerGaugeProps>) {
|
|
57
|
+
const colors = useThemeColors();
|
|
57
58
|
const gaugeWidth = Math.min(Math.max(width - 2, minWidth), maxWidth);
|
|
58
59
|
const gaugeHeight = compact ? 9 : 12;
|
|
59
60
|
const viewBoxHeight = compact ? DESKTOP_COMPACT_VIEWBOX_HEIGHT : DESKTOP_VIEWBOX_HEIGHT;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { useUiHost } from "../../ui";
|
|
2
|
-
import { useThemeColors } from "../../theme/theme-context";
|
|
3
2
|
import { DesktopSpeedometerGauge } from "./desktop";
|
|
4
3
|
import {
|
|
5
4
|
DEFAULT_MAX_WIDTH,
|
|
@@ -25,7 +24,6 @@ export function SpeedometerGauge({
|
|
|
25
24
|
maxWidth = DEFAULT_MAX_WIDTH,
|
|
26
25
|
compact = false,
|
|
27
26
|
}: SpeedometerGaugeProps) {
|
|
28
|
-
useThemeColors();
|
|
29
27
|
const props = {
|
|
30
28
|
value,
|
|
31
29
|
valueLabel,
|
|
@@ -3,7 +3,8 @@ import { Box, ChartSurface, Span, Text, TextAttributes, useNativeRenderer, useUi
|
|
|
3
3
|
import type { NativeChartBitmap } from "../chart/native/chart-rasterizer";
|
|
4
4
|
import { resolveNativeBitmapSize, shouldRenderNativeBitmap } from "../chart/native/bitmap-support";
|
|
5
5
|
import { drawCircle, drawLine, parseHex } from "../chart/native/raster/primitives";
|
|
6
|
-
import {
|
|
6
|
+
import { useThemeColors } from "../../theme/theme-context";
|
|
7
|
+
import type { ThemeColors } from "../../theme/colors";
|
|
7
8
|
import {
|
|
8
9
|
compactSegmentLabel,
|
|
9
10
|
formatGaugeValue,
|
|
@@ -73,7 +74,7 @@ function renderLabelRow(width: number, min: number, max: number, segments: Speed
|
|
|
73
74
|
return cellsToChunks(cells);
|
|
74
75
|
}
|
|
75
76
|
|
|
76
|
-
function renderTickRow(width: number, min: number, max: number): GaugeChunk[] {
|
|
77
|
+
function renderTickRow(width: number, min: number, max: number, colors: Pick<ThemeColors, "textDim">): GaugeChunk[] {
|
|
77
78
|
const cells = blankGaugeLine(width);
|
|
78
79
|
for (const tick of [min, min + (max - min) * 0.25, min + (max - min) * 0.5, min + (max - min) * 0.75, max]) {
|
|
79
80
|
placeText(cells, formatGaugeValue(tick), normalizeValue(tick, min, max) * (width - 1), colors.textDim);
|
|
@@ -81,7 +82,14 @@ function renderTickRow(width: number, min: number, max: number): GaugeChunk[] {
|
|
|
81
82
|
return cellsToChunks(cells);
|
|
82
83
|
}
|
|
83
84
|
|
|
84
|
-
function renderArcRows(
|
|
85
|
+
function renderArcRows(
|
|
86
|
+
value: number,
|
|
87
|
+
min: number,
|
|
88
|
+
max: number,
|
|
89
|
+
width: number,
|
|
90
|
+
segments: SpeedometerSegment[],
|
|
91
|
+
colors: Pick<ThemeColors, "textDim" | "textBright">,
|
|
92
|
+
): GaugeChunk[][] {
|
|
85
93
|
const dialHeight = 7;
|
|
86
94
|
const dial = Array.from({ length: dialHeight }, () => blankGaugeLine(width));
|
|
87
95
|
const centerX = Math.floor((width - 1) / 2);
|
|
@@ -144,6 +152,7 @@ function renderGaugeBitmap(
|
|
|
144
152
|
segments: SpeedometerSegment[],
|
|
145
153
|
pixelWidth: number,
|
|
146
154
|
pixelHeight: number,
|
|
155
|
+
colors: Pick<ThemeColors, "textDim" | "textBright">,
|
|
147
156
|
): NativeChartBitmap {
|
|
148
157
|
const pixels = new Uint8Array(pixelWidth * pixelHeight * 4);
|
|
149
158
|
const centerX = pixelWidth / 2;
|
|
@@ -193,6 +202,7 @@ export function TerminalSpeedometerGauge({
|
|
|
193
202
|
minWidth,
|
|
194
203
|
maxWidth,
|
|
195
204
|
}: Required<SpeedometerGaugeProps>) {
|
|
205
|
+
const colors = useThemeColors();
|
|
196
206
|
const {
|
|
197
207
|
nativeCharts,
|
|
198
208
|
cellWidthPx = 8,
|
|
@@ -202,8 +212,14 @@ export function TerminalSpeedometerGauge({
|
|
|
202
212
|
const nativeRenderer = useNativeRenderer();
|
|
203
213
|
const gaugeWidth = Math.max(minWidth, Math.min(maxWidth, Math.floor(width - 4)));
|
|
204
214
|
const labelRow = useMemo(() => renderLabelRow(gaugeWidth, min, max, segments), [gaugeWidth, max, min, segments]);
|
|
205
|
-
const tickRow = useMemo(
|
|
206
|
-
|
|
215
|
+
const tickRow = useMemo(
|
|
216
|
+
() => renderTickRow(gaugeWidth, min, max, colors),
|
|
217
|
+
[colors.textDim, gaugeWidth, max, min],
|
|
218
|
+
);
|
|
219
|
+
const arcRows = useMemo(
|
|
220
|
+
() => renderArcRows(value, min, max, gaugeWidth, segments, colors),
|
|
221
|
+
[colors.textBright, colors.textDim, gaugeWidth, max, min, segments, value],
|
|
222
|
+
);
|
|
207
223
|
const rendererCapabilities = nativeRenderer.capabilities;
|
|
208
224
|
const rendererResolution = nativeRenderer.resolution;
|
|
209
225
|
const rendererTerminalWidth = nativeRenderer.terminalWidth;
|
|
@@ -227,11 +243,14 @@ export function TerminalSpeedometerGauge({
|
|
|
227
243
|
segments,
|
|
228
244
|
bitmapSize.pixelWidth,
|
|
229
245
|
bitmapSize.pixelHeight,
|
|
246
|
+
colors,
|
|
230
247
|
);
|
|
231
248
|
}, [
|
|
232
249
|
arcRows.length,
|
|
233
250
|
cellHeightPx,
|
|
234
251
|
cellWidthPx,
|
|
252
|
+
colors.textBright,
|
|
253
|
+
colors.textDim,
|
|
235
254
|
gaugeWidth,
|
|
236
255
|
max,
|
|
237
256
|
min,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Box, Text, useTickerContextMenu, useUiCapabilities } from "../../../ui";
|
|
2
2
|
import { TextAttributes } from "../../../ui";
|
|
3
|
-
import { colors, priceColor } from "../../../theme/colors";
|
|
3
|
+
import { blendHex, colors, priceColor } from "../../../theme/colors";
|
|
4
4
|
import { getSharedRegistry } from "../../../plugins/registry";
|
|
5
5
|
import type { Quote } from "../../../types/financials";
|
|
6
6
|
import { getTickerBadgeText } from "./format";
|
|
@@ -16,23 +16,6 @@ export interface TickerBadgeProps {
|
|
|
16
16
|
onOpen: (symbol: string) => void;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
function blendHex(base: string, accent: string, ratio: number): string {
|
|
20
|
-
const parse = (hex: string) => {
|
|
21
|
-
const value = hex.replace("#", "");
|
|
22
|
-
return [
|
|
23
|
-
parseInt(value.slice(0, 2), 16),
|
|
24
|
-
parseInt(value.slice(2, 4), 16),
|
|
25
|
-
parseInt(value.slice(4, 6), 16),
|
|
26
|
-
] as const;
|
|
27
|
-
};
|
|
28
|
-
const [br, bg, bb] = parse(base);
|
|
29
|
-
const [ar, ag, ab] = parse(accent);
|
|
30
|
-
const mix = (left: number, right: number) => Math.round(left + (right - left) * ratio)
|
|
31
|
-
.toString(16)
|
|
32
|
-
.padStart(2, "0");
|
|
33
|
-
return `#${mix(br, ar)}${mix(bg, ag)}${mix(bb, ab)}`;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
19
|
export function TickerBadge({
|
|
37
20
|
symbol,
|
|
38
21
|
status,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
2
2
|
import { Box, ScrollBox, Text, TextAttributes, useNativeRenderer } from "../../../../ui";
|
|
3
|
-
import {
|
|
3
|
+
import { hoverBg } from "../../../../theme/colors";
|
|
4
4
|
import { useThemeColors } from "../../../../theme/theme-context";
|
|
5
5
|
import { useAppDispatch, usePaneInstance } from "../../../../state/app/context";
|
|
6
6
|
import { useViewport } from "../../../../react/input";
|
|
@@ -67,7 +67,7 @@ export function OpenTuiDataTable<T, C extends DataTableColumn = DataTableColumn>
|
|
|
67
67
|
scrollToIndexAlign = "nearest",
|
|
68
68
|
scrollToIndexVersion = 0,
|
|
69
69
|
}: DataTableProps<T, C>) {
|
|
70
|
-
useThemeColors();
|
|
70
|
+
const colors = useThemeColors();
|
|
71
71
|
const dispatch = useAppDispatch();
|
|
72
72
|
const paneInstanceId = usePaneInstance()?.instanceId ?? null;
|
|
73
73
|
const appViewport = useViewport();
|
|
@@ -376,7 +376,7 @@ export function OpenTuiDataTable<T, C extends DataTableColumn = DataTableColumn>
|
|
|
376
376
|
const rowBg = selected
|
|
377
377
|
? colors.selected
|
|
378
378
|
: rowBackgroundColor ?? colors.bg;
|
|
379
|
-
const rowHoverBg = selected ? undefined : hoverBg();
|
|
379
|
+
const rowHoverBg = selected ? undefined : hoverBg(colors);
|
|
380
380
|
|
|
381
381
|
return (
|
|
382
382
|
<Box
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { Box, Text, useUiHost } from "../../ui";
|
|
2
2
|
import { TextAttributes } from "../../ui";
|
|
3
3
|
import { type ComponentType, type ReactNode } from "react";
|
|
4
|
-
import { colors } from "../../theme/colors";
|
|
5
4
|
import { t } from "../../i18n";
|
|
6
5
|
import { useThemeColors } from "../../theme/theme-context";
|
|
7
6
|
|
|
@@ -15,7 +14,7 @@ export interface DialogFrameProps {
|
|
|
15
14
|
export function DialogFrame({ title: rawTitle, children, footer: rawFooter, showTitleDivider = false }: DialogFrameProps) {
|
|
16
15
|
const title = t(rawTitle);
|
|
17
16
|
const footer = rawFooter === undefined ? undefined : t(rawFooter);
|
|
18
|
-
useThemeColors();
|
|
17
|
+
const colors = useThemeColors();
|
|
19
18
|
const HostDialogFrame = useUiHost().DialogFrame as ComponentType<DialogFrameProps> | undefined;
|
|
20
19
|
if (HostDialogFrame) {
|
|
21
20
|
return (
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { afterEach, describe, expect, test } from "bun:test";
|
|
2
|
+
import { act, useMemo, useState } from "react";
|
|
3
|
+
import { testRender } from "../../renderers/opentui/test-utils";
|
|
4
|
+
import { openTuiUiHost } from "../../renderers/opentui/ui-host";
|
|
5
|
+
import {
|
|
6
|
+
Box,
|
|
7
|
+
Text,
|
|
8
|
+
UiHostProvider,
|
|
9
|
+
type RendererHost,
|
|
10
|
+
type UiHost,
|
|
11
|
+
} from "../../ui";
|
|
12
|
+
import { PageStackView, type PageStackViewProps } from "./page-stack-view";
|
|
13
|
+
|
|
14
|
+
let testSetup: Awaited<ReturnType<typeof testRender>> | undefined;
|
|
15
|
+
let setUseHost: ((useHost: boolean) => void) | undefined;
|
|
16
|
+
let backCalls = 0;
|
|
17
|
+
|
|
18
|
+
const rendererHost: RendererHost = {
|
|
19
|
+
requestExit() {},
|
|
20
|
+
openExternal: async () => {},
|
|
21
|
+
copyText: async () => {},
|
|
22
|
+
readText: async () => "",
|
|
23
|
+
notify() {},
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
afterEach(async () => {
|
|
27
|
+
setUseHost = undefined;
|
|
28
|
+
backCalls = 0;
|
|
29
|
+
if (!testSetup) return;
|
|
30
|
+
await act(async () => {
|
|
31
|
+
testSetup!.renderer.destroy();
|
|
32
|
+
});
|
|
33
|
+
testSetup = undefined;
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
function HostPageStackView({ detailContent }: PageStackViewProps) {
|
|
37
|
+
return (
|
|
38
|
+
<Box flexDirection="column">
|
|
39
|
+
<Text>Host page stack</Text>
|
|
40
|
+
{detailContent}
|
|
41
|
+
</Box>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function HostSwitchHarness() {
|
|
46
|
+
const [useHost, updateUseHost] = useState(false);
|
|
47
|
+
setUseHost = updateUseHost;
|
|
48
|
+
const ui = useMemo<UiHost>(() => ({
|
|
49
|
+
...openTuiUiHost,
|
|
50
|
+
PageStackView: useHost ? HostPageStackView : undefined,
|
|
51
|
+
}), [useHost]);
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<UiHostProvider ui={ui} renderer={rendererHost}>
|
|
55
|
+
<PageStackView
|
|
56
|
+
focused
|
|
57
|
+
detailOpen
|
|
58
|
+
onBack={() => {}}
|
|
59
|
+
rootContent={<Text>Root content</Text>}
|
|
60
|
+
detailContent={<Text>Detail content</Text>}
|
|
61
|
+
detailTitle="Detail title"
|
|
62
|
+
/>
|
|
63
|
+
</UiHostProvider>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function MouseBackHarness() {
|
|
68
|
+
const [detailOpen, setDetailOpen] = useState(true);
|
|
69
|
+
return (
|
|
70
|
+
<PageStackView
|
|
71
|
+
focused
|
|
72
|
+
detailOpen={detailOpen}
|
|
73
|
+
onBack={() => {
|
|
74
|
+
backCalls += 1;
|
|
75
|
+
setDetailOpen(false);
|
|
76
|
+
}}
|
|
77
|
+
rootContent={<Text>Root content</Text>}
|
|
78
|
+
detailContent={<Text>Detail content</Text>}
|
|
79
|
+
detailTitle="Detail title"
|
|
80
|
+
/>
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
describe("PageStackView", () => {
|
|
85
|
+
test("can switch between the fallback and host implementations without changing hook topology", async () => {
|
|
86
|
+
testSetup = await testRender(<HostSwitchHarness />, { width: 48, height: 8 });
|
|
87
|
+
await testSetup.renderOnce();
|
|
88
|
+
expect(testSetup.captureCharFrame()).toContain("← Back Detail title");
|
|
89
|
+
|
|
90
|
+
await act(async () => {
|
|
91
|
+
setUseHost?.(true);
|
|
92
|
+
await Promise.resolve();
|
|
93
|
+
});
|
|
94
|
+
await act(async () => {
|
|
95
|
+
await testSetup!.renderOnce();
|
|
96
|
+
});
|
|
97
|
+
expect(testSetup.captureCharFrame()).toContain("Host page stack");
|
|
98
|
+
|
|
99
|
+
await act(async () => {
|
|
100
|
+
setUseHost?.(false);
|
|
101
|
+
await Promise.resolve();
|
|
102
|
+
});
|
|
103
|
+
await act(async () => {
|
|
104
|
+
await testSetup!.renderOnce();
|
|
105
|
+
});
|
|
106
|
+
expect(testSetup.captureCharFrame()).toContain("← Back Detail title");
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
test("keeps the fallback back action mouse-accessible", async () => {
|
|
110
|
+
testSetup = await testRender(<MouseBackHarness />, { width: 48, height: 8 });
|
|
111
|
+
await testSetup.renderOnce();
|
|
112
|
+
expect(testSetup.captureCharFrame()).toContain("Detail content");
|
|
113
|
+
|
|
114
|
+
await act(async () => {
|
|
115
|
+
await testSetup!.mockMouse.click(1, 0);
|
|
116
|
+
await Promise.resolve();
|
|
117
|
+
});
|
|
118
|
+
await act(async () => {
|
|
119
|
+
await testSetup!.renderOnce();
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
expect(backCalls).toBe(1);
|
|
123
|
+
expect(testSetup.captureCharFrame()).toContain("Root content");
|
|
124
|
+
expect(testSetup.captureCharFrame()).not.toContain("Detail content");
|
|
125
|
+
});
|
|
126
|
+
});
|