diff --git a/sanityv3/schemas/objects/textWithIconArray.tsx b/sanityv3/schemas/objects/textWithIconArray.tsx index 855992956..13e615a3b 100644 --- a/sanityv3/schemas/objects/textWithIconArray.tsx +++ b/sanityv3/schemas/objects/textWithIconArray.tsx @@ -1,7 +1,11 @@ import { view_module } from '@equinor/eds-icons' import blocksToText from '../../helpers/blocksToText' import { EdsIcon } from '../../icons' +import CompactBlockEditor from '../components/CompactBlockEditor' import { SchemaType } from '../../types' +import { configureTitleBlockContent } from '../editors' + +const titleContentType = configureTitleBlockContent() export default { type: 'object', @@ -14,6 +18,20 @@ export default { }, ], fields: [ + { + name: 'title', + type: 'array', + inputComponent: CompactBlockEditor, + of: [titleContentType], + title: 'Title', + description: 'The list of icon/text should have a heading, can be hidden below', + }, + { + name: 'hideTitle', + type: 'boolean', + title: 'Hide title', + description: 'Hides title, but is available for screen readers and gives an meaningful heading for the list', + }, { type: 'array', name: 'group', diff --git a/web/components/src/TextWithIcon/Media.tsx b/web/components/src/TextWithIcon/Media.tsx deleted file mode 100644 index 21842bea8..000000000 --- a/web/components/src/TextWithIcon/Media.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { HTMLAttributes } from 'react' -import styled from 'styled-components' - -type MediaProps = HTMLAttributes - -const Img = styled.div` - align-self: center; - grid-area: media; - margin-bottom: var(--space-medium); -` - -export const Media = ({ children, ...rest }: MediaProps) => { - return {children} -} diff --git a/web/components/src/TextWithIcon/Text.tsx b/web/components/src/TextWithIcon/Text.tsx deleted file mode 100644 index 2cab9f54b..000000000 --- a/web/components/src/TextWithIcon/Text.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { HTMLAttributes } from 'react' -import styled from 'styled-components' - -type TextProps = HTMLAttributes - -const StyledText = styled.div` - p { - margin-bottom: 0; - } -` - -export const Text = ({ children, ...rest }: TextProps) => { - return {children} -} diff --git a/web/components/src/TextWithIcon/TextWithIcon.tsx b/web/components/src/TextWithIcon/TextWithIcon.tsx deleted file mode 100644 index 2c8c722e7..000000000 --- a/web/components/src/TextWithIcon/TextWithIcon.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { HTMLAttributes } from 'react' -import styled from 'styled-components' - -type TextWithIconProps = HTMLAttributes - -const Container = styled.div` - text-align: center; -` - -export const TextWithIcon = ({ children, ...rest }: TextWithIconProps) => { - return {children} -} diff --git a/web/components/src/TextWithIcon/Title.tsx b/web/components/src/TextWithIcon/Title.tsx deleted file mode 100644 index f61827243..000000000 --- a/web/components/src/TextWithIcon/Title.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { HTMLAttributes } from 'react' -import { Heading } from '../Heading' -import styled from 'styled-components' - -type TitleProps = HTMLAttributes - -const StyledTitle = styled(Heading)` - margin: 0; - text-align: center; -` - -export const Title = ({ children, ...rest }: TitleProps) => { - return ( - - {children} - - ) -} diff --git a/web/components/src/TextWithIcon/index.ts b/web/components/src/TextWithIcon/index.ts deleted file mode 100644 index 6a256b8c2..000000000 --- a/web/components/src/TextWithIcon/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { TextWithIcon as TextWithIconWrapper } from './TextWithIcon' -import { Media } from './Media' -import { Title } from './Title' -import { Text } from './Text' - -type TextWithIconProps = typeof TextWithIconWrapper & { - Media: typeof Media - Title: typeof Title - Text: typeof Text -} - -const TextWithIcon = TextWithIconWrapper as TextWithIconProps -TextWithIcon.Media = Media -TextWithIcon.Title = Title -TextWithIcon.Text = Text - -export { TextWithIcon } diff --git a/web/components/src/index.ts b/web/components/src/index.ts index 63a786766..26e7c653f 100644 --- a/web/components/src/index.ts +++ b/web/components/src/index.ts @@ -10,7 +10,6 @@ export * from './Teaser' export * from './Eyebrow' export * from './Backgrounds' export * from './FigureCaption' -export * from './TextWithIcon' export * from './Accordion' export * from './Menu' export * from './Heading' diff --git a/web/core/TextWithIcon/TextWithIcon.tsx b/web/core/TextWithIcon/TextWithIcon.tsx new file mode 100644 index 000000000..11a718083 --- /dev/null +++ b/web/core/TextWithIcon/TextWithIcon.tsx @@ -0,0 +1,51 @@ +import { HTMLAttributes, forwardRef } from 'react' +import envisTwMerge from '../../twMerge' +import { IconData } from '@equinor/eds-icons' +import { TransformableIcon } from '../../icons/TransformableIcon' +import { ImageWithAlt } from '../../types' +import Img from 'next/image' +import { urlFor } from '../../common/helpers' +import { PortableTextBlock } from '@portabletext/types' +import { Typography } from '@core/Typography' +import Blocks from '../../pageComponents/shared/portableText/Blocks' + +export type TextWithIconProps = { + title?: string + content?: PortableTextBlock[] + iconData?: IconData + image?: ImageWithAlt + /** Icondata or imageUrl styling */ + iconClassName?: string +} & HTMLAttributes + +export const TextWithIcon = forwardRef( + ({ title, content, iconData, className = '', image, iconClassName = '', ...rest }, ref) => { + return ( +
+ {iconData && } + {image && image?.asset && ( + {image?.isDecorative + )} + {title && ( + + {title} + + )} + {content && } +
+ ) + }, +) diff --git a/web/lib/queries/common/pageContentFields.ts b/web/lib/queries/common/pageContentFields.ts index 2b9bfa7d0..5fa3d43e4 100644 --- a/web/lib/queries/common/pageContentFields.ts +++ b/web/lib/queries/common/pageContentFields.ts @@ -119,6 +119,11 @@ _type == "keyNumbers" =>{ _type == "textWithIconArray"=>{ "type": _type, "id": _key, + title[]{ + ..., + ${markDefs}, + }, + hideTitle, "group": group[]{ "id": _key, title, diff --git a/web/pageComponents/pageTemplates/MagazineIndexPage.tsx b/web/pageComponents/pageTemplates/MagazineIndexPage.tsx deleted file mode 100644 index eacd26d90..000000000 --- a/web/pageComponents/pageTemplates/MagazineIndexPage.tsx +++ /dev/null @@ -1,197 +0,0 @@ -import { BackgroundContainer } from '@components' -import styled from 'styled-components' -import { Flags } from '../../common/helpers/datasetHelpers' -import { searchClient } from '../../lib/algolia' -import { getIsoFromLocale } from '../../lib/localization' -import type { MagazineIndexPageType } from '../../types' -import { Hits } from '../searchIndexPages/magazineIndex/Hits' -import { MagazineTagFilter } from '../searchIndexPages/magazineIndex/MagazineTagFilter' -import { Pagination } from '../shared/search/pagination/Pagination' -import { UnpaddedText } from './newsroom/StyledComponents' -import { useRef } from 'react' -import usePaginationPadding from '../../lib/hooks/usePaginationPadding' -import Seo from '../../pageComponents/shared/Seo' -import { HeroTypes } from '../../types/index' -import MagazineIndexText from '../shared/portableText/MagazineIndexText' -import Teaser from '../shared/Teaser' -import { SharedBanner } from './shared/SharedBanner' -import SharedTitle from './shared/SharedTitle' -import singletonRouter from 'next/router' -import type { UiState } from 'instantsearch.js' -import { Configure, InstantSearch } from 'react-instantsearch' -import { createInstantSearchRouterNext } from 'react-instantsearch-router-nextjs' -import { PaginationContextProvider } from '../../common/contexts/PaginationContext' - -const IngressWrapper = styled.div` - max-width: 1186px; /* 1920 - (2 * 367) */ - margin: 0 auto; -` - -const Intro = styled.div` - padding: var(--space-3xLarge) var(--layout-paddingHorizontal-large) var(--space-xLarge); -` - -const MagazineWapper = styled.div` - padding: var(--space-xLarge); - max-width: var(--maxViewportWidth); - margin: 0 auto; - - @media (min-width: 1000px) { - padding: var(--space-3xLarge); - } -` - -const StyledHits = styled(Hits)` - padding-bottom: var(--space-xLarge); - - @media (min-width: 1000px) { - padding-bottom: var(--space-3xLarge); - } -` - -const StyledPagination = styled(Pagination)` - padding: var(--space-xLarge) 0; - justify-content: center; -` - -type MagazineIndexTemplateProps = { - isServerRendered?: boolean - locale: string - pageData: MagazineIndexPageType - slug?: string - url: string -} - -const MagazineIndexPage = ({ isServerRendered = false, locale, pageData, slug, url }: MagazineIndexTemplateProps) => { - const { ingress, title, hero, seoAndSome, magazineTags, footerComponent } = pageData || {} - const envPrefix = Flags.IS_GLOBAL_PROD ? 'prod' : 'dev' - const isoCode = getIsoFromLocale(locale) - const padding = usePaginationPadding() - - const indexName = `${envPrefix}_MAGAZINE_${isoCode}` - const HITS_PER_PAGE = 12 - - const resultsRef = useRef(null) - - return ( - - -
- - {pageData?.hero.type !== HeroTypes.DEFAULT && title && ( - - )} - - - {ingress && ( - - {ingress && } - - )} - - - - { - const isIndexpageUrl = location.pathname.split('/').length === (locale === 'en' ? 2 : 3) - - if (!isIndexpageUrl) { - // do not update router state when magazine pages are clicked.. - return location.href - } - - const queryParameters: any = {} - if (routeState.page) { - queryParameters.page = routeState.page - } - if (routeState.magazineTags) { - queryParameters.tag = routeState.magazineTags - } - - const queryString = qsModule.stringify(queryParameters, { - addQueryPrefix: true, - arrayFormat: 'repeat', - format: 'RFC1738', - }) - return `${location.pathname}${queryString}` - }, - // eslint-disable-next-line - // @ts-ignore: @TODO: The types are not correct - parseURL: ({ qsModule, location }) => { - const { page, tag = '' }: any = qsModule.parse(location.search.slice(1)) - return { - page, - magazineTags: tag, - } - }, - push(url) { - if (singletonRouter.asPath.split('?')[1] !== url.split('?')[1]) { - // replace url only if there is a change in query params - singletonRouter.replace(url, undefined, { scroll: false }) - } - }, - }, - }), - - stateMapping: { - // eslint-disable-next-line - // @ts-ignore: @TODO: The types are not correct - stateToRoute(uiState: UiState) { - const indexUiState = uiState[indexName] || {} - return { - magazineTags: indexUiState.menu && indexUiState.menu.magazineTags, - page: indexUiState.page, - } - }, - // eslint-disable-next-line - // @ts-ignore: @TODO: The types are not correct - routeToState(routeState) { - return { - [indexName]: { - page: routeState.page, - menu: { - magazineTags: routeState.magazineTags, - }, - }, - } - }, - }, - }} - > - - {magazineTags && ( - - )} - - - - - - {footerComponent && } -
-
- ) -} -export default MagazineIndexPage diff --git a/web/pageComponents/pageTemplates/shared/SharedPageContent.tsx b/web/pageComponents/pageTemplates/shared/SharedPageContent.tsx index 35315bcaf..a643d8e19 100644 --- a/web/pageComponents/pageTemplates/shared/SharedPageContent.tsx +++ b/web/pageComponents/pageTemplates/shared/SharedPageContent.tsx @@ -3,7 +3,6 @@ import TextBlock from '../../topicPages/TextBlock' import FullWidthImage from '../../topicPages/FullWidthImage' import FullWidthVideo from '../../topicPages/FullWidthVideo' import Figure from '../../topicPages/Figure' -import TextWithIconArray from '../../topicPages/TextWithIconArray' import PageQuote from '../../topicPages/PageQuote' import AccordionBlock from '../../topicPages/Accordion/AccordionBlock' import PromoTileArray from '../../../sections/PromoTiles/PromoTileArray' @@ -64,6 +63,7 @@ import VideoPlayerCarousel from '@sections/VideoPlayerCarousel/VideoPlayerCarous import ImageCarousel from '@sections/ImageCarousel/ImageCarousel' import ImageForText from '@sections/ImageForText/ImageForText' import { AnchorLinkList } from '@sections/AnchorLinkList' +import TextWithIconArray from '@sections/TextWithIconArray/TextWithIconArray' import { StickyTextBlocks } from '@sections/StickyTextBlocks' type DefaultComponent = { diff --git a/web/pageComponents/topicPages/TextWithIconArray.tsx b/web/pageComponents/topicPages/TextWithIconArray.tsx deleted file mode 100644 index 2198469bb..000000000 --- a/web/pageComponents/topicPages/TextWithIconArray.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import { TextWithIcon, BackgroundContainer } from '@components' -import { urlFor } from '../../common/helpers' -import styled from 'styled-components' -import Img from 'next/image' - -import IngressText from '../shared/portableText/IngressText' -import type { TextWithIconArrayData, TextWithIconItem, ImageWithAlt } from '../../types/index' -import { twMerge } from 'tailwind-merge' - -const Container = styled.div<{ items: number }>` - --max-content-width: 1440px; - display: grid; - justify-content: center; - grid-template-columns: repeat(auto-fit, minmax(calc(13 * var(--space-medium)), calc(18 * var(--space-medium)))); - grid-gap: var(--space-xxLarge); - max-width: var(--max-content-width); - - @media (min-width: 750px) { - grid-template-columns: ${({ items }) => (items === 2 || items === 4 ? 'repeat(2, 1fr)' : 'repeat(3, 1fr)')}; - } - - @media (min-width: 1300px) { - ${({ items }) => - items === 4 && { - gridTemplateColumns: 'repeat(4, 1fr)', - }} - } -` - -const { Title, Media, Text } = TextWithIcon - -type TextWithIconArrayProps = { - data: TextWithIconArrayData - anchor?: string - className?: string -} - -const getImgSrc = (img: ImageWithAlt): string => urlFor(img).size(150, 150).auto('format').toString() || '' - -const TextWithIconArray = ({ data, anchor, className }: TextWithIconArrayProps) => { - const { designOptions, group } = data - - if (!group) return null - - return ( - - - {group.map((item: TextWithIconItem) => { - const { icon, title, text, id } = item - const altTag = icon?.isDecorative ? '' : icon?.alt || '' - return ( - - {icon && icon.asset && ( - - {altTag} - - )} - {title && {title}} - {text && ( - - - - )} - - ) - })} - - - ) -} - -export default TextWithIconArray diff --git a/web/sections/TextWithIconArray/TextWithIconArray.tsx b/web/sections/TextWithIconArray/TextWithIconArray.tsx new file mode 100644 index 000000000..817758319 --- /dev/null +++ b/web/sections/TextWithIconArray/TextWithIconArray.tsx @@ -0,0 +1,55 @@ +import { BackgroundContainer } from '@components' +import type { TextWithIconArrayData, TextWithIconItem } from '../../types/index' +import { twMerge } from 'tailwind-merge' +import { TextWithIcon } from '@core/TextWithIcon/TextWithIcon' +import { Heading } from '@core/Typography' + +type TextWithIconArrayProps = { + data: TextWithIconArrayData + anchor?: string + className?: string + listClassName?: string +} + +const TextWithIconArray = ({ data, anchor, className = '', listClassName = '' }: TextWithIconArrayProps) => { + const { designOptions, group, title, hideTitle } = data + + if (!group) return null + + return ( + + {title && } +
    + {group.map((item: TextWithIconItem) => { + const { icon, title, text, id } = item + return ( +
  • + {/*@ts-ignore:TODO*/} + +
  • + ) + })} +
+
+ ) +} + +export default TextWithIconArray diff --git a/web/types/types.ts b/web/types/types.ts index 35c6ceece..c4a5a815c 100644 --- a/web/types/types.ts +++ b/web/types/types.ts @@ -187,6 +187,8 @@ export type TextWithIconItem = { export type TextWithIconArrayData = { type: string id: string + title?: PortableTextBlock[] + hideTitle?: boolean group: TextWithIconItem[] designOptions: DesignOptions }