+ {/* Shape Preview (Visible during shape drag) */}
+ {isShapeDragging && startShapePosition && (
+
+ )}
+
+ {/* Hidden file input for image upload */}
+
+
+ {/* Current drawing path (Live preview) */}
+ {isDrawing && currentPath.length > 1 && (
+
+ )}
+
+ {/* Render all finalized elements */}
+ {elements.map((element) => {
+ const isSelected = selectedElement === element.id
+ // Base style, position is handled differently for drawing
+ const baseStyle = {
+ position: "absolute" as const,
+ zIndex: element.zIndex,
+ }
+ // Specific style for non-drawing elements, applying position
+ const elementStyle = element.type !== 'drawing' ? {
+ ...baseStyle,
+ left: `${element.position.x}px`,
+ top: `${element.position.y}px`,
+ } : baseStyle; // DrawingCanvas calculates its own position
+
+ // Delete button for selected element
+ const deleteButton =
+ isSelected && activeTool === "select" ? (
+
+ ) : null
+
+ // Wrapper div for positioning and event handling
+ const wrapperStyle = element.type === 'drawing' ? baseStyle : elementStyle;
+
+ return (
+
handleElementPointerDown(e, element.id)}>
+ {deleteButton}
+ {(() => {
+ switch (element.type) {
+ case "sticky":
+ return bringToFront(element.id)} onPositionChange={(newPos) => updateElementPosition(element.id, newPos)} onContentChange={(newContent) => updateElementContent(element.id, newContent)} canDrag={activeTool === "select"} />;
+ case "image":
+ return bringToFront(element.id)} onPositionChange={(newPos) => updateElementPosition(element.id, newPos)} canDrag={activeTool === "select"} />;
+ case "text":
+ return bringToFront(element.id)} onPositionChange={(newPos) => updateElementPosition(element.id, newPos)} onContentChange={(newContent) => updateElementContent(element.id, newContent)} canDrag={activeTool === "select"} />;
+ case "drawing":
+ // Pass baseStyle as DrawingCanvas handles its own positioning via SVG coords
+ return ;
+ case "stamp":
+ return bringToFront(element.id)} onPositionChange={(newPos) => updateElementPosition(element.id, newPos)} canDrag={activeTool === "select"} />;
+ case "shape":
+ return ;
+ default:
+ return null;
+ }
+ })()}
+
+ )
+ })}
+
+ )
+}
diff --git a/components/chat-panel.tsx b/components/chat-panel.tsx
new file mode 100644
index 0000000..b1f049b
--- /dev/null
+++ b/components/chat-panel.tsx
@@ -0,0 +1,73 @@
+"use client"
+
+import type React from "react"
+
+import { useState } from "react"
+import { Button } from "@/components/ui/button"
+import { Input } from "@/components/ui/input"
+import { Send } from "lucide-react"
+
+export default function ChatPanel() {
+ const [message, setMessage] = useState("")
+ const [messages, setMessages] = useState<{ text: string; sender: string }[]>([])
+
+ const handleSendMessage = () => {
+ if (message.trim()) {
+ setMessages([...messages, { text: message, sender: "user" }])
+ setMessage("")
+ }
+ }
+
+ const handleKeyDown = (e: React.KeyboardEvent) => {
+ if (e.key === "Enter" && !e.shiftKey) {
+ e.preventDefault()
+ handleSendMessage()
+ }
+ }
+
+ return (
+