fixed disabling for elements in presentations
This commit is contained in:
parent
8b29dd2b92
commit
e23e8bc4fd
@ -3,7 +3,7 @@
|
|||||||
*/
|
*/
|
||||||
import withSerwistInit from '@serwist/next';
|
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
|
// Configure Serwist for service worker generation
|
||||||
const withSerwist = withSerwistInit({
|
const withSerwist = withSerwistInit({
|
||||||
@ -42,4 +42,4 @@ const nextConfig = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default withSerwist(nextConfig);
|
export default withSerwist(nextConfig);
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "cross-env PORT=${FRONT_PORT:-3000} next dev --turbopack",
|
"dev": "cross-env PORT=${FRONT_PORT:-3000} next dev --turbopack",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
"start": "next start",
|
"start": "next start -H 0.0.0.0 -p ${FRONT_PORT:-3001}",
|
||||||
"lint": "eslint . --ext .ts,.tsx",
|
"lint": "eslint . --ext .ts,.tsx",
|
||||||
"format": "prettier '{components,pages,src,interfaces,hooks}/**/*.{tsx,ts,js}' --write"
|
"format": "prettier '{components,pages,src,interfaces,hooks}/**/*.{tsx,ts,js}' --write"
|
||||||
},
|
},
|
||||||
|
|||||||
@ -24,6 +24,8 @@ import { isInfoPanelElementType } from '../lib/elementDefaults';
|
|||||||
interface RuntimeElementProps {
|
interface RuntimeElementProps {
|
||||||
element: CanvasElement;
|
element: CanvasElement;
|
||||||
onClick: () => void;
|
onClick: () => void;
|
||||||
|
/** Whether runtime interaction should be ignored for this element */
|
||||||
|
isDisabled?: boolean;
|
||||||
/** Optional URL resolver for preloaded blob URLs */
|
/** Optional URL resolver for preloaded blob URLs */
|
||||||
resolveUrl?: (url: string | undefined) => string;
|
resolveUrl?: (url: string | undefined) => string;
|
||||||
/** Gallery card click handler */
|
/** Gallery card click handler */
|
||||||
@ -45,6 +47,7 @@ const clamp = (value: number, min: number, max: number) =>
|
|||||||
const RuntimeElement: React.FC<RuntimeElementProps> = ({
|
const RuntimeElement: React.FC<RuntimeElementProps> = ({
|
||||||
element,
|
element,
|
||||||
onClick,
|
onClick,
|
||||||
|
isDisabled = false,
|
||||||
resolveUrl,
|
resolveUrl,
|
||||||
onGalleryCardClick,
|
onGalleryCardClick,
|
||||||
letterboxStyles,
|
letterboxStyles,
|
||||||
@ -69,7 +72,7 @@ const RuntimeElement: React.FC<RuntimeElementProps> = ({
|
|||||||
eventHandlers,
|
eventHandlers,
|
||||||
onPersistClick,
|
onPersistClick,
|
||||||
state: effectState,
|
state: effectState,
|
||||||
} = useElementEffects(effectProperties, {
|
} = useElementEffects(isDisabled ? {} : effectProperties, {
|
||||||
resetKey: element.id, // Reset reveal on element change
|
resetKey: element.id, // Reset reveal on element change
|
||||||
forceVisible: isInfoPanelOpen,
|
forceVisible: isInfoPanelOpen,
|
||||||
});
|
});
|
||||||
@ -77,8 +80,8 @@ const RuntimeElement: React.FC<RuntimeElementProps> = ({
|
|||||||
// Audio effects - uses exposed state from useElementEffects
|
// Audio effects - uses exposed state from useElementEffects
|
||||||
// resolveUrl prop resolves to preloaded blob URLs via RuntimePresentation
|
// resolveUrl prop resolves to preloaded blob URLs via RuntimePresentation
|
||||||
useAudioEffects({
|
useAudioEffects({
|
||||||
hoverAudioUrl: effectProperties.hoverAudioUrl,
|
hoverAudioUrl: isDisabled ? undefined : effectProperties.hoverAudioUrl,
|
||||||
clickAudioUrl: effectProperties.clickAudioUrl,
|
clickAudioUrl: isDisabled ? undefined : effectProperties.clickAudioUrl,
|
||||||
volume: parseFloat(effectProperties.audioVolume || '1'),
|
volume: parseFloat(effectProperties.audioVolume || '1'),
|
||||||
isHovered: effectState.isHovered,
|
isHovered: effectState.isHovered,
|
||||||
isActive: effectState.isActive,
|
isActive: effectState.isActive,
|
||||||
@ -89,12 +92,22 @@ const RuntimeElement: React.FC<RuntimeElementProps> = ({
|
|||||||
// Combined click handler
|
// Combined click handler
|
||||||
// Skip toggle for info panel elements (their visibility is tied to panel open state)
|
// Skip toggle for info panel elements (their visibility is tied to panel open state)
|
||||||
const handleClick = () => {
|
const handleClick = () => {
|
||||||
|
if (isDisabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!isInfoPanelElementType(element.type)) {
|
if (!isInfoPanelElementType(element.type)) {
|
||||||
onPersistClick(); // Toggle persistence state
|
onPersistClick(); // Toggle persistence state
|
||||||
}
|
}
|
||||||
onClick(); // Original navigation action
|
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)
|
// Build base position style (outer div - handles positioning + animation)
|
||||||
let positionStyle: React.CSSProperties = {
|
let positionStyle: React.CSSProperties = {
|
||||||
left: `${xPercent}%`,
|
left: `${xPercent}%`,
|
||||||
@ -135,15 +148,17 @@ const RuntimeElement: React.FC<RuntimeElementProps> = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Check if we need the inner wrapper for effects
|
// Check if we need the inner wrapper for effects
|
||||||
const needsEffectWrapper = hasAnyEffects(effectProperties);
|
const needsEffectWrapper = !isDisabled && hasAnyEffects(effectProperties);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className='absolute cursor-pointer'
|
className='absolute cursor-pointer'
|
||||||
style={positionStyle}
|
style={positionStyle}
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
tabIndex={0}
|
onKeyDown={handleKeyDown}
|
||||||
{...(!needsEffectWrapper ? eventHandlers : {})}
|
tabIndex={isDisabled ? -1 : 0}
|
||||||
|
aria-disabled={isDisabled}
|
||||||
|
{...(!isDisabled && !needsEffectWrapper ? eventHandlers : {})}
|
||||||
>
|
>
|
||||||
{needsEffectWrapper ? (
|
{needsEffectWrapper ? (
|
||||||
// Inner wrapper handles hover/focus/active effects independently from animation
|
// Inner wrapper handles hover/focus/active effects independently from animation
|
||||||
|
|||||||
@ -693,6 +693,13 @@ export default function RuntimePresentation({
|
|||||||
|
|
||||||
const handleElementClick = useCallback(
|
const handleElementClick = useCallback(
|
||||||
(element: CanvasElement) => {
|
(element: CanvasElement) => {
|
||||||
|
if (isNavigationType(element.type) && element.navDisabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (isInfoPanelElementType(element.type) && element.infoPanelDisabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Handle info panel click
|
// Handle info panel click
|
||||||
if (isInfoPanelElementType(element.type)) {
|
if (isInfoPanelElementType(element.type)) {
|
||||||
setActiveInfoPanel(element);
|
setActiveInfoPanel(element);
|
||||||
@ -1014,6 +1021,12 @@ export default function RuntimePresentation({
|
|||||||
<RuntimeElement
|
<RuntimeElement
|
||||||
key={element.id}
|
key={element.id}
|
||||||
element={element}
|
element={element}
|
||||||
|
isDisabled={
|
||||||
|
(isNavigationType(element.type) &&
|
||||||
|
Boolean(element.navDisabled)) ||
|
||||||
|
(isInfoPanelElementType(element.type) &&
|
||||||
|
Boolean(element.infoPanelDisabled))
|
||||||
|
}
|
||||||
onClick={() => handleElementClick(element)}
|
onClick={() => handleElementClick(element)}
|
||||||
resolveUrl={resolveUrlWithBlob}
|
resolveUrl={resolveUrlWithBlob}
|
||||||
onGalleryCardClick={(cardIndex) =>
|
onGalleryCardClick={(cardIndex) =>
|
||||||
|
|||||||
@ -48,11 +48,7 @@ const InfoPanelElement: React.FC<InfoPanelElementProps> = ({
|
|||||||
// Common wrapper props
|
// Common wrapper props
|
||||||
const wrapperProps = {
|
const wrapperProps = {
|
||||||
className,
|
className,
|
||||||
style: {
|
style,
|
||||||
...style,
|
|
||||||
opacity: isDisabled ? 0.5 : style.opacity,
|
|
||||||
cursor: isDisabled ? 'not-allowed' : style.cursor,
|
|
||||||
},
|
|
||||||
onClick: handleClick,
|
onClick: handleClick,
|
||||||
role: 'button' as const,
|
role: 'button' as const,
|
||||||
tabIndex: isDisabled ? -1 : 0,
|
tabIndex: isDisabled ? -1 : 0,
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
"name": "app",
|
"name": "app",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"scripts": {
|
"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"
|
"start:production": "cd ./backend && NODE_ENV=production yarn start"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user