Skip to content

Complex layouts

ortfo/db allows you to declare that some content blocks are arranged in a more interesting way than just one after the other.

Usage example


Declaring layouts

Layouts are declared in the metadata frontmatter of your description file:

started: 2023-04-12
tags: [web, design, ux, ui]
made with: [figma, react, go]
	- [p1, m1]
	- [l1, l2, l3]

# My awesome project

This is a paragraph of text. It can contain **bold**, *italic*, and [links](

![](./demo.mp4 "Some caption")

[Link to the source code](


[Website using ortfodb](

You declare layouts as a grid. To refer to a content block, you put a letter that specifies the type of block (p for paragraphs, m for media and l for standalone links), and a number that refers to the position of that content block in the file.

For example, to refer to the second link, you would write l2.

The example above declares the following layout:

This is a paragraph of text. It can conta…demo.mp4
Link to the source codeDocumentationWebsite using ortfodb

You can do just about anything that you would think of.

In database.json

The advantage of declaring layouts like this in ortfo/db is that your frontend has almost nothing left to do do render the content appropriately.

The generated database file will contain a two-dimensional array that represents this layout, in a homogeneous way: every row will contain exactly the same number of columns.

The previous example generates the following in database.json:

	"my-work": {
    "content": {
      "en": {
        "blocks": [...],
        "layout": [ 
          // id of p1                                   id of m1
          [ "1JsYa91YMM", "1JsYa91YMM", "1JsYa91YMM", "GBpC-nYDgw", "GBpC-nYDgw", "GBpC-nYDgw" ], 
          // id of l1                   id of l2                    id of l3
          [ "TYxPfqjbPR", "TYxPfqjbPR", "ycmt3306Po", "ycmt3306Po", "FD-ZGJKusV", "FD-ZGJKusV" ] 

An example: rendering with grid-template-areas

Here is an example of how you could render this layout using CSS Grid's grid-template-areas:

const content = myWorkFromDatabase.content[language];

let areasDeclaration = "";

for (const row of content.layout) {
  let rowDeclaration = "";
  for (const cell of row) {
    // need to prefix with an underscore
    // because some content block IDs can start with a dash,
    // this will be fixed in the future...
    rowDeclaration += `_${cell} `;
  areasDeclaration += `'${rowDeclaration}' `;

// If you prefer, functional-style:
areasDeclaration = content.layout
  .map((row) => `'${ => `_${id}`).join(" ")}'`)
  .join(" ");

// Assuming container refers to a DOM element
// that contains all of the content blocks = areasDeclaration;

for (const { id } of content.blocks) {
  // Assuming each individual content block is
  // a DOM element with an id that is
  // the same as the content block's id
  const block = document.getElementById(id); = `_${id}`;