feat: implement label management with sidebar, hacker theme, and Docker support
- Add label selection on chart with visual highlight (size 2x, color change) - Implement keyboard delete handler (Delete/Backspace keys) - Add comprehensive label management sidebar with: - Collapsible label annotations section - Search by timestamp - Filter by type (Break Up, Break Down, All) - Individual delete buttons - Count display - Click to select/highlight on chart - Transform UI with hacker theme: - Matrix green (#00ff41) on dark background (#0a0e0a) - Monospace font (JetBrains Mono) - Glow effects on button hover and active states - Custom scrollbar styling - Terminal-inspired aesthetic - Add Docker deployment: - Multi-stage Dockerfile with standalone output - docker-compose.yml with volume persistence - Non-root user (nextjs) for security - Health check endpoint integration - Tailwind and CSS enhancements: - Custom colors (matrix, matrixDim, neonRed, etc.) - Glow box shadows and animations - Selection and scrollbar styling
This commit is contained in:
parent
74b84073a9
commit
a1fa86fe55
14 changed files with 509 additions and 42 deletions
|
|
@ -29,6 +29,8 @@ interface CandleChartProps {
|
|||
activeTool: string | null;
|
||||
onAnnotationChange?: () => void;
|
||||
selectedColor: string;
|
||||
selectedLabelId?: number | null;
|
||||
onLabelSelect?: (id: number) => void;
|
||||
}
|
||||
|
||||
export interface CandleChartHandle {
|
||||
|
|
@ -36,7 +38,7 @@ export interface CandleChartHandle {
|
|||
}
|
||||
|
||||
const CandleChart = forwardRef<CandleChartHandle, CandleChartProps>(
|
||||
({ activeTool, onAnnotationChange, selectedColor }, ref) => {
|
||||
({ activeTool, onAnnotationChange, selectedColor, selectedLabelId, onLabelSelect }, ref) => {
|
||||
const chartContainerRef = useRef<HTMLDivElement>(null);
|
||||
const chartRef = useRef<IChartApi | null>(null);
|
||||
const seriesRef = useRef<ISeriesApi<'Candlestick'> | null>(null);
|
||||
|
|
@ -159,17 +161,23 @@ const CandleChart = forwardRef<CandleChartHandle, CandleChartProps>(
|
|||
);
|
||||
|
||||
const markers = markerAnnotations
|
||||
.map((annotation) => ({
|
||||
time: annotation.timestamp as Time,
|
||||
position: annotation.label_type === 'break_up' ? ('belowBar' as const) : ('aboveBar' as const),
|
||||
color: annotation.label_type === 'break_up' ? '#22c55e' : '#ef4444',
|
||||
shape: annotation.label_type === 'break_up' ? ('arrowUp' as const) : ('arrowDown' as const),
|
||||
text: annotation.label_type === 'break_up' ? 'Break Up' : 'Break Down',
|
||||
}))
|
||||
.map((annotation) => {
|
||||
const isSelected = annotation.id === selectedLabelId;
|
||||
return {
|
||||
time: annotation.timestamp as Time,
|
||||
position: annotation.label_type === 'break_up' ? ('belowBar' as const) : ('aboveBar' as const),
|
||||
color: isSelected
|
||||
? (annotation.label_type === 'break_up' ? '#00ff41' : '#ff0040')
|
||||
: (annotation.label_type === 'break_up' ? '#22c55e' : '#ef4444'),
|
||||
shape: annotation.label_type === 'break_up' ? ('arrowUp' as const) : ('arrowDown' as const),
|
||||
text: annotation.label_type === 'break_up' ? 'Break Up' : 'Break Down',
|
||||
size: isSelected ? 2 : 1,
|
||||
};
|
||||
})
|
||||
.sort((a, b) => (a.time as number) - (b.time as number));
|
||||
|
||||
seriesRef.current.setMarkers(markers);
|
||||
}, [annotations]);
|
||||
}, [annotations, selectedLabelId]);
|
||||
|
||||
// Handle chart clicks for annotation
|
||||
useEffect(() => {
|
||||
|
|
@ -244,6 +252,23 @@ const CandleChart = forwardRef<CandleChartHandle, CandleChartProps>(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Select/deselect label markers by clicking them
|
||||
if (!activeTool || activeTool === 'break_up' || activeTool === 'break_down') {
|
||||
const timestamp = typeof time === 'string' ? Date.parse(time) / 1000 : (time as number);
|
||||
|
||||
// Find annotation at this timestamp (within tolerance)
|
||||
const tolerance = 60; // 60 seconds tolerance
|
||||
const annotation = annotations.find(
|
||||
(a) =>
|
||||
(a.label_type === 'break_up' || a.label_type === 'break_down') &&
|
||||
Math.abs(a.timestamp - timestamp) < tolerance
|
||||
);
|
||||
|
||||
if (annotation) {
|
||||
onLabelSelect?.(annotation.id === selectedLabelId ? -1 : annotation.id);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
chartRef.current.subscribeClick(handleClick);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue