@@ -4,23 +4,65 @@ import { Button } from '@onlook/ui/button';
4
4
import { DropdownMenu , DropdownMenuContent , DropdownMenuTrigger } from '@onlook/ui/dropdown-menu' ;
5
5
import { Icons } from '@onlook/ui/icons' ;
6
6
import { observer } from 'mobx-react-lite' ;
7
- import { useState } from 'react' ;
7
+ import { useMemo , useState } from 'react' ;
8
8
import { useBoxControl } from '../hooks/use-box-control' ;
9
9
import { useDropdownControl } from '../hooks/use-dropdown-manager' ;
10
10
import { HoverOnlyTooltip } from '../hover-tooltip' ;
11
11
import { InputRange } from '../inputs/input-range' ;
12
12
import { SpacingInputs } from '../inputs/spacing-inputs' ;
13
13
import { ToolbarButton } from '../toolbar-button' ;
14
14
15
+ export enum BorderTab {
16
+ ALL = 'all' ,
17
+ INDIVIDUAL = 'individual' ,
18
+ }
19
+
15
20
export const Border = observer ( ( ) => {
16
- const [ activeTab , setActiveTab ] = useState ( 'all' ) ;
17
21
const { boxState, handleBoxChange, handleUnitChange, handleIndividualChange, borderExists } =
18
22
useBoxControl ( 'border' ) ;
19
23
20
24
const { isOpen, onOpenChange } = useDropdownControl ( {
21
25
id : 'border-dropdown' ,
22
26
} ) ;
23
27
28
+ const areAllBordersEqual = useMemo ( ( ) : boolean => {
29
+ const borders = {
30
+ top : boxState . borderTopWidth . num ?? 0 ,
31
+ right : boxState . borderRightWidth . num ?? 0 ,
32
+ bottom : boxState . borderBottomWidth . num ?? 0 ,
33
+ left : boxState . borderLeftWidth . num ?? 0 ,
34
+ } ;
35
+
36
+ const values = Object . values ( borders ) ;
37
+
38
+ return values . every ( val => val === values [ 0 ] ) ;
39
+ } , [ boxState . borderTopWidth . num , boxState . borderRightWidth . num , boxState . borderBottomWidth . num , boxState . borderLeftWidth . num ] ) ;
40
+
41
+ const [ activeTab , setActiveTab ] = useState < BorderTab > ( areAllBordersEqual ? BorderTab . ALL : BorderTab . INDIVIDUAL ) ;
42
+
43
+ const getBorderDisplay = ( ) => {
44
+ const top = boxState . borderTopWidth . num ?? 0 ;
45
+ const right = boxState . borderRightWidth . num ?? 0 ;
46
+ const bottom = boxState . borderBottomWidth . num ?? 0 ;
47
+ const left = boxState . borderLeftWidth . num ?? 0 ;
48
+
49
+ if ( top === 0 && right === 0 && bottom === 0 && left === 0 ) {
50
+ return null ;
51
+ }
52
+
53
+ const nonZeroValues = [ top , right , bottom , left ] . filter ( val => val !== 0 ) ;
54
+
55
+ if ( nonZeroValues . length === 4 && nonZeroValues . every ( ( val ) => val === nonZeroValues [ 0 ] ) ) {
56
+ return boxState . borderWidth . unit === 'px'
57
+ ? `${ boxState . borderWidth . num } `
58
+ : `${ boxState . borderWidth . value } `
59
+ }
60
+
61
+ return "Mixed"
62
+ }
63
+
64
+ const borderValue = getBorderDisplay ( )
65
+
24
66
return (
25
67
< DropdownMenu open = { isOpen } onOpenChange = { onOpenChange } modal = { false } >
26
68
< HoverOnlyTooltip
@@ -35,12 +77,11 @@ export const Border = observer(() => {
35
77
isOpen = { isOpen }
36
78
className = "flex items-center gap-1 min-w-10"
37
79
>
38
- < Icons . BorderEdit className = "h-4 w-4 min-h-4 min-w-4" />
39
- { borderExists && (
80
+ < Icons . BorderEdit className = { `h-4 w-4 min-h-4 min-w-4 ${ borderExists ? 'text-white' : '' }
81
+ ` } />
82
+ { borderValue && (
40
83
< span className = "text-xs" >
41
- { boxState . borderWidth . unit === 'px'
42
- ? boxState . borderWidth . num
43
- : boxState . borderWidth . value }
84
+ { borderValue }
44
85
</ span >
45
86
) }
46
87
</ ToolbarButton >
@@ -53,25 +94,25 @@ export const Border = observer(() => {
53
94
>
54
95
< div className = "flex items-center gap-2 mb-3" >
55
96
< button
56
- onClick = { ( ) => setActiveTab ( 'all' ) }
57
- className = { `flex-1 text-sm px-4 py-1.5 rounded-md transition-colors cursor-pointer ${ activeTab === 'all'
97
+ onClick = { ( ) => setActiveTab ( BorderTab . ALL ) }
98
+ className = { `flex-1 text-sm px-4 py-1.5 rounded-md transition-colors cursor-pointer ${ activeTab === BorderTab . ALL
58
99
? 'text-foreground-primary bg-background-active/50'
59
100
: 'text-muted-foreground hover:bg-background-tertiary/20 hover:text-foreground-hover'
60
101
} `}
61
102
>
62
103
All sides
63
104
</ button >
64
105
< button
65
- onClick = { ( ) => setActiveTab ( 'individual' ) }
66
- className = { `flex-1 text-sm px-4 py-1.5 rounded-md transition-colors cursor-pointer ${ activeTab === 'individual'
106
+ onClick = { ( ) => setActiveTab ( BorderTab . INDIVIDUAL ) }
107
+ className = { `flex-1 text-sm px-4 py-1.5 rounded-md transition-colors cursor-pointer ${ activeTab === BorderTab . INDIVIDUAL
67
108
? 'text-foreground-primary bg-background-active/50'
68
109
: 'text-muted-foreground hover:bg-background-tertiary/20 hover:text-foreground-hover'
69
110
} `}
70
111
>
71
112
Individual
72
113
</ button >
73
114
</ div >
74
- { activeTab === 'all' ? (
115
+ { activeTab === BorderTab . ALL ? (
75
116
< InputRange
76
117
value = { boxState . borderWidth . num ?? 0 }
77
118
onChange = { ( value ) => handleBoxChange ( 'borderWidth' , value . toString ( ) ) }
0 commit comments