Sections
Sections
A section is the most basic building block, and is basically nothing more than a component in Astro or Vue.
In fact, a section in PageDepot is directly converted to a component file during the provisioning step, be it
an .astro
file or .vue
single-file-component.
Sections have a name, a type, props and code.
The type can be one of astro
or vue
.
It decides what type of code you can write.
The props define the input parameters your section can receive.
This is used for Brezel to be able to define a fitting UX to edit these props.
It is also used by PageDepot to prepare the prop values accordingly.
For example, if the prop’s type is select
, PageDepot loads the respective entity from Brezel.
The syntax is
{ "propName": { "type": "propType" }}
or its shorthand
{ "propName": "propType"}
For types like object
or list
, you can nest prop definitions:
{ "myObject": { "type": "object", "props": { "someProp": "text" } }, "myList": { "type": "list", "listType": { "type": "object", "props": { "someProp": "text" } } }}
Then, when using the section in a page slot, you would give the params
like this:
[ { "slot": "default", "sections": [ { "section": { "id": 10 }, "myObject": { "someProp": "lorem ipsum" }, "myList": [ { "someProp": "dolor sit amet" } ] } ] }]
Available types
Text (text
)
{ "type": "text"}
Number (number
)
{ "type": "number"}
Object (object
)
{ "type": "object", "props": {} // define the object's props here}
List (list
)
{ "type": "list", "listType": {} // define the list item type here}
Entity (select
)
Usage in props
{ "type": "select", "options": { "references": "the_module" }}
Type schema for params
An entity object with id
.
type EntityParams = { id: string | number};
Entities (entities
)
Usage in props
An object with optional property module
(the module identifier).
{ "type": "entities", "module": "the_module"}
Example for section code
const entities = props.entities;
Type schema for params
type EntitiesParams = { module?: string; filters?: Array<Record<string, unknown>> | Array<Array<Record<string, unknown>>>; results?: number;}
Module (module
)
Example for section code
const module = props.module;module.fields.forEach(field => { console.log(field);})
Type schema for params
type ModuleParams = { identifier: string;};
Image (image
)
Example for section code
const {src, alt} = props.image;
Type schema for params
type ImageParams = { id: string | number; module?: string;}
Code
The code is the actual code that defines your section. Here, you write the markup and any logic you need for the rendering. You also need to define the props again. For example:
<template> <article> <h3>{{ post.title }}</h3> <WYSIWYG :content="post.content"/> <ShareButtons :post="post"/> </article></template>
<script setup>import {defineProps} from 'vue';import WYSIWYG from '~/components/WYSIWYG.vue';import ShareButtons from '~/components/sections/ShareButtons.vue';
const props = defineProps({ post: Object, astro: Object,});</script>
Here, there is also the astro
property, which gives access to
the global Astro
object.
You can also import other sections you have defined, like ShareButtons
in this case.
General design rules and recommendations
This section explains which parts of sections/components should be styled. It also lays out some general rules how sections should be styled in the future.
- Properties that are configurable through “Style” attributes should, in most cases, not use Tailwind classes. This is because Tailwind classes get tree-shaked, so something like
w-${widthProp}
would not work. - Just like Tailwind, for fonts, widths, heights, paddings, margins etc. you should use
rem
as your unit of choice. There are exceptions, for example border widths or values that refer to breakpoints. - Make sure that, when changing a section and its props, fallbacks are always in place so that existing websites still look the same or at least similar after deployment.
- Prevent usage of the
<img>
tag, instead use ourImage
component. - Prevent usage of the style rule “background-image”, use our
Image
component instead. TheImage
can be madeposition: absolute; object-fit: cover
and the wrapper elementposition: relative
to achieve the same effect. Reason is that Astro optimizes these images and usessrcset
for optimal performance. - Prevent usage of fixed colors, like
bg-white
ortext-black
. You should preferably use the colors provided by the theme, e.g.text-primary-contrast
,bg-page
etc. - Prevent usage of arbitrary Tailwind classes (something like
border-[#ffffff29]
). - When extracting a component and you use a top-level
await
, preferably wrap this component in aSuspense
in the parent component, even if your component has noclient_directive
set and Page Depot is rendering everything correctly. This is useful for other developers, so that they are aware that this is an async component.
Common problems
My Image
, Icon
etc. component is not showing up!
In sections that aren’t rendered on the server (i.e. that have a client_directive
set), components are rendered on the client side. However, some sections load data asynchronously. This is indicated by them using the await
keyword on the top level.
Solution: Wrap the component usage in a suspense