@@ -270,22 +270,51 @@ function Inner() {
270270 const [ controlsHeight , setControlsHeight ] = createSignal <
271271 number | undefined
272272 > ( undefined ) ;
273- // Recompute placement when bounds change or window resizes
274- const placeControlsAbove = createMemo ( ( ) => {
273+ const [ controlsWidth , setControlsWidth ] = createSignal <
274+ number | undefined
275+ > ( undefined ) ;
276+
277+ // Determine the best placement for controls
278+ const controlsPlacement = createMemo ( ( ) => {
275279 const top = bounds . position . y ;
280+ const left = bounds . position . x ;
281+ const width = bounds . size . width ;
276282 const height = bounds . size . height ;
277- // Measure controls height (fallback to 64px if not yet mounted)
283+ // Measure controls dimensions (fallback if not yet mounted)
278284 const ctrlH = controlsHeight ( ) ?? 64 ;
285+ const ctrlW = controlsWidth ( ) ?? 300 ;
279286 const margin = 16 ;
280287
288+ // Check if selection spans full height (or nearly full height)
289+ const isFullHeight = height >= window . innerHeight * 0.9 ;
290+
291+ if ( isFullHeight ) {
292+ // Try to place on the right side
293+ const rightSpace = window . innerWidth - ( left + width ) ;
294+ if ( rightSpace >= ctrlW + margin )
295+ return { position : "right" as const } ;
296+
297+ // Try to place on the left side
298+ if ( left >= ctrlW + margin ) return { position : "left" as const } ;
299+
300+ // Fall back to inside at the bottom
301+ return { position : "inside-bottom" as const } ;
302+ }
303+
304+ // For non-full-height selections, use original logic
281305 const wouldOverflow =
282306 top + height + margin + ctrlH > window . innerHeight ;
283- return wouldOverflow ;
307+ return { position : wouldOverflow ? "above" : "below" } as const ;
308+ } ) ;
309+
310+ onMount ( ( ) => {
311+ setControlsHeight ( controlsEl ?. offsetHeight ) ;
312+ setControlsWidth ( controlsEl ?. offsetWidth ) ;
313+ } ) ;
314+ createEventListener ( window , "resize" , ( ) => {
315+ setControlsHeight ( controlsEl ?. offsetHeight ) ;
316+ setControlsWidth ( controlsEl ?. offsetWidth ) ;
284317 } ) ;
285- onMount ( ( ) => setControlsHeight ( controlsEl ?. offsetHeight ) ) ;
286- createEventListener ( window , "resize" , ( ) =>
287- setControlsHeight ( controlsEl ?. offsetHeight ) ,
288- ) ;
289318
290319 function createOnMouseDown (
291320 onDrag : (
@@ -725,16 +754,35 @@ function Inner() {
725754 ref = { controlsEl }
726755 class = { cx (
727756 "flex absolute flex-col items-center m-2" ,
728- placeControlsAbove ( ) ? "bottom-full" : "top-full" ,
757+ controlsPlacement ( ) . position === "above" && "bottom-full" ,
758+ controlsPlacement ( ) . position === "below" && "top-full" ,
759+ controlsPlacement ( ) . position === "right" &&
760+ "left-full top-1/2 -translate-y-1/2" ,
761+ controlsPlacement ( ) . position === "left" &&
762+ "right-full top-1/2 -translate-y-1/2" ,
763+ controlsPlacement ( ) . position === "inside-bottom" &&
764+ "bottom-2 left-1/2 -translate-x-1/2" ,
729765 ) }
730- style = { { width : `${ bounds . size . width } px` } }
766+ style = { {
767+ width :
768+ controlsPlacement ( ) . position === "right" ||
769+ controlsPlacement ( ) . position === "left"
770+ ? "auto"
771+ : controlsPlacement ( ) . position === "inside-bottom"
772+ ? "auto"
773+ : `${ bounds . size . width } px` ,
774+ } }
731775 >
732776 < RecordingControls
733777 target = { {
734778 variant : "area" ,
735779 screen : params . displayId ! ,
736780 bounds,
737781 } }
782+ setToggleModeSelect = { setToggleModeSelect }
783+ showBackground = {
784+ controlsPlacement ( ) . position === "inside-bottom"
785+ }
738786 />
739787 < ShowCapFreeWarning
740788 isInstantMode = { rawOptions . mode === "instant" }
@@ -764,9 +812,11 @@ function Inner() {
764812 </ p >
765813 </ Show >
766814 < Show when = { hasArea ( ) } >
767- < p class = "z-10 text-xl pointer-events-none text-white absolute bottom-4" >
768- Click and drag to create new area
769- </ p >
815+ < Show when = { controlsPlacement ( ) . position !== "inside-bottom" } >
816+ < p class = "z-10 text-xl pointer-events-none text-white absolute bottom-4" >
817+ Click and drag to create new area
818+ </ p >
819+ </ Show >
770820 </ Show >
771821 </ Show >
772822 </ div >
@@ -780,6 +830,7 @@ function Inner() {
780830function RecordingControls ( props : {
781831 target : ScreenCaptureTarget ;
782832 setToggleModeSelect ?: ( value : boolean ) => void ;
833+ showBackground ?: boolean ;
783834} ) {
784835 const auth = authStore . createQuery ( ) ;
785836 const { setOptions, rawOptions } = useRecordingOptions ( ) ;
@@ -945,16 +996,21 @@ function RecordingControls(props: {
945996 < IconCapGear class = "will-change-transform size-5" />
946997 </ div >
947998 </ div >
948- < div
999+ < button
9491000 onClick = { ( ) => props . setToggleModeSelect ?.( true ) }
950- class = "flex gap-1 items-center mb-5 transition-opacity duration-200 hover:opacity-60"
1001+ class = "cursor-pointer flex gap-1 items-center mb-5 transition-all duration-200"
1002+ classList = { {
1003+ "bg-black/40 p-2 rounded-lg backdrop-blur-sm border border-white/10 hover:bg-black/50 hover:opacity-80" :
1004+ props . showBackground ,
1005+ "hover:opacity-60" : props . showBackground ,
1006+ } }
9511007 >
9521008 < IconCapInfo class = "opacity-70 will-change-transform size-3" />
9531009 < p class = "text-sm text-white" >
9541010 < span class = "opacity-70" > What is </ span >
9551011 < span class = "font-medium" > { capitalize ( rawOptions . mode ) } Mode</ span > ?
9561012 </ p >
957- </ div >
1013+ </ button >
9581014 </ Show >
9591015 ) ;
9601016}
0 commit comments