Remove dead code in app and XBRL loader
This commit is contained in:
@@ -1,36 +0,0 @@
|
||||
import type { CompanyValuationSnapshot } from '@/lib/types';
|
||||
import { formatCompactCurrency, formatScaledNumber } from '@/lib/format';
|
||||
|
||||
type ValuationStatGridProps = {
|
||||
valuation: CompanyValuationSnapshot;
|
||||
};
|
||||
|
||||
function formatRatio(value: number | null) {
|
||||
return value === null ? 'n/a' : `${value.toFixed(2)}x`;
|
||||
}
|
||||
|
||||
function formatShares(value: number | null) {
|
||||
return value === null ? 'n/a' : formatScaledNumber(value, { maximumFractionDigits: 2 });
|
||||
}
|
||||
|
||||
export function ValuationStatGrid(props: ValuationStatGridProps) {
|
||||
const items = [
|
||||
{ label: 'Market cap', value: props.valuation.marketCap === null ? 'n/a' : formatCompactCurrency(props.valuation.marketCap) },
|
||||
{ label: 'Enterprise value', value: props.valuation.enterpriseValue === null ? 'n/a' : formatCompactCurrency(props.valuation.enterpriseValue) },
|
||||
{ label: 'Shares out.', value: formatShares(props.valuation.sharesOutstanding) },
|
||||
{ label: 'Trailing P/E', value: formatRatio(props.valuation.trailingPe) },
|
||||
{ label: 'EV / Revenue', value: formatRatio(props.valuation.evToRevenue) },
|
||||
{ label: 'EV / EBITDA', value: formatRatio(props.valuation.evToEbitda) }
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="grid gap-3 sm:grid-cols-2">
|
||||
{items.map((item) => (
|
||||
<div key={item.label} className="rounded-2xl border border-[color:var(--line-weak)] bg-[color:var(--panel-soft)] p-3">
|
||||
<p className="text-xs uppercase tracking-[0.14em] text-[color:var(--terminal-muted)]">{item.label}</p>
|
||||
<p className="mt-2 text-lg font-semibold text-[color:var(--terminal-bright)]">{item.value}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
import { useState, useCallback } from 'react';
|
||||
import type { ChartZoomState } from '@/lib/types';
|
||||
|
||||
export function useChartZoom(dataLength: number) {
|
||||
const [zoomState, setZoomState] = useState<ChartZoomState>({
|
||||
startIndex: 0,
|
||||
endIndex: Math.max(0, dataLength - 1),
|
||||
isZoomed: false
|
||||
});
|
||||
|
||||
const handleZoomChange = useCallback(
|
||||
(brushData: { startIndex?: number; endIndex?: number }) => {
|
||||
if (
|
||||
brushData.startIndex === undefined ||
|
||||
brushData.endIndex === undefined
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
setZoomState({
|
||||
startIndex: brushData.startIndex,
|
||||
endIndex: brushData.endIndex,
|
||||
isZoomed:
|
||||
brushData.startIndex !== 0 ||
|
||||
brushData.endIndex !== dataLength - 1
|
||||
});
|
||||
},
|
||||
[dataLength]
|
||||
);
|
||||
|
||||
const resetZoom = useCallback(() => {
|
||||
setZoomState({
|
||||
startIndex: 0,
|
||||
endIndex: Math.max(0, dataLength - 1),
|
||||
isZoomed: false
|
||||
});
|
||||
}, [dataLength]);
|
||||
|
||||
return {
|
||||
zoomState,
|
||||
handleZoomChange,
|
||||
resetZoom
|
||||
};
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
import {
|
||||
ComposedChart,
|
||||
XAxis,
|
||||
YAxis,
|
||||
CartesianGrid,
|
||||
Tooltip,
|
||||
ResponsiveContainer,
|
||||
Scatter
|
||||
} from 'recharts';
|
||||
import type { ChartDataPoint } from '@/lib/types';
|
||||
import { getChartColors } from '../utils/chart-colors';
|
||||
import { ChartTooltip } from '../primitives/chart-tooltip';
|
||||
import { CandlestickShape } from '../utils/candlestick-shapes';
|
||||
import { isOHLCVData } from '../utils/chart-data-transformers';
|
||||
|
||||
type CandlestickChartViewProps = {
|
||||
data: ChartDataPoint[];
|
||||
formatters?: {
|
||||
price?: (value: number) => string;
|
||||
date?: (value: string) => string;
|
||||
volume?: (value: number) => string;
|
||||
};
|
||||
};
|
||||
|
||||
export function CandlestickChartView({
|
||||
data,
|
||||
formatters
|
||||
}: CandlestickChartViewProps) {
|
||||
const colors = getChartColors();
|
||||
|
||||
const ohlcvData = data.filter(isOHLCVData);
|
||||
|
||||
if (ohlcvData.length === 0) {
|
||||
return (
|
||||
<div className="flex h-full items-center justify-center text-sm text-[color:var(--terminal-muted)]">
|
||||
Candlestick chart requires OHLCV data
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<ResponsiveContainer width="100%" height="100%">
|
||||
<ComposedChart data={ohlcvData}>
|
||||
<CartesianGrid strokeDasharray="2 2" stroke={colors.grid} />
|
||||
<XAxis
|
||||
dataKey="date"
|
||||
stroke={colors.muted}
|
||||
fontSize={11}
|
||||
tickFormatter={formatters?.date}
|
||||
minTickGap={32}
|
||||
/>
|
||||
<YAxis
|
||||
stroke={colors.muted}
|
||||
fontSize={11}
|
||||
tickFormatter={formatters?.price}
|
||||
width={60}
|
||||
domain={['auto', 'auto']}
|
||||
/>
|
||||
<Tooltip
|
||||
content={(tooltipProps) => <ChartTooltip {...tooltipProps} formatters={formatters} />}
|
||||
cursor={{ stroke: colors.muted, strokeDasharray: '3 3' }}
|
||||
/>
|
||||
<Scatter
|
||||
dataKey="close"
|
||||
shape={<CandlestickShape />}
|
||||
isAnimationActive={false}
|
||||
/>
|
||||
</ComposedChart>
|
||||
</ResponsiveContainer>
|
||||
);
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
import { getPriceChangeColor } from './chart-colors';
|
||||
|
||||
type CandlestickShapeProps = {
|
||||
cx?: number;
|
||||
payload?: {
|
||||
open: number;
|
||||
high: number;
|
||||
low: number;
|
||||
close: number;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Custom candlestick shape component for Recharts
|
||||
* Renders candlestick with wick and body
|
||||
*/
|
||||
export function CandlestickShape(props: CandlestickShapeProps) {
|
||||
const { cx, payload } = props;
|
||||
|
||||
if (!payload || !cx) return null;
|
||||
|
||||
const { open, high, low, close } = payload;
|
||||
const isPositive = close >= open;
|
||||
const color = getPriceChangeColor(close - open);
|
||||
|
||||
// Calculate positions
|
||||
const bodyTop = Math.min(open, close);
|
||||
const bodyBottom = Math.max(open, close);
|
||||
const bodyHeight = Math.max(bodyBottom - bodyTop, 1);
|
||||
|
||||
// Candlestick width
|
||||
const width = 8;
|
||||
|
||||
return (
|
||||
<g>
|
||||
{/* Upper wick */}
|
||||
<line
|
||||
x1={cx}
|
||||
y1={high}
|
||||
x2={cx}
|
||||
y2={bodyTop}
|
||||
stroke={color}
|
||||
strokeWidth={1}
|
||||
/>
|
||||
|
||||
{/* Body */}
|
||||
<rect
|
||||
x={cx - width / 2}
|
||||
y={bodyTop}
|
||||
width={width}
|
||||
height={bodyHeight}
|
||||
fill={isPositive ? 'transparent' : color}
|
||||
stroke={color}
|
||||
strokeWidth={1}
|
||||
/>
|
||||
|
||||
{/* Lower wick */}
|
||||
<line
|
||||
x1={cx}
|
||||
y1={bodyBottom}
|
||||
x2={cx}
|
||||
y2={low}
|
||||
stroke={color}
|
||||
strokeWidth={1}
|
||||
/>
|
||||
</g>
|
||||
);
|
||||
}
|
||||
@@ -19,14 +19,6 @@ export function getChartColors(): ChartColorPalette {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get color for price change (positive/negative)
|
||||
*/
|
||||
export function getPriceChangeColor(change: number): string {
|
||||
const colors = getChartColors();
|
||||
return change >= 0 ? colors.positive : colors.negative;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert CSS variable to computed color value
|
||||
* Used for chart export since html-to-image can't render CSS variables
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
type MetricCardSize = "default" | "compact" | "inline";
|
||||
|
||||
type MetricCardProps = {
|
||||
label: string;
|
||||
value: string;
|
||||
delta?: string;
|
||||
positive?: boolean;
|
||||
className?: string;
|
||||
size?: MetricCardSize;
|
||||
};
|
||||
|
||||
export function MetricCard({
|
||||
label,
|
||||
value,
|
||||
delta,
|
||||
positive = true,
|
||||
className,
|
||||
size = "default",
|
||||
}: MetricCardProps) {
|
||||
if (size === "inline") {
|
||||
return (
|
||||
<div className={cn("index-card", className)}>
|
||||
<p className="label">{label}</p>
|
||||
<p className="value">{value}</p>
|
||||
{delta ? (
|
||||
<p className={cn("delta", positive ? "positive" : "negative")}>
|
||||
{delta}
|
||||
</p>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (size === "compact") {
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"min-w-0 border-t border-[color:var(--line-weak)] pt-2",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<p className="text-[11px] text-[color:var(--terminal-muted)]">
|
||||
{label}
|
||||
</p>
|
||||
<p className="mt-1 text-xl font-semibold text-[color:var(--terminal-bright)]">
|
||||
{value}
|
||||
</p>
|
||||
{delta ? (
|
||||
<p
|
||||
className={cn(
|
||||
"mt-1 text-[10px]",
|
||||
positive ? "text-[#96f5bf]" : "text-[#ff9898]",
|
||||
)}
|
||||
>
|
||||
{delta}
|
||||
</p>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"min-w-0 border-t border-[color:var(--line-weak)] pt-3",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<p className="text-xs text-[color:var(--terminal-muted)]">{label}</p>
|
||||
<p className="mt-2 text-2xl font-semibold text-[color:var(--terminal-bright)]">
|
||||
{value}
|
||||
</p>
|
||||
{delta ? (
|
||||
<p
|
||||
className={cn(
|
||||
"mt-2 text-xs",
|
||||
positive ? "text-[#96f5bf]" : "text-[#ff9898]",
|
||||
)}
|
||||
>
|
||||
{delta}
|
||||
</p>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
type ControlButtonVariant = "primary" | "ghost" | "secondary" | "danger";
|
||||
|
||||
export type FinancialControlOption = {
|
||||
value: string;
|
||||
label: string;
|
||||
disabled?: boolean;
|
||||
};
|
||||
|
||||
export type FinancialControlSection = {
|
||||
id: string;
|
||||
label: string;
|
||||
value: string;
|
||||
options: FinancialControlOption[];
|
||||
onChange: (value: string) => void;
|
||||
};
|
||||
|
||||
export type FinancialControlAction = {
|
||||
id: string;
|
||||
label: string;
|
||||
onClick: () => void;
|
||||
disabled?: boolean;
|
||||
variant?: ControlButtonVariant;
|
||||
};
|
||||
|
||||
type FinancialControlBarProps = {
|
||||
title?: string;
|
||||
subtitle?: string;
|
||||
sections: FinancialControlSection[];
|
||||
actions?: FinancialControlAction[];
|
||||
className?: string;
|
||||
};
|
||||
|
||||
export function FinancialControlBar({
|
||||
title = "Control Bar",
|
||||
subtitle,
|
||||
sections,
|
||||
actions,
|
||||
className,
|
||||
}: FinancialControlBarProps) {
|
||||
return (
|
||||
<section
|
||||
className={cn("border-t border-[color:var(--line-weak)] pt-4", className)}
|
||||
>
|
||||
<div className="flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between">
|
||||
<div className="min-w-0">
|
||||
<h3 className="text-base font-semibold text-[color:var(--terminal-bright)]">
|
||||
{title}
|
||||
</h3>
|
||||
{subtitle ? (
|
||||
<p className="mt-1 text-sm text-[color:var(--terminal-muted)]">
|
||||
{subtitle}
|
||||
</p>
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
{actions && actions.length > 0 ? (
|
||||
<div className="grid w-full grid-cols-1 gap-2 sm:flex sm:w-auto sm:flex-wrap sm:items-center sm:justify-end">
|
||||
{actions.map((action) => (
|
||||
<Button
|
||||
key={action.id}
|
||||
type="button"
|
||||
variant={action.variant ?? "secondary"}
|
||||
disabled={action.disabled}
|
||||
className="px-2 py-1 text-xs sm:min-h-9"
|
||||
onClick={action.onClick}
|
||||
>
|
||||
{action.label}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
<div className="mt-4 grid grid-cols-1 gap-3">
|
||||
{sections.map((section) => (
|
||||
<div key={section.id} className="data-surface px-3 py-3">
|
||||
<span className="mb-2 block text-[11px] text-[color:var(--terminal-muted)]">
|
||||
{section.label}
|
||||
</span>
|
||||
<div className="flex flex-wrap items-center gap-1.5">
|
||||
{section.options.map((option) => (
|
||||
<Button
|
||||
key={`${section.id}-${option.value}`}
|
||||
type="button"
|
||||
variant={option.value === section.value ? "primary" : "ghost"}
|
||||
disabled={option.disabled}
|
||||
className="px-2 py-1 text-xs sm:min-h-9"
|
||||
onClick={() => section.onChange(option.value)}
|
||||
>
|
||||
{option.label}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import { X } from "lucide-react";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
type FilterChipProps = {
|
||||
label: string;
|
||||
onRemove: () => void;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
export function FilterChip({ label, onRemove, className }: FilterChipProps) {
|
||||
return (
|
||||
<span className={cn("filter-chip", className)}>
|
||||
<span className="truncate">{label}</span>
|
||||
<button
|
||||
type="button"
|
||||
onClick={onRemove}
|
||||
className="remove"
|
||||
aria-label={`Remove ${label} filter`}
|
||||
>
|
||||
<X className="size-3" />
|
||||
</button>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user