import { TickerBadgeList } from "../../../../components"; import { MarkdownText } from "../../../../components/markdown-text"; import { Button } from "../../../../components/ui/button"; import { ExternalLinkText } from "../../../../components/ui/external-link"; import type { InlineTickerCatalogEntry } from "../../../../state/hooks/inline-tickers"; import { colors } from "../../../../theme/colors"; import { Box, Text } from "../../../../ui"; import { sourceDetailEntries, text, textOrNull, tickerSymbol, truncate } from "../format"; import type { BuildoutCompany, BuildoutRelatedCompany, BuildoutSource } from "../model/types"; export type InlineTickerCatalog = Record; export type DetailSpec = { label: string; value?: string | null; color?: string; }; export function DetailSpecGrid({ items, width, marginTop = 1 }: { items: DetailSpec[]; width: number; marginTop?: number }) { const visibleItems = items.filter((item) => textOrNull(item.value) != null); if (visibleItems.length === 0) return null; const columnCount = width >= 110 ? 4 : width >= 78 ? 3 : width >= 52 ? 2 : 1; const columnWidth = Math.max(18, Math.floor(width / columnCount)); const rows: DetailSpec[][] = []; for (let index = 0; index < visibleItems.length; index += columnCount) { rows.push(visibleItems.slice(index, index + columnCount)); } return ( {rows.map((row, rowIndex) => ( {row.map((item) => { const labelWidth = Math.min(Math.max(item.label.length + 2, 8), Math.max(8, Math.floor(columnWidth * 0.45))); const valueWidth = Math.max(0, columnWidth - labelWidth); const labelText = truncate(`${item.label}:`, Math.max(0, labelWidth - 1)).padEnd(labelWidth); return ( {labelText} {truncate(text(item.value, ""), valueWidth)} ); })} ))} ); } export function InlineSources({ domains, width }: { domains: readonly string[]; width: number }) { if (domains.length === 0) return null; const label = "Sources: "; return ( {label} {truncate(domains.join(", "), Math.max(0, width - label.length))} ); } export function DetailListLine({ label, values, width, }: { label: string; values: readonly string[]; width: number; }) { if (values.length === 0) return null; const prefix = `${label}: `; return ( {prefix} {truncate(values.join(", "), Math.max(0, width - prefix.length))} ); } export function RelatedCompaniesLine({ label, companies, width, }: { label: string; companies: readonly BuildoutRelatedCompany[] | undefined; width: number; }) { const items = companies ?? []; if (items.length === 0) return null; const visible = items.slice(0, 8); const symbols = visible .map((company) => tickerSymbol(company.ticker)) .filter((symbol): symbol is string => symbol != null); const names = visible .filter((company) => !tickerSymbol(company.ticker)) .map((company) => textOrNull(company.name)) .filter((name): name is string => name != null); const overflow = items.length > visible.length ? ` +${items.length - visible.length}` : ""; const prefix = `${label}: `; const badgeWidth = Math.min(Math.max(0, width - prefix.length - (names.length > 0 ? 1 : 0)), Math.max(0, symbols.length * 9)); return ( {prefix} {symbols.length > 0 ? ( ) : null} {truncate(`${names.length > 0 ? names.join(", ") : ""}${overflow}`, Math.max(0, width - prefix.length - badgeWidth))} ); } export function SourceDetailLines({ sources, width, maxItems = 3, }: { sources: readonly BuildoutSource[] | undefined; width: number; maxItems?: number; }) { const entries = sourceDetailEntries(sources, maxItems); if (entries.length === 0) return null; return ( {entries.map((entry, index) => { const prefix = entry.domain ? `${entry.domain}${entry.tier ? ` T${entry.tier}` : ""}` : ""; const body = entry.title ?? entry.note ?? ""; const bodyText = truncate(prefix ? `: ${body}` : body, Math.max(0, width - prefix.length)); return ( {prefix ? ( entry.url ? ( ) : ( {prefix} ) ) : null} {bodyText} ); })} ); } export function MarkdownBlock({ text: markdown, width, catalog, openTicker, marginTop = 1, }: { text?: string | null; width: number; catalog: InlineTickerCatalog; openTicker: (symbol: string) => void; marginTop?: number; }) { if (!markdown) return null; return ( ); } export function tickerBadges({ symbols, width, fallbackColor, }: { symbols: readonly string[]; width: number; fallbackColor?: string; }) { if (symbols.length === 0) return null; return ( ); } export function FavoriteCell({ starred, busy, selected, onPress, }: { starred: boolean; busy: boolean; selected: boolean; onPress?: () => void; }) { return (