From 866929c358734bd758220f9a6759a1a913ba495f Mon Sep 17 00:00:00 2001 From: yveskalume Date: Wed, 7 Jan 2026 16:26:16 +0200 Subject: [PATCH] feat: enhance UI components with improved styling and interactions --- src/components/Inspector.tsx | 92 +++++++------ src/components/Toolbar.tsx | 92 ++++++++----- src/components/TopBar.tsx | 137 ++++++++++--------- src/components/elements/Arrow.tsx | 33 ++++- src/components/inspector/BackgroundPanel.tsx | 124 +++++++++-------- 5 files changed, 274 insertions(+), 204 deletions(-) diff --git a/src/components/Inspector.tsx b/src/components/Inspector.tsx index fc542dd..9a4fdd5 100644 --- a/src/components/Inspector.tsx +++ b/src/components/Inspector.tsx @@ -19,46 +19,29 @@ const Inspector: React.FC = () => { const selectedElement = snap.elements.find(el => el.id === selectedElementId); return ( -
-
+
+
{selectedElement ? ( - <> - {/* Element header */} -
-

- {selectedElement.type} Element +
+ {/* Header with Title and Element Actions */} +
+

+ {selectedElement.type}

-
- - +
+
+ {/* Layer Controls */} +
+ + +
+ +
+ {/* Element-specific inspector */} - {selectedElement.type === 'code' && ( - - )} - {selectedElement.type === 'text' && ( - - )} - {selectedElement.type === 'arrow' && ( - - )} - +
+ {selectedElement.type === 'code' && ( + + )} + {selectedElement.type === 'text' && ( + + )} + {selectedElement.type === 'arrow' && ( + + )} +
+
) : ( - <> -

Canvas Settings

+
+

Canvas Settings

- +
)}
); }; - export default Inspector; diff --git a/src/components/Toolbar.tsx b/src/components/Toolbar.tsx index dd030c6..db66b92 100644 --- a/src/components/Toolbar.tsx +++ b/src/components/Toolbar.tsx @@ -5,24 +5,57 @@ const Toolbar: React.FC = () => { const { tool, setTool, showGrid, setShowGrid, zoom, setZoom } = useCanvasStore(); const tools = [ - { id: 'select', icon: '↖', label: 'Select (V)' }, - { id: 'code', icon: '{ }', label: 'Code Block (C)' }, - { id: 'text', icon: 'T', label: 'Text (T)' }, - { id: 'arrow', icon: '→', label: 'Arrow (A)' }, + { + id: 'select', + label: 'Select (V)', + icon: ( + + + + ) + }, + { + id: 'code', + label: 'Code Block (C)', + icon: ( + + + + ) + }, + { + id: 'text', + label: 'Text (T)', + icon: ( + + + + ) + }, + { + id: 'arrow', + label: 'Arrow (A)', + icon: ( + + + + ) + }, ] as const; return ( -
- {/* Tools */} -
+
+ + {/* Tools Group */} +
{tools.map(({ id, icon, label }) => (
-
+
- {/* Grid toggle */} + {/* Grid Toggle */} - {/* Spacer */} -
- - {/* Zoom controls */} -
+ {/* Zoom Controls */} +
-
+
{Math.round(zoom * 100)}%
diff --git a/src/components/TopBar.tsx b/src/components/TopBar.tsx index 6fede89..9978c4c 100644 --- a/src/components/TopBar.tsx +++ b/src/components/TopBar.tsx @@ -96,13 +96,24 @@ const TopBar: React.FC = ({ stageRef }) => { }; return ( -
- {/* Left section */} +
+ {/* Left section: Logo & Actions */}
-
+
+
+ + + +
+ + YvCode + +
+ +
- -
- -
+
+ + {/* Center section: Title & Tools */} +
+
+ updateMeta({ title: e.target.value })} + className="bg-transparent text-sm font-medium text-center text-neutral-200 focus:text-white px-2 py-1 outline-none rounded hover:bg-white/5 focus:bg-white/10 transition-colors placeholder-neutral-600 w-48" + placeholder="Untitled Project" + /> +
+ + +
+
+
+ + {/* Right section: History & Export */} +
+
-
- - {/* Center section */} -
- updateMeta({ title: e.target.value })} - className="bg-transparent text-white text-center px-2 py-1 border-b border-transparent hover:border-neutral-600 focus:border-blue-500 outline-none" - /> - -
+
- {/* Right section */} -
- -
-
- + +
+
Format
- -
+
+
diff --git a/src/components/elements/Arrow.tsx b/src/components/elements/Arrow.tsx index 94d29c3..1ecd55f 100644 --- a/src/components/elements/Arrow.tsx +++ b/src/components/elements/Arrow.tsx @@ -26,9 +26,10 @@ const Arrow: React.FC = ({ element, isSelected, onSelect, onChange } onChange({ points: newPoints }); }; - // Arrow head pointer - const pointerLength = props.head === 'none' ? 0 : props.thickness * 4; - const pointerWidth = props.head === 'none' ? 0 : props.thickness * 3; + // Modern arrow head calculations + // Make the head slightly sleeker + const pointerLength = props.head === 'none' ? 0 : Math.max(props.thickness * 3, 12); + const pointerWidth = props.head === 'none' ? 0 : Math.max(props.thickness * 2.5, 12); return ( @@ -40,9 +41,14 @@ const Arrow: React.FC = ({ element, isSelected, onSelect, onChange } fill={props.head === 'filled' ? props.color : 'transparent'} pointerLength={pointerLength} pointerWidth={pointerWidth} - tension={props.style === 'curved' ? 0.5 : 0} + tension={props.style === 'curved' ? 0.4 : 0} lineCap="round" lineJoin="round" + // Add subtle glow/shadow for modern feel + shadowColor={props.color} + shadowBlur={8} + shadowOpacity={0.2} + shadowOffset={{ x: 0, y: 0 }} onClick={onSelect} onTap={onSelect} hitStrokeWidth={20} @@ -54,13 +60,26 @@ const Arrow: React.FC = ({ element, isSelected, onSelect, onChange } key={index} x={point.x} y={point.y} - radius={8} - fill="#3b82f6" - stroke="#ffffff" + radius={5} + fill="#ffffff" + stroke="#3b82f6" strokeWidth={2} + shadowColor="rgba(0,0,0,0.15)" + shadowBlur={4} + shadowOffset={{ x: 0, y: 1 }} draggable={!element.locked} onDragMove={(e) => handlePointDrag(index, e)} onDragEnd={(e) => handlePointDrag(index, e)} + onMouseEnter={(e) => { + const container = e.target.getStage()?.container(); + if (container) container.style.cursor = 'grab'; + e.target.scale({ x: 1.5, y: 1.5 }); + }} + onMouseLeave={(e) => { + const container = e.target.getStage()?.container(); + if (container) container.style.cursor = 'default'; + e.target.scale({ x: 1, y: 1 }); + }} /> ))} diff --git a/src/components/inspector/BackgroundPanel.tsx b/src/components/inspector/BackgroundPanel.tsx index 078963e..9eba8a4 100644 --- a/src/components/inspector/BackgroundPanel.tsx +++ b/src/components/inspector/BackgroundPanel.tsx @@ -19,27 +19,27 @@ const BackgroundPanel: React.FC = () => { const { background } = snap; return ( -
+
{/* Background type */}
- -
+ +