design: change to minimalistic and clean light theme

- Replace Matrix/terminal dark theme with modern light design
- Update Tailwind config with clean, professional color palette
- Change from monospace to Inter sans-serif font
- Update chart styling to use white background with subtle grids
- Remove glow effects and neon colors from buttons and UI
- Update color picker with better color options
- Improve sidebar spacing and typography
- Update annotation badges with softer colors
- Change scrollbar styling to match light theme
This commit is contained in:
Marko Djordjevic 2026-02-12 16:01:33 +01:00
parent 42bc3ae757
commit 08e8ebd1e0
9 changed files with 225 additions and 108 deletions

View file

@ -0,0 +1,18 @@
CREATE TABLE `annotations` (
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
`timestamp` integer NOT NULL,
`label_type` text NOT NULL,
`geometry` text,
`created_at` integer NOT NULL
);
--> statement-breakpoint
CREATE TABLE `candles` (
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
`time` integer NOT NULL,
`open` real NOT NULL,
`high` real NOT NULL,
`low` real NOT NULL,
`close` real NOT NULL
);
--> statement-breakpoint
CREATE UNIQUE INDEX `candles_time_unique` ON `candles` (`time`);

View file

@ -0,0 +1 @@
ALTER TABLE `annotations` ADD `color` text DEFAULT '#3b82f6';

View file

@ -0,0 +1,131 @@
{
"version": "6",
"dialect": "sqlite",
"id": "9a43200c-01b1-41fc-ac10-8071afa36f6f",
"prevId": "4f92efce-343c-4fa1-a55b-53b8dd7ed42e",
"tables": {
"annotations": {
"name": "annotations",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true,
"autoincrement": true
},
"timestamp": {
"name": "timestamp",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"label_type": {
"name": "label_type",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"geometry": {
"name": "geometry",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"color": {
"name": "color",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "'#3b82f6'"
},
"created_at": {
"name": "created_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"candles": {
"name": "candles",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true,
"autoincrement": true
},
"time": {
"name": "time",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"open": {
"name": "open",
"type": "real",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"high": {
"name": "high",
"type": "real",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"low": {
"name": "low",
"type": "real",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"close": {
"name": "close",
"type": "real",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {
"candles_time_unique": {
"name": "candles_time_unique",
"columns": [
"time"
],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
}
},
"views": {},
"enums": {},
"_meta": {
"schemas": {},
"tables": {},
"columns": {}
},
"internal": {
"indexes": {}
}
}

View file

@ -4,25 +4,25 @@
@layer base { @layer base {
:root { :root {
--background: 120 100% 4%; --background: 0 0% 100%;
--foreground: 120 100% 50%; --foreground: 222 47% 11%;
--card: 120 100% 6%; --card: 0 0% 100%;
--card-foreground: 120 100% 50%; --card-foreground: 222 47% 11%;
--popover: 120 100% 4%; --popover: 0 0% 100%;
--popover-foreground: 120 100% 50%; --popover-foreground: 222 47% 11%;
--primary: 120 100% 50%; --primary: 221 83% 53%;
--primary-foreground: 120 100% 4%; --primary-foreground: 210 40% 98%;
--secondary: 120 100% 8%; --secondary: 210 40% 96%;
--secondary-foreground: 120 100% 50%; --secondary-foreground: 222 47% 11%;
--muted: 120 100% 10%; --muted: 210 40% 96%;
--muted-foreground: 120 100% 40%; --muted-foreground: 215 16% 47%;
--accent: 120 100% 50%; --accent: 210 40% 96%;
--accent-foreground: 120 100% 4%; --accent-foreground: 222 47% 11%;
--destructive: 348 100% 50%; --destructive: 0 84% 60%;
--destructive-foreground: 120 100% 4%; --destructive-foreground: 210 40% 98%;
--border: 120 100% 10%; --border: 214 32% 91%;
--input: 120 100% 8%; --input: 214 32% 91%;
--ring: 120 100% 50%; --ring: 221 83% 53%;
--radius: 0.5rem; --radius: 0.5rem;
} }
} }
@ -32,14 +32,14 @@
@apply border-border; @apply border-border;
} }
body { body {
@apply bg-background text-foreground; @apply bg-background text-foreground antialiased;
font-family: 'JetBrains Mono', 'Fira Code', 'Courier New', monospace; font-family: 'Inter', system-ui, -apple-system, sans-serif;
} }
} }
@layer base { @layer base {
::selection { ::selection {
@apply bg-matrix/40 text-matrix; @apply bg-primary/20 text-foreground;
} }
::-webkit-scrollbar { ::-webkit-scrollbar {
@ -47,10 +47,10 @@
} }
::-webkit-scrollbar-track { ::-webkit-scrollbar-track {
@apply bg-matrixDark; @apply bg-muted;
} }
::-webkit-scrollbar-thumb { ::-webkit-scrollbar-thumb {
@apply bg-matrix rounded; @apply bg-border hover:bg-muted-foreground/30 rounded;
} }
} }

View file

@ -87,15 +87,17 @@ export default function Home() {
}, [selectedLabelId]); }, [selectedLabelId]);
return ( return (
<div className="flex h-screen"> <div className="flex h-screen bg-background">
{/* Sidebar */} {/* Sidebar */}
<aside className="w-64 flex-shrink-0 flex flex-col border-r border-border"> <aside className="w-72 flex-shrink-0 flex flex-col border-r border-border bg-card">
<div className="p-4 border-b border-border"> <div className="p-6 border-b border-border">
<h1 className="text-xl font-bold">Candle Annotator</h1> <h1 className="text-2xl font-semibold text-foreground">Candle Annotator</h1>
<p className="text-sm text-muted-foreground mt-1">Chart annotation tool</p>
</div> </div>
<div className="p-4"> <div className="p-6">
<FileUpload onUploadSuccess={handleUploadSuccess} /> <FileUpload onUploadSuccess={handleUploadSuccess} />
</div> </div>
<div className="px-6 pb-6">
<Toolbox <Toolbox
activeTool={activeTool} activeTool={activeTool}
onToolChange={setActiveTool} onToolChange={setActiveTool}
@ -107,10 +109,11 @@ export default function Home() {
onLabelSelect={handleLabelSelect} onLabelSelect={handleLabelSelect}
onLabelDelete={handleLabelDelete} onLabelDelete={handleLabelDelete}
/> />
</div>
</aside> </aside>
{/* Main chart area */} {/* Main chart area */}
<main className="flex-1 relative"> <main className="flex-1 relative bg-background">
<CandleChart <CandleChart
ref={chartRef} ref={chartRef}
activeTool={activeTool} activeTool={activeTool}

View file

@ -89,12 +89,12 @@ const CandleChart = forwardRef<CandleChartHandle, CandleChartProps>(
width: chartContainerRef.current.clientWidth, width: chartContainerRef.current.clientWidth,
height: chartContainerRef.current.clientHeight, height: chartContainerRef.current.clientHeight,
layout: { layout: {
background: { color: '#0f172a' }, // Slate-900 background: { color: '#ffffff' },
textColor: '#e2e8f0', // Slate-200 textColor: '#1e293b',
}, },
grid: { grid: {
vertLines: { color: '#1e293b' }, // Subtle grid vertLines: { color: '#f1f5f9' },
horzLines: { color: '#1e293b' }, horzLines: { color: '#f1f5f9' },
}, },
crosshair: { crosshair: {
mode: 1, mode: 1,
@ -102,18 +102,18 @@ const CandleChart = forwardRef<CandleChartHandle, CandleChartProps>(
timeScale: { timeScale: {
timeVisible: true, timeVisible: true,
secondsVisible: false, secondsVisible: false,
borderColor: '#334155', borderColor: '#e2e8f0',
}, },
rightPriceScale: { rightPriceScale: {
borderColor: '#334155', borderColor: '#e2e8f0',
}, },
}); });
const candlestickSeries = chart.addCandlestickSeries({ const candlestickSeries = chart.addCandlestickSeries({
upColor: '#22c55e', // Green upColor: '#10b981',
downColor: '#ef4444', // Red downColor: '#ef4444',
borderVisible: false, borderVisible: false,
wickUpColor: '#22c55e', wickUpColor: '#10b981',
wickDownColor: '#ef4444', wickDownColor: '#ef4444',
}); });
@ -167,8 +167,8 @@ const CandleChart = forwardRef<CandleChartHandle, CandleChartProps>(
time: annotation.timestamp as Time, time: annotation.timestamp as Time,
position: annotation.label_type === 'break_up' ? ('belowBar' as const) : ('aboveBar' as const), position: annotation.label_type === 'break_up' ? ('belowBar' as const) : ('aboveBar' as const),
color: isSelected color: isSelected
? (annotation.label_type === 'break_up' ? '#00ff41' : '#ff0040') ? (annotation.label_type === 'break_up' ? '#059669' : '#dc2626')
: (annotation.label_type === 'break_up' ? '#22c55e' : '#ef4444'), : (annotation.label_type === 'break_up' ? '#10b981' : '#ef4444'),
shape: annotation.label_type === 'break_up' ? ('arrowUp' as const) : ('arrowDown' as const), shape: annotation.label_type === 'break_up' ? ('arrowUp' as const) : ('arrowDown' as const),
text: annotation.label_type === 'break_up' ? 'Break Up' : 'Break Down', text: annotation.label_type === 'break_up' ? 'Break Up' : 'Break Down',
size: isSelected ? 2 : 1, size: isSelected ? 2 : 1,

View file

@ -58,8 +58,8 @@ export default function FileUpload({ onUploadSuccess }: FileUploadProps) {
}; };
return ( return (
<div className="mb-4 p-4 bg-secondary/50 rounded-lg border border-border"> <div className="p-4 bg-muted rounded-lg border border-border">
<h3 className="text-sm font-semibold mb-2">Upload CSV Data</h3> <h3 className="text-sm font-medium mb-3 text-foreground">Upload CSV Data</h3>
<input <input
ref={fileInputRef} ref={fileInputRef}
@ -73,7 +73,6 @@ export default function FileUpload({ onUploadSuccess }: FileUploadProps) {
<Button <Button
variant="outline" variant="outline"
size="sm"
className="w-full" className="w-full"
onClick={() => fileInputRef.current?.click()} onClick={() => fileInputRef.current?.click()}
disabled={isUploading} disabled={isUploading}
@ -84,10 +83,10 @@ export default function FileUpload({ onUploadSuccess }: FileUploadProps) {
{message && ( {message && (
<div <div
className={`mt-2 text-xs p-2 rounded ${ className={`mt-3 text-xs p-3 rounded-md ${
message.type === 'success' message.type === 'success'
? 'bg-green-500/10 text-green-500 border border-green-500/20' ? 'bg-emerald-50 text-emerald-700 border border-emerald-200'
: 'bg-red-500/10 text-red-500 border border-red-500/20' : 'bg-red-50 text-red-700 border border-red-200'
}`} }`}
> >
{message.text} {message.text}

View file

@ -92,7 +92,7 @@ export default function Toolbox({
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
<Button <Button
variant={activeTool === 'break_up' ? 'default' : 'outline'} variant={activeTool === 'break_up' ? 'default' : 'outline'}
className={`justify-start gap-2 ${activeTool === 'break_up' ? 'animate-glow-pulse shadow-glow' : 'hover:shadow-glow'}`} className="justify-start gap-2"
onClick={() => handleToolClick('break_up')} onClick={() => handleToolClick('break_up')}
> >
<ArrowUpCircle className="w-5 h-5" /> <ArrowUpCircle className="w-5 h-5" />
@ -101,7 +101,7 @@ export default function Toolbox({
<Button <Button
variant={activeTool === 'break_down' ? 'default' : 'outline'} variant={activeTool === 'break_down' ? 'default' : 'outline'}
className={`justify-start gap-2 ${activeTool === 'break_down' ? 'animate-glow-pulse shadow-glow' : 'hover:shadow-glow'}`} className="justify-start gap-2"
onClick={() => handleToolClick('break_down')} onClick={() => handleToolClick('break_down')}
> >
<ArrowDownCircle className="w-5 h-5" /> <ArrowDownCircle className="w-5 h-5" />
@ -110,7 +110,7 @@ export default function Toolbox({
<Button <Button
variant={activeTool === 'line' ? 'default' : 'outline'} variant={activeTool === 'line' ? 'default' : 'outline'}
className={`justify-start gap-2 ${activeTool === 'line' ? 'animate-glow-pulse shadow-glow' : 'hover:shadow-glow'}`} className="justify-start gap-2"
onClick={() => handleToolClick('line')} onClick={() => handleToolClick('line')}
> >
<TrendingUp className="w-5 h-5" /> <TrendingUp className="w-5 h-5" />
@ -121,10 +121,10 @@ export default function Toolbox({
<div className="flex gap-1 px-1"> <div className="flex gap-1 px-1">
{[ {[
{ color: '#ef4444', name: 'Red' }, { color: '#ef4444', name: 'Red' },
{ color: '#22c55e', name: 'Green' }, { color: '#10b981', name: 'Green' },
{ color: '#3b82f6', name: 'Blue' }, { color: '#3b82f6', name: 'Blue' },
{ color: '#eab308', name: 'Yellow' }, { color: '#f59e0b', name: 'Orange' },
{ color: '#ffffff', name: 'White' }, { color: '#8b5cf6', name: 'Purple' },
].map((preset) => ( ].map((preset) => (
<Button <Button
key={preset.color} key={preset.color}
@ -151,7 +151,7 @@ export default function Toolbox({
<Button <Button
variant={activeTool === 'delete' ? 'destructive' : 'outline'} variant={activeTool === 'delete' ? 'destructive' : 'outline'}
className={`justify-start gap-2 ${activeTool === 'delete' ? 'animate-glow-pulse shadow-[0_0_15px_#ff0040]' : 'hover:shadow-[0_0_15px_#ff0040]'}`} className="justify-start gap-2"
onClick={() => handleToolClick('delete')} onClick={() => handleToolClick('delete')}
> >
<Trash2 className="w-5 h-5" /> <Trash2 className="w-5 h-5" />
@ -225,22 +225,22 @@ export default function Toolbox({
onClick={() => onLabelSelect?.(annotation.id)} onClick={() => onLabelSelect?.(annotation.id)}
className={`p-2 rounded border text-xs cursor-pointer transition-colors ${ className={`p-2 rounded border text-xs cursor-pointer transition-colors ${
isSelected isSelected
? 'border-matrix bg-matrix/10' ? 'border-primary bg-primary/10'
: 'border-border hover:bg-secondary/30' : 'border-border hover:bg-secondary'
}`} }`}
> >
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div className="flex-1"> <div className="flex-1">
<div className="font-mono text-foreground">{formattedTime}</div> <div className="font-medium text-foreground">{formattedTime}</div>
<div className="mt-1 flex items-center gap-2"> <div className="mt-1 flex items-center gap-2">
<span <span
className={`px-2 py-0.5 rounded text-xs font-semibold ${ className={`px-2 py-0.5 rounded text-xs font-medium ${
annotation.label_type === 'break_up' annotation.label_type === 'break_up'
? 'bg-green-900/50 text-matrix' ? 'bg-emerald-100 text-emerald-700'
: 'bg-red-900/50 text-neonRed' : 'bg-red-100 text-red-700'
}`} }`}
> >
{annotation.label_type === 'break_up' ? 'BREAK UP' : 'BREAK DOWN'} {annotation.label_type === 'break_up' ? 'Break Up' : 'Break Down'}
</span> </span>
</div> </div>
</div> </div>

View file

@ -43,44 +43,9 @@ const config: Config = {
DEFAULT: "hsl(var(--card))", DEFAULT: "hsl(var(--card))",
foreground: "hsl(var(--card-foreground))", foreground: "hsl(var(--card-foreground))",
}, },
matrix: "#00ff41",
matrixDim: "#00cc33",
matrixDark: "#003311",
neonRed: "#ff0040",
neonCyan: "#00d4ff",
neonYellow: "#ffff00",
terminal: "#0a0e0a",
terminalLight: "#0d110d",
}, },
fontFamily: { fontFamily: {
mono: ["JetBrains Mono", "Fira Code", "Courier New", "monospace"], sans: ["Inter", "system-ui", "-apple-system", "sans-serif"],
},
boxShadow: {
"glow-sm": "0 0 8px #00ff41",
glow: "0 0 15px #00ff41, 0 0 30px rgba(0,255,65,0.5)",
"glow-lg": "0 0 20px #00ff41, 0 0 40px rgba(0,255,65,0.5)",
},
keyframes: {
"glow-pulse": {
"0%, 100%": {
boxShadow: "0 0 15px #00ff41",
},
"50%": {
boxShadow: "0 0 30px #00ff41, 0 0 50px rgba(0,255,65,0.5)",
},
},
flicker: {
"0%, 100%": {
opacity: "1",
},
"50%": {
opacity: "0.8",
},
},
},
animation: {
"glow-pulse": "glow-pulse 2s ease-in-out infinite",
flicker: "flicker 0.1s ease-in-out",
}, },
borderRadius: { borderRadius: {
lg: "var(--radius)", lg: "var(--radius)",