From 1b5c13c8aec64ea0dca1392a8e6711ebaad2a5c1 Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Wed, 18 Mar 2026 06:43:39 +0000 Subject: [PATCH] constructor (UI elements basic) --- frontend/src/pages/constructor.tsx | 152 ++++++++++++++++++++++++++++- 1 file changed, 151 insertions(+), 1 deletion(-) diff --git a/frontend/src/pages/constructor.tsx b/frontend/src/pages/constructor.tsx index 7c8f253..ef25a0e 100644 --- a/frontend/src/pages/constructor.tsx +++ b/frontend/src/pages/constructor.tsx @@ -61,8 +61,11 @@ type CanvasElement = { label: string; xPercent: number; yPercent: number; + iconUrl?: string; galleryCards?: GalleryCard[]; carouselSlides?: CarouselSlide[]; + carouselPrevIconUrl?: string; + carouselNextIconUrl?: string; tooltipTitle?: string; tooltipText?: string; descriptionTitle?: string; @@ -258,12 +261,15 @@ const createDefaultElement = (type: CanvasElementType, index: number): CanvasEle return { ...base, carouselSlides: [{ id: createLocalId(), imageUrl: '', caption: 'Slide 1' }], + carouselPrevIconUrl: '', + carouselNextIconUrl: '', }; } if (type === 'tooltip') { return { ...base, + iconUrl: '', tooltipTitle: 'Tooltip title', tooltipText: 'Tooltip text', }; @@ -272,6 +278,7 @@ const createDefaultElement = (type: CanvasElementType, index: number): CanvasEle if (type === 'description') { return { ...base, + iconUrl: '', descriptionTitle: 'Description title', descriptionText: 'Description text', }; @@ -281,6 +288,7 @@ const createDefaultElement = (type: CanvasElementType, index: number): CanvasEle return { ...base, navLabel: type === 'navigation_next' ? 'Forward' : 'Back', + iconUrl: '', transitionReverseMode: 'auto_reverse', transitionDurationSec: 0.7, }; @@ -429,6 +437,13 @@ const ConstructorPage = () => { return videoAssetOptions; }, [assets, videoAssetOptions]); + const iconAssetOptions = useMemo( + () => + assets + .filter((asset) => asset.type === 'icon' && asset.asset_type === 'image' && getAssetSourceValue(asset)) + .map((asset) => ({ value: getAssetSourceValue(asset), label: getAssetLabel(asset) })), + [assets], + ); useEffect(() => { if (newTransitionVideoUrl) return; @@ -570,6 +585,9 @@ const ConstructorPage = () => { caption: String(slide?.caption || `Slide ${index + 1}`), })) : undefined, + iconUrl: typeof item.iconUrl === 'string' ? item.iconUrl : '', + carouselPrevIconUrl: typeof item.carouselPrevIconUrl === 'string' ? item.carouselPrevIconUrl : '', + carouselNextIconUrl: typeof item.carouselNextIconUrl === 'string' ? item.carouselNextIconUrl : '', tooltipTitle: typeof item.tooltipTitle === 'string' ? item.tooltipTitle : '', tooltipText: typeof item.tooltipText === 'string' ? item.tooltipText : '', descriptionTitle: typeof item.descriptionTitle === 'string' ? item.descriptionTitle : '', @@ -951,7 +969,13 @@ const ConstructorPage = () => { const targetPageName = element.targetPageId ? pageNameById[element.targetPageId] : ''; return (
- {element.navLabel || (element.type === 'navigation_next' ? 'Forward' : 'Back')} +
+ {element.iconUrl ? ( + // eslint-disable-next-line @next/next/no-img-element + Navigation icon + ) : null} + {element.navLabel || (element.type === 'navigation_next' ? 'Forward' : 'Back')} +
{targetPageName ? To: {targetPageName} : null}
); @@ -960,6 +984,10 @@ const ConstructorPage = () => { if (element.type === 'tooltip') { return (
+ {element.iconUrl ? ( + // eslint-disable-next-line @next/next/no-img-element + Tooltip icon + ) : null}

{element.tooltipTitle || 'Tooltip title'}

{element.tooltipText || 'Tooltip text'}

@@ -969,6 +997,10 @@ const ConstructorPage = () => { if (element.type === 'description') { return (
+ {element.iconUrl ? ( + // eslint-disable-next-line @next/next/no-img-element + Description icon + ) : null}

{element.descriptionTitle || 'Description title'}

{element.descriptionText || 'Description text'}

@@ -1018,6 +1050,32 @@ const ConstructorPage = () => { )}

{firstSlide?.caption || 'No caption'}

+ {(element.carouselPrevIconUrl || element.carouselNextIconUrl) && ( +
+ + {element.carouselPrevIconUrl ? ( + // eslint-disable-next-line @next/next/no-img-element + Previous icon + ) : null} + Prev + + + Next + {element.carouselNextIconUrl ? ( + // eslint-disable-next-line @next/next/no-img-element + Next icon + ) : null} + +
+ )} ); } @@ -1419,6 +1477,25 @@ const ConstructorPage = () => { onChange={(event) => updateSelectedElement({ navLabel: event.target.value })} /> +
+ + +
updateSelectedElement({ iconUrl: event.target.value })} + > + + {addFallbackAssetOption( + iconAssetOptions, + selectedElement.iconUrl, + `Current icon · ${selectedElement.iconUrl || ''}`, + ).map((option) => ( + + ))} + +
{ {selectedElement && selectedElement.type === 'description' && (
+
+ + +
{ {selectedElement && selectedElement.type === 'carousel' && (
+
+

Navigation icons

+ + +

Carousel slides