fixed unmute for constructor

This commit is contained in:
Dmitri 2026-06-15 09:34:52 +02:00
parent c3d949702c
commit 9d7e6f6cd2
2 changed files with 93 additions and 20 deletions

View File

@ -46,6 +46,10 @@ interface RuntimeControlsProps {
isMuted?: boolean; isMuted?: boolean;
/** Callback to toggle all presentation sound on/off */ /** Callback to toggle all presentation sound on/off */
onSoundToggle?: () => void; onSoundToggle?: () => void;
/** Whether to show the offline download button */
showOfflineButton?: boolean;
/** Whether to show the fullscreen button */
showFullscreenButton?: boolean;
} }
/** /**
@ -468,6 +472,8 @@ export default function RuntimeControls({
showSoundButton = false, showSoundButton = false,
isMuted = true, isMuted = true,
onSoundToggle, onSoundToggle,
showOfflineButton = true,
showFullscreenButton = true,
}: RuntimeControlsProps) { }: RuntimeControlsProps) {
// Counter-scale to resist pinch-zoom // Counter-scale to resist pinch-zoom
const counterScale = useCounterZoom(); const counterScale = useCounterZoom();
@ -520,18 +526,22 @@ export default function RuntimeControls({
onTouchEnd={stopControlEvent} onTouchEnd={stopControlEvent}
onTouchEndCapture={stopControlEvent} onTouchEndCapture={stopControlEvent}
> >
<OfflineControl {showOfflineButton && (
projectId={projectId} <OfflineControl
projectSlug={projectSlug} projectId={projectId}
projectName={projectName} projectSlug={projectSlug}
pages={pages} projectName={projectName}
/> pages={pages}
<ControlButton />
icon={isFullscreen ? mdiFullscreenExit : mdiFullscreen} )}
color='info' {showFullscreenButton && (
onClick={toggleFullscreen} <ControlButton
title={isFullscreen ? 'Exit fullscreen' : 'Enter fullscreen'} icon={isFullscreen ? mdiFullscreenExit : mdiFullscreen}
/> color='info'
onClick={toggleFullscreen}
title={isFullscreen ? 'Exit fullscreen' : 'Enter fullscreen'}
/>
)}
{showSoundButton && onSoundToggle && ( {showSoundButton && onSoundToggle && (
<ControlButton <ControlButton
icon={isMuted ? mdiVolumeOff : mdiVolumeHigh} icon={isMuted ? mdiVolumeOff : mdiVolumeHigh}

View File

@ -18,6 +18,7 @@ import TransitionBlackOverlay from '../components/TransitionBlackOverlay';
import ConstructorToolbar from '../components/Constructor/ConstructorToolbar'; import ConstructorToolbar from '../components/Constructor/ConstructorToolbar';
import TransitionPreviewOverlay from '../components/Constructor/TransitionPreviewOverlay'; import TransitionPreviewOverlay from '../components/Constructor/TransitionPreviewOverlay';
import CanvasElementComponent from '../components/Constructor/CanvasElement'; import CanvasElementComponent from '../components/Constructor/CanvasElement';
import RuntimeControls from '../components/Runtime/RuntimeControls';
import GalleryCarouselOverlay from '../components/UiElements/GalleryCarouselOverlay'; import GalleryCarouselOverlay from '../components/UiElements/GalleryCarouselOverlay';
import InfoPanelOverlay from '../components/UiElements/InfoPanelOverlay'; import InfoPanelOverlay from '../components/UiElements/InfoPanelOverlay';
import ImageDetailPanel from '../components/UiElements/ImageDetailPanel'; import ImageDetailPanel from '../components/UiElements/ImageDetailPanel';
@ -198,7 +199,12 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => {
}); });
// Canvas scale for responsive UI elements and letterbox mode // Canvas scale for responsive UI elements and letterbox mode
const { cssVars: canvasCssVars, letterboxStyles } = useCanvasScale({ const {
cssVars: canvasCssVars,
letterboxStyles,
canvasWidth,
canvasHeight,
} = useCanvasScale({
designWidth: project?.design_width, designWidth: project?.design_width,
designHeight: project?.design_height, designHeight: project?.design_height,
}); });
@ -241,13 +247,6 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => {
backgroundAudioEndTime, backgroundAudioEndTime,
} = usePageBackground(); } = usePageBackground();
// Global sound control starts muted for browser autoplay compatibility.
const soundControl = useVideoSoundControl({
pageHasSound: backgroundVideoMuted === false,
hasBackgroundVideo: Boolean(backgroundVideoUrl),
hasBackgroundAudio: Boolean(backgroundAudioUrl),
});
// Network-aware transitions: skip video on slow networks, use CSS fade instead // Network-aware transitions: skip video on slow networks, use CSS fade instead
const { shouldUseVideoTransitions, networkInfo } = useNetworkAware(); const { shouldUseVideoTransitions, networkInfo } = useNetworkAware();
@ -367,6 +366,49 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => {
[elements], [elements],
); );
const hasElementAudio = useMemo(
() =>
elements.some((element) => {
if (element.hoverAudioUrl || element.clickAudioUrl) return true;
if (
(element.type === 'audio_player' ||
element.type === 'video_player') &&
element.mediaUrl &&
!element.mediaMuted
) {
return true;
}
if (
element.galleryCards?.some(
(card: GalleryCarouselMediaItem) =>
card.mediaType === 'video' || Boolean(card.videoUrl),
)
) {
return true;
}
if (
element.infoPanelSections?.some((section) =>
section.images?.some(
(item: InfoPanelImage) =>
item.itemType === 'video' || Boolean(item.videoUrl),
),
)
) {
return true;
}
return false;
}),
[elements],
);
// Global sound control starts muted for browser autoplay compatibility.
const soundControl = useVideoSoundControl({
pageHasSound: backgroundVideoMuted === false,
hasBackgroundVideo: Boolean(backgroundVideoUrl),
hasBackgroundAudio: Boolean(backgroundAudioUrl),
hasElementAudio,
});
// Look up current element for gallery carousel (so it receives updates from element editor) // Look up current element for gallery carousel (so it receives updates from element editor)
const activeGalleryCarouselElement = useMemo(() => { const activeGalleryCarouselElement = useMemo(() => {
if (!activeGalleryCarousel) return null; if (!activeGalleryCarousel) return null;
@ -2184,6 +2226,27 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => {
</BackdropPortalProvider> </BackdropPortalProvider>
</div> </div>
{!isConstructorEditMode &&
!activeGalleryCarousel &&
!activeInfoPanelGallery &&
soundControl.showSoundButton && (
<RuntimeControls
projectId={projectId || null}
projectSlug=''
projectName={projectName}
pages={pages}
isFullscreen={false}
toggleFullscreen={() => undefined}
canvasWidth={canvasWidth}
canvasHeight={canvasHeight}
showOfflineButton={false}
showFullscreenButton={false}
showSoundButton={soundControl.showSoundButton}
isMuted={soundControl.isMuted}
onSoundToggle={soundControl.toggleSound}
/>
)}
{/* ElementEditorPanel now uses ConstructorContext for all state */} {/* ElementEditorPanel now uses ConstructorContext for all state */}
{pages.length > 0 && hasEditorSelection && ( {pages.length > 0 && hasEditorSelection && (
<ElementEditorPanel <ElementEditorPanel