Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Key numbers component. #2048 #2054

Merged
merged 9 commits into from
Jan 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions sanityv3/schemas/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ import videoPlayer from './objects/videoPlayer'
import videoPlayerCarousel from './objects/videoPlayerCarousel'
import videoControls from './objects/videoControls'
import hlsVideo from './objects/hlsVideo'
import keyNumbers from './objects/keyNumbers'
import keyNumberItem from './objects/keyNumberItem'

const routeSchemas = languages.map(({ name, title }) => {
return route(name, title)
Expand Down Expand Up @@ -164,6 +166,8 @@ const RemainingSchemas = [
videoPlayerCarousel,
videoControls,
hlsVideo,
keyNumbers,
keyNumberItem,
]

// Then we give our schema to the builder and provide the result to Sanity
Expand Down
44 changes: 44 additions & 0 deletions sanityv3/schemas/objects/keyNumberItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { Rule } from 'sanity'
import { NumberIcon } from '@sanity/icons'

export default {
name: 'keyNumberItem',
type: 'object',
title: 'Key Number',
fields: [
{
name: 'keyNumber',
title: 'Key Number',
type: 'number',
validation: (Rule: Rule) => Rule.required(),
},
{
name: 'unit',
title: 'Unit',
description: 'A short abbreviated text describing the unit of the key number',
type: 'string',
},
{
name: 'description',
title: 'Description',
type: 'string',
description: 'Short description to show below the key number',
},
],

preview: {
select: {
keyNumber: 'keyNumber',
unit: 'unit',
description: 'description',
},
prepare(selection: Record<string, string | number>) {
const { keyNumber, unit, description } = selection
return {
title: `${keyNumber} ${unit ?? ''}`,
subtitle: description,
media: NumberIcon,
}
},
},
}
116 changes: 116 additions & 0 deletions sanityv3/schemas/objects/keyNumbers.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import CompactBlockEditor from '../components/CompactBlockEditor'
import { configureBlockContent, configureTitleBlockContent } from '../editors'
import { PortableTextBlock, Rule } from 'sanity'
import { NumberIcon } from '@sanity/icons'
import blocksToText from '../../helpers/blocksToText'

const titleContentType = configureTitleBlockContent()
const ingressContentType = configureBlockContent({
h1: false,
h2: false,
h3: false,
h4: false,
attachment: false,
})

const disclaimerContentType = configureBlockContent({
h1: false,
h2: false,
h3: false,
h4: false,
attachment: false,
smallText: true,
})

export default {
name: 'keyNumbers',
title: 'Key Numbers',
type: 'object',
fieldsets: [
{
name: 'link',
title: 'Link',
description: 'Select either an internal link or external URL.',
},
{
name: 'design',
title: 'Design options',
},
],

fields: [
{
title: 'Title',
name: 'title',
type: 'array',
components: {
input: CompactBlockEditor,
},
of: [titleContentType],
validation: (Rule: Rule) => Rule.required().warning('In most cases you should add a title'),
},
{
name: 'ingress',
title: 'Ingress',
type: 'array',
of: [ingressContentType],
},
{
name: 'keyNumberItems',
title: 'Key Number Items',
type: 'array',
of: [{ type: 'keyNumberItem' }],
validation: (Rule: Rule) => Rule.min(2).error('Need minimum 2 key numbers'),
},
{
name: 'useHorizontalScroll',
title: 'Use horizontal scroll',
description:
'When this is enabled, the key numbers will use horizontal scroll if the amount of content is greater than the screen size allows. Only for mobiles.',
type: 'boolean',
initialValue: false,
},
{
name: 'disclaimer',
title: 'Disclaimer',
type: 'array',
components: {
input: CompactBlockEditor,
},
of: [disclaimerContentType],
},
{
name: 'action',
title: 'Link/action',
description: 'Select the link or downloadable file for the teaser',
fieldset: 'link',
type: 'array',
of: [
{ type: 'linkSelector', title: 'Link' },
{ type: 'downloadableImage', title: 'Downloadable image' },
{ type: 'downloadableFile', title: 'Downloadable file' },
],
validation: (Rule: Rule) => Rule.max(1).error('Only one action is permitted'),
},
{
title: 'Background',
description: 'Pick a colour for the background. Default is white.',
name: 'background',
type: 'colorlist',
fieldset: 'design',
},
],
preview: {
select: {
title: 'title',
items: 'keyNumberItems',
},
prepare(selection: { title: PortableTextBlock[]; items: Array<object> }) {
return {
title: blocksToText(selection.title),
subtitle: `Showing ${selection.items.length} key numbers`,
media: NumberIcon,
}
},
},
}
27 changes: 27 additions & 0 deletions web/lib/queries/common/keyNumbersFields.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import downloadableFileFields from './actions/downloadableFileFields'
import downloadableImageFields from './actions/downloadableImageFields'
import linkSelectorFields from './actions/linkSelectorFields'
import markDefs from './blockEditorMarks'

export const keyNumbersFields = /*groq*/ `
"type": _type,
"id" : _key,
title,
ingress[]{..., ${markDefs}},
disclaimer[]{..., ${markDefs}},
useHorizontalScroll,
"designOptions": {
"background": coalesce(background.title, 'White'),
},
"action": action[0]{
${linkSelectorFields},
${downloadableFileFields},
${downloadableImageFields},
},
"items" : keyNumberItems[]{
"id": _key,
keyNumber,
unit,
description,
},
`
4 changes: 4 additions & 0 deletions web/lib/queries/common/pageContentFields.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,15 @@ import linkSelectorFields, { linkReferenceFields } from './actions/linkSelectorF
import markDefs from './blockEditorMarks'
import { eventPromotionFields, futureEventsQuery, pastEventsQuery } from './eventPromotion'
import { imageCarouselFields } from './imageCarouselFields'
import { keyNumbersFields } from './keyNumbersFields'
import { noDrafts, sameLang } from './langAndDrafts'
import promoteMagazine from './promotions/promoteMagazine'
import { publishDateTimeQuery } from './publishDateTime'

const pageContentFields = /* groq */ `
_type == "keyNumbers" =>{
${keyNumbersFields}
},
_type == "teaser" => {
"type": _type,
"id": _key,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import ImageCarousel from '../../shared/ImageCarousel/ImageCarousel'
import IframeCarousel from '../../shared/IframeCarousel/IframeCarousel'
import VideoPlayer from '../../shared/VideoPlayer'
import VideoPlayerCarousel from '../../shared/VideoPlayerCarousel'
import KeyNumbers from '../../topicPages/KeyNumbers/KeyNumbers'
import {
AnchorLinkData,
TopicPageSchema,
Expand All @@ -45,6 +46,7 @@ import {
IframeCarouselData,
VideoPlayerData,
VideoPlayerCarouselData,
KeyNumbersData,
} from '../../../types/types'

// How could we do this for several different component types?
Expand All @@ -68,6 +70,7 @@ type ComponentProps =
| VideoPlayerData
| VideoPlayerCarouselData
| CookieDeclarationData
| KeyNumbersData

type PageContentProps = { data: TopicPageSchema | MagazinePageSchema }

Expand Down Expand Up @@ -121,6 +124,9 @@ export const PageContent = ({ data }: PageContentProps) => {
return <VideoPlayer key={c.id} data={c as VideoPlayerData} anchor={anchorReference} />
case 'videoPlayerCarousel':
return <VideoPlayerCarousel key={c.id} data={c as VideoPlayerCarouselData} anchor={anchorReference} />
case 'keyNumbers':
return <KeyNumbers key={c.id} data={c as KeyNumbersData} anchor={anchorReference} />

default:
return null
}
Expand Down
7 changes: 6 additions & 1 deletion web/pageComponents/shared/Carousel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,12 @@ export const Carousel = ({ children, scrollOffset, horizontalPadding = false, ..
const handleScroll = (scrollType: string) => {
const container = scrollRef.current
if (container) {
const offset = scrollOffset || Math.max(0.5 * container.offsetWidth, 320)
const noOfItems = container?.childElementCount - 2 // exclude right & left arrow from children count.
const itemWidth = container?.lastElementChild?.clientWidth || 0
const padding = (container?.scrollWidth - itemWidth * noOfItems) / (noOfItems - 1)
const calculatedOffset = itemWidth + padding / 2
const offset = scrollOffset || calculatedOffset

container.scrollBy({
left: scrollType === 'forward' ? offset : -offset,
behavior: prefersReducedMotion ? 'auto' : 'smooth',
Expand Down
34 changes: 34 additions & 0 deletions web/pageComponents/shared/ReadMoreLink.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { LinkData } from '../../types'
import { getUrlFromAction } from '../../common/helpers'
import { getLocaleFromName } from '../../lib/localization'
import { Link } from '@components/Link'
import styled from 'styled-components'

const StyledLink = styled(Link)`
font-size: var(--typeScale-1);
`
const ReadMoreLink = ({ action }: { action: LinkData }) => {
padms marked this conversation as resolved.
Show resolved Hide resolved
const { type, label, extension } = action
const url = getUrlFromAction(action)
if (!url) {
console.warn(`Missing URL on 'TeaserAction' link with type: '${type}' and label: '${label}'`)
return null
}

if (action.type === 'internalUrl') {
const locale = getLocaleFromName(action.link?.lang)
return (
<StyledLink href={url} locale={locale} variant="readMore" aria-label={action.ariaLabel}>
{action.label}
</StyledLink>
)
}

return (
<StyledLink variant="readMore" href={url} type={action.type} aria-label={action.ariaLabel}>
{action.label} {extension && `(${extension.toUpperCase()})`}
</StyledLink>
)
}

export default ReadMoreLink
34 changes: 4 additions & 30 deletions web/pageComponents/shared/Teaser.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import { Teaser as EnvisTeaser, Link, Eyebrow, BackgroundContainer, Text } from '@components'
import { Teaser as EnvisTeaser, Eyebrow, BackgroundContainer, Text } from '@components'
import styled from 'styled-components'
import IngressText from './portableText/IngressText'
import TitleText from './portableText/TitleText'
import { urlFor } from '../../common/helpers'
import Img from 'next/image'
import Image from './SanityImage'
import { getUrlFromAction } from '../../common/helpers/getUrlFromAction'

import type { TeaserData, ImageWithAlt, LinkData } from '../../types/types'
import { getLocaleFromName } from '../../lib/localization'
import type { TeaserData, ImageWithAlt } from '../../types/types'
import ReadMoreLink from './ReadMoreLink'
import { BlockType } from './portableText/helpers/defaultSerializers'

const { Content, Media } = EnvisTeaser
Expand Down Expand Up @@ -57,30 +55,6 @@ const TeaserImage = ({ image }: { image: ImageWithAlt }) => {
)
}

const TeaserAction = ({ action }: { action: LinkData }) => {
const { type, label, extension } = action
const url = getUrlFromAction(action)
if (!url) {
console.warn(`Missing URL on 'TeaserAction' link with type: '${type}' and label: '${label}'`)
return null
}

if (action.type === 'internalUrl') {
const locale = getLocaleFromName(action.link?.lang)
return (
<Link href={url} locale={locale} variant="readMore" aria-label={action.ariaLabel}>
{action.label}
</Link>
)
}

return (
<Link variant="readMore" href={url} type={action.type} aria-label={action.ariaLabel}>
{action.label} {extension && `(${extension.toUpperCase()})`}
</Link>
)
}

const Teaser = ({ data, anchor }: TeaserProps) => {
const { title, overline, text, image, action, designOptions, isBigText } = data
const { background, imageSize, imagePosition } = designOptions
Expand Down Expand Up @@ -125,7 +99,7 @@ const Teaser = ({ data, anchor }: TeaserProps) => {
{text && <IngressText value={text} />}
</ContentWrapper>
)}
{action && <TeaserAction action={action} />}
{action && <ReadMoreLink action={action} />}
</Content>
</StyledEnvisTeaser>
</BackgroundContainer>
Expand Down
Loading
Loading