UI Improvements: - Style scrollbars with primary color accent - Scrollbar thumb transitions on hover (40% → 60% → 80% opacity) - Add fill tool options to toolbar (color picker + opacity) - Support for Firefox with scrollbar-color property Transparency Support: - Set default canvas background to transparent - First layer now transparent instead of white fill - Enables creating images with transparency - Checkerboard pattern shows through transparent areas - Proper PNG export support with alpha channel 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
214 lines
7.4 KiB
TypeScript
214 lines
7.4 KiB
TypeScript
'use client';
|
|
|
|
import { useToolStore } from '@/store';
|
|
import { useShapeStore } from '@/store/shape-store';
|
|
import { useSelectionStore } from '@/store/selection-store';
|
|
|
|
export function ToolOptions() {
|
|
const { activeTool, settings, setSize, setOpacity, setHardness, setColor, setFlow } = useToolStore();
|
|
const { settings: shapeSettings, setShapeType } = useShapeStore();
|
|
const { selectionType, setSelectionType } = useSelectionStore();
|
|
|
|
// Drawing tools: brush, pencil, eraser
|
|
const isDrawingTool = ['brush', 'eraser', 'pencil'].includes(activeTool);
|
|
const showHardness = ['brush'].includes(activeTool);
|
|
const showColor = ['brush', 'pencil'].includes(activeTool);
|
|
const showFlow = ['brush'].includes(activeTool);
|
|
|
|
// Fill tool
|
|
const isFillTool = activeTool === 'fill';
|
|
|
|
// Shape tool
|
|
const isShapeTool = activeTool === 'shape';
|
|
|
|
// Selection tool
|
|
const isSelectionTool = activeTool === 'select';
|
|
|
|
// Don't show options bar if no options available
|
|
if (!isDrawingTool && !isFillTool && !isShapeTool && !isSelectionTool) {
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
<div className="flex items-center gap-6 px-4 flex-1">
|
|
{/* Drawing Tools Options */}
|
|
{isDrawingTool && (
|
|
<>
|
|
{showColor && (
|
|
<div className="flex items-center gap-2">
|
|
<label className="text-sm font-medium text-card-foreground whitespace-nowrap">
|
|
Color:
|
|
</label>
|
|
<input
|
|
type="color"
|
|
value={settings.color}
|
|
onChange={(e) => setColor(e.target.value)}
|
|
className="h-8 w-16 rounded border border-border cursor-pointer"
|
|
/>
|
|
<input
|
|
type="text"
|
|
value={settings.color}
|
|
onChange={(e) => setColor(e.target.value)}
|
|
className="w-24 px-2 py-1 text-xs rounded border border-border bg-background text-foreground"
|
|
/>
|
|
</div>
|
|
)}
|
|
|
|
<div className="flex items-center gap-2">
|
|
<label className="text-sm font-medium text-card-foreground whitespace-nowrap">
|
|
Size:
|
|
</label>
|
|
<input
|
|
type="range"
|
|
min="1"
|
|
max="200"
|
|
value={settings.size}
|
|
onChange={(e) => setSize(Number(e.target.value))}
|
|
className="w-32"
|
|
/>
|
|
<span className="text-sm text-muted-foreground w-12">
|
|
{settings.size}px
|
|
</span>
|
|
</div>
|
|
|
|
<div className="flex items-center gap-2">
|
|
<label className="text-sm font-medium text-card-foreground whitespace-nowrap">
|
|
Opacity:
|
|
</label>
|
|
<input
|
|
type="range"
|
|
min="0"
|
|
max="100"
|
|
value={settings.opacity * 100}
|
|
onChange={(e) => setOpacity(Number(e.target.value) / 100)}
|
|
className="w-32"
|
|
/>
|
|
<span className="text-sm text-muted-foreground w-10">
|
|
{Math.round(settings.opacity * 100)}%
|
|
</span>
|
|
</div>
|
|
|
|
{showHardness && (
|
|
<div className="flex items-center gap-2">
|
|
<label className="text-sm font-medium text-card-foreground whitespace-nowrap">
|
|
Hardness:
|
|
</label>
|
|
<input
|
|
type="range"
|
|
min="0"
|
|
max="100"
|
|
value={settings.hardness * 100}
|
|
onChange={(e) => setHardness(Number(e.target.value) / 100)}
|
|
className="w-32"
|
|
/>
|
|
<span className="text-sm text-muted-foreground w-10">
|
|
{Math.round(settings.hardness * 100)}%
|
|
</span>
|
|
</div>
|
|
)}
|
|
|
|
{showFlow && (
|
|
<div className="flex items-center gap-2">
|
|
<label className="text-sm font-medium text-card-foreground whitespace-nowrap">
|
|
Flow:
|
|
</label>
|
|
<input
|
|
type="range"
|
|
min="0"
|
|
max="100"
|
|
value={settings.flow * 100}
|
|
onChange={(e) => setFlow(Number(e.target.value) / 100)}
|
|
className="w-32"
|
|
/>
|
|
<span className="text-sm text-muted-foreground w-10">
|
|
{Math.round(settings.flow * 100)}%
|
|
</span>
|
|
</div>
|
|
)}
|
|
</>
|
|
)}
|
|
|
|
{/* Fill Tool Options */}
|
|
{isFillTool && (
|
|
<>
|
|
<div className="flex items-center gap-2">
|
|
<label className="text-sm font-medium text-card-foreground whitespace-nowrap">
|
|
Color:
|
|
</label>
|
|
<input
|
|
type="color"
|
|
value={settings.color}
|
|
onChange={(e) => setColor(e.target.value)}
|
|
className="h-8 w-16 rounded border border-border cursor-pointer"
|
|
/>
|
|
<input
|
|
type="text"
|
|
value={settings.color}
|
|
onChange={(e) => setColor(e.target.value)}
|
|
className="w-24 px-2 py-1 text-xs rounded border border-border bg-background text-foreground"
|
|
/>
|
|
</div>
|
|
|
|
<div className="flex items-center gap-2">
|
|
<label className="text-sm font-medium text-card-foreground whitespace-nowrap">
|
|
Opacity:
|
|
</label>
|
|
<input
|
|
type="range"
|
|
min="0"
|
|
max="100"
|
|
value={settings.opacity * 100}
|
|
onChange={(e) => setOpacity(Number(e.target.value) / 100)}
|
|
className="w-32"
|
|
/>
|
|
<span className="text-sm text-muted-foreground w-10">
|
|
{Math.round(settings.opacity * 100)}%
|
|
</span>
|
|
</div>
|
|
</>
|
|
)}
|
|
|
|
{/* Shape Tool Options */}
|
|
{isShapeTool && (
|
|
<div className="flex items-center gap-2">
|
|
<label className="text-sm font-medium text-card-foreground whitespace-nowrap">
|
|
Shape:
|
|
</label>
|
|
<select
|
|
value={shapeSettings.type}
|
|
onChange={(e) => setShapeType(e.target.value as any)}
|
|
className="px-3 py-1.5 text-sm rounded-md border border-border bg-background text-foreground"
|
|
>
|
|
<option value="rectangle">Rectangle</option>
|
|
<option value="ellipse">Ellipse</option>
|
|
<option value="line">Line</option>
|
|
<option value="arrow">Arrow</option>
|
|
<option value="polygon">Polygon</option>
|
|
<option value="star">Star</option>
|
|
<option value="triangle">Triangle</option>
|
|
</select>
|
|
</div>
|
|
)}
|
|
|
|
{/* Selection Tool Options */}
|
|
{isSelectionTool && (
|
|
<div className="flex items-center gap-2">
|
|
<label className="text-sm font-medium text-card-foreground whitespace-nowrap">
|
|
Mode:
|
|
</label>
|
|
<select
|
|
value={selectionType}
|
|
onChange={(e) => setSelectionType(e.target.value as any)}
|
|
className="px-3 py-1.5 text-sm rounded-md border border-border bg-background text-foreground"
|
|
>
|
|
<option value="rectangular">Rectangular</option>
|
|
<option value="elliptical">Elliptical</option>
|
|
<option value="lasso">Lasso</option>
|
|
<option value="magic-wand">Magic Wand</option>
|
|
</select>
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|