The Bookshop blueprint
of your component config can help configure
some advanced Structure use cases on CloudCannon.
Nesting components#
Your blueprint can reference other components and Structures, which will embed their structured data within.
For example, this saves you from having to re-define the required inputs if your hero
component
contains an editable button
component — using component nesting your blueprint might look like this:
blueprint:
hero_text: Hello World
button: bookshop:button
This is a string, and could also be written button: "bookshop:button"
.
In this example, the button key will become an Object Structure containing the values specified in your button component blueprint. If you desired an array of buttons, you could use the following:
blueprint:
hero_text: Hello World
buttons:
- bookshop:button
Or more concisely, buttons: [bookshop:button]
In general, any bookshop:<component_name>
string will be replaced with the structure of that component,
and will allow editors to add and remove that component.
Nesting a set of components#
If you're creating a layout component, you likely want to support a set of components.
For this, you can reference the keys we defined in spec.structures
:
blueprint:
section_label: My Section
header: bookshop:structure:content_blocks
inner_components: [bookshop:structure:content_blocks]
The header
key will become a single component that can be selected from the set of components tagged as content_blocks
The inner_components
key will become an array that can contain any components tagged as content_blocks
Nesting Example#
To give a concrete example, let's say we have a hero
component:
spec:
structures: [content_blocks]
blueprint:
hero_text: Hello World
cta_button: bookshop:button
column_components: [bookshop:structure:content_blocks]
Then our matching component template file might look like this:
---
import Button from './button.astro'
const { hero_text, cta_button, column_components } = Astro.props;
const components = import.meta.glob("./**/*.astro", {
eager: true,
});
---
<div class="hero">
<h1>{ hero_text }</h1>
{cta_button && <Button {...cta_button}/>}
{column_components.map((block) => {
const name = `components/${block._bookshop_name}.astro`;
const Component = components[name].default;
return <Component {...block} />;
})}
</div>
Object Structures in CloudCannon may be empty, as the component can be removed and replaced, so your template should check for the existence of this component.
Initializing Nested Components#
Nested components using the bookshop:*
shorthand will be initialized empty by default. For example, the blueprint:
blueprint:
hero_text: Hello World
button: bookshop:button
Will be initialized in CloudCannon as:
- _bookshop_name: hero
hero_text: Hello World
button:
Where the button
input will provide an editor with the option to add a button component.
To instead have the button component exist on creation, you can use the syntax bookshop:button!
:
blueprint:
hero_text: Hello World
button: bookshop:button!
The same setting can be applied to a structure shorthand by specifying the component that should be initialized. Take the following example:
blueprint:
section_label: Hello World
column_components:
- bookshop:structure:content_blocks!(hero)
- bookshop:structure:content_blocks!(button)
This will be initialized in CloudCannon as:
- _bookshop_name: section
section_label: Hello World
column_components:
- _bookshop_name: hero
# ... hero fields
- _bookshop_name: button
# ... button fields
Where column_components
can be then further added to or removed from by an editor,
using components from the tagged structure.