Áreas de widgets são regiões nomeadas nos seus templates onde administradores podem colocar blocos de conteúdo. Use-as para barras laterais, colunas de rodapé, banners promocionais ou qualquer seção que editores devem controlar sem tocar no código.
Consultando áreas de widgets
Use getWidgetArea() para buscar uma área de widget 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 widget não existir.
Estrutura da área de widgets
Uma área de widget contém metadados e um array de widgets:
interface WidgetArea {
id: string;
name: string; // Identificador único ("sidebar", "footer-1")
label: string; // Nome de exibição ("Barra Lateral Principal")
description?: string;
widgets: Widget[];
}
interface Widget {
id: string;
type: "content" | "menu" | "component";
title?: string;
// Campos específicos do tipo
content?: PortableTextBlock[]; // Para widgets de conteúdo
menuName?: string; // Para widgets de menu
componentId?: string; // Para widgets de componente
componentProps?: Record<string, unknown>;
}
Tipos de widgets
O 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
Exibir um menu de navegação dentro de uma área de widget:
---
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 componente
Renderize um componente registrado com props configuráveis. O EmDash inclui estes componentes principais:
| ID do componente | 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 busca | placeholder |
core:archives | Arquivos mensais/anuais | type, limit |
Renderizando widgets
Crie um componente renderizador de widgets reutilizável:
---
import { PortableText } from "emdash/ui";
import { getMenu } from "emdash";
import type { Widget } from "emdash";
// Importar seus componentes de widget
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 widget
Widget de posts recentes
O seguinte componente renderiza os posts mais recentes, com thumbnails e datas opcionais:
---
import { getEmDashCollection } from "emdash";
import { Image } from "emdash/ui";
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 && (
<Image image={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 busca
O seguinte componente renderiza um formulário de busca que envia para uma página de busca:
---
interface Props {
placeholder?: string;
}
const { placeholder = "Buscar..." } = Astro.props;
---
<form action="/search" method="get" class="search-form">
<input
type="search"
name="q"
placeholder={placeholder}
aria-label="Buscar"
/>
<button type="submit">Buscar</button>
</form>
Usando áreas de widgets em layouts
O seguinte exemplo mostra um layout de blog com uma área de widget 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 widget com seus widgets:
import { getWidgetAreas } from "emdash";
const areas = await getWidgetAreas();
// Retorna todas as áreas com widgets preenchidos
Criando áreas de widgets
Crie áreas de widgets através da interface admin em /_emdash/admin/widgets, ou use a API de administração:
POST /_emdash/api/widget-areas
Content-Type: application/json
{
"name": "footer-1",
"label": "Rodapé Coluna 1",
"description": "Primeira coluna no rodapé"
}
Adicionar um widget de conteúdo:
POST /_emdash/api/widget-areas/footer-1/widgets
Content-Type: application/json
{
"type": "content",
"title": "Sobre nós",
"content": [
{
"_type": "block",
"style": "normal",
"children": [{ "_type": "span", "text": "Bem-vindo ao nosso site." }]
}
]
}
Adicionar um widget de componente:
POST /_emdash/api/widget-areas/sidebar/widgets
Content-Type: application/json
{
"type": "component",
"title": "Posts recentes",
"componentId": "core:recent-posts",
"componentProps": { "count": 5, "showDate": true }
}
Referência da API
getWidgetArea(name)
Buscar uma área de widget por nome com todos os widgets.
Parâmetros:
name— O identificador único da área de widget (string)
Retorna: Promise<WidgetArea | null>
getWidgetAreas()
Listar todas as áreas de widget com seus widgets.
Retorna: Promise<WidgetArea[]>
getWidgetComponents()
Listar definições de componentes widget disponíveis para a UI de administração.
Retorna: WidgetComponentDef[]