diff --git a/frontend/harness.html b/frontend/harness.html deleted file mode 100644 index 55b0e16..0000000 --- a/frontend/harness.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - FundamentalsPanel harness - - - - - -
- - - diff --git a/frontend/src/dev/harness.tsx b/frontend/src/dev/harness.tsx deleted file mode 100644 index 3afdab4..0000000 --- a/frontend/src/dev/harness.tsx +++ /dev/null @@ -1,146 +0,0 @@ -/* Dev-only visual harness for FundamentalsPanel. Served at /harness.html by - * `vite`. Not imported by the app. Renders the three key states so desktop and - * mobile can be eyeballed with representative fixtures. */ -import { createRoot } from 'react-dom/client'; -import '../styles/globals.css'; -import { FundamentalsPanel } from '../components/ticker/FundamentalsPanel'; -import type { FundamentalResponse, MetricItem } from '../lib/types'; - -function h(period: string, value: number | null) { - return { period_end: period, value }; -} -const P = ['2025-06-30', '2025-09-30', '2025-12-31', '2026-03-28']; - -function dateFromToday(days: number): string { - const date = new Date(); - date.setHours(12, 0, 0, 0); - date.setDate(date.getDate() + days); - return [ - date.getFullYear(), - String(date.getMonth() + 1).padStart(2, '0'), - String(date.getDate()).padStart(2, '0'), - ].join('-'); -} - -function metric(key: string, value: number | null, hist: (number | null)[], - industry: MetricItem['industry'] = null, - caveat: string | null = null): MetricItem { - return { - key: key as MetricItem['key'], value, - history: hist.map((v, i) => h(P[i], v)), - industry, period_end: '2026-03-28', filed_date: '2026-05-01', caveat, - source: 'sec', - }; -} -const ind = (median: number, favorable_percentile: number) => - ({ label: 'SIC 35 peers', median, favorable_percentile, peer_count: 12 }); - -const legacy = { - pe_ratio: null, revenue_growth: null, earnings_surprise: null, market_cap: null, - next_earnings_date: null, fetched_at: null, unavailable_fields: {}, - setup_eligible: true, setup_block_code: null, setup_block_reason: null, -}; - -const full: FundamentalResponse = { - symbol: 'AAPL', ...legacy, - earnings: { - next: { date: dateFromToday(12), session: 'amc', days_until: 12 }, - recent: [ - { announce_date: '2025-08-01', period_end: '2025-06-30', eps_estimate: 1.4, eps_actual: 1.6, surprise_pct: 14.3 }, - { announce_date: '2025-11-01', period_end: '2025-09-30', eps_estimate: 1.7, eps_actual: 1.9, surprise_pct: 11.8 }, - { announce_date: '2026-02-01', period_end: '2025-12-31', eps_estimate: 2.6, eps_actual: 2.4, surprise_pct: -7.7 }, - { announce_date: '2026-05-01', period_end: '2026-03-28', eps_estimate: 1.5, eps_actual: 1.65, surprise_pct: 10.0 }, - ], - }, - metrics: [ - metric('revenue_growth_yoy', 18, [8, 11, 15, 18], ind(11, 82)), - metric('eps_growth_yoy', 24, [10, 18, 22, 24], ind(15, 70)), - metric('operating_margin', 32, [30, 31, 31, 32], ind(22, 88)), - metric('fcf_margin', 28, [24, 25, 27, 28], ind(18, 80)), - metric('net_debt', 16.2e9, [46e9, 44e9, 24e9, 16.2e9], null), - metric('net_debt_to_ebitda', 1.4, [1.9, 1.7, 1.5, 1.4], ind(2.1, 68)), - metric('share_count_change_yoy', -1.7, [-2.4, -2.2, -2.3, -1.7], null), - ], - valuation: { - pe: 29.2, fcf_yield: 3.8, market_cap_est: 3.2e12, - pe_industry: ind(23.5, 30), fcf_yield_industry: ind(3.1, 70), price_date: '2026-05-01', - }, - reads: { - header: 'growth accelerating · margins improving · valuation priced above peers', - by_key: { - revenue_growth_yoy: 'accelerating', eps_growth_yoy: 'accelerating', - operating_margin: 'improving', fcf_margin: 'improving', - share_count_change_yoy: 'buying back', net_debt_to_ebitda: 'conservative leverage', - pe: 'priced above peers', fcf_yield: 'above peers', net_debt: null, - }, - }, -}; - -const partial: FundamentalResponse = { - symbol: 'NEWCO', ...legacy, - earnings: { next: { date: dateFromToday(0), session: 'unknown', days_until: 0 }, recent: [] }, - metrics: [ - metric('revenue_growth_yoy', 12, [null, 8, 10, 12], null), - metric( - 'eps_growth_yoy', - null, - [null, null, null, null], - null, - 'Not comparable: share count changed at least 25%; possible split or corporate action.', - ), - metric('operating_margin', 25, [24, 24, 25, 25], null), - metric('fcf_margin', null, [null, null, null, null], null), - metric('net_debt', null, [], null), - metric('net_debt_to_ebitda', 1.9, [1.7, 1.8, 1.9, 1.9], null), - metric( - 'share_count_change_yoy', - null, - [1.8, 2.0, 2.0, null], - null, - 'Not comparable: share count changed at least 25%; possible split or corporate action.', - ), - ], - valuation: { - pe: 15.2, fcf_yield: null, market_cap_est: 5.4e8, - pe_industry: null, fcf_yield_industry: null, price_date: '2026-05-01', - }, - reads: { - header: 'growth steady · margins stable', - by_key: { - revenue_growth_yoy: 'steady', operating_margin: 'stable', - share_count_change_yoy: '2.1% dilution', net_debt_to_ebitda: null, - pe: null, fcf_yield: null, eps_growth_yoy: null, fcf_margin: null, net_debt: null, - }, - }, -}; - -const empty: FundamentalResponse = { - symbol: 'ADR', ...legacy, - earnings: { next: null, recent: [] }, - metrics: [ - 'revenue_growth_yoy', 'eps_growth_yoy', 'operating_margin', 'fcf_margin', - 'net_debt', 'net_debt_to_ebitda', 'share_count_change_yoy', - ].map((k) => metric(k, null, [])), - valuation: null, - reads: { header: null, by_key: {} }, -}; - -function Case({ title, data }: { title: string; data: FundamentalResponse }) { - return ( -
-
{title}
- -
- ); -} - -createRoot(document.getElementById('root')!).render( -
-

- Desktop width (~768px, two columns). Resize the browser to ~390px to check mobile (single column). -

- - - -
, -);