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
Page (grey) or Section (white) ? → documents
Fields: …, RichText
(Array of blocks) with references to Components
Components → documents themselves
Need to project on references (→) and serialise every Component inside of Portable Text
Breaking changes possible
Easier to patch and work on since each doc das an _id
but has consequences:
→ Might be more work in the long run, although patching etc. might be easier
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.
Page (grey) or Section (white) ? → documents
Fields: …, content
Array of: RichText
(Array of blocks) and Components
Components → objects
_id
and simple groq *[_type == "section" && COMPONENT_TYPE in content[]]
for example (get all sections where Accordion is defined)
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
}
}`;