Build Your WorkspaceBlocks
Defining Blocks
Server-side block definitions — fields, admin metadata, and categories.
Blocks are defined in blocks/ using the block() factory. Each block has fields, admin metadata, and optional prefetch config.
Basic Block
blocks/hero.ts
import { block } from "#questpie/factories";
export const heroBlock = block("hero")
.admin(({ c }) => ({
label: { en: "Hero Section", sk: "Hero sekcia" },
icon: c.icon("ph:image"),
category: "sections",
}))
.fields(({ f }) => ({
title: f.text().required().localized(),
subtitle: f.textarea().localized(),
backgroundImage: f.upload({ to: "assets" }),
overlayOpacity: f.number().default(60),
alignment: f.select(["left", "center", "right"]).default("center"),
ctaText: f.text().localized(),
ctaLink: f.text(),
}))
.prefetch({ with: { backgroundImage: true } });Admin Metadata
.admin(({ c }) => ({
label: { en: "Hero Section" }, // Display name in block picker
icon: c.icon("ph:image"), // Icon in block picker
category: "sections", // Group in block picker
}))Using Blocks in Collections
Add a blocks field to any collection:
collections/pages.ts
import { collection } from "#questpie/factories";
export const pages = collection("pages").fields(({ f }) => ({
title: f.text().required().localized(),
slug: f.text().required(),
content: f.blocks().localized(), // Block content field
}));The admin renders a visual block editor for this field.
Multiple Blocks Per File
Export multiple named blocks from one file:
blocks/layout.ts
import { block } from "#questpie/factories";
export const twoColumnBlock = block("twoColumn")
.admin(({ c }) => ({
label: { en: "Two Columns" },
icon: c.icon("ph:columns"),
category: "layout",
}))
.fields(({ f }) => ({
left: f.blocks(),
right: f.blocks(),
}));
export const spacerBlock = block("spacer")
.admin(({ c }) => ({
label: { en: "Spacer" },
icon: c.icon("ph:arrows-out-line-vertical"),
category: "layout",
}))
.fields(({ f }) => ({
height: f.select(["sm", "md", "lg", "xl"]).default("md"),
}));