From 007172caf7580fa8999e2fa0df62a3fbfc13e1bd Mon Sep 17 00:00:00 2001 From: Femke Reunes Date: Wed, 16 Sep 2026 10:57:35 +0200 Subject: [PATCH] ARC-3949: enable link for image in carousel --- .../BlockImageCarousel.editorconfig.ts | 15 ++++++++ .../BlockImageCarousel.scss | 9 +++++ .../BlockImageCarousel/BlockImageCarousel.tsx | 2 ++ .../BlockImageCarouselSlide.tsx | 34 ++++++++++++------- 4 files changed, 47 insertions(+), 13 deletions(-) diff --git a/ui/src/react-admin/modules/content-page/components/blocks/BlockImageCarousel/BlockImageCarousel.editorconfig.ts b/ui/src/react-admin/modules/content-page/components/blocks/BlockImageCarousel/BlockImageCarousel.editorconfig.ts index 56e5cca8..585e1fc5 100644 --- a/ui/src/react-admin/modules/content-page/components/blocks/BlockImageCarousel/BlockImageCarousel.editorconfig.ts +++ b/ui/src/react-admin/modules/content-page/components/blocks/BlockImageCarousel/BlockImageCarousel.editorconfig.ts @@ -1,3 +1,4 @@ +import { AvoCoreContentPickerType } from '@viaa/avo2-types'; import { BLOCK_FIELD_DEFAULTS, BLOCK_STATE_DEFAULTS, @@ -115,6 +116,20 @@ export const IMAGE_CAROUSEL_CONFIG = (position = 0): ContentBlockConfig => ({ validator: undefined, }), ...COPYRIGHT_FIELDS(), + imageAction: { + label: tText( + 'modules/content-page/components/blocks/block-image-carousel/block-image-carousel___link' + ), + editorType: ContentBlockEditor.ContentPicker, + editorProps: { + allowedTypes: [ + AvoCoreContentPickerType.EXTERNAL_LINK, + AvoCoreContentPickerType.CONTENT_PAGE, + AvoCoreContentPickerType.IE_OBJECT, + ], + hideTargetSwitch: true, + }, + }, }, type: 'fieldGroup', repeat: { diff --git a/ui/src/react-admin/modules/content-page/components/blocks/BlockImageCarousel/BlockImageCarousel.scss b/ui/src/react-admin/modules/content-page/components/blocks/BlockImageCarousel/BlockImageCarousel.scss index 9dfa1861..a1a39df1 100644 --- a/ui/src/react-admin/modules/content-page/components/blocks/BlockImageCarousel/BlockImageCarousel.scss +++ b/ui/src/react-admin/modules/content-page/components/blocks/BlockImageCarousel/BlockImageCarousel.scss @@ -2,6 +2,7 @@ @use "../../../../shared/styles/settings/variables" as variables; @use "../../../../shared/styles/settings/colors" as colors; @use "../../../../shared/styles/mixins/typography" as typography; +@use "../../../../shared/styles/mixins/animations" as animations; .c-block-image-carousel { .c-block-image-carousel__header { @@ -83,6 +84,14 @@ object-fit: contain; object-position: center; } + + &--link > img { + @include animations.zoom-in-transition; + + &:hover { + @include animations.zoom-in-animation; + } + } } // Compound selector (both classes are on the same element, see BlockImageCarousel.tsx): diff --git a/ui/src/react-admin/modules/content-page/components/blocks/BlockImageCarousel/BlockImageCarousel.tsx b/ui/src/react-admin/modules/content-page/components/blocks/BlockImageCarousel/BlockImageCarousel.tsx index 3fd20ff1..ee060b82 100644 --- a/ui/src/react-admin/modules/content-page/components/blocks/BlockImageCarousel/BlockImageCarousel.tsx +++ b/ui/src/react-admin/modules/content-page/components/blocks/BlockImageCarousel/BlockImageCarousel.tsx @@ -14,6 +14,7 @@ import type { import type { DefaultComponentProps } from '~modules/shared/types/components'; import './BlockImageCarousel.scss'; +import type { ButtonAction } from '@viaa/avo2-components'; export interface BlockImageCarouselProps extends DefaultComponentProps { title: string; @@ -21,6 +22,7 @@ export interface BlockImageCarouselProps extends DefaultComponentProps { elements: ({ image: string; imageAlt: string; + imageAction?: ButtonAction; } & CopyrightComponentState)[]; } diff --git a/ui/src/react-admin/modules/content-page/components/blocks/BlockImageCarousel/BlockImageCarouselSlide.tsx b/ui/src/react-admin/modules/content-page/components/blocks/BlockImageCarousel/BlockImageCarouselSlide.tsx index 6e75e673..0f519185 100644 --- a/ui/src/react-admin/modules/content-page/components/blocks/BlockImageCarousel/BlockImageCarouselSlide.tsx +++ b/ui/src/react-admin/modules/content-page/components/blocks/BlockImageCarousel/BlockImageCarouselSlide.tsx @@ -1,16 +1,16 @@ -import { Image } from '@viaa/avo2-components'; +import { type ButtonAction, Image } from '@viaa/avo2-components'; import clsx from 'clsx'; import React, { type CSSProperties, type FunctionComponent, type ReactElement, useEffect, - useRef, useState, } from 'react'; import { useSwiper } from 'swiper/react'; import type { CopyrightComponentState } from '~modules/content-page/types/content-block.types'; import { CopyrightAttribution } from '~shared/components/CopyrightAttribution'; +import { generateSmartLink } from '~shared/components/SmartLink/SmartLink.tsx'; import './BlockImageCarousel.scss'; @@ -18,22 +18,24 @@ export interface ImageCarouselSlideProps extends CopyrightComponentState { title: string; image: string; imageAlt: string; + imageAction?: ButtonAction; } export const ImageCarouselSlide: FunctionComponent = ({ title, image, imageAlt, + imageAction, copyrightTitle, copyrightText, copyrightIconVisible, }): ReactElement => { - const imageWrapperRef = useRef(null); + const [imageWrapperRef, setImageWrapperRef] = useState(null); const [imageWidth, setImageWidth] = useState(undefined); const swiper = useSwiper(); useEffect(() => { - const imageEl = imageWrapperRef.current?.querySelector('img'); + const imageEl = imageWrapperRef?.querySelector('img'); if (!imageEl) { return; } @@ -54,7 +56,7 @@ export const ImageCarouselSlide: FunctionComponent = ({ resizeObserver.observe(imageEl); return () => resizeObserver.disconnect(); - }, [swiper]); + }, [swiper, imageWrapperRef]); return (
= ({ } as CSSProperties) } > -
- {imageAlt -
+ {generateSmartLink( + imageAction, +
+ {imageAlt +
, + imageAlt || title + )} {imageWidth !== undefined && (