diff --git a/sanityv3/schemas/documents/newsroom.ts b/sanityv3/schemas/documents/newsroom.ts index 07bff7781..68bbd278e 100644 --- a/sanityv3/schemas/documents/newsroom.ts +++ b/sanityv3/schemas/documents/newsroom.ts @@ -6,6 +6,8 @@ import { file } from '@equinor/eds-icons' import { EdsIcon } from '../../icons' import type { PortableTextBlock, Rule } from 'sanity' import { lang } from './langField' +import routes from '../routes' +import { filterByRoute } from '../../helpers/referenceFilters' const titleContentType = configureTitleBlockContent() const textContentType = configureBlockContent({ @@ -66,6 +68,42 @@ export default { type: 'array', of: [textContentType], }, + { + name: 'subscriptionLink', + title: 'Link to the email subscription page', + type: 'reference', + to: routes, + options: { + filter: filterByRoute, + }, + }, + { + name: 'subscriptionLinkTitle', + title: 'Title for the subscription link', + type: 'string', + }, + { + title: 'List of local news pages', + name: 'localNewsPages', + type: 'array', + of: [{ type: 'linkSelector', title: 'Link' }], + }, + { + title: 'Image thumbnail fallbacks', + name: 'imageThumbnailFallbacks', + type: 'array', + of: [ + { + type: 'image', + title: 'Fallback image', + options: { + hotspot: true, + collapsed: false, + }, + }, + ], + validation: (Rule: Rule) => Rule.max(3), + }, ], preview: { select: { diff --git a/sanityv3/schemas/textSnippets.ts b/sanityv3/schemas/textSnippets.ts index 903206bdf..5bf1e0bfc 100644 --- a/sanityv3/schemas/textSnippets.ts +++ b/sanityv3/schemas/textSnippets.ts @@ -81,6 +81,16 @@ const snippets: textSnippet = { defaultValue: 'Search', group: groups.search, }, + search_quick_search: { + title: 'Quick search', + defaultValue: 'Quick search', + group: groups.search, + }, + search_quick_search_label: { + title: 'Quick search label', + defaultValue: 'Search among Equinor corporate-level news releases', + group: groups.search, + }, search_news_tab: { title: 'News tab name', defaultValue: 'News', @@ -116,6 +126,31 @@ const snippets: textSnippet = { defaultValue: 'Sorry, no results were found. Please try again with some different keywords.', group: groups.search, }, + search_submit: { + title: 'Submit search', + defaultValue: 'Submit search', + group: groups.search, + }, + search_reset: { + title: 'Reset', + defaultValue: 'Reset', + group: groups.search, + }, + search_filter_by: { + title: 'Filter by', + defaultValue: 'Filter by', + group: groups.search, + }, + search_pagination_first_page: { + title: 'First page', + defaultValue: 'First page', + group: groups.search, + }, + search_pagination_last_page: { + title: 'Last page', + defaultValue: 'Last page', + group: groups.search, + }, copyright: { title: 'Copyright', defaultValue: 'Copyright 2022 Equinor ASA', @@ -672,6 +707,21 @@ const snippets: textSnippet = { defaultValue: 'Topic', group: groups.newsroom, }, + newsroom_filters_label: { + title: 'Filters label', + defaultValue: 'Filter by:', + group: groups.newsroom, + }, + newsroom_filters_selected: { + title: 'Selected', + defaultValue: 'Selected', + group: groups.newsroom, + }, + newsroom_filters_clear_all: { + title: 'Clear all', + defaultValue: 'Clear all', + group: groups.newsroom, + }, newsroom_country_filter: { title: 'Country filter heading', defaultValue: 'Country', @@ -703,6 +753,16 @@ const snippets: textSnippet = { defaultValue: 'Your search returned no results', group: groups.newsroom, }, + newsroom_related_links: { + title: 'Related links', + defaultValue: 'Related links', + group: groups.newsroom, + }, + newsroom_skip_to_news: { + title: 'Skip to list of news', + defaultValue: 'Skip to list of news', + group: groups.newsroom, + }, magazineindex_list_header: { title: 'Magazine index: Stories list heading', defaultValue: 'Stories', @@ -749,6 +809,26 @@ const snippets: textSnippet = { defaultValue: 'Switch to', group: groups.others, }, + next: { + title: 'Next', + defaultValue: 'Next', + group: groups.others, + }, + previous: { + title: 'Previous', + defaultValue: 'Previous', + group: groups.others, + }, + page: { + title: 'Page', + defaultValue: 'Page', + group: groups.others, + }, + remove: { + title: 'Remove', + defaultValue: 'Remove', + group: groups.others, + }, } type textSnippetGroup = { title: string; hidden?: boolean } diff --git a/search/IndexSanityContent/common/news/SharedNewsFields.ts b/search/IndexSanityContent/common/news/SharedNewsFields.ts index d780ddf23..d51341ca7 100644 --- a/search/IndexSanityContent/common/news/SharedNewsFields.ts +++ b/search/IndexSanityContent/common/news/SharedNewsFields.ts @@ -1,4 +1,5 @@ import { Page } from '../../../common' +import { ImageWithAltAndCaption } from '../types' export type SharedNewsFields = Page & { title: string @@ -18,4 +19,5 @@ export type SharedNewsFields = Page & { text: string }[] _id: string + heroImage?: ImageWithAltAndCaption } diff --git a/search/IndexSanityContent/common/types.ts b/search/IndexSanityContent/common/types.ts new file mode 100644 index 000000000..b09a62f06 --- /dev/null +++ b/search/IndexSanityContent/common/types.ts @@ -0,0 +1,30 @@ +export type ImageWithAlt = { + _type: 'imageWithAlt' + alt: string + isDecorative?: boolean + asset: { + _ref: string + _type: 'reference' + } + crop?: { + _type: 'sanity.imageCrop' + bottom: number + left: number + right: number + top: number + } + hotspot?: { + _type: 'sanity.imageHotspot' + height: number + width: number + x: number + y: number + } +} + +export type ImageWithAltAndCaption = { + _type: 'imageWithAltAndCaption' + attribution?: string + caption?: string + image: ImageWithAlt +} diff --git a/search/IndexSanityContent/localNews/sanity.ts b/search/IndexSanityContent/localNews/sanity.ts index e33d744d7..9bdbdcd45 100644 --- a/search/IndexSanityContent/localNews/sanity.ts +++ b/search/IndexSanityContent/localNews/sanity.ts @@ -33,6 +33,7 @@ export const query = /* groq */ `*[_type == "localNews" && lang == $lang && !(_i title, "text": pt::text(content) }, + heroImage, "docToClear": _id match $id } ` diff --git a/search/IndexSanityContent/magazine/mapper.ts b/search/IndexSanityContent/magazine/mapper.ts index d171c1f33..0a9288cef 100644 --- a/search/IndexSanityContent/magazine/mapper.ts +++ b/search/IndexSanityContent/magazine/mapper.ts @@ -1,9 +1,10 @@ import { pipe } from 'fp-ts/lib/function' import * as A from 'fp-ts/lib/Array' import * as O from 'fp-ts/lib/Option' -import { ImageWithAlt, MagazineArticle } from './sanity' +import { MagazineArticle } from './sanity' import { AccordionIndex, MagazineIndex, TextBlockIndex } from '../../common' import { mappedAccordions, mappedTextBlocks } from '../common/mappers' +import { ImageWithAlt } from '../common/types' const getHeroImage = (article: MagazineArticle): ImageWithAlt | null => { if (article?.heroFigure?.image?.asset) { diff --git a/search/IndexSanityContent/magazine/sanity.ts b/search/IndexSanityContent/magazine/sanity.ts index 9f8425744..6da06254e 100644 --- a/search/IndexSanityContent/magazine/sanity.ts +++ b/search/IndexSanityContent/magazine/sanity.ts @@ -5,6 +5,7 @@ import { SanityClient } from '@sanity/client' import { Language } from '../../common' import { MappableAccordionType, MappableTextBlockType } from '../common/mappers' import { plainTextExcludingStrikeThrough } from '../../common/queryHelpers' +import { ImageWithAlt, ImageWithAltAndCaption } from '../common/types' export enum HeroTypes { DEFAULT = 'default', @@ -62,37 +63,6 @@ const getQueryParams = (language: Language, id: string) => ({ id: id, }) -export type ImageWithAlt = { - _type: 'imageWithAlt' - alt: string - isDecorative?: boolean - asset: { - _ref: string - _type: 'reference' - } - crop?: { - _type: 'sanity.imageCrop' - bottom: number - left: number - right: number - top: number - } - hotspot?: { - _type: 'sanity.imageHotspot' - height: number - width: number - x: number - y: number - } -} - -export type ImageWithAltAndCaption = { - _type: 'imageWithAltAndCaption' - attribution?: string - caption?: string - image: ImageWithAlt -} - export type MagazineArticle = { slug: string title: string diff --git a/search/IndexSanityContent/news/mapper.ts b/search/IndexSanityContent/news/mapper.ts index 81633608a..5d8daf60e 100644 --- a/search/IndexSanityContent/news/mapper.ts +++ b/search/IndexSanityContent/news/mapper.ts @@ -5,7 +5,7 @@ import type { NewsArticle } from './sanity' type MapDataType = (article: NewsArticle) => NewsIndex[] export const mapData: MapDataType = (article) => { - const { publishDateTime, topicTags, countryTags, title, ingress, slug, factboxes } = article + const { publishDateTime, topicTags, countryTags, title, ingress, slug, factboxes, heroImage } = article // Hu hei hvor det går const year = publishDateTime ? new Date(publishDateTime).getFullYear() : '' return pipe( @@ -24,6 +24,7 @@ export const mapData: MapDataType = (article) => { topicTags, countryTags, year, + heroImage, } as NewsIndex), ), A.concat( @@ -40,6 +41,7 @@ export const mapData: MapDataType = (article) => { topicTags, countryTags, year, + heroImage, } as NewsIndex), ), ), diff --git a/search/IndexSanityContent/news/sanity.ts b/search/IndexSanityContent/news/sanity.ts index 5e1aec631..e5fea6def 100644 --- a/search/IndexSanityContent/news/sanity.ts +++ b/search/IndexSanityContent/news/sanity.ts @@ -34,6 +34,7 @@ export const query = /* groq */ `*[_type == "news" && lang == $lang && !(_id in title, "text": pt::text(content) }, + heroImage, "docToClear": _id match $id } ` diff --git a/search/common/types.ts b/search/common/types.ts index 2d072a696..2fa403899 100644 --- a/search/common/types.ts +++ b/search/common/types.ts @@ -58,6 +58,7 @@ export type NewsIndex = { countryTags: string[] thumbnailUrl: string localNewsTag: string + heroImage: object } export type MagazineIndex = { diff --git a/web/common/helpers/getPaths.ts b/web/common/helpers/getPaths.ts index 892d5b786..0b29f13df 100644 --- a/web/common/helpers/getPaths.ts +++ b/web/common/helpers/getPaths.ts @@ -1,7 +1,7 @@ import { groq } from 'next-sanity' import { getNameFromLocale } from '../../lib/localization' import { publishDateTimeQuery } from '../../lib/queries/common/publishDateTime' -import { sanityClient } from '../../lib/sanity.server' +import { getClient } from '../../lib/sanity.server' import { noDrafts, sameLang } from './../../lib/queries/common/langAndDrafts' // These URLs uses SSR and thus should not be static rendered @@ -14,7 +14,7 @@ const getTopicRoutesForLocale = async (locale: string) => { const lang = getNameFromLocale(locale) // Empty array as fallback for satelittes const blacklist = topicSlugBlackList[lang as keyof typeof topicSlugBlackList] || [] - const data: { slug: string; _updatedAt: string }[] = await sanityClient.fetch( + const data: { slug: string; _updatedAt: string }[] = await getClient(false).fetch( groq`*[_type match "route_" + $lang + "*" && (!(slug.current in $blacklist)) && defined(slug.current) && !(_id in path("drafts.**"))][] { _updatedAt, "slug": slug.current, @@ -30,7 +30,7 @@ const getTopicRoutesForLocaleToStaticallyBuild = async (locale: string) => { const lang = getNameFromLocale(locale) // Empty array as fallback for satelittes const blacklist = topicSlugBlackList[lang as keyof typeof topicSlugBlackList] || [] - const data: { slug: string; _updatedAt: string }[] = await sanityClient.fetch( + const data: { slug: string; _updatedAt: string }[] = await getClient(false).fetch( groq`*[_type match "route_" + $lang + "*" && (!(slug.current in $blacklist)) && includeInBuild && defined(slug.current) && !(_id in path("drafts.**"))][] { _updatedAt, "slug": slug.current, @@ -45,7 +45,7 @@ const getTopicRoutesForLocaleToStaticallyBuild = async (locale: string) => { const getDocumentsForLocale = async (type: 'news' | 'localNews' | 'magazine', locale: string) => { const lang = getNameFromLocale(locale) - const data: { slug: string; _updatedAt: string }[] = await sanityClient.fetch( + const data: { slug: string; _updatedAt: string }[] = await getClient(false).fetch( groq`*[_type == $type && defined(slug.current) && ${sameLang} && ${noDrafts}][] { _updatedAt, "slug": slug.current, @@ -62,7 +62,7 @@ const getDocumentsForLocale = async (type: 'news' | 'localNews' | 'magazine', lo // Only include drafts if preview mode is enabled export const getDocumentBySlug = async (slug: string, isPreview = false) => { const draft = isPreview ? `` : /* groq */ `&& ${noDrafts}` - const data: { slug: string; _updatedAt: string }[] = await sanityClient.fetch( + const data: { slug: string; _updatedAt: string }[] = await getClient(false).fetch( groq`*[defined(slug.current) && slug.current == $slug ${draft}][0] { _updatedAt, "slug": slug.current, @@ -148,7 +148,7 @@ export const getLocalNewsPaths = async (locales: string[]): Promise export const getNewsroomPaths = async (): Promise => { // Use last published news as updatedAt field for newsroom const getUpdatedAt = async (lang: 'en_GB' | 'nb_NO'): Promise<{ _updatedAt: string }> => - await sanityClient.fetch( + await getClient(false).fetch( groq`*[_type == 'news' && ${sameLang} && ${noDrafts}] | order(${publishDateTimeQuery} desc)[0] { _updatedAt, }`, @@ -177,7 +177,7 @@ export const getNewsroomPaths = async (): Promise => { export const getMagazineIndexPaths = async (): Promise => { // Use last published news as updatedAt field for newsroom const getUpdatedAt = async (lang: 'en_GB' | 'nb_NO'): Promise<{ _updatedAt: string }> => - await sanityClient.fetch( + await getClient(false).fetch( groq`*[_type == 'magazine' && ${sameLang} && ${noDrafts}] | order(_createdAt desc)[0] { _updatedAt, }`, diff --git a/web/components/src/Accordion/Header.tsx b/web/components/src/Accordion/Header.tsx index 764072934..2b8a8aa59 100644 --- a/web/components/src/Accordion/Header.tsx +++ b/web/components/src/Accordion/Header.tsx @@ -53,7 +53,7 @@ const StyledHeader = styled(Typography)` } ` -const StyledTypography = styled(Typography)<{ isExpanded?: boolean }>` +const StyledTypography = styled(Typography)<{ $isExpanded?: boolean }>` font-size: var(--typeScale-1); line-height: var(--lineHeight-2); display: inline-block; @@ -65,8 +65,8 @@ const StyledTypography = styled(Typography)<{ isExpanded?: boolean }>` color: var(--color-on-background); - ${({ isExpanded }) => - isExpanded && { + ${({ $isExpanded }) => + $isExpanded && { fontWeight: 700, }} ` @@ -92,7 +92,7 @@ export const Header = forwardRef(functi )} - + {children} diff --git a/web/components/src/FormattedDateTime/FormattedDate.tsx b/web/components/src/FormattedDateTime/FormattedDate.tsx index 5a2d198f5..159b298f5 100644 --- a/web/components/src/FormattedDateTime/FormattedDate.tsx +++ b/web/components/src/FormattedDateTime/FormattedDate.tsx @@ -13,15 +13,22 @@ export const FormattedDate = ({ year = 'numeric', month = 'long', day = '2-digit', + weekday, icon = false, uppercase = false, ...rest }: DateProps): JSX.Element => { return ( - + {icon && } - + ) diff --git a/web/components/src/FormattedDateTime/shared.tsx b/web/components/src/FormattedDateTime/shared.tsx index e5ae6e147..742250481 100644 --- a/web/components/src/FormattedDateTime/shared.tsx +++ b/web/components/src/FormattedDateTime/shared.tsx @@ -9,14 +9,15 @@ export type DateProps = { year?: 'numeric' | '2-digit' month?: 'numeric' | '2-digit' | 'long' | 'short' | 'narrow' day?: 'numeric' | '2-digit' + weekday?: 'long' /** Uppercase letter for the date or not */ uppercase?: boolean } & HTMLAttributes -export const StyledDate = styled.span<{ uppercase?: boolean }>` +export const StyledDate = styled.span<{ $uppercase?: boolean }>` display: inline-flex; align-items: center; - text-transform: ${(props) => (props.uppercase ? 'uppercase' : 'none')}; + text-transform: ${(props) => (props.$uppercase ? 'uppercase' : 'none')}; & > svg { flex-shrink: 0; box-sizing: content-box; diff --git a/web/components/src/List/List.tsx b/web/components/src/List/List.tsx index 6c36040e2..8e958880b 100644 --- a/web/components/src/List/List.tsx +++ b/web/components/src/List/List.tsx @@ -8,7 +8,7 @@ export type ListProps = { splitList?: boolean } & EdsListProps -const StyledList = styled(EdsList)` +const StyledList = styled(EdsList)<{ $unstyled?: boolean; $centered?: boolean; $splitList?: boolean }>` font-size: var(--typeScale-1); line-height: var(--lineHeight-3); /* EDS list removes margin */ @@ -16,20 +16,20 @@ const StyledList = styled(EdsList)` margin-right: var(--space-medium); padding-left: var(--space-medium); list-style-position: outside; - ${({ unstyled }) => - unstyled && { + ${({ $unstyled }) => + $unstyled && { margin: 0, padding: 0, listStyle: 'none', }} - ${({ centered }) => - centered && { + ${({ $centered }) => + $centered && { display: 'grid', placeContent: 'center', }} @media (min-width: 800px) { - ${({ splitList }) => - splitList && { + ${({ $splitList }) => + $splitList && { display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gridColumnGap: `var(--space-xLarge)`, @@ -45,9 +45,9 @@ export const List = forwardRef(f return ( ` +const StyledMenuButton = styled.button<{ $expanded: boolean }>` min-width: 48px; min-height: 48px; position: relative; @@ -41,8 +41,8 @@ const StyledMenuButton = styled.button<{ expanded: boolean }>` grid-template-columns: min-content 1fr; } - ${({ expanded }) => - !expanded && + ${({ $expanded }) => + !$expanded && ` &:hover .menuIcon { span:nth-child(1) { @@ -61,7 +61,7 @@ export const MenuButton = forwardRef(functio ) { return ( ` +const Icon = styled.span<{ $expanded: boolean }>` width: 30px; height: 30px; position: relative; @@ -39,11 +39,11 @@ const Icon = styled.span<{ expanded: boolean }>` transform-origin: left center; } - ${({ expanded }) => expanded && ExpandedStyle} + ${({ $expanded }) => $expanded && ExpandedStyle} ` export const MenuIcon = ({ expanded }: { expanded: boolean }) => ( -