Áreas de widgets são regiões nomeadas em seus templates onde os administradores podem colocar blocos de conteúdo. Use-as para barras laterais, colunas de rodapé, banners promocionais ou qualquer seção que os editores devam controlar sem tocar no código.
Consultando Áreas de Widgets
Use getWidgetArea() para buscar uma área de widgets por nome:
---
import { getWidgetArea } from "emdash";
const sidebar = await getWidgetArea("sidebar");
---
{sidebar && sidebar.widgets.length > 0 && (
<aside class="sidebar">
{sidebar.widgets.map(widget => (
<div class="widget">
{widget.title && <h3>{widget.title}</h3>}
<!-- Renderizar conteúdo do widget -->
</div>
))}
</aside>
)}
A função retorna null se a área de widgets não existir.
Estrutura da Área de Widgets
Uma área de widgets contém metadados e um array de widgets:
interface WidgetArea {
id: string;
name: string; // Unique identifier ("sidebar", "footer-1")
label: string; // Display name ("Main Sidebar")
description?: string;
widgets: Widget[];
}
interface Widget {
id: string;
type: "content" | "menu" | "component";
title?: string;
// Type-specific fields
content?: PortableTextBlock[]; // For content widgets
menuName?: string; // For menu widgets
componentId?: string; // For component widgets
componentProps?: Record<string, unknown>;
}
Tipos de Widgets
EmDash suporta três tipos de widgets:
Widgets de Conteúdo
Conteúdo de texto rico armazenado como Portable Text. Renderize usando o componente PortableText:
---
import { PortableText } from "emdash/ui";
---
{widget.type === "content" && widget.content && (
<div class="widget-content">
<PortableText value={widget.content} />
</div>
)}
Widgets de Menu
Exiba um menu de navegação dentro de uma área de widgets:
---
import { getMenu } from "emdash";
const menu = widget.menuName ? await getMenu(widget.menuName) : null;
---
{widget.type === "menu" && menu && (
<nav class="widget-nav">
<ul>
{menu.items.map(item => (
<li><a href={item.url}>{item.label}</a></li>
))}
</ul>
</nav>
)}
Widgets de Componentes
Renderize um componente registrado com props configuráveis. EmDash inclui estes componentes principais:
| Component ID | Descrição | Props |
|---|---|---|
core:recent-posts | Lista de posts recentes | count, showThumbnails, showDate |
core:categories | Lista de categorias | showCount, hierarchical |
core:tags | Nuvem de tags | showCount, limit |
core:search | Formulário de pesquisa | placeholder |
core:archives | Arquivos mensais/anuais | type, limit |
Renderizando Widgets
Crie um componente de renderização de widgets reutilizável:
---
import { PortableText } from "emdash/ui";
import { getMenu } from "emdash";
import type { Widget } from "emdash";
// Import your widget components
import RecentPosts from "./widgets/RecentPosts.astro";
import Categories from "./widgets/Categories.astro";
import TagCloud from "./widgets/TagCloud.astro";
import SearchForm from "./widgets/SearchForm.astro";
import Archives from "./widgets/Archives.astro";
interface Props {
widget: Widget;
}
const { widget } = Astro.props;
const componentMap: Record<string, any> = {
"core:recent-posts": RecentPosts,
"core:categories": Categories,
"core:tags": TagCloud,
"core:search": SearchForm,
"core:archives": Archives,
};
const menu = widget.type === "menu" && widget.menuName
? await getMenu(widget.menuName)
: null;
---
<div class="widget">
{widget.title && <h3 class="widget-title">{widget.title}</h3>}
{widget.type === "content" && widget.content && (
<div class="widget-content">
<PortableText value={widget.content} />
</div>
)}
{widget.type === "menu" && menu && (
<nav class="widget-menu">
<ul>
{menu.items.map(item => (
<li><a href={item.url}>{item.label}</a></li>
))}
</ul>
</nav>
)}
{widget.type === "component" && widget.componentId && componentMap[widget.componentId] && (
<Fragment>
{(() => {
const Component = componentMap[widget.componentId!];
return <Component {...widget.componentProps} />;
})()}
</Fragment>
)}
</div>
Exemplos de Componentes de Widgets
Widget de Posts Recentes
O componente a seguir renderiza os posts mais recentes, com miniaturas e datas opcionais:
---
import { getEmDashCollection } from "emdash";
interface Props {
count?: number;
showThumbnails?: boolean;
showDate?: boolean;
}
const { count = 5, showThumbnails = false, showDate = true } = Astro.props;
const { entries: posts } = await getEmDashCollection("posts", {
limit: count,
orderBy: { publishedAt: "desc" },
});
---
<ul class="recent-posts">
{posts.map(post => (
<li>
{showThumbnails && post.data.featured_image && (
<img src={post.data.featured_image} alt="" class="thumbnail" />
)}
<a href={`/posts/${post.data.slug}`}>{post.data.title}</a>
{showDate && post.data.publishedAt && (
<time datetime={post.data.publishedAt.toISOString()}>
{post.data.publishedAt.toLocaleDateString()}
</time>
)}
</li>
))}
</ul>
Widget de Pesquisa
O componente a seguir renderiza um formulário de pesquisa que envia para uma página de pesquisa:
---
interface Props {
placeholder?: string;
}
const { placeholder = "Search..." } = Astro.props;
---
<form action="/search" method="get" class="search-form">
<input
type="search"
name="q"
placeholder={placeholder}
aria-label="Search"
/>
<button type="submit">Search</button>
</form>
Usando Áreas de Widgets em Layouts
O exemplo a seguir mostra um layout de blog com uma área de widgets na barra lateral:
---
import { getWidgetArea } from "emdash";
import WidgetRenderer from "../components/WidgetRenderer.astro";
const sidebar = await getWidgetArea("sidebar");
---
<div class="layout">
<main class="content">
<slot />
</main>
{sidebar && sidebar.widgets.length > 0 && (
<aside class="sidebar">
{sidebar.widgets.map(widget => (
<WidgetRenderer widget={widget} />
))}
</aside>
)}
</div>
<style>
.layout {
display: grid;
grid-template-columns: 1fr 300px;
gap: 2rem;
}
@media (max-width: 768px) {
.layout {
grid-template-columns: 1fr;
}
}
</style>
Listando Todas as Áreas de Widgets
Use getWidgetAreas() para recuperar todas as áreas de widgets com seus widgets:
import { getWidgetAreas } from "emdash";
const areas = await getWidgetAreas();
// Returns all areas with widgets populated
Criando Áreas de Widgets
Crie áreas de widgets através da interface de administração em /_emdash/admin/widgets, ou use a API de administração:
POST /_emdash/api/widget-areas
Content-Type: application/json
{
"name": "footer-1",
"label": "Footer Column 1",
"description": "First column in the footer"
}
Adicionar um widget de conteúdo:
POST /_emdash/api/widget-areas/footer-1/widgets
Content-Type: application/json
{
"type": "content",
"title": "About Us",
"content": [
{
"_type": "block",
"style": "normal",
"children": [{ "_type": "span", "text": "Welcome to our site." }]
}
]
}
Adicionar um widget de componente:
POST /_emdash/api/widget-areas/sidebar/widgets
Content-Type: application/json
{
"type": "component",
"title": "Recent Posts",
"componentId": "core:recent-posts",
"componentProps": { "count": 5, "showDate": true }
}
Referência da API
getWidgetArea(name)
Busca uma área de widgets por nome com todos os widgets.
Parâmetros:
name— O identificador único da área de widgets (string)
Retorna: Promise<WidgetArea | null>
getWidgetAreas()
Lista todas as áreas de widgets com seus widgets.
Retorna: Promise<WidgetArea[]>
getWidgetComponents()
Lista definições de componentes de widgets disponíveis para a interface de administração.
Retorna: WidgetComponentDef[]