From 006e95c2669fbac92d8d39f261c02a1a1339ff6f Mon Sep 17 00:00:00 2001 From: Marko Djordjevic Date: Thu, 12 Feb 2026 14:04:51 +0100 Subject: [PATCH] feat: add color support for line annotations - Add color field to annotations schema with default blue (#3b82f6) - Add color picker UI with 5 preset colors (red, green, blue, yellow, white) - Pass selected color through component hierarchy (Page -> Toolbox, CandleChart -> SvgOverlay) - Store color when creating line annotations - Render lines with their stored color - Update database with color column - Preview lines show selected color during drawing Phase 1 of LINE_DRAWING_IMPROVEMENTS.md complete --- src/app/api/annotations/route.ts | 3 ++- src/app/page.tsx | 4 ++++ src/components/CandleChart.tsx | 4 +++- src/components/SvgOverlay.tsx | 8 +++++-- src/components/Toolbox.tsx | 36 +++++++++++++++++++++++++++++++- src/lib/db/schema.ts | 1 + 6 files changed, 51 insertions(+), 5 deletions(-) diff --git a/src/app/api/annotations/route.ts b/src/app/api/annotations/route.ts index 507a488..bc1316d 100644 --- a/src/app/api/annotations/route.ts +++ b/src/app/api/annotations/route.ts @@ -26,7 +26,7 @@ export async function GET() { export async function POST(request: NextRequest) { try { const body = await request.json(); - const { timestamp, label_type, geometry } = body; + const { timestamp, label_type, geometry, color } = body; // Validate required fields if (!timestamp || !label_type) { @@ -45,6 +45,7 @@ export async function POST(request: NextRequest) { timestamp, label_type, geometry: geometryString, + color: color || '#3b82f6', created_at: Math.floor(Date.now() / 1000), }) .returning(); diff --git a/src/app/page.tsx b/src/app/page.tsx index 233be10..0664b40 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -7,6 +7,7 @@ import CandleChart, { CandleChartHandle } from '@/components/CandleChart'; export default function Home() { const [activeTool, setActiveTool] = useState(null); + const [selectedColor, setSelectedColor] = useState('#3b82f6'); const chartRef = useRef(null); const handleExport = () => { @@ -37,6 +38,8 @@ export default function Home() { activeTool={activeTool} onToolChange={setActiveTool} onExport={handleExport} + selectedColor={selectedColor} + onColorChange={setSelectedColor} /> @@ -46,6 +49,7 @@ export default function Home() { ref={chartRef} activeTool={activeTool} onAnnotationChange={handleAnnotationChange} + selectedColor={selectedColor} /> diff --git a/src/components/CandleChart.tsx b/src/components/CandleChart.tsx index c5689c9..63522f0 100644 --- a/src/components/CandleChart.tsx +++ b/src/components/CandleChart.tsx @@ -28,6 +28,7 @@ interface Annotation { interface CandleChartProps { activeTool: string | null; onAnnotationChange?: () => void; + selectedColor: string; } export interface CandleChartHandle { @@ -35,7 +36,7 @@ export interface CandleChartHandle { } const CandleChart = forwardRef( - ({ activeTool, onAnnotationChange }, ref) => { + ({ activeTool, onAnnotationChange, selectedColor }, ref) => { const chartContainerRef = useRef(null); const chartRef = useRef(null); const seriesRef = useRef | null>(null); @@ -277,6 +278,7 @@ const CandleChart = forwardRef( series={seriesRef.current} activeTool={activeTool} onAnnotationChange={onAnnotationChange} + selectedColor={selectedColor} /> ); diff --git a/src/components/SvgOverlay.tsx b/src/components/SvgOverlay.tsx index d0d68fa..ee0002c 100644 --- a/src/components/SvgOverlay.tsx +++ b/src/components/SvgOverlay.tsx @@ -13,6 +13,7 @@ interface Annotation { endTime?: number; endPrice?: number; } | null; + color?: string; created_at: number; } @@ -21,6 +22,7 @@ interface SvgOverlayProps { series: ISeriesApi<'Candlestick'> | null; activeTool: string | null; onAnnotationChange?: () => void; + selectedColor: string; } interface Point { @@ -33,6 +35,7 @@ export default function SvgOverlay({ series, activeTool, onAnnotationChange, + selectedColor, }: SvgOverlayProps) { const svgRef = useRef(null); const [dimensions, setDimensions] = useState({ width: 0, height: 0 }); @@ -169,6 +172,7 @@ export default function SvgOverlay({ body: JSON.stringify({ timestamp: drawingLine.start.time, label_type: 'line', + color: selectedColor, geometry: { startTime: drawingLine.start.time, startPrice: drawingLine.start.price, @@ -299,7 +303,7 @@ export default function SvgOverlay({ y1={start.y} x2={end.x} y2={end.y} - stroke="#3b82f6" + stroke={annotation.color || '#3b82f6'} strokeWidth="2" style={{ cursor: activeTool === 'delete' ? 'pointer' : 'default' }} /> @@ -322,7 +326,7 @@ export default function SvgOverlay({ y1={start.y} x2={end.x} y2={end.y} - stroke="#3b82f6" + stroke={selectedColor} strokeWidth="2" strokeDasharray="5,5" opacity="0.6" diff --git a/src/components/Toolbox.tsx b/src/components/Toolbox.tsx index 1ae0cbc..845584f 100644 --- a/src/components/Toolbox.tsx +++ b/src/components/Toolbox.tsx @@ -10,9 +10,11 @@ interface ToolboxProps { activeTool: Tool; onToolChange: (tool: Tool) => void; onExport: () => void; + selectedColor: string; + onColorChange: (color: string) => void; } -export default function Toolbox({ activeTool, onToolChange, onExport }: ToolboxProps) { +export default function Toolbox({ activeTool, onToolChange, onExport, selectedColor, onColorChange }: ToolboxProps) { const handleToolClick = (tool: Tool) => { // Toggle: if clicking the active tool, deactivate it if (activeTool === tool) { @@ -54,6 +56,38 @@ export default function Toolbox({ activeTool, onToolChange, onExport }: ToolboxP Draw Line + {/* Color picker - shown when line tool is available */} +
+ {[ + { color: '#ef4444', name: 'Red' }, + { color: '#22c55e', name: 'Green' }, + { color: '#3b82f6', name: 'Blue' }, + { color: '#eab308', name: 'Yellow' }, + { color: '#ffffff', name: 'White' }, + ].map((preset) => ( + + ))} +
+