Setup now: Block Array (PT) with components

Untitled

Schema

Page (grey) or Section (white) ? → documents

Fields: …, RichText (Array of blocks) with Components (as additional object blocks which are deserialised in the same way as text, annotations and styles)

Components (like Accordion & ReadMore) → objects

Frontend

Setup Option: components as individual documents

Untitled

Schema

Page (grey) or Section (white) ? → documents

Fields: …, RichText (Array of blocks) with references to Components

Components → documents themselves

Frontend

Issue with components being referenced

Untitled

Example

ReadMore 1 was generated for the left section.

It is now also selected from the dropdown menu of the reference field a second time for the right section, instead of ReadMe2.

The editor now realises, that the content of ReadMe1 should actually be different for the right section and clicks on the reference, which now opens ReadMe1 in a new Pane.

The editor changes some fields in ReadMe1 to what should be in ReadMe2 and this changes the content in all references (which means the Section on the left will now have wrong content in it).

The same can be said for Accordion2.

Setup Option 🌟 : Content Array

Untitled

Schema

Page (grey) or Section (white) ? → documents

Fields: …, content Array of: RichText (Array of blocks) and Components

Components → objects

Frontend

Exmple from Landingpage generator (Saskia)

Studio

// studio/schemas/landingpage.js
export default {
    name: 'landingpage',
    title: 'Landingpage',
    type: 'document',
		...,
		{
            name: 'contentArray',
            title: 'Content',
            type: 'array',
            validation: Rule => Rule.custom(content => {
                const headers = (content || []).filter(
                    item =>
                        item._type === 'heroSection' || item._type === 'headerSection'
                )
                console.log(headers);
                const headerPaths = headers.map(
                    (header, index) => [{ _key: header._key }] || [index]
                )
                console.log(headerPaths.length);

                return headerPaths.length === 1
                    ? true
                    : {
                        message: 'There can only be one header section. Please delete one.',
                        paths: headerPaths
                    }
            }),
            of: [

                { type: 'heroSection' },
                { type: 'headerSection' },
                { type: 'textSection' }, // is portableText
                { type: 'cardSection' },
                { type: 'accordionSection' },
                { type: 'furtherLinkSection' },
                { type: 'tabSection' },
                { type: 'cta' }
            ],
        },

Frontend:

// pages/[slug].js (exerpt)

export default function Landingpage({ data, preview }) {
	  const {
	    title,
	    description,
	    image,
	    slug,
	    contentArray,
			// the rest
	  } = data?.page;

// find Header Section in Array which has special settings in my case and illustrates that using an array can be quite usefull
  const header = contentArray.find(
    (section) =>
      section._type === "heroSection" || section._type === "headerSection"
  );

  // render Section, but omit header (else return null)
	// can also be refactured so you can reuse it wherever you need :) 

  const renderedItems = contentArray.map((section) => {
    /* TEXT SECTION */
    if (section._type === "textSection") {
      return (
        <SectionContainer key={section._key} id={`${section.type}-${section._key}`}>
          <FadeInWhenVisible>
            <SectionHeader // is richText with some other functionalities on top and only inline components
              headline={section.title}
              subline={section.subtitle || null}
              body={section.body || null}
              color={color.title}
              left={true}
            />
          </FadeInWhenVisible>
        </SectionContainer>
      );
    }
		// map through all of the other section of the page 
}
return (
    <Layout
      preview={preview}
      description={description}
      image={image}
      siteSettings={siteSettings}
    >
      <Head>
        <title>{title}</title>
      </Head>
			
      {/* CONTENT SECTION */}
      <Container>{renderedItems}</Container>
    </Layout>
  );
}

Query

const query = groq`*[_type == 'landingpage' && slug.current == $slug]{
        ..., 
    contentArray[]{
        ...,
         _type == "textSection" => {..., /* SOME SPECIAL QUERY YOU MIGHT NEED */},
				// the rest of your components can be manipulated in the same way if needed
        }
    }`;