Las colecciones son la base del modelo de contenido de EmDash. Cada colección representa un tipo de contenido (entradas, páginas, productos) e incluye definiciones de campos que determinan la forma de tus datos.
Crear colecciones
Crea colecciones desde el panel de administración en Tipos de contenido. Cada colección tiene:
| Propiedad | Descripción |
|---|---|
slug | Identificador seguro para URL (p. ej. posts, products) |
label | Nombre visible (p. ej. «Blog Posts») |
labelSingular | Forma singular (p. ej. «Post») |
description | Descripción opcional para editoras |
icon | Nombre de icono Lucide para la barra lateral del admin |
supports | Funciones como borradores, revisiones, vista previa, programación, búsqueda, SEO |
Funciones de la colección
Al crear una colección, activa las funciones que necesites:
| Función | Descripción |
|---|---|
drafts | Flujo de borrador/publicado |
revisions | Historial de contenido con instantáneas de versión |
preview | URLs de vista previa firmadas para borradores |
scheduling | Programar publicación en una fecha futura |
// Ejemplo de colección con todas las funciones
{
slug: "posts",
label: "Blog Posts",
labelSingular: "Post",
supports: ["drafts", "revisions", "preview", "scheduling"]
}
Tipos de campo
EmDash admite 15 tipos de campo que se mapean a tipos de columna SQLite:
Campos de texto
string
Texto corto. Se mapea a columna TEXT.
{ slug: "title", type: "string", label: "Title" } text
Área de texto multilínea. Se mapea a columna TEXT.
{ slug: "excerpt", type: "text", label: "Excerpt" } slug
Campo slug seguro para URL. Se mapea a columna TEXT.
{ slug: "handle", type: "slug", label: "URL Handle" } Contenido enriquecido
portableText
Editor de texto enriquecido (TipTap/ProseMirror). Almacenado como JSON.
{ slug: "content", type: "portableText", label: "Content" }Portable Text es un formato basado en bloques que conserva la estructura sin incrustar HTML.
json
Datos JSON arbitrarios. Almacenados como JSON.
{ slug: "metadata", type: "json", label: "Custom Metadata" } Números
number
Números decimales. Se mapea a columna REAL.
{ slug: "price", type: "number", label: "Price" } integer
Números enteros. Se mapea a columna INTEGER.
{ slug: "quantity", type: "integer", label: "Stock Quantity" } Booleanos y fechas
boolean
Interruptor verdadero/falso. Se mapea a INTEGER (0/1).
{ slug: "featured", type: "boolean", label: "Featured Post" } datetime
Selector de fecha y hora. Almacenado como cadena ISO 8601.
{ slug: "eventDate", type: "datetime", label: "Event Date" } Selección
select
Una opción de una lista. Se mapea a columna TEXT.
{
slug: "status",
type: "select",
label: "Product Status",
validation: {
options: ["active", "discontinued", "coming_soon"]
}
} multiSelect
Varias opciones de una lista. Almacenado como array JSON.
{
slug: "features",
type: "multiSelect",
label: "Product Features",
validation: {
options: ["wireless", "waterproof", "eco-friendly"]
}
} Medios y referencias
image
Selector de imagen de la biblioteca multimedia. Guarda el ID de medio como TEXT.
{ slug: "featuredImage", type: "image", label: "Featured Image" } file
Selector de archivo de la biblioteca multimedia. Guarda el ID de medio como TEXT.
{ slug: "attachment", type: "file", label: "PDF Attachment" } reference
Referencia a una entrada de otra colección. Guarda el ID de entrada como TEXT.
{
slug: "author",
type: "reference",
label: "Author",
options: {
collection: "authors"
}
} Propiedades de campo
Cada campo admite estas propiedades:
| Propiedad | Tipo | Descripción |
|---|---|---|
slug | string | Nombre de columna en la base de datos |
label | string | Etiqueta visible en la UI del admin |
type | FieldType | Uno de los 15 tipos de campo |
required | boolean | Si el campo debe tener valor |
unique | boolean | Si los valores deben ser únicos entre entradas |
defaultValue | unknown | Valor por defecto para entradas nuevas |
validation | object | Reglas de validación específicas del tipo |
widget | string | Identificador de widget personalizado |
options | object | Configuración específica del widget |
sortOrder | number | Orden de visualización en el editor |
Reglas de validación
El objeto validation varía según el tipo de campo:
interface FieldValidation {
required?: boolean; // todos los tipos
min?: number; // number, integer
max?: number; // number, integer
minLength?: number; // string, text
maxLength?: number; // string, text
pattern?: string; // string (regex)
options?: string[]; // select, multiSelect
}
Ejemplo con validación:
{
slug: "email",
type: "string",
label: "Email Address",
required: true,
unique: true,
validation: {
pattern: "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"
}
}
Opciones de widget
El objeto options configura el comportamiento de la UI específico del campo:
interface FieldWidgetOptions {
rows?: number; // text (filas del textarea)
showPreview?: boolean; // image, file
collection?: string; // reference (colección destino)
allowMultiple?: boolean; // reference (varias referencias)
[key: string]: unknown; // opciones de widget personalizado
}
Ejemplo de campo de referencia:
{
slug: "relatedProducts",
type: "reference",
label: "Related Products",
options: {
collection: "products",
allowMultiple: true
}
}
Consultar colecciones
Usa las funciones de consulta incluidas para obtener contenido. Siguen el patrón de colecciones en vivo de Astro y devuelven resultados estructurados:
import { getEmDashCollection, getEmDashEntry } from "emdash";
// Todas las entradas — devuelve { entries, error }
const { entries: posts } = await getEmDashCollection("posts");
// Filtrar por estado
const { entries: drafts } = await getEmDashCollection("posts", {
status: "draft",
});
// Limitar resultados
const { entries: recent } = await getEmDashCollection("posts", {
limit: 5,
});
// Filtrar por taxonomía
const { entries: newsPosts } = await getEmDashCollection("posts", {
where: { category: "news" },
});
// Una entrada por slug — devuelve { entry, error, isPreview }
const { entry: post } = await getEmDashEntry("posts", "my-post-slug");
// Manejo de errores
const { entries, error } = await getEmDashCollection("posts");
if (error) {
console.error("Failed to load posts:", error);
}
Generación de tipos
Ejecuta npx emdash types para generar tipos TypeScript desde tu esquema:
// .emdash/types.ts (generado)
export interface Post {
title: string;
content: PortableTextBlock[];
excerpt?: string;
featuredImage?: string;
author: string; // ID de referencia
}
export interface Product {
title: string;
price: number;
description: PortableTextBlock[];
}
Mapeo en base de datos
Los tipos de campo se mapean a tipos de columna SQLite:
| Tipo de campo | Tipo SQLite | Notas |
|---|---|---|
string | TEXT | |
text | TEXT | |
slug | TEXT | |
number | REAL | coma flotante 64 bits |
integer | INTEGER | entero con signo 64 bits |
boolean | INTEGER | 0 o 1 |
datetime | TEXT | formato ISO 8601 |
select | TEXT | |
multiSelect | JSON | array de cadenas |
portableText | JSON | array de bloques |
image | TEXT | ID de medio |
file | TEXT | ID de medio |
reference | TEXT | ID de entrada |
json | JSON | JSON arbitrario |
Próximos pasos
Modelo de contenido
Entender el enfoque primero en base de datos.
Taxonomías
Organizar contenido con categorías y etiquetas.
Biblioteca multimedia
Gestionar imágenes y archivos.