gloomberb 0.17.0 → 0.17.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/{plugins/builtin/cloud → account}/auth-dialog.tsx +7 -7
- package/src/api-client/data.ts +5 -1
- package/src/api-client/doe.ts +19 -0
- package/src/api-client/earnings.ts +4 -2
- package/src/api-client/index.ts +1 -0
- package/src/app/global-shortcuts.ts +10 -0
- package/src/app/keybindings/actions.ts +16 -0
- package/src/app/runtime/desktop-deeplink.ts +1 -1
- package/src/app/runtime/update.ts +16 -0
- package/src/app.tsx +1 -1
- package/src/architecture/core-builtin-allowlist.json +4 -9
- package/src/architecture/dom-cell-metrics-allowlist.json +100 -26
- package/src/cli/commands/market.ts +87 -17
- package/src/cli/commands/options-chain.ts +93 -23
- package/src/cli/commands/options-leaps.ts +462 -63
- package/src/cli/commands/search.ts +10 -7
- package/src/cli/commands/ticker.ts +19 -10
- package/src/cli/glossary.ts +1 -1
- package/src/cli/index.ts +14 -6
- package/src/cli/known-gaps.ts +22 -0
- package/src/cli/pane-functions/catalog.ts +45 -10
- package/src/cli/pane-functions/dom.ts +36 -10
- package/src/cli/pane-functions/function-help.ts +4 -2
- package/src/cli/pane-functions/headless.ts +12 -1
- package/src/cli/pane-functions/index.ts +44 -3
- package/src/cli/pane-functions/lock-note.ts +56 -0
- package/src/cli/pane-functions/report-notices.ts +15 -0
- package/src/cli/symbol-args.ts +19 -0
- package/src/components/command-bar/list/view.tsx +2 -1
- package/src/components/command-bar/workflow/builtin.ts +2 -2
- package/src/components/command-bar/workflow/collection-actions.ts +1 -1
- package/src/components/feedback-dialog.tsx +1 -1
- package/src/components/index.ts +3 -2
- package/src/components/layout/header.tsx +58 -14
- package/src/components/layout/shell/chrome.ts +10 -4
- package/src/components/layout/shell/index.tsx +1 -1
- package/src/components/layout/status-bar-groups.ts +1 -1
- package/src/components/layout/status-bar.tsx +2 -2
- package/src/components/markdown-text.tsx +14 -2
- package/src/components/reader/article-reader.tsx +1 -1
- package/src/components/reader/detail-reader.tsx +10 -7
- package/src/components/reader/reader-text.tsx +32 -17
- package/src/components/ui/column-grid.tsx +206 -0
- package/src/components/ui/display.tsx +40 -3
- package/src/components/ui/fill.ts +8 -0
- package/src/components/ui/index.ts +2 -0
- package/src/layout-marketplace/gallery.tsx +2 -2
- package/src/layout-marketplace/linked-sync.ts +1 -1
- package/src/market-data/market/freshness.ts +3 -0
- package/src/market-data/published-apac-sessions.ts +12 -2
- package/src/market-data/quotes/screener-live-quotes.ts +31 -7
- package/src/plugins/builtin/account-management/form-components.tsx +4 -7
- package/src/plugins/builtin/account-management/password-dialog.tsx +3 -2
- package/src/plugins/builtin/backtest/pane.tsx +9 -3
- package/src/plugins/builtin/buildout/detail/company.tsx +4 -3
- package/src/plugins/builtin/buildout/detail/ui.tsx +9 -12
- package/src/plugins/builtin/chart-composer/index.tsx +1 -1
- package/src/plugins/builtin/chart-composer/presets.ts +33 -1
- package/src/plugins/builtin/chat/channel-labels.ts +2 -2
- package/src/plugins/builtin/chat/content/channel-navigation.ts +1 -1
- package/src/plugins/builtin/chat/content/index.tsx +2 -2
- package/src/plugins/builtin/chat/conversations.ts +1 -1
- package/src/plugins/builtin/chat/index.tsx +2 -2
- package/src/plugins/builtin/chat/share/flow.tsx +1 -1
- package/src/plugins/builtin/chat/sidebar-rows.ts +1 -1
- package/src/plugins/builtin/chat/sidebar.tsx +2 -2
- package/src/plugins/builtin/chat/unread-inbox-pane.tsx +2 -2
- package/src/plugins/builtin/cloud/askg/pane.tsx +2 -1
- package/src/plugins/builtin/cloud/askg/tool-timeline.tsx +3 -2
- package/src/plugins/builtin/cloud/auth-actions.tsx +1 -1
- package/src/plugins/builtin/cloud/auth-commands.ts +1 -1
- package/src/plugins/builtin/cloud/mcp-connect/dialog.tsx +1 -1
- package/src/plugins/builtin/cloud/team/acm-tab.tsx +3 -3
- package/src/plugins/builtin/cloud/team/capability.ts +2 -2
- package/src/plugins/builtin/cloud/team/command.ts +4 -4
- package/src/plugins/builtin/cloud/team/module.tsx +3 -3
- package/src/plugins/builtin/cloud/team/pane-model.ts +2 -2
- package/src/plugins/builtin/cloud/team/pane-sections.tsx +1 -1
- package/src/plugins/builtin/cloud/team/pane-ui.tsx +1 -1
- package/src/plugins/builtin/cloud/team/pane.tsx +3 -3
- package/src/plugins/builtin/cloud/team/status-widget.tsx +3 -3
- package/src/plugins/builtin/cloud/team/team-state-host.ts +1 -1
- package/src/plugins/builtin/cloud/team/views.ts +2 -2
- package/src/plugins/builtin/cloud/thesis/board-pane.tsx +1 -1
- package/src/plugins/builtin/cloud/thesis/detail.tsx +12 -10
- package/src/plugins/builtin/cloud/thesis/ticker-tab.tsx +1 -1
- package/src/plugins/builtin/cloud/upgrade-command.ts +1 -1
- package/src/plugins/builtin/congress-trades/detail.tsx +8 -4
- package/src/plugins/builtin/connections/pane.tsx +16 -5
- package/src/plugins/builtin/cpi/pane.tsx +5 -4
- package/src/plugins/builtin/custom-view/pane.tsx +2 -2
- package/src/plugins/builtin/dividend-yield/headless.ts +8 -2
- package/src/plugins/builtin/dividend-yield/pane.tsx +4 -2
- package/src/plugins/builtin/docs/blocks.tsx +13 -2
- package/src/plugins/builtin/docs/pane.tsx +6 -5
- package/src/plugins/builtin/doe/index.tsx +11 -4
- package/src/plugins/builtin/doe/pane.tsx +5 -4
- package/src/plugins/builtin/doe/prices.ts +84 -0
- package/src/plugins/builtin/doe/series.ts +4 -1
- package/src/plugins/builtin/earnings/board-model.ts +18 -1
- package/src/plugins/builtin/earnings/board-table.ts +18 -3
- package/src/plugins/builtin/earnings/headless.ts +13 -2
- package/src/plugins/builtin/earnings/history-model.ts +1 -1
- package/src/plugins/builtin/earnings/history-table.ts +2 -2
- package/src/plugins/builtin/earnings-calls/headless.ts +7 -21
- package/src/plugins/builtin/earnings-calls/index.tsx +2 -0
- package/src/plugins/builtin/earnings-calls/lock-note.ts +17 -0
- package/src/plugins/builtin/equity-screener/headless.ts +59 -1
- package/src/plugins/builtin/equity-screener/live.ts +82 -31
- package/src/plugins/builtin/equity-screener/pane.tsx +60 -23
- package/src/plugins/builtin/estimate-revisions/client.ts +1 -1
- package/src/plugins/builtin/estimate-revisions/headless.ts +9 -2
- package/src/plugins/builtin/estimate-revisions/index.tsx +3 -0
- package/src/plugins/builtin/estimate-revisions/lock-note.ts +23 -0
- package/src/plugins/builtin/executives/index.tsx +18 -0
- package/src/plugins/builtin/exposure/charts.tsx +4 -3
- package/src/plugins/builtin/filing-events/index.tsx +8 -10
- package/src/plugins/builtin/fixed-income/pane.tsx +2 -1
- package/src/plugins/builtin/gpu/equities.tsx +9 -6
- package/src/plugins/builtin/help/feedback-tab.tsx +1 -1
- package/src/plugins/builtin/iv-history/format.ts +3 -0
- package/src/plugins/builtin/iv-history/headless.ts +3 -1
- package/src/plugins/builtin/iv-history/index.tsx +3 -1
- package/src/plugins/builtin/iv-history/model.ts +3 -1
- package/src/plugins/builtin/iv-history/screen-pane.tsx +3 -1
- package/src/plugins/builtin/iv-history/universe.ts +1 -1
- package/src/plugins/builtin/jobs/headless.ts +6 -20
- package/src/plugins/builtin/jobs/index.tsx +2 -0
- package/src/plugins/builtin/jobs/lock-note.ts +16 -0
- package/src/plugins/builtin/notes/index.tsx +1 -1
- package/src/plugins/builtin/notes/owner.tsx +2 -2
- package/src/plugins/builtin/options/carry.ts +36 -0
- package/src/plugins/builtin/options/index.tsx +2 -1
- package/src/plugins/builtin/options/model-spot.ts +94 -0
- package/src/plugins/builtin/options/open-interest-as-of.ts +74 -0
- package/src/plugins/builtin/options/view.tsx +69 -11
- package/src/plugins/builtin/options-calculator/pane.tsx +56 -1
- package/src/plugins/builtin/options-calculator/premium-history.ts +34 -0
- package/src/plugins/builtin/options-scenario/client.ts +33 -9
- package/src/plugins/builtin/options-scenario/csp.ts +168 -0
- package/src/plugins/builtin/options-scenario/evidence.ts +3 -0
- package/src/plugins/builtin/options-scenario/headless.ts +24 -8
- package/src/plugins/builtin/options-scenario/index.tsx +3 -1
- package/src/plugins/builtin/options-scenario/pane.tsx +32 -6
- package/src/plugins/builtin/portfolio-list/mutations.ts +1 -1
- package/src/plugins/builtin/portfolio-list/pane/remove-ticker.ts +1 -1
- package/src/plugins/builtin/research/corporate-actions-pane.tsx +4 -2
- package/src/plugins/builtin/research/event-model.ts +7 -4
- package/src/plugins/builtin/risk-factors/index.tsx +18 -0
- package/src/plugins/builtin/risk-factors/pane.tsx +2 -1
- package/src/plugins/builtin/scanner/headless.ts +9 -2
- package/src/plugins/builtin/scanner/index.ts +3 -0
- package/src/plugins/builtin/scanner/lock-note.ts +17 -0
- package/src/plugins/builtin/series-inventory.ts +2 -1
- package/src/plugins/builtin/shared/cloud-denied.ts +39 -8
- package/src/plugins/builtin/shared/earnings-report.ts +10 -4
- package/src/plugins/builtin/shared/pro-lock-note.ts +58 -0
- package/src/plugins/builtin/shared/series-list-detail.tsx +10 -5
- package/src/plugins/builtin/social-mentions/client.ts +3 -3
- package/src/plugins/builtin/social-mentions/headless.ts +6 -2
- package/src/plugins/builtin/social-mentions/index.tsx +2 -1
- package/src/plugins/builtin/social-mentions/lock-note.ts +15 -0
- package/src/plugins/builtin/supply-chain/flow.tsx +15 -13
- package/src/plugins/builtin/supply-chain/graph.tsx +6 -4
- package/src/plugins/builtin/supply-chain/pane.tsx +8 -5
- package/src/plugins/builtin/ticker-detail/financials/aggregation.ts +14 -1
- package/src/plugins/builtin/ticker-detail/financials/ratios.ts +9 -7
- package/src/plugins/builtin/ticker-detail/headless.ts +4 -1
- package/src/plugins/builtin/ticker-detail/overview/components.tsx +105 -104
- package/src/plugins/builtin/ticker-detail/overview/model.ts +9 -2
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +34 -8
- package/src/plugins/builtin/vol-surface/pane.tsx +6 -3
- package/src/public/__snapshots__/public-api.test.ts.snap +2 -0
- package/src/renderers/dom/data-table/index.tsx +48 -15
- package/src/renderers/dom/data-table/row.tsx +1 -1
- package/src/renderers/dom/desktop/popover.tsx +6 -15
- package/src/renderers/dom/host/input.tsx +27 -3
- package/src/renderers/dom/host/surface-3d.tsx +6 -4
- package/src/renderers/dom/styles.css +26 -6
- package/src/renderers/electrobun/view/app-services.ts +2 -22
- package/src/renderers/electrobun/view/news-source.ts +42 -0
- package/src/series/validate.ts +5 -0
- package/src/shares/dialog.tsx +2 -1
- package/src/sources/gloomberb-cloud/normalizers.ts +2 -0
- package/src/sources/provider-router/financials.ts +5 -0
- package/src/{plugins/builtin/cloud/team → team}/collections-sync.ts +6 -6
- package/src/{plugins/builtin/cloud/team → team}/collections.ts +3 -3
- package/src/{plugins/builtin/cloud/team → team}/model.ts +2 -2
- package/src/{plugins/builtin/cloud/team → team}/pane-request.ts +1 -1
- package/src/{plugins/builtin/cloud/team → team}/store.ts +3 -3
- package/src/types/data-provider.ts +3 -0
- package/src/types/financials.ts +28 -0
- package/src/types/plugin.ts +17 -4
- package/src/utils/decimal-comma.ts +18 -0
- package/src/utils/exchanges.ts +7 -0
- package/src/utils/financial-statements.ts +25 -0
- package/src/utils/forward-dividend.ts +39 -9
- package/src/utils/fundamentals.ts +41 -1
- package/src/utils/option-expiry.ts +16 -0
- package/src/utils/sec.ts +2 -1
|
@@ -26,6 +26,21 @@ export function renderedReportNotices(semanticUi: readonly RemoteUiNodeSnapshot[
|
|
|
26
26
|
return { notices, facts };
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
/**
|
|
30
|
+
* Why a rendered pane cannot give the report it was asked for, from the
|
|
31
|
+
* `report-failure` node it publishes: `{ message, details? }`. OMON opened on
|
|
32
|
+
* an expiry the chain does not list says so in its body; the report fails with
|
|
33
|
+
* the error the plain command (`options --expiration`) prints, instead of
|
|
34
|
+
* reading that body back as a view. Null when the pane publishes none.
|
|
35
|
+
*/
|
|
36
|
+
export function renderedReportFailure(semanticUi: readonly RemoteUiNodeSnapshot[]): { message: string; details?: string } | null {
|
|
37
|
+
const metadata = semanticUi.find((node) => node.role === "report-failure")?.metadata;
|
|
38
|
+
const message = typeof metadata?.message === "string" ? metadata.message.trim() : "";
|
|
39
|
+
if (!message) return null;
|
|
40
|
+
const details = typeof metadata?.details === "string" && metadata.details.trim() ? metadata.details.trim() : undefined;
|
|
41
|
+
return details ? { message, details } : { message };
|
|
42
|
+
}
|
|
43
|
+
|
|
29
44
|
const FRESHNESS_STATUSES: readonly HeadlessFreshnessStatus[] = ["live", "delayed", "stale", "not-a-feed"];
|
|
30
45
|
|
|
31
46
|
/** The `sources` a pane publishes: each a name and a time. */
|
package/src/cli/symbol-args.ts
CHANGED
|
@@ -13,6 +13,25 @@ export function symbolInputKey(symbol: string): string {
|
|
|
13
13
|
return symbol.trim().replace(/^\$/, "").toUpperCase();
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
/**
|
|
17
|
+
* How a command's symbol list spots one security typed twice: `symbolInputKey`,
|
|
18
|
+
* with a share class written with a dot or a dash as one (BRK.B and BRK-B).
|
|
19
|
+
*/
|
|
20
|
+
function securityInputKey(symbol: string): string {
|
|
21
|
+
return symbolInputKey(symbol).replace(/-/g, ".");
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** The securities of a symbol list, each once, in the first spelling typed: `AAPL aapl BRK.B BRK-B` is AAPL and BRK.B. */
|
|
25
|
+
export function uniqueSecuritySymbols(symbols: readonly string[]): string[] {
|
|
26
|
+
const seen = new Set<string>();
|
|
27
|
+
return symbols.filter((symbol) => {
|
|
28
|
+
const key = securityInputKey(symbol);
|
|
29
|
+
if (!key || seen.has(key)) return false;
|
|
30
|
+
seen.add(key);
|
|
31
|
+
return true;
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
16
35
|
/** The symbols without repeats, first spelling kept, and how many repeats were dropped. */
|
|
17
36
|
export function uniqueSymbols(symbols: readonly string[]): { symbols: string[]; repeated: number } {
|
|
18
37
|
const seen = new Set<string>();
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
} from "../../../ui";
|
|
14
14
|
import { displayWidth, truncateTextSegments, truncateToDisplayWidth } from "../../../utils/format";
|
|
15
15
|
import { Spinner } from "../../ui";
|
|
16
|
+
import { ClippedText } from "../../ui/display";
|
|
16
17
|
import { useCommandBarPalette } from "../panel/palette";
|
|
17
18
|
import { getRowPresentation } from "../view-model";
|
|
18
19
|
import {
|
|
@@ -306,7 +307,7 @@ export const CommandBarListBody = memo(function CommandBarListBody({
|
|
|
306
307
|
if (row.kind === "message") {
|
|
307
308
|
return (
|
|
308
309
|
<Box key={row.id} height={1} paddingLeft={labelEdgePadding} paddingRight={contentPadding} {...(!nativePaneChrome ? { onMouseScroll: onListScroll } : {})}>
|
|
309
|
-
<
|
|
310
|
+
<ClippedText fg={palette.text} text={t(row.label)} width={labelEdgeWidth} />
|
|
310
311
|
</Box>
|
|
311
312
|
);
|
|
312
313
|
}
|
|
@@ -5,8 +5,8 @@ import {
|
|
|
5
5
|
} from "../../../plugins/builtin/portfolio-list/command-bar";
|
|
6
6
|
import type { CommandBarFieldOption, CommandBarWorkflowField, CommandBarWorkflowRoute } from "./types";
|
|
7
7
|
import { buildCommandBarWorkflowRoute } from "./route-builder";
|
|
8
|
-
import { teamPrefix } from "../../../
|
|
9
|
-
import { teamStore } from "../../../
|
|
8
|
+
import { teamPrefix } from "../../../team/model";
|
|
9
|
+
import { teamStore } from "../../../team/store";
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Where a new collection lives: me, or one of my teams. Only asked when there
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Dispatch } from "react";
|
|
2
2
|
import { apiClient } from "../../../api-client";
|
|
3
3
|
import { t } from "../../../i18n";
|
|
4
|
-
import { teamCollectionLocalId } from "../../../
|
|
4
|
+
import { teamCollectionLocalId } from "../../../team/collections";
|
|
5
5
|
import type { DataProvider } from "../../../types/data-provider";
|
|
6
6
|
import type { AppTickerRepositoryPort } from "../../../core/app-service-ports";
|
|
7
7
|
import type { PluginRegistry } from "../../../plugins/registry";
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
} from "../feedback/types";
|
|
20
20
|
import { t, tf } from "../i18n";
|
|
21
21
|
import { useAppLanguage } from "../i18n/react";
|
|
22
|
-
import { requestAuthDialog } from "../
|
|
22
|
+
import { requestAuthDialog } from "../account/auth-dialog";
|
|
23
23
|
import { getSharedRegistry } from "../plugins/registry";
|
|
24
24
|
import { useViewport } from "../react/input";
|
|
25
25
|
import { useAppStateRef } from "../state/app/context";
|
package/src/components/index.ts
CHANGED
|
@@ -125,7 +125,7 @@ export { MarkdownText } from "./markdown-text";
|
|
|
125
125
|
// this file is the public `gloomberb/components` surface: a kit component
|
|
126
126
|
// reaches plugins only once it is added here.
|
|
127
127
|
export {
|
|
128
|
-
ActionRow, Badge, BulletList, Button, ButtonActionScope, Checkbox, ChoiceDialog, ConfirmDialog, confirmDialog, DataTable,
|
|
128
|
+
ActionRow, Badge, BulletList, Button, ButtonActionScope, Checkbox, ChoiceDialog, ColumnGrid, ColumnGridPair, ConfirmDialog, confirmDialog, DataTable,
|
|
129
129
|
DetailScrollBody, DialogFrame, DisclosureMarker, Divider, EmptyState, ExternalLink, ExternalLinkText, FieldGrid, FieldLabel,
|
|
130
130
|
fieldGridColumns, fieldGridRows, FigureList, getMessageComposerBlockHeight, GridFieldView, Icon, ICON_GLYPHS,
|
|
131
131
|
IconButton, InlineQuickAddRow, KeyValueRow, ListView, loadingText, Menu, MenuPopover,
|
|
@@ -136,7 +136,8 @@ export {
|
|
|
136
136
|
useFieldRing, usePaneLinkMenuEntry, useQueryBarSearch,
|
|
137
137
|
} from "./ui";
|
|
138
138
|
export type {
|
|
139
|
-
ActionRowProps, BadgeProps, BulletListProps, ButtonProps, ButtonVariant, CheckboxProps, ChoiceDialogChoice,
|
|
139
|
+
ActionRowProps, BadgeProps, BulletListProps, ButtonProps, ButtonVariant, CheckboxProps, ChoiceDialogChoice, ColumnGridCell,
|
|
140
|
+
ColumnGridColumn, ColumnGridPairProps, ColumnGridProps, ConfirmDialogOptions,
|
|
140
141
|
DataTableCell, DataTableColumn, DataTableProps, DataTableVisibleRange, DetailScrollBodyProps, DialogFrameProps,
|
|
141
142
|
DisclosureMarkerProps, DividerProps, EmptyStateProps, FieldGridProps, FieldLabelProps, FieldRing, FieldRingOptions,
|
|
142
143
|
FigureListItem, FigureListProps, GridField,
|
|
@@ -28,14 +28,29 @@ import { useAppDispatch, useAppSelector } from "../../state/app/context";
|
|
|
28
28
|
import { useViewport } from "../../react/input";
|
|
29
29
|
import { canRetryUpdate } from "../../app/global-shortcuts";
|
|
30
30
|
import { t, tf } from "../../i18n";
|
|
31
|
-
import { truncateToDisplayWidth } from "../../utils/format";
|
|
31
|
+
import { displayWidth, truncateToDisplayWidth } from "../../utils/format";
|
|
32
|
+
import { ClippedText } from "../ui/display";
|
|
32
33
|
import { resolveMarketSummaryFit, useMarketSummary } from "./market-summary";
|
|
33
34
|
import { resolveHeaderPromptGeometry } from "./shell/chrome";
|
|
34
35
|
import { useWindowFullscreen } from "./window-fullscreen";
|
|
35
36
|
import { WindowControls, WINDOWS_CONTROL_GROUP_WIDTH_PX } from "./window-controls";
|
|
36
|
-
import { Button } from "../ui/button";
|
|
37
|
+
import { Button, terminalButtonColumns } from "../ui/button";
|
|
37
38
|
|
|
38
39
|
const UPDATE_NOTICE_DURATION_MS = 5_000;
|
|
40
|
+
/**
|
|
41
|
+
* The failed-update message is cut to the room it has, but not below this many
|
|
42
|
+
* columns ("Update fa..."): narrower says nothing, so the banner is left out.
|
|
43
|
+
* The retry hint gives way before the message goes under it.
|
|
44
|
+
*/
|
|
45
|
+
const UPDATE_ERROR_MIN_COLUMNS = 12;
|
|
46
|
+
/** Kept clear after the failed-update banner, so its last character never touches the Help pill. */
|
|
47
|
+
const UPDATE_ERROR_GAP_COLUMNS = 1;
|
|
48
|
+
/** Left padding of the update status's slot, in cells; the desktop's title-bar layout also pads its right. */
|
|
49
|
+
const UPDATE_SLOT_PADDING_COLUMNS = 2;
|
|
50
|
+
/** The Help pill's own props, shared by its button and the width the update status leaves it. */
|
|
51
|
+
const helpButtonProps = () => ({ label: "Open Help", displayLabel: t("Help"), shortcut: "?", compact: true });
|
|
52
|
+
/** The terminal pads the pill's right edge by a cell; the desktop pads it in px. */
|
|
53
|
+
const TERMINAL_HELP_PADDING_COLUMNS = 1;
|
|
39
54
|
|
|
40
55
|
type HeaderActionEvent = {
|
|
41
56
|
key?: string;
|
|
@@ -157,11 +172,17 @@ function HeaderPromptInput({
|
|
|
157
172
|
placeholderColor={subtleColor}
|
|
158
173
|
cursorColor={colors.textBright}
|
|
159
174
|
/>
|
|
160
|
-
{ghostSuffix && (
|
|
175
|
+
{ghostSuffix && (nativePaneChrome ? (
|
|
176
|
+
// The desktop sets the suggestion right after the typed text, one
|
|
177
|
+
// character per `ch` of the field's font, and cuts it where the field ends.
|
|
178
|
+
<Box position="absolute" top={0} height={1} flexDirection="row" style={{ left: `${displayWidth(query)}ch`, right: 0 }}>
|
|
179
|
+
<ClippedText fg={subtleColor} text={ghostSuffix} width={0} />
|
|
180
|
+
</Box>
|
|
181
|
+
) : (
|
|
161
182
|
<Box position="absolute" top={0} left={ghostLeft} width={Math.max(0, width - ghostLeft)} height={1}>
|
|
162
183
|
<Text fg={subtleColor}>{truncateToDisplayWidth(ghostSuffix, Math.max(0, width - ghostLeft))}</Text>
|
|
163
184
|
</Box>
|
|
164
|
-
)}
|
|
185
|
+
))}
|
|
165
186
|
</Box>
|
|
166
187
|
);
|
|
167
188
|
}
|
|
@@ -244,8 +265,14 @@ function HeaderCommandPrompt({
|
|
|
244
265
|
);
|
|
245
266
|
}
|
|
246
267
|
|
|
247
|
-
|
|
268
|
+
/**
|
|
269
|
+
* What the header says about an update. In the terminal it is cut to `columns`,
|
|
270
|
+
* the room its slot is guaranteed (the desktop clips it in CSS where the slot
|
|
271
|
+
* ends), so it never runs into the Help pill or the market cluster beside it.
|
|
272
|
+
*/
|
|
273
|
+
function UpdateStatus({ columns, onRestart }: { columns: number; onRestart?: () => void }) {
|
|
248
274
|
const colors = useThemeColors();
|
|
275
|
+
const { nativePaneChrome = false } = useUiCapabilities();
|
|
249
276
|
const dispatch = useAppDispatch();
|
|
250
277
|
const updateAvailable = useAppSelector((state) => state.updateAvailable);
|
|
251
278
|
const updateProgress = useAppSelector((state) => state.updateProgress);
|
|
@@ -301,11 +328,20 @@ function UpdateStatus({ onRestart }: { onRestart?: () => void }) {
|
|
|
301
328
|
return <Text fg={colors.headerText}>{t(updateProgress.message ?? "Update ready, restart to apply")}</Text>;
|
|
302
329
|
}
|
|
303
330
|
if (updateProgress.phase === "error") {
|
|
331
|
+
// One line: an error that carries a stack or a command's output must not grow the header.
|
|
332
|
+
const message = tf("Update failed: {error}", { error: (updateProgress.error ?? "Unknown error").replace(/\s+/g, " ").trim() });
|
|
304
333
|
const retry = updateKey && canRetryUpdate({ updateAvailable, updateProgress, updateCheckInProgress });
|
|
334
|
+
const hint = retry ? ` ${updateKey} ${t("retry")}` : "";
|
|
335
|
+
const hintColumns = displayWidth(hint);
|
|
336
|
+
// The message goes first, and keeps its room before the hint takes any.
|
|
337
|
+
const room = columns - UPDATE_ERROR_GAP_COLUMNS;
|
|
338
|
+
const showHint = hintColumns > 0 && (nativePaneChrome || room - hintColumns >= UPDATE_ERROR_MIN_COLUMNS);
|
|
339
|
+
const messageColumns = room - (showHint ? hintColumns : 0);
|
|
340
|
+
if (!nativePaneChrome && messageColumns < UPDATE_ERROR_MIN_COLUMNS) return null;
|
|
305
341
|
return (
|
|
306
|
-
<Box flexDirection="row">
|
|
307
|
-
<
|
|
308
|
-
{
|
|
342
|
+
<Box flexDirection="row" overflow="hidden" paddingRight={UPDATE_ERROR_GAP_COLUMNS}>
|
|
343
|
+
<ClippedText fg={colors.headerText} text={message} width={messageColumns} />
|
|
344
|
+
{showHint ? <Text fg={blendHex(colors.headerText, colors.header, 0.62)}>{hint}</Text> : null}
|
|
309
345
|
</Box>
|
|
310
346
|
);
|
|
311
347
|
}
|
|
@@ -404,11 +440,11 @@ function HeaderHelpButton({ nativePaneChrome, onPress }: { nativePaneChrome: boo
|
|
|
404
440
|
return (
|
|
405
441
|
<Box
|
|
406
442
|
flexShrink={0}
|
|
407
|
-
paddingRight={nativePaneChrome ? undefined :
|
|
443
|
+
paddingRight={nativePaneChrome ? undefined : TERMINAL_HELP_PADDING_COLUMNS}
|
|
408
444
|
data-gloom-role="header-help-action"
|
|
409
445
|
style={nativePaneChrome ? { marginRight: 8 } : undefined}
|
|
410
446
|
>
|
|
411
|
-
<Button
|
|
447
|
+
<Button {...helpButtonProps()} onPress={onPress} stopPropagation />
|
|
412
448
|
</Box>
|
|
413
449
|
);
|
|
414
450
|
}
|
|
@@ -437,6 +473,14 @@ export function Header({
|
|
|
437
473
|
windowFullscreen,
|
|
438
474
|
});
|
|
439
475
|
const shortcutLabel = useCommandBarShortcut();
|
|
476
|
+
// The terminal lays the header out by cell counts, so it works out what is left
|
|
477
|
+
// for the update status once the Help pill and the slot's padding are paid for.
|
|
478
|
+
const updateStatusColumns = Math.max(
|
|
479
|
+
0,
|
|
480
|
+
prompt.updateColumns
|
|
481
|
+
- (onOpenHelp ? terminalButtonColumns(helpButtonProps()) + TERMINAL_HELP_PADDING_COLUMNS : 0)
|
|
482
|
+
- UPDATE_SLOT_PADDING_COLUMNS * (titleBarOverlay ? 2 : 1),
|
|
483
|
+
);
|
|
440
484
|
// Desktop has its own window chrome to sit on; the terminal has none, so the
|
|
441
485
|
// bar itself wears the prompt's fill and reads as a single strip.
|
|
442
486
|
const headerBg = nativePaneChrome ? colors.header : headerSurface(colors);
|
|
@@ -483,8 +527,8 @@ export function Header({
|
|
|
483
527
|
>
|
|
484
528
|
<Box width={prompt.left} />
|
|
485
529
|
{commandPrompt}
|
|
486
|
-
<Box flexGrow={1} paddingLeft={
|
|
487
|
-
<UpdateStatus onRestart={onRestartForUpdate} />
|
|
530
|
+
<Box flexGrow={1} paddingLeft={UPDATE_SLOT_PADDING_COLUMNS} paddingRight={UPDATE_SLOT_PADDING_COLUMNS} minWidth={0}>
|
|
531
|
+
<UpdateStatus columns={updateStatusColumns} onRestart={onRestartForUpdate} />
|
|
488
532
|
</Box>
|
|
489
533
|
{onOpenHelp ? <HeaderHelpButton nativePaneChrome onPress={onOpenHelp} /> : null}
|
|
490
534
|
{marketSummary}
|
|
@@ -505,8 +549,8 @@ export function Header({
|
|
|
505
549
|
>
|
|
506
550
|
<Box width={prompt.left} />
|
|
507
551
|
{commandPrompt}
|
|
508
|
-
<Box flexGrow={1} minWidth={0} paddingLeft={
|
|
509
|
-
<UpdateStatus onRestart={onRestartForUpdate} />
|
|
552
|
+
<Box flexGrow={1} minWidth={0} paddingLeft={UPDATE_SLOT_PADDING_COLUMNS}>
|
|
553
|
+
<UpdateStatus columns={updateStatusColumns} onRestart={onRestartForUpdate} />
|
|
510
554
|
</Box>
|
|
511
555
|
{onOpenHelp ? <HeaderHelpButton nativePaneChrome={nativePaneChrome} onPress={onOpenHelp} /> : null}
|
|
512
556
|
{marketSummary}
|
|
@@ -73,6 +73,12 @@ export interface HeaderPromptGeometry {
|
|
|
73
73
|
width: number;
|
|
74
74
|
/** Columns held at the header's right edge for the market cluster. */
|
|
75
75
|
marketColumns: number;
|
|
76
|
+
/**
|
|
77
|
+
* Columns between the prompt and the market cluster: the update status, its
|
|
78
|
+
* padding and the Help pill share them. Never negative, so a window too narrow
|
|
79
|
+
* for the header reads as no room rather than a negative width.
|
|
80
|
+
*/
|
|
81
|
+
updateColumns: number;
|
|
76
82
|
}
|
|
77
83
|
|
|
78
84
|
/**
|
|
@@ -95,14 +101,14 @@ export function resolveHeaderPromptGeometry(options: {
|
|
|
95
101
|
? getTitlebarLeadingInset({ platform, windowFullscreen })
|
|
96
102
|
: 0;
|
|
97
103
|
const left = leadingInset + 1;
|
|
98
|
-
const
|
|
99
|
-
const marketColumns = headerMarketColumns(termWidth, left,
|
|
104
|
+
const updateReserve = headerPromptUpdateColumns(termWidth);
|
|
105
|
+
const marketColumns = headerMarketColumns(termWidth, left, updateReserve);
|
|
100
106
|
const width = Math.max(
|
|
101
107
|
HEADER_PROMPT_MIN_WIDTH,
|
|
102
108
|
Math.min(
|
|
103
109
|
resolveCommandSurfaceWidth({ nativePaneChrome, termWidth }),
|
|
104
|
-
termWidth - left -
|
|
110
|
+
termWidth - left - updateReserve - marketColumns,
|
|
105
111
|
),
|
|
106
112
|
);
|
|
107
|
-
return { left, width, marketColumns };
|
|
113
|
+
return { left, width, marketColumns, updateColumns: Math.max(0, termWidth - left - width - marketColumns) };
|
|
108
114
|
}
|
|
@@ -61,7 +61,7 @@ import {
|
|
|
61
61
|
useShellVisibleLayout,
|
|
62
62
|
} from "./layout-state";
|
|
63
63
|
import { restoreShellHiddenPanes } from "./visible-layout";
|
|
64
|
-
import { AuthDialogHost } from "../../../
|
|
64
|
+
import { AuthDialogHost } from "../../../account/auth-dialog";
|
|
65
65
|
import { DeviceSignInDialogHost } from "../../../account/device-signin-dialog";
|
|
66
66
|
import { McpConnectDialogHost } from "../../../plugins/builtin/cloud/mcp-connect/dialog";
|
|
67
67
|
import { BrokerSignInDialogHost } from "../../../brokers/signed-in/sign-in-dialog";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { TeamSummary } from "../../api-client";
|
|
2
2
|
import type { SavedLayout } from "../../types/config";
|
|
3
|
-
import type { TeamStoreSnapshot } from "../../
|
|
3
|
+
import type { TeamStoreSnapshot } from "../../team/store";
|
|
4
4
|
|
|
5
5
|
export type TabGroupId = "personal" | `team:${string}`;
|
|
6
6
|
|
|
@@ -43,8 +43,8 @@ import { confirmDialog } from "../ui/confirm-dialog";
|
|
|
43
43
|
import { Tabs } from "../ui/tabs";
|
|
44
44
|
import { useTransientLayout } from "./transient-layout";
|
|
45
45
|
import { linkedLayoutMarker, linkedLayoutStatus, linkedLayoutUpdates } from "../../layout-marketplace/linked";
|
|
46
|
-
import { teamAccentHex } from "../../
|
|
47
|
-
import { teamStore } from "../../
|
|
46
|
+
import { teamAccentHex } from "../../team/model";
|
|
47
|
+
import { teamStore } from "../../team/store";
|
|
48
48
|
import { buildStatusBarTabGroups, groupIdFromMarkerValue, groupMarkerValue } from "./status-bar-groups";
|
|
49
49
|
import { requestFeedbackDialog } from "../feedback-dialog";
|
|
50
50
|
import { openFormModal } from "../form-modal";
|
|
@@ -17,6 +17,8 @@ export interface MarkdownTextProps {
|
|
|
17
17
|
lineWidth?: number;
|
|
18
18
|
/** Desktop and web: the space a blank line leaves between paragraphs, in CSS units; one line when unset. */
|
|
19
19
|
paragraphGap?: string;
|
|
20
|
+
/** Desktop and web: the size, weight and space of a heading line, such as a reader's section heading; the text's own when unset. */
|
|
21
|
+
headingStyle?: Readonly<Record<string, string | number>>;
|
|
20
22
|
catalog?: Record<string, InlineTickerCatalogEntry>;
|
|
21
23
|
textColor?: string;
|
|
22
24
|
openTicker?: (symbol: string) => void;
|
|
@@ -86,9 +88,11 @@ function parseInlineMarkdown(text: string, links = false): StyledSegment[] {
|
|
|
86
88
|
return segments;
|
|
87
89
|
}
|
|
88
90
|
|
|
91
|
+
const HEADING_RE = /^(#{1,3})\s+(.+)$/;
|
|
92
|
+
|
|
89
93
|
function parseLine(line: string, links: boolean): ParsedLine {
|
|
90
94
|
// Headings
|
|
91
|
-
const headingMatch = line.match(
|
|
95
|
+
const headingMatch = line.match(HEADING_RE);
|
|
92
96
|
if (headingMatch) {
|
|
93
97
|
return {
|
|
94
98
|
heading: true,
|
|
@@ -595,6 +599,7 @@ export function MarkdownText({
|
|
|
595
599
|
openTicker = () => {},
|
|
596
600
|
onOpenLink,
|
|
597
601
|
paragraphGap,
|
|
602
|
+
headingStyle,
|
|
598
603
|
}: MarkdownTextProps) {
|
|
599
604
|
const { nativePaneChrome } = useUiCapabilities();
|
|
600
605
|
const links = onOpenLink !== undefined;
|
|
@@ -620,12 +625,15 @@ export function MarkdownText({
|
|
|
620
625
|
}
|
|
621
626
|
const line = block.text;
|
|
622
627
|
if (line.trim() === "") {
|
|
628
|
+
// Under a heading set in its own style, the heading's margin is the space: it sits with what it names.
|
|
629
|
+
const previous = blocks[index - 1];
|
|
630
|
+
if (nativePaneChrome && headingStyle && previous?.kind === "line" && HEADING_RE.test(previous.text)) return null;
|
|
623
631
|
return nativePaneChrome && paragraphGap
|
|
624
632
|
? <Box key={index} flexShrink={0} style={{ height: paragraphGap }} />
|
|
625
633
|
: <Text key={index}>{" "}</Text>;
|
|
626
634
|
}
|
|
627
635
|
const parsed = parseLine(line, links);
|
|
628
|
-
|
|
636
|
+
const markdownLine = (
|
|
629
637
|
<MarkdownLine
|
|
630
638
|
key={index}
|
|
631
639
|
parsed={parsed}
|
|
@@ -638,6 +646,10 @@ export function MarkdownText({
|
|
|
638
646
|
onOpenLink={onOpenLink}
|
|
639
647
|
/>
|
|
640
648
|
);
|
|
649
|
+
// A line's height comes from --cell-h, in em of its own size.
|
|
650
|
+
return nativePaneChrome && headingStyle && parsed.heading
|
|
651
|
+
? <Box key={index} flexDirection="column" width="100%" style={{ ...headingStyle, "--cell-h": `${headingStyle.lineHeight ?? 1.35}em` }}>{markdownLine}</Box>
|
|
652
|
+
: markdownLine;
|
|
641
653
|
})}
|
|
642
654
|
</Box>
|
|
643
655
|
);
|
|
@@ -375,7 +375,7 @@ function ArticleReaderView({
|
|
|
375
375
|
<ReaderText text={lead} geometry={geometry} color={colors.textBright} variant="lead" />
|
|
376
376
|
) : null}
|
|
377
377
|
{!raw && facts.length > 0 ? (
|
|
378
|
-
<Box flexDirection="column" style={desktop ? { margin: "0.3em 0
|
|
378
|
+
<Box flexDirection="column" style={desktop ? { margin: "0.3em 0 1em" } : undefined}>
|
|
379
379
|
<ReaderText text={readerLabel("Key facts")} geometry={geometry} color={colors.textDim} variant="label" />
|
|
380
380
|
{facts.map((fact, index) => (
|
|
381
381
|
<ReaderText key={index} text={fact} geometry={geometry} color={colors.text} variant="fact" segments={figureSegments(fact)} figureColor={colors.textBright} />
|
|
@@ -9,7 +9,7 @@ import { DetailScrollBody } from "../ui/detail-scroll-body";
|
|
|
9
9
|
import { KeyValueRow } from "../ui/display";
|
|
10
10
|
import { ExternalLink, usePaneLinkMenuEntry } from "../ui/external-link";
|
|
11
11
|
import { parseArticle } from "./article-text";
|
|
12
|
-
import { DESKTOP_LINE_HEIGHT, READER_APP_FONT, READER_COLUMN_FONT, ReaderBlock, ReaderText, type ReaderGeometry } from "./reader-text";
|
|
12
|
+
import { DESKTOP_LINE_HEIGHT, READER_APP_FONT, READER_COLUMN_FONT, READER_HEADING_STYLE, ReaderBlock, ReaderText, type ReaderGeometry } from "./reader-text";
|
|
13
13
|
|
|
14
14
|
export interface DetailFact {
|
|
15
15
|
label: string;
|
|
@@ -50,14 +50,17 @@ const URL_LINE = /^https?:\/\/\S+$/;
|
|
|
50
50
|
|
|
51
51
|
const COLUMN_STYLE = { fontSize: READER_COLUMN_FONT, lineHeight: DESKTOP_LINE_HEIGHT } as const;
|
|
52
52
|
const META_STYLE = { marginBottom: "0.8em" } as const;
|
|
53
|
-
/**
|
|
53
|
+
/**
|
|
54
|
+
* At the app's own size, as metadata is in every reader. Its columns come from
|
|
55
|
+
* styles.css: one pair to a row, or two in a wide reader.
|
|
56
|
+
*/
|
|
54
57
|
const FACTS_STYLE = {
|
|
55
58
|
display: "grid",
|
|
56
|
-
columnGap: "
|
|
57
|
-
rowGap: "0.
|
|
58
|
-
fontSize:
|
|
59
|
+
columnGap: "2em",
|
|
60
|
+
rowGap: "0.3em",
|
|
61
|
+
fontSize: READER_APP_FONT,
|
|
59
62
|
lineHeight: 1.5,
|
|
60
|
-
marginBottom: "1.
|
|
63
|
+
marginBottom: "1.6em",
|
|
61
64
|
} as const;
|
|
62
65
|
const FACT_TEXT_STYLE = { display: "block", lineHeight: "inherit", minWidth: 0 } as const;
|
|
63
66
|
/** Markdown lines take the reader's line height (the host sets Text line height from --cell-h). */
|
|
@@ -118,7 +121,7 @@ function NativeDetail({ meta, facts, body, bodyFormat, note }: DetailContentProp
|
|
|
118
121
|
) : null}
|
|
119
122
|
{bodyFormat === "markdown" && body ? (
|
|
120
123
|
<Box flexDirection="column" width="100%" style={MARKDOWN_STYLE}>
|
|
121
|
-
<MarkdownText text={body} paragraphGap={PARAGRAPH_GAP} />
|
|
124
|
+
<MarkdownText text={body} paragraphGap={PARAGRAPH_GAP} headingStyle={READER_HEADING_STYLE} />
|
|
122
125
|
</Box>
|
|
123
126
|
) : blocks.map((block, index) => (
|
|
124
127
|
<Box key={index} flexDirection="column">
|
|
@@ -12,18 +12,32 @@ import type { ArticleBlock } from "./article-text";
|
|
|
12
12
|
* detail reader of list panes.
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
-
/** Line height of reading text on the desktop, against its own size. */
|
|
16
|
-
export const DESKTOP_LINE_HEIGHT = 1.65;
|
|
17
|
-
|
|
18
15
|
/**
|
|
19
|
-
* The
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
16
|
+
* The reader's type scale on the desktop and the web, one for every reader
|
|
17
|
+
* (the article reader, the detail reader, the markdown and docs headings in
|
|
18
|
+
* them). Reading text sits a step above the app's own size (12px by default)
|
|
19
|
+
* and every other level is a modest step from it, so the page reads as part
|
|
20
|
+
* of the app and the levels differ by weight and space as much as by size:
|
|
21
|
+
*
|
|
22
|
+
* | Level | Wide | Column under 480px |
|
|
23
|
+
* |---|---|---|
|
|
24
|
+
* | Metadata, facts, tables, coverage | 12px, dimmer | 12px |
|
|
25
|
+
* | Body | 14px, line height 1.6 | 13.2px |
|
|
26
|
+
* | Lead | 15px | 14.1px |
|
|
27
|
+
* | Section heading | 16px bold | 15.2px |
|
|
28
|
+
* | Title | 20px bold | 18.9px |
|
|
29
|
+
*
|
|
30
|
+
* The body size comes from `--reader-em`, which a container query in
|
|
31
|
+
* styles.css lowers in a narrow column, so a resize changes it with the
|
|
32
|
+
* layout and nothing counts cells. The levels above it are in em of it.
|
|
23
33
|
*/
|
|
24
|
-
export const READER_COLUMN_FONT = "calc(var(--reader-em, 1.
|
|
25
|
-
/** Back to the app's own size inside a reading column: chips, controls, tables. */
|
|
26
|
-
export const READER_APP_FONT = "calc(1em / var(--reader-em, 1.
|
|
34
|
+
export const READER_COLUMN_FONT = "calc(var(--reader-em, 1.1667) * 1em)";
|
|
35
|
+
/** Back to the app's own size inside a reading column: metadata, chips, controls, tables. */
|
|
36
|
+
export const READER_APP_FONT = "calc(1em / var(--reader-em, 1.1667))";
|
|
37
|
+
/** Line height of reading text on the desktop, against its own size. */
|
|
38
|
+
export const DESKTOP_LINE_HEIGHT = 1.6;
|
|
39
|
+
/** A section heading in reading text: a step above the body, set apart by weight and the space above it. */
|
|
40
|
+
export const READER_HEADING_STYLE = { fontSize: "1.15em", fontWeight: 700, lineHeight: 1.35, margin: "0.9em 0 0.4em" } as const;
|
|
27
41
|
|
|
28
42
|
export type Segment = { text: string; marked?: boolean; figure?: boolean };
|
|
29
43
|
|
|
@@ -58,14 +72,15 @@ function hasHeaderRow(rows: readonly string[][]): boolean {
|
|
|
58
72
|
export type TextVariant = "headline" | "meta" | "lead" | "body" | "heading" | "label" | "fact" | "item";
|
|
59
73
|
|
|
60
74
|
const DESKTOP_VARIANT_STYLE: Record<TextVariant, Record<string, string | number>> = {
|
|
61
|
-
headline: { fontSize: "1.
|
|
62
|
-
meta: { fontSize:
|
|
63
|
-
lead: { fontSize: "1.
|
|
75
|
+
headline: { fontSize: "1.43em", lineHeight: 1.25 },
|
|
76
|
+
meta: { fontSize: READER_APP_FONT, lineHeight: 1.5 },
|
|
77
|
+
lead: { fontSize: "1.07em", lineHeight: 1.55, marginBottom: "1em" },
|
|
64
78
|
body: { lineHeight: DESKTOP_LINE_HEIGHT, marginBottom: "0.9em" },
|
|
65
|
-
heading:
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
79
|
+
heading: READER_HEADING_STYLE,
|
|
80
|
+
// Names what follows (key facts, coverage) as a section heading does, without the air above a section.
|
|
81
|
+
label: { ...READER_HEADING_STYLE, margin: "0 0 0.4em" },
|
|
82
|
+
fact: { fontSize: "0.93em", lineHeight: 1.55, marginBottom: "0.35em" },
|
|
83
|
+
item: { lineHeight: DESKTOP_LINE_HEIGHT, marginBottom: "0.3em" },
|
|
69
84
|
};
|
|
70
85
|
|
|
71
86
|
function styled(segments: readonly Segment[], color: string, markColor: string, figureColor: string | undefined, attributes: number): StyledText {
|