fix: alignment, section order, and tooltip duplication
- Move symbol badge inline with input (flex items-end) so symbol and rack inputs align at the bottom - Move Signal Timeline chart above Slot Evidence table - Deduplicate signal fires by slotId per day in chart data processing and by slotName in tooltip rendering (prevents MACD Bullish etc from appearing twice)
This commit is contained in:
@@ -83,15 +83,22 @@ function ChartTooltip({ active, payload }: { active?: boolean; payload?: Array<{
|
||||
if (!active || !payload?.length) return null;
|
||||
const point = payload[0].payload;
|
||||
const allFires = [...point.bullFires, ...point.bearFires];
|
||||
// Deduplicate by slot name (a slot can fire multiple times on the same day)
|
||||
const seen = new Set<string>();
|
||||
const uniqueFires = allFires.filter((f) => {
|
||||
if (seen.has(f.slotName)) return false;
|
||||
seen.add(f.slotName);
|
||||
return true;
|
||||
});
|
||||
return (
|
||||
<div className="rounded border border-line bg-surface-raised px-3 py-2 text-xs shadow-lg">
|
||||
<div className="font-medium text-fg mb-1">{formatDateFull(point.date)}</div>
|
||||
<div className="text-fg-muted">
|
||||
Close: <span className="text-fg font-medium">${point.close.toFixed(2)}</span>
|
||||
</div>
|
||||
{allFires.length > 0 && (
|
||||
{uniqueFires.length > 0 && (
|
||||
<div className="mt-1.5 space-y-0.5 border-t border-line/50 pt-1.5">
|
||||
{allFires.map((f, i) => (
|
||||
{uniqueFires.map((f, i) => (
|
||||
<div key={i} className="flex items-center gap-1.5">
|
||||
<span className="inline-block w-1.5 h-1.5 rounded-full" style={{ backgroundColor: BODY_COLOR[f.body] }} />
|
||||
<span className="text-fg">{f.slotName}</span>
|
||||
@@ -185,12 +192,19 @@ export function ConfluenceChart({ symbol }: ConfluenceChartProps) {
|
||||
const data: ChartPoint[] = candles.map((c) => {
|
||||
const key = toDateKey(c.ts);
|
||||
const dayFires = firesByDate.get(key) ?? [];
|
||||
// Deduplicate by slot name per day (a slot can fire multiple times)
|
||||
const seenSlots = new Set<string>();
|
||||
const uniqueDayFires = dayFires.filter((f) => {
|
||||
if (seenSlots.has(f.slotId)) return false;
|
||||
seenSlots.add(f.slotId);
|
||||
return true;
|
||||
});
|
||||
return {
|
||||
date: c.ts,
|
||||
dateShort: formatDate(c.ts),
|
||||
close: c.c,
|
||||
bullFires: dayFires.filter((f) => f.body === 'bull'),
|
||||
bearFires: dayFires.filter((f) => f.body === 'bear' || f.body === 'exit'),
|
||||
bullFires: uniqueDayFires.filter((f) => f.body === 'bull'),
|
||||
bearFires: uniqueDayFires.filter((f) => f.body === 'bear' || f.body === 'exit'),
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@@ -119,6 +119,7 @@ export function ConfluencePanel() {
|
||||
|
||||
{/* Header */}
|
||||
<div className="flex flex-wrap items-end gap-4">
|
||||
<div className="flex items-end gap-2">
|
||||
<div>
|
||||
<label className="block text-xs text-fg-muted mb-1">Symbol</label>
|
||||
<div className="relative w-48">
|
||||
@@ -130,8 +131,9 @@ export function ConfluencePanel() {
|
||||
inputClassName="w-full bg-surface-sunken border border-line rounded-lg px-3 py-1.5 text-xs text-fg placeholder:text-fg-muted focus:outline-none focus:border-accent focus:ring-1 focus:ring-accent"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{symbol && (
|
||||
<span className="mt-1 inline-flex items-center rounded bg-accent/10 border border-accent/30 px-2 py-0.5 text-xs font-medium text-accent">
|
||||
<span className="mb-0.5 inline-flex items-center rounded bg-accent/10 border border-accent/30 px-2 py-1.5 text-xs font-medium text-accent">
|
||||
{symbol}
|
||||
</span>
|
||||
)}
|
||||
@@ -187,6 +189,13 @@ export function ConfluencePanel() {
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{/* Signal Timeline chart */}
|
||||
{symbol && (
|
||||
<CollapsibleSection title="Signal Timeline" defaultOpen>
|
||||
<ConfluenceChart symbol={symbol} />
|
||||
</CollapsibleSection>
|
||||
)}
|
||||
|
||||
{/* Slot evidence grid */}
|
||||
{assessments.length > 0 && (
|
||||
<CollapsibleSection title="Slot Evidence" defaultOpen>
|
||||
@@ -211,13 +220,6 @@ export function ConfluencePanel() {
|
||||
</CollapsibleSection>
|
||||
)}
|
||||
|
||||
{/* Signal Timeline chart */}
|
||||
{symbol && (
|
||||
<CollapsibleSection title="Signal Timeline" defaultOpen>
|
||||
<ConfluenceChart symbol={symbol} />
|
||||
</CollapsibleSection>
|
||||
)}
|
||||
|
||||
{/* Scorecard */}
|
||||
{scorecard && scorecard.slots.length > 0 && (
|
||||
<CollapsibleSection title="Reliability Scorecard">
|
||||
|
||||
Reference in New Issue
Block a user