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
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([
{ value: "left", label: "Left" },
{ value: "center", label: "Center" },
{ value: "right", label: "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:
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:
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([
{ value: "sm", label: "Small" },
{ value: "md", label: "Medium" },
{ value: "lg", label: "Large" },
{ value: "xl", label: "Extra large" },
])
.default("md"),
}));