fixed carousel z-indexes issue
This commit is contained in:
parent
fc624c0700
commit
4a61fd1a69
@ -35,7 +35,7 @@ const ConstructorControlsPanel: React.FC<ConstructorControlsPanelProps> = ({
|
||||
}) => {
|
||||
return (
|
||||
<div
|
||||
className='fixed z-40 w-[min(92vw,460px)] rounded-lg border border-gray-200 bg-white shadow-xl'
|
||||
className='fixed z-[1000] w-[min(92vw,460px)] rounded-lg border border-gray-200 bg-white shadow-xl'
|
||||
style={{
|
||||
left: position.x,
|
||||
top: position.y,
|
||||
|
||||
@ -66,7 +66,7 @@ const ConstructorMenu = forwardRef<HTMLDivElement, ConstructorMenuProps>(
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
className='fixed z-40 w-60 border border-gray-200 rounded-lg bg-white shadow-xl'
|
||||
className='fixed z-[1000] w-60 border border-gray-200 rounded-lg bg-white shadow-xl'
|
||||
style={{ left: position.x, top: position.y }}
|
||||
>
|
||||
<div
|
||||
|
||||
@ -181,7 +181,7 @@ export function ElementEditorPanel({
|
||||
return (
|
||||
<div
|
||||
ref={elementEditorRef}
|
||||
className={`fixed z-40 ${isCollapsed ? 'w-[260px]' : 'w-[380px]'} max-h-[calc(100vh-2rem)] overflow-auto rounded-lg border border-gray-200 bg-white/95 p-3 shadow-xl`}
|
||||
className={`fixed z-[1000] ${isCollapsed ? 'w-[260px]' : 'w-[380px]'} max-h-[calc(100vh-2rem)] overflow-auto rounded-lg border border-gray-200 bg-white/95 p-3 shadow-xl`}
|
||||
style={{ left: position.x, top: position.y }}
|
||||
>
|
||||
<ElementEditorHeader
|
||||
|
||||
@ -574,9 +574,10 @@ export default function RuntimePresentation({
|
||||
|
||||
{/* Outer container: full viewport with black background for letterbox bars */}
|
||||
<div className='relative w-screen h-screen overflow-hidden bg-black'>
|
||||
{/* Inner canvas: maintains aspect ratio centered in viewport */}
|
||||
{/* Inner canvas: maintains aspect ratio centered in viewport.
|
||||
z-[46] creates stacking context above carousel (z-10 bg, z-45 controls) portaled to body. */}
|
||||
<div
|
||||
className='overflow-hidden'
|
||||
className='relative z-[46] overflow-hidden'
|
||||
style={{
|
||||
...cssVars,
|
||||
...letterboxStyles,
|
||||
@ -630,19 +631,17 @@ export default function RuntimePresentation({
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* New page content wrapper - fades in for non-transition navigation.
|
||||
z-1 ensures it's above previous backgrounds (z-0) during fade.
|
||||
{/* Page background wrapper - z-5 keeps it BELOW carousel slide (z-10).
|
||||
Fades in for non-transition navigation.
|
||||
onAnimationEnd resets isFadingIn when CSS animation completes. */}
|
||||
<div
|
||||
data-testid='page-content-wrapper'
|
||||
className={`absolute inset-0 z-1 ${isFadingIn ? 'animate-crossfade-in' : ''}`}
|
||||
data-testid='page-background-wrapper'
|
||||
className={`absolute inset-0 z-5 ${isFadingIn ? 'animate-crossfade-in' : ''}`}
|
||||
onAnimationEnd={onFadeInAnimationEnd}
|
||||
>
|
||||
{/* Background image element - z-1 keeps it below backdrop blur (z-5).
|
||||
CSS backgroundImage provides instant display.
|
||||
Use native img for blob URLs to prevent repeated fetch requests from Next.js Image. */}
|
||||
{/* Background image element */}
|
||||
{backgroundImageUrl && !backgroundVideoUrl && (
|
||||
<div className='absolute inset-0 z-1 pointer-events-none'>
|
||||
<div className='absolute inset-0 pointer-events-none'>
|
||||
{backgroundImageUrl.startsWith('blob:') ? (
|
||||
// eslint-disable-next-line @next/next/no-img-element
|
||||
<img
|
||||
@ -682,12 +681,12 @@ export default function RuntimePresentation({
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Background video - z-1 keeps it below backdrop blur (z-5) */}
|
||||
{/* Background video */}
|
||||
{backgroundVideoUrl && (
|
||||
<video
|
||||
ref={bgVideoRef}
|
||||
key={backgroundVideoUrl}
|
||||
className='absolute inset-0 z-1 h-full w-full object-contain'
|
||||
className='absolute inset-0 h-full w-full object-contain'
|
||||
src={backgroundVideoUrl}
|
||||
autoPlay={videoAutoplay}
|
||||
loop={useNativeLoop}
|
||||
@ -695,23 +694,29 @@ export default function RuntimePresentation({
|
||||
playsInline
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Page elements - z-40 ensures they appear above carousel background (z-10) and carousel controls (z-30) */}
|
||||
<div className='absolute inset-0 z-40'>
|
||||
{pageElements.map((element: CanvasElement) => (
|
||||
<RuntimeElement
|
||||
key={element.id}
|
||||
element={element}
|
||||
onClick={() => handleElementClick(element)}
|
||||
resolveUrl={resolveUrlWithBlob}
|
||||
onGalleryCardClick={(cardIndex) =>
|
||||
handleGalleryCardClick(element, cardIndex)
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
{/* End new page content wrapper */}
|
||||
{/* End page background wrapper */}
|
||||
|
||||
{/* Page elements wrapper - z-[46] keeps it ABOVE carousel slide (z-10) AND carousel controls (z-45).
|
||||
UI controls (z-50) remain on top.
|
||||
Fades in together with background. */}
|
||||
<div
|
||||
data-testid='page-elements-wrapper'
|
||||
className={`absolute inset-0 z-[46] ${isFadingIn ? 'animate-crossfade-in' : ''}`}
|
||||
>
|
||||
{pageElements.map((element: CanvasElement) => (
|
||||
<RuntimeElement
|
||||
key={element.id}
|
||||
element={element}
|
||||
onClick={() => handleElementClick(element)}
|
||||
resolveUrl={resolveUrlWithBlob}
|
||||
onGalleryCardClick={(cardIndex) =>
|
||||
handleGalleryCardClick(element, cardIndex)
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
{/* End page elements wrapper */}
|
||||
|
||||
{/* Controls: Offline toggle and Fullscreen button */}
|
||||
<div className='absolute top-4 right-4 z-50 flex items-center gap-2'>
|
||||
|
||||
@ -340,8 +340,8 @@ const CarouselElement: React.FC<CarouselElementProps> = ({
|
||||
};
|
||||
|
||||
// Full-width carousel - two layers:
|
||||
// 1. Background image layer at z-10 (behind canvas elements)
|
||||
// 2. Navigation/caption layer at z-30 (above everything for clickability)
|
||||
// 1. Background image layer at z-10 (behind canvas z-[46])
|
||||
// 2. Navigation/caption layer at z-[47] (above canvas z-[46], below UI controls z-50)
|
||||
const fullWidthBackground = (
|
||||
<div className='fixed inset-0 z-10 overflow-hidden bg-black pointer-events-none'>
|
||||
{currentSlide?.imageUrl && (
|
||||
@ -359,7 +359,7 @@ const CarouselElement: React.FC<CarouselElementProps> = ({
|
||||
const fullWidthControls = (
|
||||
<div
|
||||
ref={overlayRef}
|
||||
className='fixed inset-0 z-30 pointer-events-none'
|
||||
className='fixed inset-0 z-[47] pointer-events-none'
|
||||
onTouchStart={handleTouchStart}
|
||||
onTouchEnd={handleTouchEnd}
|
||||
>
|
||||
@ -400,7 +400,7 @@ const CarouselElement: React.FC<CarouselElementProps> = ({
|
||||
);
|
||||
|
||||
// Full-width mode: use portal to render outside transform hierarchy
|
||||
// Background at z-10, controls at z-30 for clickability
|
||||
// Background at z-10, controls at z-[47] for clickability (above canvas z-[46])
|
||||
if (isFullWidth) {
|
||||
// SSR safety: only use portal when mounted in browser
|
||||
if (!isMounted) {
|
||||
|
||||
@ -1426,7 +1426,7 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => {
|
||||
</title>
|
||||
</Head>
|
||||
<div className='relative w-screen h-screen bg-black overflow-hidden'>
|
||||
<div className='absolute top-4 left-4 z-30 flex max-w-[80vw] flex-col gap-2'>
|
||||
<div className='absolute top-4 left-4 z-[1000] flex max-w-[80vw] flex-col gap-2'>
|
||||
<p className='text-xs font-semibold text-gray-700'>
|
||||
{projectName || 'Loading project...'}
|
||||
</p>
|
||||
@ -1476,10 +1476,11 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => {
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Canvas container: z-[46] creates stacking context above carousel (z-10 bg, z-45 controls) portaled to body */}
|
||||
<div
|
||||
ref={canvasRef}
|
||||
tabIndex={-1}
|
||||
className={`z-20 overflow-clip ${hasFullWidthCarousel ? 'bg-transparent' : 'bg-black'}`}
|
||||
className={`relative z-[46] overflow-clip ${hasFullWidthCarousel ? 'bg-transparent' : 'bg-black'}`}
|
||||
style={{
|
||||
...canvasCssVars,
|
||||
...letterboxStyles,
|
||||
@ -1487,29 +1488,33 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => {
|
||||
}}
|
||||
>
|
||||
<BackdropPortalProvider>
|
||||
<CanvasBackground
|
||||
backgroundImageUrl={backgroundImageSrc}
|
||||
backgroundVideoUrl={backgroundVideoSrc}
|
||||
backgroundAudioUrl={backgroundAudioSrc}
|
||||
previousBgImageUrl={pageSwitch.previousBgImageUrl}
|
||||
previousBgVideoUrl={pageSwitch.previousBgVideoUrl}
|
||||
isSwitching={pageSwitch.isSwitching}
|
||||
isNewBgReady={pageSwitch.isNewBgReady}
|
||||
isFadingIn={isFadingIn}
|
||||
onBackgroundReady={() => {
|
||||
pageSwitch.markBackgroundReady();
|
||||
setIsBackgroundReady(true);
|
||||
}}
|
||||
videoAutoplay={backgroundVideoAutoplay}
|
||||
videoLoop={backgroundVideoLoop}
|
||||
videoMuted={backgroundVideoMuted}
|
||||
videoStartTime={backgroundVideoStartTime}
|
||||
videoEndTime={backgroundVideoEndTime}
|
||||
/>
|
||||
{/* Background wrapper - z-5 keeps it BELOW carousel slide (z-10) */}
|
||||
<div className={`absolute inset-0 z-5 ${isFadingIn ? 'animate-crossfade-in' : ''}`}>
|
||||
<CanvasBackground
|
||||
backgroundImageUrl={backgroundImageSrc}
|
||||
backgroundVideoUrl={backgroundVideoSrc}
|
||||
backgroundAudioUrl={backgroundAudioSrc}
|
||||
previousBgImageUrl={pageSwitch.previousBgImageUrl}
|
||||
previousBgVideoUrl={pageSwitch.previousBgVideoUrl}
|
||||
isSwitching={pageSwitch.isSwitching}
|
||||
isNewBgReady={pageSwitch.isNewBgReady}
|
||||
isFadingIn={isFadingIn}
|
||||
onBackgroundReady={() => {
|
||||
pageSwitch.markBackgroundReady();
|
||||
setIsBackgroundReady(true);
|
||||
}}
|
||||
videoAutoplay={backgroundVideoAutoplay}
|
||||
videoLoop={backgroundVideoLoop}
|
||||
videoMuted={backgroundVideoMuted}
|
||||
videoStartTime={backgroundVideoStartTime}
|
||||
videoEndTime={backgroundVideoEndTime}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Elements container - z-10 ensures they appear above backdrop layer */}
|
||||
{/* Elements container - z-[46] keeps it ABOVE carousel slide (z-10) AND carousel controls (z-45).
|
||||
UI controls (z-50) remain on top. */}
|
||||
<div
|
||||
className={`absolute inset-0 z-10 ${isFadingIn ? 'animate-crossfade-in' : ''}`}
|
||||
className={`absolute inset-0 z-[46] ${isFadingIn ? 'animate-crossfade-in' : ''}`}
|
||||
>
|
||||
{isLoading ? (
|
||||
<div className='absolute inset-0 flex items-center justify-center'>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user