Skip to content

Commit

Permalink
✨ Iframe carousel (#1455)
Browse files Browse the repository at this point in the history
  • Loading branch information
padms committed Feb 1, 2023
1 parent 3f9c931 commit 48ef16c
Show file tree
Hide file tree
Showing 13 changed files with 379 additions and 108 deletions.
1 change: 1 addition & 0 deletions studio/schemas/documents/page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ export default {
{ type: 'anchorLink' },
Flags.HAS_MUX && { type: 'video' },
Flags.IS_DEV && { type: 'imageCarousel' },
Flags.IS_DEV && { type: 'iframeCarousel' },
].filter((e) => e),
},
].filter((e) => e),
Expand Down
1 change: 0 additions & 1 deletion studio/schemas/editors/titleEditorContentType.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import type { BlockFieldType } from '../../types/schemaTypes'

// TODO: Add relevant styles for titles (i.e. highlighted text)
export const configureTitleBlockContent = (): BlockFieldType => {
// const { strong, emphasis, strikethrough } = options
return {
type: 'block',
styles: [],
Expand Down
113 changes: 10 additions & 103 deletions studio/schemas/objects/iframe.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,12 @@ import React from 'react'
import { code } from '@equinor/eds-icons'
import { EdsIcon } from '../../icons'
import { Colors } from '../../helpers/ColorListValues'
import { configureTitleBlockContent, configureBlockContent } from '../editors'
import CompactBlockEditor from '../components/CompactBlockEditor'
import { configureBlockContent } from '../editors'
import CharCounterEditor from '../components/CharCounterEditor'
import blocksToText from '../../helpers/blocksToText'
import type { Rule, ValidationContext, Block } from '@sanity/types'
import type { Rule, Block } from '@sanity/types'
import type { ColorListValue } from 'sanity-plugin-color-list'

const titleContentType = configureTitleBlockContent()

const descriptionContentType = configureBlockContent({
h1: false,
h2: false,
h3: false,
h4: false,
attachment: false,
internalLink: false,
externalLink: false,
lists: false,
})
import { title, frameTitle, description, cookiePolicy, aspectRatio, url, height } from './iframe/sharedIframeFields'

const ingressContentType = configureBlockContent({
h1: false,
Expand Down Expand Up @@ -68,99 +55,20 @@ export default {
},
],
fields: [
{
name: 'title',
type: 'array',
title: 'Title',
description: 'The (optional) title/heading shown above the iframe.',
inputComponent: CompactBlockEditor,
of: [titleContentType],
},
title,
{
name: 'ingress',
title: 'Ingress',
type: 'array',
inputComponent: CharCounterEditor,
of: [ingressContentType],
},
{
name: 'frameTitle',
type: 'string',
title: 'Frame title',
fieldset: 'iframe',

description: 'The title of the iframe. This value is not visible on the page but is required for accessibility.',
validation: (Rule: Rule) =>
Rule.custom((value: string, context: ValidationContext) => {
const { parent } = context as { parent: IFrame }
return parent?.url && value === undefined ? 'Required' : true
}),
},
{
name: 'url',
type: 'url',
title: 'Frame URL',
description:
'Link to the content to be loaded inside the iframe. Any URL must be whitelisted to load. Please make sure to verify that the iframe loads correctly before publishing, otherwise contact dev team for whitelisting.',
fieldset: 'iframe',
validation: (Rule: Rule) =>
Rule.custom((value: any, context: ValidationContext) => {
const { parent } = context as { parent: IFrame }
return (parent?.title || parent?.frameTitle) && value === undefined ? 'Required' : true
}),
},
{
name: 'cookiePolicy',
type: 'string',
title: 'Cookie policy',
description: 'Select which cookie policy applies to this iframe.',
fieldset: 'iframe',

options: {
list: [
{ title: 'None', value: 'none' },
{ title: 'Marketing', value: 'marketing' },
{ title: 'Statistics', value: 'statistics' },
],
layout: 'dropdown',
},
initialValue: 'none',
validation: (Rule: Rule) => Rule.required(),
},

{
name: 'aspectRatio',
type: 'string',
title: 'Aspect ratio',
options: {
list: [
{ title: '16:9', value: '16:9' },
{ title: '4:3', value: '4:3' },
{ title: '1:1', value: '1:1' },
],
layout: 'dropdown',
},
fieldset: 'iframe',
initialValue: '16:9',
validation: (Rule: Rule) => Rule.required(),
},
{
name: 'height',
type: 'number',
title: 'Height',
description: 'Set a fixed height in pixels for the iframe. Note: this will override the aspect ratio setting.',
fieldset: 'iframe',
validation: (Rule: Rule) => Rule.positive().greaterThan(0).precision(0),
},

{
name: 'description',
title: 'Description/caption',
description: `Here you can write a short description of the iframes content. This text will show up as a caption text right below the iframe.`,
type: 'array',
inputComponent: CharCounterEditor,
of: [descriptionContentType],
},
frameTitle,
url,
cookiePolicy,
aspectRatio,
height,
description,
{
name: 'action',
title: 'Link/action',
Expand All @@ -169,7 +77,6 @@ export default {
of: [{ type: 'linkSelector', title: 'Link' }],
validation: (Rule: Rule) => Rule.max(1),
},

{
title: 'Background',
description: 'Pick a colour for the background. Default is white.',
Expand Down
108 changes: 108 additions & 0 deletions studio/schemas/objects/iframe/sharedIframeFields.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import { configureTitleBlockContent, configureBlockContent } from '../../editors'
import CompactBlockEditor from '../../components/CompactBlockEditor'
import CharCounterEditor from '../../components/CharCounterEditor'
import type { Rule, ValidationContext, Block } from '@sanity/types'
import type { IFrame } from '../iframe'

const titleContentType = configureTitleBlockContent()

const descriptionContentType = configureBlockContent({
h1: false,
h2: false,
h3: false,
h4: false,
attachment: false,
internalLink: false,
externalLink: false,
lists: false,
})

export const title = {
name: 'title',
type: 'array',
title: 'Title',
description: 'The (optional) title/heading shown above the iframe.',
inputComponent: CompactBlockEditor,
of: [titleContentType],
}

export const frameTitle = {
name: 'frameTitle',
type: 'string',
title: 'Frame title',
fieldset: 'iframe',

description: 'The title of the iframe. This value is not visible on the page but is required for accessibility.',
validation: (Rule: Rule) =>
Rule.custom((value: string, context: ValidationContext) => {
const { parent } = context as { parent: IFrame }
return parent?.url && value === undefined ? 'Required' : true
}),
}

export const url = {
name: 'url',
type: 'url',
title: 'Frame URL',
description:
'Link to the content to be loaded inside the iframe. Any URL must be whitelisted to load. Please make sure to verify that the iframe loads correctly before publishing, otherwise contact dev team for whitelisting.',
fieldset: 'iframe',
validation: (Rule: Rule) =>
Rule.custom((value: any, context: ValidationContext) => {
const { parent } = context as { parent: IFrame }
return (parent?.title || parent?.frameTitle) && value === undefined ? 'Required' : true
}),
}

export const cookiePolicy = {
name: 'cookiePolicy',
type: 'string',
title: 'Cookie policy',
description: 'Select which cookie policy applies to this iframe.',
fieldset: 'iframe',

options: {
list: [
{ title: 'None', value: 'none' },
{ title: 'Marketing', value: 'marketing' },
{ title: 'Statistics', value: 'statistics' },
],
layout: 'dropdown',
},
initialValue: 'none',
validation: (Rule: Rule) => Rule.required(),
}

export const aspectRatio = {
name: 'aspectRatio',
type: 'string',
title: 'Aspect ratio',
options: {
list: [
{ title: '16:9', value: '16:9' },
{ title: '4:3', value: '4:3' },
{ title: '1:1', value: '1:1' },
],
layout: 'dropdown',
},
fieldset: 'iframe',
initialValue: '16:9',
validation: (Rule: Rule) => Rule.required(),
}
export const height = {
name: 'height',
type: 'number',
title: 'Height',
description: 'Set a fixed height in pixels for the iframe. Note: this will override the aspect ratio setting.',
fieldset: 'iframe',
validation: (Rule: Rule) => Rule.positive().greaterThan(0).precision(0),
}

export const description = {
name: 'description',
title: 'Description/caption',
description: `Here you can write a short description of the iframes content. This text will show up as a caption text right below the iframe.`,
type: 'array',
inputComponent: CharCounterEditor,
of: [descriptionContentType],
}
92 changes: 92 additions & 0 deletions studio/schemas/objects/iframeCarousel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { Colors } from '../../helpers/ColorListValues'
import { EdsIcon } from '../../icons'
import { library_image } from '@equinor/eds-icons'
import blocksToText from '../../helpers/blocksToText'
import type { Rule } from '@sanity/types'
import { title, frameTitle, description, cookiePolicy, aspectRatio, url, height } from './iframe/sharedIframeFields'

const carouselItemFields = [title, frameTitle, description, cookiePolicy, aspectRatio, url, height]
export default {
name: 'iframeCarousel',
title: 'Iframe carousel',
type: 'object',
fieldsets: [
{
title: 'Design options',
name: 'design',
description: 'Some options for design',
options: {
collapsible: true,
collapsed: false,
},
},
],
fields: [
title,
{
type: 'array',
name: 'items',
description: 'Add iframes for the carousel',
title: 'Carousel items',
of: [
{
title: 'Iframe carousel item',
type: 'object',
fieldsets: [
{
title: 'IFrame settings',
name: 'iframe',
options: {
collapsible: true,
collapsed: false,
},
},
{
title: 'Design options',
name: 'design',
description: 'Some options for design',
options: {
collapsible: true,
collapsed: false,
},
},
],
fields: [...carouselItemFields],
},
],
validation: (Rule: Rule) => Rule.required().min(2),
},
{
title: 'Background',
description: 'Pick a colour for the background. Default is white.',
name: 'background',
type: 'colorlist',
options: {
borderradius: {
outer: '100%',
inner: '100%',
},
tooltip: false,
list: Colors,
},
fieldset: 'design',
initialValue: Colors[0],
},
],
preview: {
select: {
title: 'title',
items: 'items',
},
prepare(selection: any) {
const { title, items } = selection
const length = items ? items.length : 0

return {
title: title ? blocksToText(title) : 'Untitled iframe carousel',
subtitle: `Iframe carousel with ${length} items`,
media: EdsIcon(library_image),
}
},
},
}
3 changes: 2 additions & 1 deletion studio/schemas/schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ import twitterEmbed from './objects/twitterEmbed'
import video from './objects/video'
import videoFile from './objects/videoFile'
import imageCarousel from './objects/imageCarousel'
import iframeCarousel from './objects/iframeCarousel'

const routeSchemas = languages.map(({ name, title }) => {
return route(name, title)
Expand Down Expand Up @@ -172,6 +173,6 @@ export default createSchema({
...NewsSchemas,
...NewsRoomSchema,
...RemainingSchemas,
...(Flags.IS_DEV ? [imageCarousel] : []),
...(Flags.IS_DEV ? [imageCarousel,iframeCarousel] : []),
]),
})
4 changes: 4 additions & 0 deletions web/lib/queries/common/pageContentFields.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { iframeCarouselFields } from '../iframeCarouselFields'
import downloadableFileFields from './actions/downloadableFileFields'
import downloadableImageFields from './actions/downloadableImageFields'
import linkSelectorFields, { linkReferenceFields } from './actions/linkSelectorFields'
Expand Down Expand Up @@ -504,6 +505,9 @@ const pageContentFields = /* groq */ `
_type == "imageCarousel" =>{
${imageCarouselFields}
},
_type == "iframeCarousel" =>{
${iframeCarouselFields}
}
`
Expand Down
Loading

0 comments on commit 48ef16c

Please sign in to comment.