/** @jsxImportSource react */ import type { CSSProperties } from "react"; import type { DockLayoutNode, PaneInstanceConfig } from "../../types/config"; import type { LayoutMarketplaceEntry } from "../../layout-marketplace/payload"; const PANE_NAMES: Record = { "chart-composer": "Chart", "credit-conditions": "Credit Spreads", "earnings-calendar": "Earnings Calendar", "fx-matrix": "FX Cross Rates", "kelly-sizer": "Position Sizer", "market-halts": "Market Halts", "market-heatmap": "Market Heatmap", "news-breaking": "Breaking News", "news-feed": "News Feed", "news-industry": "Sector News", "news-top": "Top News", "options-calculator": "Options Calculator", "portfolio-list": "Portfolio", "prediction-markets": "Prediction Markets", "quick-notes": "Notes", sec: "SEC", "thirteenf-funds": "13F Funds", "ticker-news": "Ticker News", "ticker-research": "Ticker Research", "twitter-feed": "X Feed", "volatility-term-structure": "VIX Term Structure", "world-indices": "World Indices", }; export function marketplacePaneName(paneId: string): string { return PANE_NAMES[paneId] ?? paneId .split("-") .filter(Boolean) .map((part) => part.charAt(0).toUpperCase() + part.slice(1)) .join(" "); } function paneSubtitle(pane: PaneInstanceConfig): string | null { if (pane.binding?.kind === "fixed") return pane.binding.symbol; const query = pane.params?.query; return query?.trim() ? query.trim().slice(0, 80) : null; } function PaneCard({ pane }: { pane: PaneInstanceConfig | undefined }) { if (!pane) return
Unavailable pane
; const subtitle = paneSubtitle(pane); return (
{pane.title?.trim() || marketplacePaneName(pane.paneId)} {subtitle ? {subtitle} : null}
); } function DockPreview({ node, panes, }: { node: DockLayoutNode; panes: ReadonlyMap; }) { if (node.kind === "pane") return ; const firstStyle = { "--share-ratio": node.ratio } as CSSProperties; const secondStyle = { "--share-ratio": 1 - node.ratio } as CSSProperties; return (
); } function formatDate(value: string): string { const date = new Date(value); return Number.isNaN(date.getTime()) ? "" : date.toLocaleDateString(undefined, { year: "numeric", month: "short", day: "numeric" }); } export function LayoutShareView({ entry, openLiveUrl, }: { entry: LayoutMarketplaceEntry; openLiveUrl: string; }) { const panes = new Map(entry.layout.instances.map((pane) => [pane.instanceId, pane])); const docked = new Set(); const collect = (node: DockLayoutNode | null) => { if (!node) return; if (node.kind === "pane") { docked.add(node.instanceId); return; } collect(node.first); collect(node.second); }; collect(entry.layout.dockRoot); const extra = entry.layout.instances.filter((pane) => !docked.has(pane.instanceId)); const author = entry.author.username ? `@${entry.author.username}` : entry.author.displayName; const date = formatDate(entry.publishedAt); return (

Shared via Gloomberb

{entry.name}

{[author, date, `${entry.layout.instances.length} panes`].filter(Boolean).join(" ยท ")}

{entry.layout.dockRoot ? :

No docked panes

} {extra.length > 0 ? (
{extra.map((pane) => )}
) : null}
Use this layout

Opens in Gloomberb as an independent, editable copy.

); }