Skip to content

Commit

Permalink
Merge 2010
Browse files Browse the repository at this point in the history
  • Loading branch information
padms committed Jan 18, 2024
1 parent fcbc7c5 commit 9fd99b0
Show file tree
Hide file tree
Showing 19 changed files with 502 additions and 4 deletions.
103 changes: 103 additions & 0 deletions sanityv3/schemas/components/ThemeSelector/ThemeSelector.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import { Box, Card, Flex, Stack, Tooltip, Text } from '@sanity/ui'
import { useCallback } from 'react'
import { set } from 'sanity'
import type { ObjectInputProps } from 'sanity'
import styled from 'styled-components'
import { defaultColors, getColorForTheme } from './defaultColors'
import { EdsIcon } from '../../../icons'
import { text_field } from '@equinor/eds-icons'

const Circle = styled.div<{ active: boolean }>`
display: inline-block;
border: solid 2px ${({ active }) => (active ? 'var(--card-focus-ring-color)' : 'transparent')};
border-radius: 50%;
padding: 4px;
cursor: pointer;
`

const InnerCircle = styled.div<{ color: string; fillColor: string }>`
display: flex;
background-color: ${({ color }) => color};
border: 1px solid var(--card-hairline-soft-color);
padding: 15px;
border-radius: 50%;
color: ${({ fillColor }) => fillColor};
`

export type ThemeSelectorValue = {
title: string
value: number
}

type ColorCircleProps = {
color: ThemeSelectorValue
active: boolean
onClickHandler: (val: ThemeSelectorValue) => void
}

const ColorCircle = ({ color, active, onClickHandler }: ColorCircleProps) => {
const { background, highlight } = getColorForTheme(color.value)
return (
<Card paddingY={1}>
<Tooltip
content={
<Box padding={2}>
<Text muted size={1}>
{color.title}
</Text>
</Box>
}
fallbackPlacements={['right', 'left']}
placement="top"
portal
>
<Circle active={active} onClick={() => onClickHandler(color)}>
<InnerCircle color={background} fillColor={highlight}>
<EdsIcon {...text_field} />
</InnerCircle>
</Circle>
</Tooltip>
</Card>
)
}

type ThemeSelectorProps = ObjectInputProps

export const ThemeSelector = ({ value, onChange, schemaType }: ThemeSelectorProps) => {
const { options } = schemaType
const colors = (options?.colors as ThemeSelectorValue[]) || defaultColors

const handleSelect = useCallback(
(selected: ThemeSelectorValue) => {
if (selected === value) return

onChange(set(selected.title, ['title']))
onChange(set(selected.value, ['value']))
},
[onChange, value],
)

return (
<Stack space={3}>
{colors && (
<Card>
<Flex direction={'row'} wrap={'wrap'}>
{colors.map((colorItem: ThemeSelectorValue) => {
const { background } = getColorForTheme(colorItem.value)
return (
<ColorCircle
key={background}
color={colorItem}
active={colorItem.value === value?.value}
onClickHandler={handleSelect}
/>
)
})}
</Flex>
</Card>
)}
</Stack>
)
}

export default ThemeSelector
36 changes: 36 additions & 0 deletions sanityv3/schemas/components/ThemeSelector/defaultColors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
export const defaultColors = [
{ title: 'White', value: 0 },
{ title: 'Moss Green Light', value: 1 },
{ title: 'Spruce Wood', value: 2 },
{ title: 'Mist Blue', value: 3 },
{ title: 'Mid Yellow', value: 4 },
{ title: 'Mid Orange', value: 5 },
{ title: 'Mid Blue 1', value: 6 },
{ title: 'Mid Blue 2', value: 7 },
{ title: 'Mid Green', value: 8 },
]

export const getColorForTheme = (pattern: number) => {
switch (pattern) {
case 1:
return { background: 'hsl(184, 30%, 96%)', highlight: 'hsl(348, 100%, 54%)' }
case 2:
return { background: 'hsl(25, 100%, 94%)', highlight: 'hsl(348, 100%, 54%)' }
case 3:
return { background: 'hsl(199, 58%, 90%)', highlight: 'hsl(348, 100%, 54%)' }
case 4:
return { background: '#FFF5B8', highlight: 'hsl(348, 100%, 54%)' }
case 5:
return { background: '#F8D1AF', highlight: 'hsl(348, 100%, 54%)' }
case 6:
return { background: '#49709C', highlight: '#F8D1AF' }
case 7:
return { background: '#49709C', highlight: '#FFF5B8' }
case 8:
return { background: '#C3E4CE', highlight: 'hsl(348, 100%, 54%)' }

case 0:
default:
return { background: 'hsl(0, 0%, 100%)', highlight: 'hsl(348, 100%, 54%)' }
}
}
2 changes: 2 additions & 0 deletions sanityv3/schemas/components/ThemeSelector/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './ThemeSelector'
export * from './defaultColors'
2 changes: 1 addition & 1 deletion sanityv3/schemas/components/renderers.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {ReactNode} from 'react'
import { ReactNode } from 'react'

type Props = {
children: ReactNode
Expand Down
1 change: 1 addition & 0 deletions sanityv3/schemas/documents/magazine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ export default {
of: [
{ type: 'textBlock' },
{ type: 'teaser' },
{ type: 'textTeaser' },
{ type: 'fullWidthImage' },
{ type: 'fullWidthVideo' },
{ type: 'figure' },
Expand Down
1 change: 1 addition & 0 deletions sanityv3/schemas/documents/page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export default {
of: [
{ type: 'textBlock' },
{ type: 'teaser' },
{ type: 'textTeaser' },
{ type: 'fullWidthImage' },
{ type: 'fullWidthVideo' },
{ type: 'figure' },
Expand Down
1 change: 1 addition & 0 deletions sanityv3/schemas/editors/titleEditorContentType.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ export const configureTitleBlockContent = (
if (highlight) {
config.marks?.decorators?.push(textColorConfig)
}

return config
}

Expand Down
4 changes: 4 additions & 0 deletions sanityv3/schemas/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ import stockValuesApi from './objects/stockValuesApi'
import table from './objects/table'
import tableRichText from './objects/table/tableRichText'
import teaser from './objects/teaser'
import textTeaser from './objects/textTeaser'
import textBlock from './objects/textBlock'
import textWithIcon from './objects/textWithIcon'
import textWithIconArray from './objects/textWithIconArray'
Expand All @@ -87,6 +88,7 @@ import videoControls from './objects/videoControls'
import hlsVideo from './objects/hlsVideo'
import keyNumbers from './objects/keyNumbers'
import keyNumberItem from './objects/keyNumberItem'
import themeList from './objects/themeList'

const routeSchemas = languages.map(({ name, title }) => {
return route(name, title)
Expand Down Expand Up @@ -124,6 +126,7 @@ const RemainingSchemas = [
downloadableFile,
downloadableImage,
teaser,
textTeaser,
textBlock,
accordion,
accordionItem,
Expand Down Expand Up @@ -168,6 +171,7 @@ const RemainingSchemas = [
hlsVideo,
keyNumbers,
keyNumberItem,
themeList,
]

// Then we give our schema to the builder and provide the result to Sanity
Expand Down
142 changes: 142 additions & 0 deletions sanityv3/schemas/objects/textTeaser.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
/* eslint-disable react/display-name */
import blocksToText from '../../helpers/blocksToText'
import { LeftAlignedImage, RightAlignedImage } from '../../icons'
import { RadioIconSelector } from '../components'
import CompactBlockEditor from '../components/CompactBlockEditor'
import { configureBlockContent, configureTitleBlockContent } from '../editors'
import { validateCharCounterEditor } from '../validations/validateCharCounterEditor'

import type { PortableTextBlock, Rule } from 'sanity'
import type { DownloadableImage } from './downloadableImage'
import type { DownloadableFile } from './files'
import type { LinkSelector } from './linkSelector'
import { ThemeSelectorValue } from '../components/ThemeSelector'

const titleContentType = configureTitleBlockContent({
highlight: true,
styles: [
{
title: 'Normal',
value: 'normal',
},
],
})

const titleAlignmentOptions = [
{ value: 'left', icon: LeftAlignedImage },
{ value: 'right', icon: RightAlignedImage },
]

const blockConfig = {
h1: false,
h2: false,
h3: false,
h4: false,
internalLink: false,
externalLink: false,
attachment: false,
lists: true,
}

const blockContentType = configureBlockContent({ ...blockConfig })

export type TextTeaser = {
_type: 'textTeaser'
title?: PortableTextBlock[]
text?: PortableTextBlock[]
action?: (LinkSelector | DownloadableFile | DownloadableImage)[]
titlePosition?: string
theme?: ThemeSelectorValue
}

export default {
name: 'textTeaser',
title: 'Text Teaser',
type: 'object',
localize: true,
fieldsets: [
{
name: 'link',
title: 'Link',
description: 'Select either an internal link or external URL.',
},
{
name: 'design',
title: 'Design options',
},
],
fields: [
{
name: 'title',
type: 'array',
components: {
input: CompactBlockEditor,
},
of: [titleContentType],
validation: (Rule: Rule) => Rule.required(),
},
{
name: 'text',
title: 'Text content',
type: 'array',
of: [blockContentType],
validation: (Rule: Rule) =>
Rule.custom((value: PortableTextBlock[]) => {
return validateCharCounterEditor(value, 600)
}).warning(),
},

{
name: 'action',
title: 'Link/action',
description: 'Select the link or downloadable file for the teaser',
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'),
},
{
name: 'titlePosition',
title: 'Title position',
description: 'Select which side of the teaser the title should be displayed at on larger screens.',
type: 'string',
fieldset: 'design',
components: {
input: function ({ onChange, value }: { onChange: any; value: string }) {
return (
<RadioIconSelector
name="imageAlignmentSelector"
options={titleAlignmentOptions}
defaultValue="left"
currentValue={value}
onChange={onChange}
/>
)
},
},
},
{
title: 'Theme',
description: 'Pick a colour combination for the background and title highlight. Default is white.',
name: 'theme',
type: 'themeList',
fieldset: 'design',
},
],
preview: {
select: {
title: 'title',
text: 'text',
},
prepare({ title, text }: { title: PortableTextBlock[]; text: PortableTextBlock[] }) {
const plainTitle = blocksToText(title)
return {
title: plainTitle || 'Missing teaser title',
subtitle: blocksToText(text) || 'Mising teaser text',
}
},
},
}
27 changes: 27 additions & 0 deletions sanityv3/schemas/objects/themeList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { ThemeSelector, defaultColors } from '../components/ThemeSelector'
import { defineType, defineField } from 'sanity'

export default defineType({
name: 'themeList',
title: 'Theme',
type: 'object',
fields: [
defineField({
name: 'title',
type: 'string',
}),
defineField({
name: 'value',
type: 'number',
}),
],
initialValue: {
title: defaultColors[0].title,
value: defaultColors[0].value,
},
components: {
input: (props) => {
return <ThemeSelector {...props} />
},
},
})
16 changes: 16 additions & 0 deletions web/lib/queries/common/pageContentFields.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,22 @@ const pageContentFields = /* groq */ `
${downloadableImageFields},
},
},
_type == "textTeaser" => {
"type": _type,
"id": _key,
title,
"text": text[]{..., ${markDefs}},
"designOptions": {
"theme": coalesce(theme.value, 0),
"titlePosition": coalesce(titlePosition, 'left'),
},
"action": action[0]{
${linkSelectorFields},
${downloadableFileFields},
${downloadableImageFields},
},
},
_type == "textBlock"=>{
"type": _type,
"id": _key,
Expand Down
Loading

0 comments on commit 9fd99b0

Please sign in to comment.