Modelo de Contenido
Comprende el enfoque de base de datos primero.
Las colecciones son la base del modelo de contenido de EmDash. Cada colección representa un tipo de contenido (publicaciones, páginas, productos) y contiene definiciones de campos que determinan la estructura de tus datos.
Crea colecciones a través del panel de administración en Tipos de Contenido. Cada colección tiene:
| Propiedad | Descripción |
|---|---|
slug | Identificador seguro para URL (ej., posts, products) |
label | Nombre para mostrar (ej., “Entradas del Blog”) |
labelSingular | Forma singular (ej., “Entrada”) |
description | Descripción opcional para editores |
icon | Nombre del icono de Lucide para la barra lateral del administrador |
supports | Funcionalidades como borradores, revisiones, vista previa, programación, búsqueda, seo |
Al crear una colección, activa las características que necesites:
| Característica | Descripción |
|---|---|
drafts | Habilita el flujo de trabajo de borrador/publicado |
revisions | Rastrea el historial de contenido con instantáneas de versiones |
preview | Genera URLs de vista previa firmadas para contenido en borrador |
scheduling | Programa contenido para publicarse en una fecha futura |
// Example collection with all features enabled{ slug: "posts", label: "Blog Posts", labelSingular: "Post", supports: ["drafts", "revisions", "preview", "scheduling"]}EmDash admite 15 tipos de campos que se asignan a tipos de columna SQLite:
Entrada de texto corto. Se asigna a columna TEXT.
{ slug: "title", type: "string", label: "Title" }Área de texto multilínea. Se asigna a columna TEXT.
{ slug: "excerpt", type: "text", label: "Excerpt" }Campo de slug seguro para URL. Se asigna a columna TEXT.
{ slug: "handle", type: "slug", label: "URL Handle" }Editor de texto enriquecido (TipTap/ProseMirror). Almacenado como JSON.
{ slug: "content", type: "portableText", label: "Content" }Portable Text es un formato basado en bloques que preserva la estructura sin incrustar HTML.
Datos JSON arbitrarios. Almacenado como JSON.
{ slug: "metadata", type: "json", label: "Custom Metadata" }Números decimales. Se asigna a columna REAL.
{ slug: "price", type: "number", label: "Price" }Números enteros. Se asigna a columna INTEGER.
{ slug: "quantity", type: "integer", label: "Stock Quantity" }Alternador verdadero/falso. Se asigna a INTEGER (0/1).
{ slug: "featured", type: "boolean", label: "Featured Post" }Selector de fecha y hora. Almacenado como cadena ISO 8601.
{ slug: "eventDate", type: "datetime", label: "Event Date" }Opción única de una lista. Se asigna a columna TEXT.
{ slug: "status", type: "select", label: "Estado del Producto", validation: { options: ["active", "discontinued", "coming_soon"] }}Múltiples opciones de una lista. Almacenado como arreglo JSON.
{ slug: "features", type: "multiSelect", label: "Características del Producto", validation: { options: ["wireless", "waterproof", "eco-friendly"] }}Selector de imagen desde la biblioteca multimedia. Almacena el ID del medio como TEXT.
{ slug: "featuredImage", type: "image", label: "Featured Image" }Selector de archivo desde la biblioteca multimedia. Almacena el ID del medio como TEXT.
{ slug: "attachment", type: "file", label: "PDF Attachment" }Referencia a una entrada de otra colección. Almacena el ID de la entrada como TEXT.
{ slug: "author", type: "reference", label: "Autor", options: { collection: "authors" }}Cada campo admite estas propiedades:
| Propiedad | Tipo | Descripción |
|---|---|---|
slug | string | Nombre de la columna en la base de datos |
label | string | Etiqueta de visualización en la UI de administración |
type | FieldType | Uno de los 15 tipos de campo |
required | boolean | Si el campo debe tener un valor |
unique | boolean | Si los valores deben ser únicos entre entradas |
defaultValue | unknown | Valor por defecto para nuevas entradas |
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 |
El objeto validation varía según el tipo de campo:
interface FieldValidation { required?: boolean; // All types 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,}$" }}El objeto options configura el comportamiento de la UI específico del campo:
interface FieldWidgetOptions { rows?: number; // text (textarea rows) showPreview?: boolean; // image, file collection?: string; // reference (target collection) allowMultiple?: boolean; // reference (multiple refs) [key: string]: unknown; // Custom widget options}Ejemplo de campo de referencia:
{ slug: "relatedProducts", type: "reference", label: "Related Products", options: { collection: "products", allowMultiple: true }}Usa las funciones de consulta proporcionadas para obtener contenido. Estas siguen el patrón de colecciones dinámicas de Astro, devolviendo resultados estructurados:
import { getEmDashCollection, getEmDashEntry } from "emdash";
// Obtener todas las entradas - devuelve { entries, error }const { entries: posts } = await getEmDashCollection("posts");
// Filtrar por estadoconst { entries: drafts } = await getEmDashCollection("posts", { status: "draft",});
// Limitar resultadosconst { entries: recent } = await getEmDashCollection("posts", { limit: 5,});
// Filtrar por taxonomíaconst { entries: newsPosts } = await getEmDashCollection("posts", { where: { category: "news" },});
// Obtener una entrada única por slug - devuelve { entry, error, isPreview }const { entry: post } = await getEmDashEntry("posts", "my-post-slug");
// Manejar erroresconst { entries, error } = await getEmDashCollection("posts");if (error) { console.error("Failed to load posts:", error);}Ejecuta npx emdash types para generar tipos de TypeScript desde tu esquema:
// .emdash/types.ts (generated)export interface Post { title: string; content: PortableTextBlock[]; excerpt?: string; featuredImage?: string; author: string; // reference ID}
export interface Product { title: string; price: number; description: PortableTextBlock[];}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 | Punto flotante 64-bit |
integer | INTEGER | Entero con signo 64-bit |
boolean | INTEGER | 0 o 1 |
datetime | TEXT | Formato ISO 8601 |
select | TEXT | |
multiSelect | JSON | Arreglo de cadenas |
portableText | JSON | Arreglo de bloques |
image | TEXT | ID de medio |
file | TEXT | ID de medio |
reference | TEXT | ID de entrada |
json | JSON | JSON arbitrario |
Modelo de Contenido
Comprende el enfoque de base de datos primero.
Taxonomías
Organiza contenido con categorías y etiquetas.
Biblioteca de Medios
Gestiona imágenes y archivos.