Skip to content
Snippets Groups Projects
PortableTextBlock.js 4.48 KiB
Newer Older
Tarje Lavik's avatar
Tarje Lavik committed
import React from 'react'
import NextLink from 'next/link'
Tarje.Lavik's avatar
Tarje.Lavik committed
import { kebabCase } from 'lodash'
import { Heading, Link, Text } from '@chakra-ui/react'
import {
  BigText,
  Hero,
  Iframe,
  InstagramPost,
  PageHeader,
  Quote,
  MiradorGallery,
  SectionText,
  SingleLevelChart,
  SingleObject,
  Social,
  SubStory,
  TimelineSection,
  TwoColumn,
  Video,
  IllustrationWithCaption,
  ExhibitionElement,
Tarje.Lavik's avatar
Tarje.Lavik committed
} from './Sections'
Sanity.io's avatar
Sanity.io committed

const BlockContent = require('@sanity/block-content-to-react')

export default function PortableTextBlock(props) {
Tarje.Lavik's avatar
Tarje.Lavik committed
  if (!props.blocks || !Array.isArray(props.blocks) || !props.blocks.length) {
Sanity.io's avatar
Sanity.io committed
    return null
  }

Tarje.Lavik's avatar
Tarje.Lavik committed
    fontSize = { base: 'lg', sm: 'xl', md: 'xl', xl: 'xl' },
    lineHeight = ['1.25', '1.3'],
    fontWeight = 'normal',
Sanity.io's avatar
Sanity.io committed

Tarje Lavik's avatar
Tarje Lavik committed
  const getFontSize = (level) => {
Tarje.Lavik's avatar
Tarje.Lavik committed
    switch (level) {
      case 'h2':
        return { base: 'lg', sm: '2xl', md: '3xl', xl: '4xl' }
      case 'h3':
        return { base: 'md', sm: 'xl', md: '2xl', xl: '3xl' }
      default:
        return null
Sanity.io's avatar
Sanity.io committed
  const BlockRenderer = (props) => {
Tarje.Lavik's avatar
Tarje.Lavik committed
    if (!props) {
      return null
    }
    const { style = 'normal' } = props.node
Sanity.io's avatar
Sanity.io committed

    if (/^h\d/.test(style)) {
Tarje Lavik's avatar
Tarje Lavik committed
      const level = style
Tarje.Lavik's avatar
Tarje.Lavik committed
      // TODO: This is prone to breaking when there is both hX and strong
      const id = kebabCase(props.children)
      return (
Tarje.Lavik's avatar
Tarje.Lavik committed
        <Heading
Tarje.Lavik's avatar
Tarje.Lavik committed
          id={id}
Tarje.Lavik's avatar
Tarje.Lavik committed
          maxWidth={['xl', null, 'xl', null]}
          margin="auto"
Tarje.Lavik's avatar
Tarje.Lavik committed
          as={level}
          fontSize={getFontSize(level)}
        >
          {props.children}
Tarje.Lavik's avatar
Tarje.Lavik committed
        </Heading>
      )
Sanity.io's avatar
Sanity.io committed
    }

    if (style === 'blockquote') {
      return <blockquote>- {props.children}</blockquote>
    }

    return (
Tarje.Lavik's avatar
Tarje.Lavik committed
      <Text
        maxWidth={['xl', null, 'xl', null]}
        fontSize={fontSize}
        lineHeight={lineHeight}
        fontWeight={fontWeight}
        fontFamily={fontFamily}
        mx={mx ?? 'auto'}
Sanity.io's avatar
Sanity.io committed
        {props.children}
      </Text>
    )
    // Fall back to default handling
    // return BlockContent.defaultSerializers.types.block(props)
  }

  const serializers = {
    marks: {
Tarje.Lavik's avatar
Tarje.Lavik committed
      internalLink: ({ mark, children }) => {
        const { reference } = mark
Sanity.io's avatar
Sanity.io committed
        const href = `/id/${reference._ref}`
        const text = children.length ? children[0] : children
Sanity.io's avatar
Sanity.io committed
        return (
          <Link as={NextLink} href={href}>
Sanity.io's avatar
Sanity.io committed
          </Link>
        )
      },
Tarje.Lavik's avatar
Tarje.Lavik committed
      link: ({ mark, children }) => {
Tarje.Lavik's avatar
Tarje.Lavik committed
        // console.log(children)
Sanity.io's avatar
Sanity.io committed
        // Read https://css-tricks.com/use-target_blank/
Tarje.Lavik's avatar
Tarje.Lavik committed
        const { blank, href } = mark
        const text = children.length ? children[0] : children
Sanity.io's avatar
Sanity.io committed
        return blank ? (
          <Link href={href} isExternal>
Sanity.io's avatar
Sanity.io committed
          </Link>
        ) : (
Tarje.Lavik's avatar
Tarje.Lavik committed
          <Link href={href}>{text}</Link>
Sanity.io's avatar
Sanity.io committed
        )
      },
    },
    types: {
      code: (props) => (
        <pre data-language={props.node.language}>
          <code>{props.node.code}</code>
        </pre>
      ),
      block: BlockRenderer,
      ActorCollection: (props) => <ActorCollection {...props.node} />,
Tarje.Lavik's avatar
Tarje.Lavik committed
      BigText: (props) => <BigText {...props.node} />,
      ExhibitionElement: (props) => <ExhibitionElement {...props.node} />,
      Hero: (props) => <Hero {...props.node} />,
      Iframe: (props) => <Iframe {...props.node} />,
      IllustrationWithCaption: (props) => <IllustrationWithCaption {...props.node} />,
      InstagramPost: (props) => <InstagramPost {...props.node} />,
      MiradorGallery: (props) => <MiradorGallery {...props.node} />,
      PageHeader: (props) => <PageHeader {...props.node} />,
      Quote: (props) => <Quote {...props.node} />,
      SectionText: (props) => <SectionText {...props.node} />,
      SingleLevelChart: (props) => <SingleLevelChart {...props.node} />,
      SingleObject: (props) => <SingleObject {...props.node} />,
      Social: (props) => <Social {...props.node} />,
      SubStory: (props) => <SubStory {...props.node} />,
      TimelineSection: (props) => <TimelineSection {...props.node} />,
      TwoColumn: (props) => <TwoColumn {...props.node} />,
      Video: (props) => <Video {...props.node} />,
Tarje Lavik's avatar
Tarje Lavik committed
      Place: (props) => (
Sanity.io's avatar
Sanity.io committed
        <div>
          <h2>Demo: referanse til dokument i en Portable Text blokk</h2>
          <p>
Tarje.Lavik's avatar
Tarje.Lavik committed
            <Link as={NextLink} href={`/id/${props.node._id}`}>
              {props.node.label.no}
            </Link>
Sanity.io's avatar
Sanity.io committed
          </p>
        </div>
Tarje.Lavik's avatar
Tarje.Lavik committed
      ),
Sanity.io's avatar
Sanity.io committed
    },
  }

  return <BlockContent blocks={blocks} serializers={serializers} />
Sanity.io's avatar
Sanity.io committed
}