diff --git a/backend/src/services/tour_pages.js b/backend/src/services/tour_pages.js
index 1512641..d3a9652 100644
--- a/backend/src/services/tour_pages.js
+++ b/backend/src/services/tour_pages.js
@@ -483,6 +483,10 @@ class TourPagesService extends BaseService {
* @private
*/
static isForwardElementWithTarget(element) {
+ if (element.navigationTargetMode === 'external_url') {
+ return false;
+ }
+
const isForward =
element.type === 'navigation_next' ||
(element.type?.startsWith?.('navigation') &&
diff --git a/frontend/src/components/Constructor/ElementEditorPanel.tsx b/frontend/src/components/Constructor/ElementEditorPanel.tsx
index f2113a8..b797c5b 100644
--- a/frontend/src/components/Constructor/ElementEditorPanel.tsx
+++ b/frontend/src/components/Constructor/ElementEditorPanel.tsx
@@ -175,7 +175,6 @@ export function ElementEditorPanel({
activePageId,
allowedNavigationTypes,
normalizeNavigationType,
- onPreviewTransition,
} = useConstructorNavigation();
const { activeTab, setActiveTab } = useConstructorEditorTab();
@@ -336,7 +335,11 @@ export function ElementEditorPanel({
}
navDisabled={selectedElement.navDisabled || false}
iconUrl={selectedElement.iconUrl || ''}
+ navigationTargetMode={
+ selectedElement.navigationTargetMode || 'target_page'
+ }
targetPageSlug={selectedElement.targetPageSlug || ''}
+ externalUrl={selectedElement.externalUrl || ''}
transitionVideoUrl={
selectedElement.transitionVideoUrl || ''
}
@@ -363,10 +366,25 @@ export function ElementEditorPanel({
}
onChange={(prop, value) => {
if (prop === 'type') {
- const nextType = value as NavigationElementType;
- updateSelectedElement(
- normalizeNavigationType(selectedElement, nextType),
- );
+ if (typeof value === 'object') {
+ const nextType = (value.type ||
+ selectedElement.type) as NavigationElementType;
+ updateSelectedElement({
+ ...normalizeNavigationType(
+ selectedElement,
+ nextType,
+ ),
+ ...value,
+ });
+ } else {
+ const nextType = value as NavigationElementType;
+ updateSelectedElement(
+ normalizeNavigationType(
+ selectedElement,
+ nextType,
+ ),
+ );
+ }
} else if (prop === 'transitionVideoUrl') {
const nextVideoUrl = value as string;
const resolvedDuration = getDuration(nextVideoUrl);
@@ -380,13 +398,16 @@ export function ElementEditorPanel({
targetPageSlug: value as string,
targetPageId: '',
});
+ } else if (prop === 'navigationTargetMode') {
+ if (typeof value === 'object') {
+ updateSelectedElement(value);
+ }
} else {
updateSelectedElement({
[prop]: value,
});
}
}}
- onPreviewTransition={onPreviewTransition}
/>
)}
diff --git a/frontend/src/components/Constructor/types.ts b/frontend/src/components/Constructor/types.ts
index 3d36ba4..b9345eb 100644
--- a/frontend/src/components/Constructor/types.ts
+++ b/frontend/src/components/Constructor/types.ts
@@ -203,7 +203,6 @@ export interface ElementEditorPanelProps {
onUpdateTransitionVideoUrl: (url: string) => void;
onUpdateTransitionSupportsReverse: (value: boolean) => void;
onCreateTransition: () => void;
- onPreviewTransition: (direction: 'forward' | 'back') => void;
// Gallery operations
onAddGalleryCard: () => void;
diff --git a/frontend/src/components/ElementSettings/NavigationSettingsSectionCompact.tsx b/frontend/src/components/ElementSettings/NavigationSettingsSectionCompact.tsx
index 2cabb84..3617598 100644
--- a/frontend/src/components/ElementSettings/NavigationSettingsSectionCompact.tsx
+++ b/frontend/src/components/ElementSettings/NavigationSettingsSectionCompact.tsx
@@ -6,10 +6,10 @@
*/
import React from 'react';
-import BaseButton from '../BaseButton';
import type {
AssetOption,
NavigationButtonKind,
+ NavigationTargetMode,
CanvasElementType,
} from '../../types/constructor';
import type { TransitionType, EasingFunction } from '../../types/transition';
@@ -42,7 +42,9 @@ interface NavigationSettingsSectionCompactProps {
navLabelFontFamily: string;
navDisabled: boolean;
iconUrl: string;
+ navigationTargetMode: NavigationTargetMode;
targetPageSlug: string;
+ externalUrl: string;
transitionVideoUrl: string;
transitionReverseMode: 'auto_reverse' | 'separate_video';
reverseVideoUrl: string;
@@ -67,11 +69,14 @@ interface NavigationSettingsSectionCompactProps {
| Partial<{
type: NavigationElementType;
navType: NavigationButtonKind;
+ navigationTargetMode: NavigationTargetMode;
label?: string;
navLabel?: string;
+ targetPageSlug?: string;
+ targetPageId?: string;
+ externalUrl?: string;
}>,
) => void;
- onPreviewTransition?: (direction: 'forward' | 'back') => void;
}
const NavigationSettingsSectionCompact: React.FC<
@@ -83,7 +88,9 @@ const NavigationSettingsSectionCompact: React.FC<
navLabelFontFamily,
navDisabled,
iconUrl,
+ navigationTargetMode,
targetPageSlug,
+ externalUrl,
transitionVideoUrl,
transitionReverseMode,
reverseVideoUrl,
@@ -99,10 +106,13 @@ const NavigationSettingsSectionCompact: React.FC<
selectedMediaDurationNote,
selectedTransitionDurationNote,
onChange,
- onPreviewTransition,
}) => {
+ const currentTargetMode: NavigationTargetMode =
+ navigationTargetMode === 'external_url' ? 'external_url' : 'target_page';
const currentKind: NavigationButtonKind =
- navType || (type === 'navigation_prev' ? 'back' : 'forward');
+ currentTargetMode === 'external_url'
+ ? 'forward'
+ : navType || (type === 'navigation_prev' ? 'back' : 'forward');
return (
@@ -121,7 +131,15 @@ const NavigationSettingsSectionCompact: React.FC<
const nextType = allowedNavigationTypes.includes(requestedType)
? requestedType
: allowedNavigationTypes[0];
- onChange('type', nextType);
+ onChange('type', {
+ type: nextType,
+ navType: requestedKind,
+ navigationTargetMode:
+ requestedKind === 'back' ? 'target_page' : currentTargetMode,
+ targetPageSlug: requestedKind === 'back' ? '' : targetPageSlug,
+ targetPageId: '',
+ externalUrl: requestedKind === 'back' ? '' : externalUrl,
+ });
}}
>