diff --git a/sanityv3/schemas/documents/subMenu.tsx b/sanityv3/schemas/documents/subMenu.tsx index 1981b2aae..16012addd 100644 --- a/sanityv3/schemas/documents/subMenu.tsx +++ b/sanityv3/schemas/documents/subMenu.tsx @@ -9,6 +9,7 @@ import routes from '../routes' import { filterByRoute, filterByRouteNewsMagazineAndTitle } from '../../helpers/referenceFilters' import { Flags } from '../../src/lib/datasetHelpers' import { lang } from './langField' +import { description } from '../objects/iframe/sharedIframeFields' export type SubMenu = { _type: 'subMenu' @@ -45,6 +46,14 @@ export default { collapsed: false, }, }, + { + title: 'Featured content', + name: 'featured', + options: { + collapsible: true, + collapsed: false, + }, + }, ], fields: [ lang, @@ -103,6 +112,24 @@ export default { filter: filterByRouteNewsMagazineAndTitle, disableNew: true, }, + fieldset: 'featured', + }, + { + name: 'featuredIngress', + title: 'Featured ingress', + description: + 'If the featured content does not have ingress and is not event, you can add an ingress here (max. 215 chars)', + type: 'array', + of: [introBlockContentType], + validation: (Rule: Rule) => Rule.custom((value: any) => validateCharCounterEditor(value, 215, true)), + fieldset: 'featured', + }, + { + name: 'featuredCTALabel', + title: 'Featured CTA label text', + description: 'The label text appearing with the CTA arrow link style if not event', + fieldset: 'featured', + type: 'string', }, { name: 'intro', diff --git a/sanityv3/schemas/objects/accordionItem.tsx b/sanityv3/schemas/objects/accordionItem.tsx index b5c1c2d36..642f8f7a8 100644 --- a/sanityv3/schemas/objects/accordionItem.tsx +++ b/sanityv3/schemas/objects/accordionItem.tsx @@ -14,6 +14,8 @@ const contentType = configureBlockContent({ h3: false, h4: false, attachment: false, + internalLink: false, + externalLink: false, }) export default { @@ -27,12 +29,28 @@ export default { type: 'string', validation: (Rule: Rule) => Rule.required().error(), }, + { + title: 'Image', + name: 'image', + type: 'image', + description: 'Image will be presented as landscape format', + options: { + hotspot: true, + collapsed: false, + }, + }, { title: 'Content', name: 'content', type: 'array', of: [contentType], }, + { + name: 'links', + type: 'array', + title: 'Links', + of: [{ type: 'linkSelector', title: 'Link' }], + }, ], preview: { select: { diff --git a/sanityv3/schemas/textSnippets.ts b/sanityv3/schemas/textSnippets.ts index 21aae7ac3..19e1b2f1c 100644 --- a/sanityv3/schemas/textSnippets.ts +++ b/sanityv3/schemas/textSnippets.ts @@ -827,6 +827,16 @@ const snippets: textSnippet = { defaultValue: 'Carousel controls', group: groups.carousel, }, + logolink_title: { + title: 'Equinor logo link', + defaultValue: 'Equinor homepage', + group: groups.common, + }, + featured_content: { + title: 'Featured content', + defaultValue: 'Featured content', + group: groups.common, + }, } type textSnippetGroup = { title: string; hidden?: boolean } diff --git a/web/components/src/Accordion/Accordion.tsx b/web/components/src/Accordion/Accordion.tsx deleted file mode 100644 index 0ea59ce15..000000000 --- a/web/components/src/Accordion/Accordion.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { forwardRef } from 'react' - -import { Accordion as CAccordion, AccordionProps as ChakraAccordionProps } from '@chakra-ui/react' - -export type AccordionProps = { - id: string -} & ChakraAccordionProps - -export const Accordion = forwardRef(function Accordion({ id, children }, ref) { - return ( - - {children} - - ) -}) diff --git a/web/components/src/Accordion/Header.tsx b/web/components/src/Accordion/Header.tsx deleted file mode 100644 index 1691693b6..000000000 --- a/web/components/src/Accordion/Header.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import { forwardRef } from 'react' -import { Icon } from '@equinor/eds-core-react' -import { Typography } from '@core/Typography' -import { add_circle_outlined, remove_outlined, add_circle_filled, remove } from '@equinor/eds-icons' - -import { - AccordionButton, - useAccordionItemState, - AccordionButtonProps as ChakraAccordionButtonProps, -} from '@chakra-ui/react' - -export type AccordionHeaderProps = { - headingLevel?: 'h2' | 'h3' | 'h4' | 'h5' -} & ChakraAccordionButtonProps - -export const Header = forwardRef(function Header( - { headingLevel = 'h3', children, ...rest }, - ref, -) { - const iconSize = 24 - const { isOpen } = useAccordionItemState() - const fillColor = `fill-[var(--accordion-icon-color)]` - - return ( - - - - - - - - {children} - - - - ) -}) diff --git a/web/components/src/Accordion/Item.tsx b/web/components/src/Accordion/Item.tsx deleted file mode 100644 index 54d69b8df..000000000 --- a/web/components/src/Accordion/Item.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { AccordionItem } from '@chakra-ui/react' - -export type AccordionItemProps = { - id: number - children: React.ReactNode -} - -export const Item = ({ id, children, ...rest }: AccordionItemProps) => { - return ( - - {children} - - ) -} diff --git a/web/components/src/Accordion/Panel.tsx b/web/components/src/Accordion/Panel.tsx deleted file mode 100644 index 99e9a1dfb..000000000 --- a/web/components/src/Accordion/Panel.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { forwardRef } from 'react' -import { useDivHeight } from './hooks/useDivHeight' -import styled from 'styled-components' -import { AccordionPanel, AccordionPanelProps as ChakraAccordionPanelProps } from '@chakra-ui/react' - -export type AccordionPanelProps = ChakraAccordionPanelProps - -const StyledPanel = styled.div` - padding: var(--space-small) var(--space-small) var(--space-large) 0; - margin-left: calc(var(--space-xLarge) / 2); - p:last-child { - margin-bottom: 0; - } -` -const ContentWithBorder = styled.div` - border-left: 1px dashed var(--accordion-icon-color); - padding-left: calc(var(--space-xLarge) / 2); -` - -export const Panel = forwardRef(function Panel( - { children, ...rest }, - forwardedRef, -) { - const { ref } = useDivHeight() - return ( - - - {children} - - - ) -}) diff --git a/web/components/src/Accordion/hooks/useDivHeight.ts b/web/components/src/Accordion/hooks/useDivHeight.ts deleted file mode 100644 index 297ab70fe..000000000 --- a/web/components/src/Accordion/hooks/useDivHeight.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { useRef, useEffect, useState } from 'react' - -export function useDivHeight() { - const ref = useRef(null) - const [height, setHeight] = useState(0) - - useEffect(() => { - const resizeObserver = new ResizeObserver(([entry]) => { - requestAnimationFrame(() => { - if (!entry) { - return - } - setHeight(entry.target.getBoundingClientRect().height) - }) - }) - - if (ref.current) { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore: Do you have any suggestions here Sven - resizeObserver.observe(ref.current) - } - - return () => { - resizeObserver.disconnect() - } - }, []) - - return { ref, height } -} diff --git a/web/components/src/Accordion/index.ts b/web/components/src/Accordion/index.ts deleted file mode 100644 index 6586f6637..000000000 --- a/web/components/src/Accordion/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Accordion as AccordionWrapper, AccordionProps } from './Accordion' -import { Panel, AccordionPanelProps } from './Panel' -import { Item, AccordionItemProps } from './Item' -import { Header, AccordionHeaderProps } from './Header' - -type AccordionCompoundProps = typeof AccordionWrapper & { - Item: typeof Item - Header: typeof Header - Panel: typeof Panel -} - -const Accordion = AccordionWrapper as AccordionCompoundProps - -Accordion.Item = Item -Accordion.Header = Header -Accordion.Panel = Panel - -export { Accordion } -export type { AccordionProps, AccordionHeaderProps, AccordionItemProps, AccordionPanelProps } diff --git a/web/components/src/Backgrounds/BackgroundContainer.tsx b/web/components/src/Backgrounds/BackgroundContainer.tsx index a6168cae7..e5023b6b4 100644 --- a/web/components/src/Backgrounds/BackgroundContainer.tsx +++ b/web/components/src/Backgrounds/BackgroundContainer.tsx @@ -5,6 +5,7 @@ import type { BackgroundColours, BackgroundTypes, ImageBackground } from '../../ import { ColouredContainer } from './ColouredContainer' import { ImageBackgroundContainer } from './ImageBackgroundContainer' import { ColorKeyTokens } from '../../../styles/colorKeyToUtilityMap' +import envisTwMerge from '../../../twMerge' const StyledImageBackground = styled(ImageBackgroundContainer)<{ $isInverted: boolean }>` ${({ $isInverted }) => ($isInverted ? inverted : normal)} @@ -57,7 +58,7 @@ export const BackgroundContainer = forwardRef @@ -77,7 +78,7 @@ export const BackgroundContainer = forwardRef {children} diff --git a/web/components/src/index.ts b/web/components/src/index.ts index 8ad6b9cda..4c480d6cf 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 './Accordion' export * from './Menu' export * from './Heading' export * from './Table' diff --git a/web/core/Accordion/Accordion.tsx b/web/core/Accordion/Accordion.tsx index 1ba53c0bc..6f66a4909 100644 --- a/web/core/Accordion/Accordion.tsx +++ b/web/core/Accordion/Accordion.tsx @@ -2,16 +2,14 @@ import { forwardRef } from 'react' import * as _Accordion from '@radix-ui/react-accordion' import envisTwMerge from '../../twMerge' -interface AccordionSingleProps extends _Accordion.AccordionSingleProps { +export interface AccordionSingleProps extends _Accordion.AccordionSingleProps { type: 'single' } -interface AccordionMultipleProps extends _Accordion.AccordionMultipleProps { +export interface AccordionMultipleProps extends _Accordion.AccordionMultipleProps { type: 'multiple' } -export type AccordionProps = { - className?: string -} & (AccordionSingleProps | AccordionMultipleProps) +export type Variants = 'primary' | 'menu' | 'simpleMenu' /** * Accordion @@ -33,10 +31,10 @@ export type AccordionProps = { * * ``` */ -export const Accordion = forwardRef, AccordionProps>(function Accordion( - { id, children, type = 'single', className = '', ...rest }, - ref, -) { +export const Accordion = forwardRef< + React.ElementRef, + AccordionSingleProps | AccordionMultipleProps +>(function Accordion({ id, children, type = 'single', className = '', ...rest }, ref) { const props = type === 'single' ? (rest as AccordionSingleProps) : (rest as AccordionMultipleProps) return ( //@ts-ignore: TODO solve type casting diff --git a/web/core/Accordion/Content.tsx b/web/core/Accordion/Content.tsx index 81b12b5eb..a044e9d1d 100644 --- a/web/core/Accordion/Content.tsx +++ b/web/core/Accordion/Content.tsx @@ -1,46 +1,78 @@ -import { CSSProperties, forwardRef, useEffect, useMemo, useRef, useState } from 'react' +import { forwardRef } from 'react' import { AccordionContent, AccordionContentProps as _AccordionContentProps } from '@radix-ui/react-accordion' import envisTwMerge from '../../twMerge' -import { mergeRefs } from '@equinor/eds-utils' +import { Variants } from './Accordion' +import { motion } from 'framer-motion' +import { useMediaQuery } from '../../lib/hooks/useMediaQuery' -export type AccordionContentProps = _AccordionContentProps +const contentVariants = { + hidden: { opacity: 0 }, + visible: { opacity: 1 }, +} + +export type AccordionContentProps = { + variant?: Variants +} & _AccordionContentProps export const Content = forwardRef(function Content( - { children, className = '', forceMount, ...rest }, - forwardedRef, + { variant = 'primary', children, className = '', ...rest }, + ref, ) { - const contentRef = useRef(null) - const combinedContentRef = useMemo( - () => mergeRefs(contentRef, forwardedRef), - [contentRef, forwardedRef], - ) - const [collapsedHeight, setCollapsedHeight] = useState() + const isMobile = useMediaQuery(`(max-width: 1300px)`) - useEffect(() => { - if (!contentRef.current) { - return - } - if (contentRef.current && forceMount) { - const currentHeight = contentRef.current.clientHeight - const height = Math.max(collapsedHeight ?? 0, currentHeight) + const commonSlideUpDown = `overflow-hidden motion-safe:data-closed:animate-slideDown motion-safe:data-open:animate-slideUp` + + const variantClassName: Partial> = { + primary: `${commonSlideUpDown}`, + menu: `max-xl:overflow-hidden + max-xl:motion-safe:data-closed:animate-slideDown + max-xl:motion-safe:data-open:animate-slideUp + `, + simpleMenu: `max-xl:overflow-hidden + max-xl:motion-safe:data-closed:animate-slideDown + max-xl:motion-safe:data-open:animate-slideUp`, + } + + const getVariantBody = () => { + switch (variant) { + case 'menu': + return isMobile ? ( + <>{children} + ) : ( + + {children} + + ) + case 'simpleMenu': + return
{children}
- setCollapsedHeight(height) + default: + return ( +
+ {children} +
+ ) } - }, [collapsedHeight, contentRef, forceMount]) + } return ( - {children} + {getVariantBody()} ) }) diff --git a/web/core/Accordion/Header.tsx b/web/core/Accordion/Header.tsx index 39746805e..4319fc0b6 100644 --- a/web/core/Accordion/Header.tsx +++ b/web/core/Accordion/Header.tsx @@ -6,10 +6,14 @@ import { AccordionTriggerProps, } from '@radix-ui/react-accordion' import envisTwMerge from '../../twMerge' -import { chevron_down } from '@equinor/eds-icons' +import { add_circle_filled, add_circle_outlined, remove, remove_outlined } from '@equinor/eds-icons' import { TransformableIcon } from '../../icons/TransformableIcon' +import { Variants } from './Accordion' +import { Typography } from '@core/Typography' export type AccordionHeaderProps = { + hasSectionTitle?: boolean + variant?: Variants headerClassName?: string className?: string } & _AccordionHeaderProps & @@ -23,22 +27,146 @@ export type AccordionHeaderProps = { * @see 🏷️ {@link AccordionHeaderProps} */ export const Header = forwardRef(function Header( - { children, className = '', headerClassName = '', ...rest }, + { variant = 'primary', children, hasSectionTitle = false, className = '', headerClassName = '', ...rest }, ref, ) { + const headerVariantClassName: Partial> = { + primary: '', + menu: '', + simpleMenu: '', + } + const variantClassName: Partial> = { + primary: ` + items-center + py-4 + xl:pt-5 + xl:pb-4 + border-none`, + menu: ` + py-3 + px-2 + items-center + text-base + aria-current:bg-grey-10 + border-b + border-grey-20 + aria-current:border-moss-green-95 + font-normal + data-open:font-bold + leading-none + xl:px-6 + xl:my-4 + xl:text-sm + xl:border-t-0 + xl:border-transparent + xl:border-b-2 + data-open:xl:border-moss-green-95 + data-open:xl:font-normal`, + simpleMenu: `py-3 + px-2 + items-center + text-base + aria-current:bg-grey-10 + aria-current:border-moss-green-95 + font-normal + data-open:font-bold + leading-none`, + } + + const textVariantClassName: Partial> = { + primary: 'text-base', + menu: 'text-base xl:text-sm', + simpleMenu: 'text-base xl:text-sm', + } + return ( - - - {children} - - + + + + + + + + + + + {children} + + + ) }) diff --git a/web/core/Accordion/Item.tsx b/web/core/Accordion/Item.tsx index f443d610c..169147a2b 100644 --- a/web/core/Accordion/Item.tsx +++ b/web/core/Accordion/Item.tsx @@ -1,15 +1,23 @@ import { forwardRef } from 'react' import { AccordionItem, AccordionItemProps as _AccordionItemProps } from '@radix-ui/react-accordion' import envisTwMerge from '../../twMerge' +import { Variants } from './Accordion' -export type AccordionItemProps = _AccordionItemProps +export type AccordionItemProps = { + variant?: Variants +} & _AccordionItemProps export const Item = forwardRef(function Item( - { children, className = '', ...rest }, + { variant = 'primary', children, className = '', ...rest }, forwardedRef, ) { + const variantClassName: Partial> = { + primary: 'border-b border-grey-40 dark:border-white-100', + menu: '', + simpleMenu: 'border-b border-grey-40 dark:border-white-100', + } return ( - + {children} ) diff --git a/web/core/Accordion/index.ts b/web/core/Accordion/index.ts index 41ffff119..f3dc73f01 100644 --- a/web/core/Accordion/index.ts +++ b/web/core/Accordion/index.ts @@ -1,4 +1,4 @@ -import { Accordion as AccordionWrapper, AccordionProps } from './Accordion' +import { Accordion as AccordionWrapper, AccordionSingleProps, AccordionMultipleProps } from './Accordion' import { Item, AccordionItemProps } from './Item' import { Content, AccordionContentProps } from './Content' import { Header, AccordionHeaderProps } from './Header' @@ -16,4 +16,10 @@ Accordion.Header = Header Accordion.Content = Content export { Accordion } -export type { AccordionProps, AccordionHeaderProps, AccordionItemProps, AccordionContentProps } +export type { + AccordionSingleProps, + AccordionMultipleProps, + AccordionHeaderProps, + AccordionItemProps, + AccordionContentProps, +} diff --git a/web/core/Banner/Banner.tsx b/web/core/Banner/Banner.tsx new file mode 100644 index 000000000..ac2fc32fc --- /dev/null +++ b/web/core/Banner/Banner.tsx @@ -0,0 +1,114 @@ +/* eslint-disable @typescript-eslint/ban-ts-comment */ +import { forwardRef, HTMLAttributes } from 'react' +import Blocks from '../../pageComponents/shared/portableText/Blocks' +import { PortableTextBlock } from '@portabletext/types' +import { ImageWithAlt } from '../../types' +import { ColorKeyTokens } from '../../styles/colorKeyToUtilityMap' +import { BaseLink, ResourceLink } from '@core/Link' +import Image, { Ratios } from '../../pageComponents/shared/SanityImage' +import { Heading, Typography } from '@core/Typography' +import envisTwMerge from '../../twMerge' +import IngressText from '../../pageComponents/shared/portableText/IngressText' + +export type Variants = 'primary' | 'secondary' + +export type BannerProps = { + variant?: Variants + title?: PortableTextBlock[] | string + ingress?: PortableTextBlock[] + content?: PortableTextBlock[] + image?: ImageWithAlt + ctaLabel?: string + ctaLink?: string + className?: string + /* Override styling on typography element. */ + titleClassName?: string + backgroundUtility?: keyof ColorKeyTokens +} & HTMLAttributes + +export const Banner = forwardRef(function Banner( + { title, ingress, content, image, ctaLabel, ctaLink, className = '', variant = 'primary', titleClassName = '' }, + ref, +) { + const contentVariantClassName: Partial> = { + primary: 'group flex flex-col pt-4 pb-6 xl:pb-16', + secondary: 'group flex flex-col pt-4 pb-6 xl:pb-16', + } + const titleVariantClassName: Partial> = { + primary: 'text-md', + secondary: 'text-base pb-4', + } + const titleClassNames = envisTwMerge( + `${!ctaLabel ? 'group-hover:underline peer-hover:underline' : ''} + ${titleVariantClassName[variant]}`, + titleClassName, + ) + + const titleElement = ( + <> + {typeof title === 'string' ? ( + + {title} + + ) : ( + //@ts-ignore: Checked earlier for undefined title + + )} + + ) + + const contentElements = ( + <> + {ingress && } + {content && variant !== 'secondary' && } + + ) + return ( +
+ {ctaLink && ( +
+ {ctaLabel ? ( + <> + {title && titleElement} + {contentElements} + + {ctaLabel} + + + ) : ( + <> + + {titleElement ?? 'Missing title'} + + {contentElements} + + )} +
+ )} + {!ctaLink && ( +
+ {title && titleElement} + {contentElements} +
+ )} +
+ {image && ( + + )} +
+
+ ) +}) diff --git a/web/pageComponents/shared/LogoLink.tsx b/web/core/Link/LogoLink.tsx similarity index 63% rename from web/pageComponents/shared/LogoLink.tsx rename to web/core/Link/LogoLink.tsx index 7741f6f20..639d1d1ab 100644 --- a/web/pageComponents/shared/LogoLink.tsx +++ b/web/core/Link/LogoLink.tsx @@ -1,14 +1,16 @@ import { AnchorHTMLAttributes } from 'react' import { LogoSecondary } from '@components' import NextLink from 'next/link' +import { useIntl } from 'react-intl' -type LogoLinkProps = AnchorHTMLAttributes +export type LogoLinkProps = AnchorHTMLAttributes export const LogoLink = ({ ...rest }: LogoLinkProps) => { + const intl = useIntl() return ( { ) } + +export default LogoLink diff --git a/web/core/Link/ResourceLink.tsx b/web/core/Link/ResourceLink.tsx index 5d359d2bc..ae0d7807e 100644 --- a/web/core/Link/ResourceLink.tsx +++ b/web/core/Link/ResourceLink.tsx @@ -21,6 +21,7 @@ export const ResourceLink = forwardRef(fun relative flex flex-col + justify-end gap-0 w-full text-slate-blue-95 @@ -61,7 +62,7 @@ export const ResourceLink = forwardRef(fun return ( - + {children} diff --git a/web/core/Link/index.ts b/web/core/Link/index.ts index 324dc4a9e..13f6bcf18 100644 --- a/web/core/Link/index.ts +++ b/web/core/Link/index.ts @@ -3,3 +3,4 @@ export { default as ReadMoreLink, type ReadMoreLinkProps } from './ReadMoreLink' export { default as ResourceLink, type ResourceLinkProps } from './ResourceLink' export { default as ButtonLink, type ButtonLinkProps } from './ButtonLink' export { default as BaseLink, type BaseLinkProps } from './BaseLink' +export { default as LogoLink, type LogoLinkProps } from './LogoLink' diff --git a/web/core/MenuAccordion/MenuAccordion.tsx b/web/core/MenuAccordion/MenuAccordion.tsx new file mode 100644 index 000000000..e29590738 --- /dev/null +++ b/web/core/MenuAccordion/MenuAccordion.tsx @@ -0,0 +1,37 @@ +import { Accordion, AccordionSingleProps } from '@core/Accordion' +import { useMediaQuery } from '../../lib/hooks/useMediaQuery' +import { forwardRef } from 'react' + +export type Variants = 'default' | 'simple' + +export type MenuAccordionProps = { + id?: string + variant?: Variants +} & Omit + +export const MenuAccordion = forwardRef(function MenuAccordion( + { children, variant = 'default', ...rest }, + ref, +) { + const isMobile = useMediaQuery(`(max-width: 800px)`) + + const variantClassName: Partial> = { + default: 'w-auto mx-auto flex flex-col xl:flex-row', + simple: 'flex flex-col', + } + + return ( + +
    {children}
+
+ ) +}) diff --git a/web/core/MenuAccordion/MenuButton.tsx b/web/core/MenuAccordion/MenuButton.tsx new file mode 100644 index 000000000..ab768a66a --- /dev/null +++ b/web/core/MenuAccordion/MenuButton.tsx @@ -0,0 +1,81 @@ +import { forwardRef, ButtonHTMLAttributes } from 'react' + +export type MenuButtonProps = { + expanded?: boolean + title: string +} & ButtonHTMLAttributes + +export const MenuButton = forwardRef(function MenuButton( + { expanded = false, title, ...rest }, + ref, +) { + const lineClassName = ` + block + absolute + h-[2.5px] + w-full + bg-slate-80 + rounded-[3px] + l-0 + transition-all duration-[250ms] + nth-1:top-2.5 + nth-1:origin-[left_center] + nth-2:top-[18px] + nth-2:origin-[left_center] + group-data-open:nth-1:rotate-45 + group-data-open:nth-1:top-1 + group-data-open:nth-1:left-[5px] + group-data-open:nth-2:-rotate-45 + group-data-open:nth-2:top-[25px] + group-data-open:nth-2:left-[5px] + ` + + return ( + + ) +}) diff --git a/web/core/MenuAccordion/MenuContent.tsx b/web/core/MenuAccordion/MenuContent.tsx new file mode 100644 index 000000000..849bc6e40 --- /dev/null +++ b/web/core/MenuAccordion/MenuContent.tsx @@ -0,0 +1,18 @@ +import { forwardRef } from 'react' +import { Variants } from './MenuAccordion' +import { Accordion, AccordionContentProps } from '@core/Accordion' + +export type MenuContentProps = { + variant?: Variants +} & Omit + +export const MenuContent = forwardRef(function SubMenuPanel( + { className = '', variant = 'default', children, ...rest }, + ref, +) { + return ( + + {children} + + ) +}) diff --git a/web/core/MenuAccordion/MenuHeader.tsx b/web/core/MenuAccordion/MenuHeader.tsx new file mode 100644 index 000000000..6e2f11eaf --- /dev/null +++ b/web/core/MenuAccordion/MenuHeader.tsx @@ -0,0 +1,28 @@ +import { forwardRef } from 'react' +import envisTwMerge from '../../twMerge' +import { Variants } from './MenuAccordion' +import { Accordion, AccordionHeaderProps } from '@core/Accordion' + +export type MenuHeaderProps = { + variant?: Variants +} & Omit + +export const MenuHeader = forwardRef(function MenuHeader( + { children, variant = 'default', className = '' }, + ref, +) { + const variantClassName: Partial> = { + default: ``, + simple: '', + } + + return ( + + {children} + + ) +}) diff --git a/web/core/MenuAccordion/MenuItem.tsx b/web/core/MenuAccordion/MenuItem.tsx new file mode 100644 index 000000000..5905e311d --- /dev/null +++ b/web/core/MenuAccordion/MenuItem.tsx @@ -0,0 +1,15 @@ +import { Accordion, AccordionItemProps } from '@core/Accordion' +import { Variants } from './MenuAccordion' + +export type MenuItemProps = { + children: React.ReactNode + variant?: Variants +} & Omit + +export const MenuItem = ({ children, variant = 'default', ...rest }: MenuItemProps) => { + return ( + +
  • {children}
  • +
    + ) +} diff --git a/web/core/MenuAccordion/index.ts b/web/core/MenuAccordion/index.ts new file mode 100644 index 000000000..399923131 --- /dev/null +++ b/web/core/MenuAccordion/index.ts @@ -0,0 +1,19 @@ +import { MenuButton, MenuButtonProps } from './MenuButton' +import { MenuAccordion as MenuWrapper, MenuAccordionProps } from './MenuAccordion' +import { MenuItem, MenuItemProps } from './MenuItem' +import { MenuHeader, MenuHeaderProps } from './MenuHeader' +import { MenuContent, MenuContentProps } from './MenuContent' + +type MenuCompoundProps = typeof MenuWrapper & { + MenuItem: typeof MenuItem + MenuHeader: typeof MenuHeader + MenuContent: typeof MenuContent +} + +const Menu = MenuWrapper as MenuCompoundProps +Menu.MenuItem = MenuItem +Menu.MenuHeader = MenuHeader +Menu.MenuContent = MenuContent + +export { MenuButton, Menu } +export type { MenuButtonProps, MenuAccordionProps, MenuItemProps, MenuHeaderProps, MenuContentProps } diff --git a/web/lib/queries/common/pageContentFields.ts b/web/lib/queries/common/pageContentFields.ts index e27516cdd..c0c345d1f 100644 --- a/web/lib/queries/common/pageContentFields.ts +++ b/web/lib/queries/common/pageContentFields.ts @@ -163,10 +163,14 @@ _type == "keyNumbers" =>{ "accordion": accordion[]{ "id": _key, title, + image, content[]{ ..., ${markDefs}, - } + }, + links[]{ + ${linkSelectorFields}, + }, }, "designOptions": { ${background}, diff --git a/web/lib/queries/menu.ts b/web/lib/queries/menu.ts index d477e1d87..0acd04cb1 100644 --- a/web/lib/queries/menu.ts +++ b/web/lib/queries/menu.ts @@ -48,6 +48,8 @@ export const menuQuery = /* groq */ ` "location": content->location, } }, + featuredIngress, + featuredCTALabel, } } ` diff --git a/web/pageComponents/pageTemplates/shared/SharedPageContent.tsx b/web/pageComponents/pageTemplates/shared/SharedPageContent.tsx index 41fb27160..20df29a2d 100644 --- a/web/pageComponents/pageTemplates/shared/SharedPageContent.tsx +++ b/web/pageComponents/pageTemplates/shared/SharedPageContent.tsx @@ -4,7 +4,6 @@ import FullWidthImage from '../../topicPages/FullWidthImage' import FullWidthVideo from '../../topicPages/FullWidthVideo' import Figure from '../../topicPages/Figure' import PageQuote from '../../topicPages/PageQuote' -import AccordionBlock from '../../topicPages/Accordion/AccordionBlock' import PromoTileArray from '../../../sections/PromoTiles/PromoTileArray' import IFrame from '../../topicPages/IFrame' import Promotion from '../../topicPages/Promotion' @@ -63,6 +62,7 @@ import ImageCarousel from '@sections/ImageCarousel/ImageCarousel' import { AnchorLinkList } from '@sections/AnchorLinkList' import ImageForText from '@sections/ImageForText/ImageForText' import TextWithIconArray from '@sections/TextWithIconArray/TextWithIconArray' +import AccordionBlock from '@sections/AccordionBlock/AccordionBlock' type DefaultComponent = { id?: string diff --git a/web/pageComponents/shared/Header.tsx b/web/pageComponents/shared/Header.tsx index a9f7f7928..516cc4d07 100644 --- a/web/pageComponents/shared/Header.tsx +++ b/web/pageComponents/shared/Header.tsx @@ -6,10 +6,7 @@ import { default as NextLink } from 'next/link' import { Topbar, BackgroundContainer } from '@components' import { AllSlugsType, LocalizationSwitch } from './LocalizationSwitch' import type { MenuData, SimpleMenuData } from '../../types/index' -import SiteMenu from './siteMenu/SiteMenu' -import SimpleSiteMenu from './siteMenu/simple/SimpleSiteMenu' import { Flags } from '../../common/helpers/datasetHelpers' -import { LogoLink } from './LogoLink' import { languages, defaultLanguage } from '../../languages' import { FormattedMessage, useIntl } from 'react-intl' import { search } from '@equinor/eds-icons' @@ -18,7 +15,8 @@ import Head from 'next/head' import getConfig from 'next/config' import { getAllSitesLink } from '../../common/helpers/getAllSitesLink' import { Icon } from '@equinor/eds-core-react' -import { ButtonLink } from '@core/Link' +import { ButtonLink, LogoLink } from '@core/Link' +import SiteMenu from '@sections/SiteMenu/SiteMenu' const TopbarOffset = createGlobalStyle` body { @@ -38,9 +36,6 @@ const TopbarContainer = styled(Topbar.InnerContainer)` grid-column-gap: var(--space-large); column-gap: var(--space-large); ` -const LogoLinkInGrid = styled(LogoLink)` - grid-area: logo; -` /* This div is needed because of the grid layout to wrap focus lock panes. We might look into to improve this at some point. */ @@ -160,7 +155,7 @@ const Header = ({ slugs, menuData }: HeaderProps) => { - + { ) : ( - + )} diff --git a/web/pageComponents/shared/SanityImage.tsx b/web/pageComponents/shared/SanityImage.tsx index dcc283f6c..38dc72ac2 100644 --- a/web/pageComponents/shared/SanityImage.tsx +++ b/web/pageComponents/shared/SanityImage.tsx @@ -1,9 +1,10 @@ +import { SanityImageObject } from '@sanity/image-url/lib/types/types' import { useSanityLoader } from '../../lib/hooks/useSanityLoader' import Img, { ImageProps } from 'next/image' import type { ImageWithAlt } from 'types' type Props = Omit & { - image: ImageWithAlt + image: ImageWithAlt | SanityImageObject maxWidth?: number aspectRatio?: number alt?: string @@ -46,7 +47,15 @@ const Image = ({ image, aspectRatio, sizes = DEFAULT_SIZES, maxWidth = DEFAULT_M } } - return {image.isDecorative + const getAltText = () => { + if ('alt' in image && image.alt) { + return image.alt + } else { + return '' + } + } + + return {getAltText()} } export default Image diff --git a/web/pageComponents/shared/portableText/Blocks.tsx b/web/pageComponents/shared/portableText/Blocks.tsx index 810d52b1e..83de9a59f 100644 --- a/web/pageComponents/shared/portableText/Blocks.tsx +++ b/web/pageComponents/shared/portableText/Blocks.tsx @@ -122,7 +122,7 @@ export type BlockProps = { */ id?: string /** Use to clamp lines on number */ - clampLines?: number + clampLines?: 3 | 4 | 5 includeFootnotes?: boolean noInvert?: boolean } & PortableTextProps diff --git a/web/pageComponents/shared/portableText/IngressText.tsx b/web/pageComponents/shared/portableText/IngressText.tsx index 7415bed01..6702ff57b 100644 --- a/web/pageComponents/shared/portableText/IngressText.tsx +++ b/web/pageComponents/shared/portableText/IngressText.tsx @@ -1,12 +1,13 @@ -import { PortableTextProps } from '@portabletext/react' -import Blocks from './Blocks' +import Blocks, { BlockProps } from './Blocks' import { twMerge } from 'tailwind-merge' type IngressTextProps = { centered?: boolean className?: string includeFootnotes?: boolean -} & PortableTextProps + /** Use to clamp lines on number */ + clampLines?: number +} & BlockProps const IngressText = ({ value, centered = false, components = {}, className = '', ...rest }: IngressTextProps) => { return ( diff --git a/web/pageComponents/shared/siteMenu/FeaturedContent.tsx b/web/pageComponents/shared/siteMenu/FeaturedContent.tsx deleted file mode 100644 index 506de2d6d..000000000 --- a/web/pageComponents/shared/siteMenu/FeaturedContent.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import type { EventCardData, FeaturedContentData } from '../../../types/index' -import PromotionCard from '@sections/cards/PromotionCard/PromotionCard' -import { EventCard } from '@sections/cards/EventCard' - -type Props = { - data: FeaturedContentData -} - -const FeaturedContent = ({ data }: Props) => { - if (!data.type) return null - - const isEvent = (data: FeaturedContentData): boolean => data?.routeContentType === 'event' - //To destructure and get rid of 2 but keep rest - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const { routeContentType, type, ...restData } = data - const containerClassName = 'hidden xl:block pl-6 border-l border-autumn-storm-50 w-[16vw]' - - if (isEvent(data)) { - return ( -
    - -
    - ) - } - - return ( -
    - -
    - ) -} - -export default FeaturedContent diff --git a/web/pageComponents/shared/siteMenu/MenuContainer.tsx b/web/pageComponents/shared/siteMenu/MenuContainer.tsx deleted file mode 100644 index 0bcbd1e5d..000000000 --- a/web/pageComponents/shared/siteMenu/MenuContainer.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import { ReactNode } from 'react' -import styled from 'styled-components' - -const StyledMenuContainer = styled.div` - font-size: var(--typeScale-1); - background-color: transparent; - padding: 0 var(--space-large); - @media (min-width: 1300px) { - background-color: var(--moss-green-50); - margin: var(--space-xLarge) var(--space-large) 0 var(--space-large); - display: flex; - justify-content: space-between; - align-items: center; - } -` - -type Props = { - children: ReactNode -} - -export const MenuContainer = ({ children, ...rest }: Props) => { - return {children} -} diff --git a/web/pageComponents/shared/siteMenu/MenuGroup.tsx b/web/pageComponents/shared/siteMenu/MenuGroup.tsx deleted file mode 100644 index 5ecf1e710..000000000 --- a/web/pageComponents/shared/siteMenu/MenuGroup.tsx +++ /dev/null @@ -1,88 +0,0 @@ -import { Fragment } from 'react' -import styled from 'styled-components' -import RichText from '../portableText/RichText' -import { Link, ReadMoreLink } from '@core/Link' -import { Menu } from '@components' -import type { MenuLinkData, SubMenuData, SubMenuGroupData } from '../../../types/index' -import { SubMenuGroupHeading, SubMenuGroupList } from './SubMenuGroup' -import FeaturedContent from './FeaturedContent' -import { useRouter } from 'next/router' - -const { SubMenu, SubMenuHeader, SubMenuPanel, SubMenuGroups } = Menu - -const PositionedSubMenuPanel = styled(SubMenuPanel)` - top: 265px; -` -const Grid = styled.div` - @media (min-width: 1300px) { - display: grid; - grid-template-columns: 1fr min-content; - } -` - -function getLink(linkData: MenuLinkData) { - // Fallback to home page, if this happens it is an error somewhere - // Sanity should take care of the validation here, and this is temp. until - // the static pages are migrated - if (!linkData) return 'something-wrong' - const { link } = linkData - - return (link && link.slug) || '/' -} - -type MenuGroupType = { - topLevelItem: SubMenuData - index: number -} - -export const MenuGroup = ({ topLevelItem, index }: MenuGroupType) => { - const { topLevelLink, groups, intro, featuredContent } = topLevelItem - - const topLevelHref = getLink(topLevelLink) - const router = useRouter() - - return ( - - {topLevelLink?.label} - - -
    -
    - {intro && } - {topLevelLink?.label} -
    - {groups && groups.length > 0 && ( - - {groups.map((groupItem: SubMenuGroupData) => { - return ( - - {groupItem.label && ( - - {groupItem.label} - - )} - - {groupItem.links?.map((link: MenuLinkData) => ( -
  • - - {link.label} - -
  • - ))} -
    -
    - ) - })} -
    - )} -
    - {featuredContent && } -
    -
    -
    - ) -} diff --git a/web/pageComponents/shared/siteMenu/NavTopbar.tsx b/web/pageComponents/shared/siteMenu/NavTopbar.tsx deleted file mode 100644 index e7916e273..000000000 --- a/web/pageComponents/shared/siteMenu/NavTopbar.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { ReactNode } from 'react' -import styled from 'styled-components' - -const StyledNavTopbar = styled.div` - height: var(--topbar-height); - width: 100%; - max-width: var(--maxViewportWidth); - margin: auto; - padding: var(--space-small) var(--layout-paddingHorizontal-small); - display: flex; - align-items: center; - justify-content: space-between; -` - -type Props = { - children: ReactNode -} - -export const NavTopbar = ({ children, ...rest }: Props) => { - return {children} -} diff --git a/web/pageComponents/shared/siteMenu/SiteMenu.tsx b/web/pageComponents/shared/siteMenu/SiteMenu.tsx deleted file mode 100644 index 14cfc5b0d..000000000 --- a/web/pageComponents/shared/siteMenu/SiteMenu.tsx +++ /dev/null @@ -1,121 +0,0 @@ -import { useEffect, useCallback, useState } from 'react' -import styled from 'styled-components' -import { useFloating, useInteractions, useDismiss, FloatingOverlay, FloatingFocusManager } from '@floating-ui/react' -import { useRouter } from 'next/router' -import { Menu, MenuButton } from '@components' -import { MenuGroup } from './MenuGroup' -import { TopbarDropdown } from './TopbarDropdown' -import { MenuContainer } from './MenuContainer' -import { NavTopbar } from './NavTopbar' -import { getAllSitesLink } from '../../../common/helpers/getAllSitesLink' - -import { LogoLink } from '../LogoLink' -import { Link } from '@core/Link' - -import type { MenuData, SubMenuData } from '../../../types/index' -import { FormattedMessage, useIntl } from 'react-intl' - -const AllSitesLink = styled(Link)` - text-decoration: none; - width: 100%; - margin: var(--space-small) 0 0 0; - color: var(--grey-80); - &:hover { - background-color: var(--grey-10); - } - padding: calc(var(--space-small) + var(--space-xSmall)) 0; - @media (min-width: 700px) { - margin: var(--space-small) 0 0 var(--menu-paddingHorizontal); - width: var(--minViewportWidth); - } - - @media (min-width: 1300px) { - display: inline-flex; - border-left: 2px solid var(--white-100); - padding: var(--space-large) var(--space-large); - width: fit-content; - margin: 0; - } -` - -export type MenuProps = { - data?: MenuData -} - -const SiteMenu = ({ data, ...rest }: MenuProps) => { - const router = useRouter() - const [isOpen, setIsOpen] = useState(false) - const intl = useIntl() - - const { refs, context } = useFloating({ - open: isOpen, - onOpenChange: setIsOpen, - }) - - const { getReferenceProps, getFloatingProps } = useInteractions([useDismiss(context)]) - - const handleRouteChange = useCallback(() => { - setIsOpen(false) - }, []) - const menuItems = (data && data.subMenus) || [] - - useEffect(() => { - router.events.on('routeChangeComplete', handleRouteChange) - return () => router.events.off('routeChangeComplete', handleRouteChange) - }, [router.events, handleRouteChange]) - - const title = intl.formatMessage({ id: 'menu', defaultMessage: 'Menu' }) - const allSitesURL = getAllSitesLink('internal', router?.locale || 'en') - - const getCurrentMenuItemIndex = (menuItems: SubMenuData[]) => { - return menuItems.findIndex((menuItem) => - menuItem.groups?.some((group) => group.links.some((link) => link.link?.slug === router.asPath)), - ) - } - - return ( - <> - setIsOpen(!isOpen)} - aria-expanded={isOpen} - aria-haspopup={true} - {...rest} - /> - {isOpen && ( - - - - - - - - )} - - ) -} -export default SiteMenu diff --git a/web/pageComponents/shared/siteMenu/SubMenuGroup.tsx b/web/pageComponents/shared/siteMenu/SubMenuGroup.tsx deleted file mode 100644 index 4d97b2e1f..000000000 --- a/web/pageComponents/shared/siteMenu/SubMenuGroup.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { ReactNode } from 'react' -import styled from 'styled-components' -import { List, Heading, HeadingProps, ListProps } from '@components' - -const StyledSubMenuGroupHeading = styled(Heading)` - color: var(--moss-green-95); - font-weight: 650; - letter-spacing: 0.15em; - font-size: var(--typeScale-05) !important; // TODO: Eliminate the need for !important - line-height: var(--lineHeight-2) !important; - padding: var(--space-xLarge) var(--space-medium) calc(var(--space-small) + var(--space-xSmall)) var(--space-medium); - @media (min-width: 1300px) { - font-weight: 600; - font-size: var(--typeScale-0); - padding: 0; - } -` - -const StyledSubMenuGroupList = styled(List)` - @media (min-width: 1300px) { - display: flex; - flex-direction: column; - flex-wrap: wrap; - height: 100%; - max-width: calc(13 * var(--space-medium)); - } -` - -type Props = { - children: ReactNode -} - -export const SubMenuGroupHeading = ({ children, ...rest }: Props & HeadingProps) => { - return ( - - {children} - - ) -} -export const SubMenuGroupList = ({ children, ...rest }: Props & ListProps) => { - return {children} -} diff --git a/web/pageComponents/shared/siteMenu/TopbarDropdown.tsx b/web/pageComponents/shared/siteMenu/TopbarDropdown.tsx deleted file mode 100644 index 2ace7a532..000000000 --- a/web/pageComponents/shared/siteMenu/TopbarDropdown.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { BackgroundContainer, BackgroundContainerProps } from '@components/Backgrounds' -import { ReactNode, CSSProperties } from 'react' -import styled from 'styled-components' - -/* If we need this for e.g. the search, let's move it to components folder */ -const StyledTopbarDropdown = styled(BackgroundContainer)` - position: fixed; - overflow: auto; - left: 0; - top: 0; - right: var(--right); - bottom: 0; -` -type Props = { - right?: string - children: ReactNode -} & BackgroundContainerProps - -export const TopbarDropdown = ({ children, right = '0px', style, ...rest }: Props) => { - return ( - - {children} - - ) -} diff --git a/web/pageComponents/shared/siteMenu/simple/SimpleHeader.tsx b/web/pageComponents/shared/siteMenu/simple/SimpleHeader.tsx deleted file mode 100644 index 2ca73dc1f..000000000 --- a/web/pageComponents/shared/siteMenu/simple/SimpleHeader.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { Icon } from '@equinor/eds-core-react' -import { add, minimize } from '@equinor/eds-icons' -import { AccordionButton, useAccordionItemState } from '@chakra-ui/react' -import { Typography, TypographyProps } from '@core/Typography' - -type SimpleHeaderProps = TypographyProps - -export const SimpleHeader = ({ children, ...rest }: SimpleHeaderProps) => { - const { isOpen } = useAccordionItemState() - - return ( - - - - {children} - - - - - ) -} diff --git a/web/pageComponents/shared/siteMenu/simple/SimpleMenuItem.tsx b/web/pageComponents/shared/siteMenu/simple/SimpleMenuItem.tsx deleted file mode 100644 index da9c3ad4b..000000000 --- a/web/pageComponents/shared/siteMenu/simple/SimpleMenuItem.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import styled from 'styled-components' - -import { List, Menu } from '@components' -import { Link, ReadMoreLink } from '@core/Link' -import { SimpleHeader } from './SimpleHeader' -import type { SimpleGroupData } from '../../../../types/index' -import { SubMenuGroupList } from '../SubMenuGroup' -import { AccordionPanel } from '@chakra-ui/react' - -const { SubMenu } = Menu -const { Item } = List - -const SimpleSubMenu = styled(SubMenu)` - @media (min-width: 1300px) { - border-bottom: 0.5px solid var(--grey-40); - } -` - -type MenuGroupType = { - item: SimpleGroupData - index: number -} - -export const SimpleMenuItem = ({ item, index }: MenuGroupType) => { - const { label, links = [], readMoreLink } = item - - return ( - - {label && {label}} - -
    -
    {!!readMoreLink?.link?.slug && {readMoreLink.label}} -
    - - {links?.map((link) => ( - - {link.label} - - ))} - -
    -
    -
    - ) -} diff --git a/web/pageComponents/shared/siteMenu/simple/SimpleSiteMenu.tsx b/web/pageComponents/shared/siteMenu/simple/SimpleSiteMenu.tsx deleted file mode 100644 index 6d882bf87..000000000 --- a/web/pageComponents/shared/siteMenu/simple/SimpleSiteMenu.tsx +++ /dev/null @@ -1,101 +0,0 @@ -// The simple variant for the menu is used by the satellite sites - -import { useEffect, useCallback, useState } from 'react' -import { useRouter } from 'next/router' -import { FormattedMessage, useIntl } from 'react-intl' -import { MenuButton } from '@components' -import { Link } from '@core/Link' -import { SimpleMenuItem } from './SimpleMenuItem' -import { getAllSitesLink } from '../../../../common/helpers/getAllSitesLink' - -import type { SimpleMenuData, SimpleGroupData } from '../../../../types/index' - -import { TopbarDropdown } from '../TopbarDropdown' -import { LogoLink } from '../../LogoLink' -import { NavTopbar } from '../NavTopbar' -import { FloatingFocusManager, FloatingOverlay, useDismiss, useFloating, useInteractions } from '@floating-ui/react' -import { Accordion } from '@chakra-ui/react' - -export type MenuProps = { - data?: SimpleMenuData -} - -const SimpleSiteMenu = ({ data, ...rest }: MenuProps) => { - const router = useRouter() - const [isOpen, setIsOpen] = useState(false) - const menuItems = (data && data.groups) || [] - const intl = useIntl() - const handleRouteChange = useCallback(() => { - setIsOpen(false) - }, []) - - const { refs, context } = useFloating({ - open: isOpen, - onOpenChange: setIsOpen, - }) - - const { getReferenceProps, getFloatingProps } = useInteractions([useDismiss(context)]) - - useEffect(() => { - router.events.on('routeChangeComplete', handleRouteChange) - return () => router.events.off('routeChangeComplete', handleRouteChange) - }, [router.events, handleRouteChange]) - - function onMenuButtonClick() { - setIsOpen(!isOpen) - } - - const title = intl.formatMessage({ id: 'menu', defaultMessage: 'Menu' }) - const allSitesURL = getAllSitesLink('external') - - return ( -
    - - {isOpen && ( - - - - - - - - )} -
    - ) -} -export default SimpleSiteMenu diff --git a/web/pageComponents/topicPages/Accordion/Accordion.tsx b/web/pageComponents/topicPages/Accordion/Accordion.tsx deleted file mode 100644 index 0eb85bf72..000000000 --- a/web/pageComponents/topicPages/Accordion/Accordion.tsx +++ /dev/null @@ -1,73 +0,0 @@ -import { useState, useEffect } from 'react' -import { useRouter } from 'next/router' -import { ParsedUrlQuery } from 'querystring' -import useRouterReplace from '../../hooks/useRouterReplace' -import { Accordion as EnvisAccordion } from '@components' -import type { AccordionListData } from '../../../types/index' -import Blocks from '../../../pageComponents/shared/portableText/Blocks' - -const { Item, Header, Panel } = EnvisAccordion - -// Next.js uses ParsedUrlQuery under the hood -function getPreExpanded(query: ParsedUrlQuery, queryParamName: string) { - let preExpanded: string[] = [] - if (query[queryParamName]) { - if (Array.isArray(query[queryParamName])) { - preExpanded = query[queryParamName] as string[] - } else { - preExpanded = [query[queryParamName]] as string[] - } - } - const preExpandedAsNumbers = preExpanded - .map((item: string) => parseInt(item, 10)) - //Because technically somebody could alter the url - .filter((value: number | typeof NaN) => !Number.isNaN(value)) - - return preExpandedAsNumbers -} - -type AccordionProps = { - hasTitle?: boolean - data: AccordionListData[] - queryParamName: string - id: string -} - -const Accordion = ({ data, id, hasTitle = true, queryParamName }: AccordionProps) => { - const router = useRouter() - const replaceUrl = useRouterReplace() - // Query is an empty object initially https://nextjs.org/docs/routing/dynamic-routes#caveats - const [indices, setIndices] = useState([]) - - useEffect(() => { - if (!router.isReady) return - setIndices(getPreExpanded(router.query, queryParamName)) - }, [router.isReady, router.query, queryParamName]) - - function toggleItem(toggledIndex: number) { - let expandedItems = [] - if (indices.includes(toggledIndex)) { - expandedItems = indices.filter((currentIndex) => currentIndex !== toggledIndex) - } else { - expandedItems = [...indices, toggledIndex].sort() - } - replaceUrl({ [queryParamName]: expandedItems }) - } - - return ( - - {data.map((item, idx) => { - const { id, title: itemTitle, content } = item - - return ( - -
    {itemTitle}
    - {content && } -
    - ) - })} -
    - ) -} - -export default Accordion diff --git a/web/pages/search/index.global.tsx b/web/pages/search/index.global.tsx index 57d5cba3d..6265034d8 100644 --- a/web/pages/search/index.global.tsx +++ b/web/pages/search/index.global.tsx @@ -7,12 +7,12 @@ import { getIsoFromLocale } from '../../lib/localization' import getIntl from '../../common/helpers/getIntl' import { Icon } from '@equinor/eds-core-react' import { close } from '@equinor/eds-icons' -import { TopbarDropdown } from '../../pageComponents/shared/siteMenu/TopbarDropdown' -import { NavTopbar } from '../../pageComponents/shared/siteMenu/NavTopbar' -import { LogoLink } from '../../pageComponents/shared/LogoLink' +import { LogoLink } from '../../core/Link/LogoLink' import Search from '../../pageComponents/search/Search' import { useRouter } from 'next/router' import { FloatingOverlay } from '@floating-ui/react' +import { TopbarDropdown } from '@sections/SiteMenu/TopbarDropdown' +import { NavTopbar } from '@sections/SiteMenu/NavTopbar' export default function SearchPage() { const router = useRouter() @@ -24,7 +24,7 @@ export default function SearchPage() { <> - +