11import from "...constants .colors " { PRESET_COLORS }
22import from "...constants .fonts " { FONTS , FONT_SIZES }
3- import from "...constants .tools " { LINE_STYLES }
3+ import from "...constants .tools " { LINE_STYLES , CURVE_STYLES }
44
55def :pub Sidebar (props : dict ) -> JsxElement {
66 currentTool = props.currentTool or " select" ;
@@ -10,6 +10,7 @@ def:pub Sidebar(props: dict) -> JsxElement {
1010 currentFontSize = props.currentFontSize or 24 ;
1111 currentFontFamily = props.currentFontFamily or " Virgil" ;
1212 currentLineStyle = props.currentLineStyle or " solid" ;
13+ currentCurveStyle = props.currentCurveStyle or " curved" ;
1314 currentFillColor = props.currentFillColor or " transparent" ;
1415
1516 selectedElement = props.selectedElement;
@@ -19,13 +20,15 @@ def:pub Sidebar(props: dict) -> JsxElement {
1920 onFontSizeChange = props.onFontSizeChange;
2021 onFontFamilyChange = props.onFontFamilyChange;
2122 onLineStyleChange = props.onLineStyleChange;
23+ onCurveStyleChange = props.onCurveStyleChange;
2224 onFillColorChange = props.onFillColorChange;
2325 onUpdateElement = props.onUpdateElement;
2426
2527 presetColors = PRESET_COLORS();
2628 fontSizes = FONT_SIZES();
2729 fonts = FONTS();
2830 lineStyles = LINE_STYLES();
31+ curveStyles = CURVE_STYLES();
2932
3033 # Determine if we're editing an existing element or setting defaults for new ones
3134 hasSelection = selectedElement and selectedElement.element;
@@ -41,6 +44,7 @@ def:pub Sidebar(props: dict) -> JsxElement {
4144 showFont = False ;
4245 showFontSize = False ;
4346 showLineStyle = False ;
47+ showCurveStyle = False ;
4448 showFillColor = False ;
4549 showShapeTextColor = False ;
4650
@@ -50,6 +54,7 @@ def:pub Sidebar(props: dict) -> JsxElement {
5054 activeFontSize = currentFontSize;
5155 activeFontFamily = currentFontFamily;
5256 activeLineStyle = currentLineStyle;
57+ activeCurveStyle = currentCurveStyle;
5358 activeFillColor = currentFillColor;
5459 activeShapeTextColor = currentColor;
5560
@@ -75,6 +80,12 @@ def:pub Sidebar(props: dict) -> JsxElement {
7580 if elType != " freehand" {
7681 showLineStyle = True ;
7782 }
83+ if elType == " line" or elType == " arrow" {
84+ showCurveStyle = True ;
85+ selRawCurve = sel.curveStyle or " curved" ;
86+ # Map legacy "straight" to "sharp" for display
87+ activeCurveStyle = (selRawCurve == " straight" ) and " sharp" or selRawCurve;
88+ }
7889 activeColor = sel.color;
7990 activeStrokeWidth = sel.strokeWidth;
8091 activeOpacity = sel.opacity or 1.0 ;
@@ -111,14 +122,17 @@ def:pub Sidebar(props: dict) -> JsxElement {
111122 if currentTool != " freehand" {
112123 showLineStyle = True ;
113124 }
125+ if currentTool == " line" or currentTool == " arrow" {
126+ showCurveStyle = True ;
127+ }
114128 if currentTool == " rectangle" or currentTool == " circle" or currentTool == " diamond" {
115129 showFillColor = True ;
116130 }
117131 }
118132 }
119133
120134 # Hide sidebar entirely when nothing to show
121- hasContent = showColor or showStroke or showOpacity or showFont or showFontSize or showLineStyle or showFillColor or hasSelection;
135+ hasContent = showColor or showStroke or showOpacity or showFont or showFontSize or showLineStyle or showCurveStyle or showFillColor or hasSelection;
122136 if not hasContent {
123137 return None ;
124138 }
@@ -181,6 +195,13 @@ def:pub Sidebar(props: dict) -> JsxElement {
181195 }
182196 }
183197
198+ def handleCurveStyleChange (style : str ) -> None {
199+ onCurveStyleChange(style);
200+ if hasSelection {
201+ onUpdateElement({" curveStyle" : style});
202+ }
203+ }
204+
184205 def handleFillColorChange (color : str ) -> None {
185206 onFillColorChange(color);
186207 if hasSelection {
@@ -319,6 +340,28 @@ def:pub Sidebar(props: dict) -> JsxElement {
319340 </div >
320341 </div > or None }
321342
343+ { showCurveStyle and <div >
344+ <span className = " sidebar-label" >Arrow Type </span >
345+ <div className = " flex items-center gap-1 mt-1.5" >
346+ { [
347+ <button
348+ key = { cs.id}
349+ onClick = { lambda - > None { handleCurveStyleChange(cs.id); }}
350+ title = { cs.label}
351+ className = { " flex-1 h-9 rounded-lg flex flex-col items-center justify-center gap-0.5 transition-all duration-150 " + (activeCurveStyle == cs.id and " bg-orange-50 ring-1 ring-orange-200" or " bg-gray-50 hover:bg-gray-100" )}
352+ >
353+ <svg width = " 32" height = " 16" viewBox = " 0 0 32 16" >
354+ { cs.id == " sharp" and <path d = " M2 14 L16 4 L30 14" stroke = { activeCurveStyle == cs.id and " #ea580c" or " #9ca3af" } strokeWidth = " 1.8" fill = " none" strokeLinecap = " round" strokeLinejoin = " round" /> or None }
355+ { cs.id == " curved" and <path d = " M2 14 Q16 2 30 14" stroke = { activeCurveStyle == cs.id and " #ea580c" or " #9ca3af" } strokeWidth = " 1.8" fill = " none" strokeLinecap = " round" /> or None }
356+ { cs.id == " elbow" and <path d = " M2 14 L2 8 Q2 4 6 4 L30 4" stroke = { activeCurveStyle == cs.id and " #ea580c" or " #9ca3af" } strokeWidth = " 1.8" fill = " none" strokeLinecap = " round" strokeLinejoin = " round" /> or None }
357+ </svg >
358+ <span className = { " text-[9px] font-medium " + (activeCurveStyle == cs.id and " text-orange-600" or " text-gray-400" )} >{ cs.label} </span >
359+ </button >
360+ for cs in curveStyles
361+ ]}
362+ </div >
363+ </div > or None }
364+
322365 { showOpacity and <div >
323366 <div className = " flex items-center justify-between" >
324367 <span className = " sidebar-label" >Opacity </span >
0 commit comments