@ -346,26 +346,15 @@ function GroupControls({ groupId, zoom }: GroupControlsProps) {
{ /* Vertical context menu - appears above the three-dot button */ }
{ /* Vertical context menu - appears above the three-dot button */ }
{ showMenu && (
{ showMenu && (
< div className = "absolute bottom-full left-1/2 -translate-x-1/2 mb-1 bg-neutral-800/90 backdrop-blur rounded-lg py-1 min-w-[130px] shadow-lg shadow-black/30" >
< div className = "absolute bottom-full left-1/2 -translate-x-1/2 mb-1 bg-neutral-800/90 backdrop-blur rounded-lg py-1 min-w-[130px] shadow-lg shadow-black/30" ref = { colorPickerRef } >
{ /* Background color row */ }
{ /* Color fan - anchored to top-left corner of menu */ }
< div className = "relative" ref = { colorPickerRef } >
< button
onClick = { ( e ) = > { e . stopPropagation ( ) ; setShowColorPicker ( ! showColorPicker ) ; } }
className = "flex items-center gap-2 px-3 py-1.5 w-full hover:bg-white/10 text-xs text-white/80 transition-colors"
>
< div
className = "w-3 h-3 rounded-full border border-white/30"
style = { { backgroundColor : bgColor } }
/ >
< span > Background < / span >
< / button >
{ showColorPicker && (
{ showColorPicker && (
< >
< >
< div
< div
className = "fixed inset-0 z-40"
className = "fixed inset-0 z-40"
onClick = { ( ) = > setShowColorPicker ( false ) }
onClick = { ( ) = > setShowColorPicker ( false ) }
/ >
/ >
< div className = "absolute bottom-full left-0 mb-1 z-50 pointer-events-auto" >
< div className = "absolute top-0 left-0 z-50 pointer-events-auto" >
{ COLOR_OPTIONS . map ( ( { color , label } , index ) = > {
{ COLOR_OPTIONS . map ( ( { color , label } , index ) = > {
const totalItems = COLOR_OPTIONS . length ;
const totalItems = COLOR_OPTIONS . length ;
const arcSpread = 180 ;
const arcSpread = 180 ;
@ -377,7 +366,7 @@ function GroupControls({ groupId, zoom }: GroupControlsProps) {
const x = Math . cos ( rad ) * radius ;
const x = Math . cos ( rad ) * radius ;
const y = Math . sin ( rad ) * radius ;
const y = Math . sin ( rad ) * radius ;
const finalX = x ;
const finalX = x ;
const finalY = y - 12 ;
const finalY = y ;
return (
return (
< button
< button
@ -390,8 +379,8 @@ function GroupControls({ groupId, zoom }: GroupControlsProps) {
} ` }
} ` }
style = { {
style = { {
backgroundColor : PICKER_PREVIEW_COLORS [ color ] ,
backgroundColor : PICKER_PREVIEW_COLORS [ color ] ,
left : finalX ,
left : finalX - 12 ,
top : finalY ,
top : finalY - 12 ,
animation : ` colorFanIn- ${ index } 0.25s cubic-bezier(0.34, 1.56, 0.64, 1) forwards ` ,
animation : ` colorFanIn- ${ index } 0.25s cubic-bezier(0.34, 1.56, 0.64, 1) forwards ` ,
animationDelay : ` ${ index * 0.025 } s ` ,
animationDelay : ` ${ index * 0.025 } s ` ,
opacity : 0 ,
opacity : 0 ,
@ -402,14 +391,14 @@ function GroupControls({ groupId, zoom }: GroupControlsProps) {
@keyframes colorFanIn - $ { index } {
@keyframes colorFanIn - $ { index } {
0 % {
0 % {
opacity : 0 ;
opacity : 0 ;
left : 0 px ;
left : - 12 px ;
top : 0 px ;
top : - 12 px ;
transform : scale ( 0.3 ) ;
transform : scale ( 0.3 ) ;
}
}
100 % {
100 % {
opacity : 1 ;
opacity : 1 ;
left : $ { finalX } px ;
left : $ { finalX - 12 } px ;
top : $ { finalY } px ;
top : $ { finalY - 12 } px ;
transform : scale ( 1 ) ;
transform : scale ( 1 ) ;
}
}
}
}
@ -420,7 +409,18 @@ function GroupControls({ groupId, zoom }: GroupControlsProps) {
< / div >
< / div >
< / >
< / >
) }
) }
< / div >
{ /* Background color row */ }
< button
onClick = { ( e ) = > { e . stopPropagation ( ) ; setShowColorPicker ( ! showColorPicker ) ; } }
className = "flex items-center gap-2 px-3 py-1.5 w-full hover:bg-white/10 text-xs text-white/80 transition-colors"
>
< div
className = "w-3 h-3 rounded-full border border-white/30"
style = { { backgroundColor : bgColor } }
/ >
< span > Background < / span >
< / button >
{ /* Lock/Unlock row */ }
{ /* Lock/Unlock row */ }
< button
< button