From e23e8bc4fdbe51387443815b51452d87ce71d56f Mon Sep 17 00:00:00 2001 From: Dmitri Date: Thu, 25 Jun 2026 11:33:40 +0200 Subject: [PATCH] fixed disabling for elements in presentations --- frontend/next.config.mjs | 4 +-- frontend/package.json | 2 +- frontend/src/components/RuntimeElement.tsx | 27 ++++++++++++++----- .../src/components/RuntimePresentation.tsx | 13 +++++++++ .../UiElements/elements/InfoPanelElement.tsx | 6 +---- package.json | 2 +- 6 files changed, 39 insertions(+), 15 deletions(-) diff --git a/frontend/next.config.mjs b/frontend/next.config.mjs index 830f247..fc51dfc 100644 --- a/frontend/next.config.mjs +++ b/frontend/next.config.mjs @@ -3,7 +3,7 @@ */ import withSerwistInit from '@serwist/next'; -const output = process.env.NODE_ENV === 'production' ? 'export' : 'standalone'; +const output = process.env.NEXT_OUTPUT || undefined; // Configure Serwist for service worker generation const withSerwist = withSerwistInit({ @@ -42,4 +42,4 @@ const nextConfig = { }, }; -export default withSerwist(nextConfig); \ No newline at end of file +export default withSerwist(nextConfig); diff --git a/frontend/package.json b/frontend/package.json index 41f78d8..8cb2155 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -3,7 +3,7 @@ "scripts": { "dev": "cross-env PORT=${FRONT_PORT:-3000} next dev --turbopack", "build": "next build", - "start": "next start", + "start": "next start -H 0.0.0.0 -p ${FRONT_PORT:-3001}", "lint": "eslint . --ext .ts,.tsx", "format": "prettier '{components,pages,src,interfaces,hooks}/**/*.{tsx,ts,js}' --write" }, diff --git a/frontend/src/components/RuntimeElement.tsx b/frontend/src/components/RuntimeElement.tsx index 61dbd38..1a8406b 100644 --- a/frontend/src/components/RuntimeElement.tsx +++ b/frontend/src/components/RuntimeElement.tsx @@ -24,6 +24,8 @@ import { isInfoPanelElementType } from '../lib/elementDefaults'; interface RuntimeElementProps { element: CanvasElement; onClick: () => void; + /** Whether runtime interaction should be ignored for this element */ + isDisabled?: boolean; /** Optional URL resolver for preloaded blob URLs */ resolveUrl?: (url: string | undefined) => string; /** Gallery card click handler */ @@ -45,6 +47,7 @@ const clamp = (value: number, min: number, max: number) => const RuntimeElement: React.FC = ({ element, onClick, + isDisabled = false, resolveUrl, onGalleryCardClick, letterboxStyles, @@ -69,7 +72,7 @@ const RuntimeElement: React.FC = ({ eventHandlers, onPersistClick, state: effectState, - } = useElementEffects(effectProperties, { + } = useElementEffects(isDisabled ? {} : effectProperties, { resetKey: element.id, // Reset reveal on element change forceVisible: isInfoPanelOpen, }); @@ -77,8 +80,8 @@ const RuntimeElement: React.FC = ({ // Audio effects - uses exposed state from useElementEffects // resolveUrl prop resolves to preloaded blob URLs via RuntimePresentation useAudioEffects({ - hoverAudioUrl: effectProperties.hoverAudioUrl, - clickAudioUrl: effectProperties.clickAudioUrl, + hoverAudioUrl: isDisabled ? undefined : effectProperties.hoverAudioUrl, + clickAudioUrl: isDisabled ? undefined : effectProperties.clickAudioUrl, volume: parseFloat(effectProperties.audioVolume || '1'), isHovered: effectState.isHovered, isActive: effectState.isActive, @@ -89,12 +92,22 @@ const RuntimeElement: React.FC = ({ // Combined click handler // Skip toggle for info panel elements (their visibility is tied to panel open state) const handleClick = () => { + if (isDisabled) { + return; + } if (!isInfoPanelElementType(element.type)) { onPersistClick(); // Toggle persistence state } onClick(); // Original navigation action }; + const handleKeyDown = (event: React.KeyboardEvent) => { + if (event.key === 'Enter' || event.key === ' ') { + event.preventDefault(); + handleClick(); + } + }; + // Build base position style (outer div - handles positioning + animation) let positionStyle: React.CSSProperties = { left: `${xPercent}%`, @@ -135,15 +148,17 @@ const RuntimeElement: React.FC = ({ ); // Check if we need the inner wrapper for effects - const needsEffectWrapper = hasAnyEffects(effectProperties); + const needsEffectWrapper = !isDisabled && hasAnyEffects(effectProperties); return (
{needsEffectWrapper ? ( // Inner wrapper handles hover/focus/active effects independently from animation diff --git a/frontend/src/components/RuntimePresentation.tsx b/frontend/src/components/RuntimePresentation.tsx index 685e38e..bb4a271 100644 --- a/frontend/src/components/RuntimePresentation.tsx +++ b/frontend/src/components/RuntimePresentation.tsx @@ -693,6 +693,13 @@ export default function RuntimePresentation({ const handleElementClick = useCallback( (element: CanvasElement) => { + if (isNavigationType(element.type) && element.navDisabled) { + return; + } + if (isInfoPanelElementType(element.type) && element.infoPanelDisabled) { + return; + } + // Handle info panel click if (isInfoPanelElementType(element.type)) { setActiveInfoPanel(element); @@ -1014,6 +1021,12 @@ export default function RuntimePresentation({ handleElementClick(element)} resolveUrl={resolveUrlWithBlob} onGalleryCardClick={(cardIndex) => diff --git a/frontend/src/components/UiElements/elements/InfoPanelElement.tsx b/frontend/src/components/UiElements/elements/InfoPanelElement.tsx index 550bdb7..05892aa 100644 --- a/frontend/src/components/UiElements/elements/InfoPanelElement.tsx +++ b/frontend/src/components/UiElements/elements/InfoPanelElement.tsx @@ -48,11 +48,7 @@ const InfoPanelElement: React.FC = ({ // Common wrapper props const wrapperProps = { className, - style: { - ...style, - opacity: isDisabled ? 0.5 : style.opacity, - cursor: isDisabled ? 'not-allowed' : style.cursor, - }, + style, onClick: handleClick, role: 'button' as const, tabIndex: isDisabled ? -1 : 0, diff --git a/package.json b/package.json index cf4ff37..de78912 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "app", "version": "0.0.1", "scripts": { - "build:production": "cd ./frontend && yarn install && yarn run build && rm -rf ./node_modules && cd ../backend && yarn install", + "build:production": "cd ./frontend && yarn install && yarn run build && cd ../backend && yarn install", "start:production": "cd ./backend && NODE_ENV=production yarn start" } }