cffy.in/public/snapmark/components/PropertiesPanel.tsx

137 lines
5.9 KiB
TypeScript

import React from 'react';
import { Shape, COLORS, STROKE_WIDTHS, FONT_SIZES } from '../types';
interface PropertiesPanelProps {
selectedShape: Shape | null;
updateShape: (id: string, attrs: Partial<Shape>) => void;
}
const PropertiesPanel: React.FC<PropertiesPanelProps> = ({
selectedShape,
updateShape,
}) => {
if (!selectedShape) {
return (
<div className="w-72 bg-amber-100 border-l-4 border-amber-900 p-6 flex flex-col items-center justify-center text-center text-amber-800/60 font-comic shrink-0">
<span className="text-4xl mb-4 opacity-50">👆</span>
<p className="font-bold text-lg">Select something!</p>
<p className="text-sm">Click an item to tweak it.</p>
</div>
);
}
return (
<div className="w-72 bg-amber-100 border-l-4 border-amber-900 p-6 flex flex-col gap-8 overflow-y-auto shrink-0 font-comic">
<div className="border-b-2 border-amber-900/20 pb-4">
<h2 className="font-impact text-2xl text-amber-900 uppercase tracking-wide">
Edit {selectedShape.type}
</h2>
</div>
<div>
<h3 className="text-sm font-bold text-amber-900 uppercase tracking-wider mb-3 flex items-center gap-2">
Color <span className="text-xs bg-amber-200 px-1 border border-amber-900 rounded-sm text-amber-900 font-normal normal-case">Pick one</span>
</h3>
<div className="grid grid-cols-6 gap-3">
{COLORS.map((color) => (
<button
key={color}
onClick={() => updateShape(selectedShape.id, { stroke: color, fill: selectedShape.type === 'text' ? color : undefined })}
className={`w-8 h-8 rounded-full border-2 focus:outline-none transition-transform hover:scale-110 ${
selectedShape.stroke === color
? 'ring-2 ring-offset-2 ring-amber-900 border-black scale-110'
: 'border-amber-900/30 hover:border-amber-900'
}`}
style={{ backgroundColor: color }}
title={color}
/>
))}
</div>
</div>
{(selectedShape.type === 'rect' || selectedShape.type === 'arrow') && (
<div>
<h3 className="text-sm font-bold text-amber-900 uppercase tracking-wider mb-3">
Thickness
</h3>
<div className="flex gap-2 bg-amber-50 p-2 border-2 border-amber-900 shadow-[2px_2px_0px_0px_rgba(69,26,3,0.1)]">
{STROKE_WIDTHS.map((width) => (
<button
key={width}
onClick={() => updateShape(selectedShape.id, { strokeWidth: width })}
className={`flex-1 py-1 text-sm font-bold border-2 transition-all ${
selectedShape.strokeWidth === width
? 'bg-amber-900 text-white border-black shadow-sm'
: 'bg-white text-amber-900 border-transparent hover:border-amber-200'
}`}
>
{width}
</button>
))}
</div>
</div>
)}
{selectedShape.type === 'text' && (
<>
<div>
<h3 className="text-sm font-bold text-amber-900 uppercase tracking-wider mb-3">
Size
</h3>
<select
value={(selectedShape as any).fontSize}
onChange={(e) =>
updateShape(selectedShape.id, { fontSize: Number(e.target.value) })
}
className="w-full bg-white border-2 border-amber-900 text-amber-900 font-bold p-2 shadow-[4px_4px_0px_0px_rgba(69,26,3,0.1)] focus:outline-none focus:shadow-[2px_2px_0px_0px_rgba(69,26,3,0.1)] focus:translate-x-[2px] focus:translate-y-[2px]"
>
{FONT_SIZES.map((size) => (
<option key={size} value={size}>
{size}px
</option>
))}
</select>
</div>
<div>
<h3 className="text-sm font-bold text-amber-900 uppercase tracking-wider mb-3">
Text
</h3>
<textarea
rows={4}
value={(selectedShape as any).text}
onChange={(e) => updateShape(selectedShape.id, { text: e.target.value })}
className="w-full bg-white border-2 border-amber-900 text-amber-900 p-2 font-comic shadow-[4px_4px_0px_0px_rgba(69,26,3,0.1)] focus:outline-none focus:shadow-[2px_2px_0px_0px_rgba(69,26,3,0.1)] focus:translate-x-[2px] focus:translate-y-[2px]"
/>
</div>
</>
)}
{selectedShape.type === 'rect' && (
<div>
<h3 className="text-sm font-bold text-amber-900 uppercase tracking-wider mb-3">
Fill
</h3>
<div className="flex flex-col gap-2">
<button
onClick={() => updateShape(selectedShape.id, { fill: 'transparent' })}
className={`px-3 py-2 text-sm font-bold border-2 text-left flex items-center gap-2 ${selectedShape.fill === 'transparent' ? 'bg-white border-amber-900 text-amber-900 shadow-[2px_2px_0px_0px_rgba(69,26,3,0.2)]' : 'border-transparent text-amber-800/70 hover:bg-amber-200/50'}`}
>
<div className="w-4 h-4 border border-amber-900 bg-white"></div>
Empty (Transparent)
</button>
<button
onClick={() => updateShape(selectedShape.id, { fill: selectedShape.stroke + '40' })}
className={`px-3 py-2 text-sm font-bold border-2 text-left flex items-center gap-2 ${selectedShape.fill !== 'transparent' ? 'bg-white border-amber-900 text-amber-900 shadow-[2px_2px_0px_0px_rgba(69,26,3,0.2)]' : 'border-transparent text-amber-800/70 hover:bg-amber-200/50'}`}
>
<div className="w-4 h-4 border border-amber-900 bg-current opacity-40"></div>
Filled (Transparent)
</button>
</div>
</div>
)}
</div>
);
};
export default PropertiesPanel;