@@ -11,6 +11,7 @@ import {
11
11
PopoverContent ,
12
12
Portal ,
13
13
Skeleton ,
14
+ Text ,
14
15
} from '@invoke-ai/ui-library' ;
15
16
import { skipToken } from '@reduxjs/toolkit/query' ;
16
17
import { POPPER_MODIFIERS } from 'common/components/InformationalPopover/constants' ;
@@ -21,7 +22,9 @@ import { RefImageHeader } from 'features/controlLayers/components/RefImage/RefIm
21
22
import { RefImageSettings } from 'features/controlLayers/components/RefImage/RefImageSettings' ;
22
23
import { useRefImageEntity } from 'features/controlLayers/components/RefImage/useRefImageEntity' ;
23
24
import { useRefImageIdContext } from 'features/controlLayers/contexts/RefImageIdContext' ;
24
- import { memo , useCallback , useRef } from 'react' ;
25
+ import { isIPAdapterConfig } from 'features/controlLayers/store/types' ;
26
+ import { round } from 'lodash-es' ;
27
+ import { memo , useCallback , useEffect , useMemo , useRef , useState } from 'react' ;
25
28
import { PiImageBold } from 'react-icons/pi' ;
26
29
import { useGetImageDTOQuery } from 'services/api/endpoints/images' ;
27
30
@@ -80,10 +83,11 @@ export const RefImage = memo(() => {
80
83
} ) ;
81
84
RefImage . displayName = 'RefImage' ;
82
85
83
- const imageSx : SystemStyleObject = {
86
+ const baseSx : SystemStyleObject = {
84
87
opacity : 0.7 ,
85
88
transitionProperty : 'opacity' ,
86
89
transitionDuration : 'normal' ,
90
+ position : 'relative' ,
87
91
_hover : {
88
92
opacity : 1 ,
89
93
} ,
@@ -92,11 +96,58 @@ const imageSx: SystemStyleObject = {
92
96
} ,
93
97
} ;
94
98
99
+ const weightDisplaySx : SystemStyleObject = {
100
+ pointerEvents : 'none' ,
101
+ transitionProperty : 'opacity' ,
102
+ transitionDuration : 'normal' ,
103
+ opacity : 0 ,
104
+ '&[data-visible="true"]' : {
105
+ opacity : 1 ,
106
+ } ,
107
+ } ;
108
+
109
+ const getImageSxWithWeight = ( weight : number ) : SystemStyleObject => {
110
+ const fillPercentage = Math . max ( 0 , Math . min ( 100 , weight * 100 ) ) ;
111
+
112
+ return {
113
+ ...baseSx ,
114
+ _after : {
115
+ content : '""' ,
116
+ position : 'absolute' ,
117
+ inset : 0 ,
118
+ background : `linear-gradient(to top, transparent ${ fillPercentage } %, rgba(0, 0, 0, 0.8) ${ fillPercentage } %)` ,
119
+ pointerEvents : 'none' ,
120
+ borderRadius : 'base' ,
121
+ } ,
122
+ } ;
123
+ } ;
124
+
95
125
const Thumbnail = memo ( ( { disclosure } : { disclosure : UseDisclosure } ) => {
96
126
const id = useRefImageIdContext ( ) ;
97
127
const entity = useRefImageEntity ( id ) ;
128
+ const [ showWeightDisplay , setShowWeightDisplay ] = useState ( false ) ;
98
129
const { data : imageDTO } = useGetImageDTOQuery ( entity . config . image ?. image_name ?? skipToken ) ;
99
130
131
+ const sx = useMemo ( ( ) => {
132
+ if ( ! isIPAdapterConfig ( entity . config ) ) {
133
+ return baseSx ;
134
+ }
135
+ return getImageSxWithWeight ( entity . config . weight ) ;
136
+ } , [ entity . config ] ) ;
137
+
138
+ useEffect ( ( ) => {
139
+ if ( ! isIPAdapterConfig ( entity . config ) ) {
140
+ return ;
141
+ }
142
+ setShowWeightDisplay ( true ) ;
143
+ const timeout = window . setTimeout ( ( ) => {
144
+ setShowWeightDisplay ( false ) ;
145
+ } , 1000 ) ;
146
+ return ( ) => {
147
+ window . clearTimeout ( timeout ) ;
148
+ } ;
149
+ } , [ entity . config ] ) ;
150
+
100
151
if ( ! entity . config . image ) {
101
152
return (
102
153
< PopoverAnchor >
@@ -120,25 +171,47 @@ const Thumbnail = memo(({ disclosure }: { disclosure: UseDisclosure }) => {
120
171
}
121
172
return (
122
173
< PopoverAnchor >
123
- < Image
174
+ < Flex
175
+ position = "relative"
124
176
borderWidth = { 1 }
125
177
borderStyle = "solid"
126
- id = { getRefImagePopoverTriggerId ( id ) }
127
- role = "button"
128
- src = { imageDTO ?. thumbnail_url }
129
- objectFit = "contain"
178
+ borderRadius = "base"
130
179
aspectRatio = "1/1"
131
- // width={imageDTO?.width}
132
- height = { imageDTO ?. height }
133
- fallback = { < Skeleton h = "full" aspectRatio = "1/1" /> }
134
180
maxW = "full"
135
181
maxH = "full"
136
- borderRadius = "base"
137
- onClick = { disclosure . toggle }
138
182
flexShrink = { 0 }
139
- sx = { imageSx }
183
+ sx = { sx }
140
184
data-is-open = { disclosure . isOpen }
141
- />
185
+ id = { getRefImagePopoverTriggerId ( id ) }
186
+ role = "button"
187
+ onClick = { disclosure . toggle }
188
+ cursor = "pointer"
189
+ >
190
+ < Image
191
+ src = { imageDTO ?. thumbnail_url }
192
+ objectFit = "contain"
193
+ aspectRatio = "1/1"
194
+ height = { imageDTO ?. height }
195
+ fallback = { < Skeleton h = "full" aspectRatio = "1/1" /> }
196
+ maxW = "full"
197
+ maxH = "full"
198
+ borderRadius = "base"
199
+ />
200
+ < Flex
201
+ position = "absolute"
202
+ inset = { 0 }
203
+ fontWeight = "semibold"
204
+ alignItems = "center"
205
+ justifyContent = "center"
206
+ zIndex = { 1 }
207
+ data-visible = { showWeightDisplay }
208
+ sx = { weightDisplaySx }
209
+ >
210
+ < Text filter = "drop-shadow(0px 0px 4px rgb(0, 0, 0)) drop-shadow(0px 0px 2px rgba(0, 0, 0, 1))" >
211
+ { `${ round ( entity . config . weight * 100 , 2 ) } %` }
212
+ </ Text >
213
+ </ Flex >
214
+ </ Flex >
142
215
</ PopoverAnchor >
143
216
) ;
144
217
} ) ;
0 commit comments