Á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 secção que editores devam controlar sem alterar código.
Consultar áreas de widgets
Use getWidgetArea() para obter uma área de widgets pelo 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 devolve 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; // Identificador único ("sidebar", "footer-1")
label: string; // Nome apresentado ("Barra lateral principal")
description?: string;
widgets: Widget[];
}
interface Widget {
id: string;
type: "content" | "menu" | "component";
title?: string;
// Campos específicos do tipo
content?: PortableTextBlock[]; // Widgets de conteúdo
menuName?: string; // Widgets de menu
componentId?: string; // Widgets de componente
componentProps?: Record<string, unknown>;
}
Tipos de widget
O EmDash suporta três tipos de widget:
Widgets de conteúdo
Texto rico armazenado como Portable Text. Renderize com 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
Mostram um menu de navegação dentro da á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 componente
Renderizam um componente registado com props configuráveis. O EmDash inclui estes componentes principais:
| ID do componente | Descrição | Props |
|---|---|---|
core:recent-posts | Lista de artigos recentes | count, showThumbnails, showDate |
core:categories | Lista de categorias | showCount, hierarchical |
core:tags | Nuvem de etiquetas | showCount, limit |
core:search | Formulário de pesquisa | placeholder |
core:archives | Arquivos mensais/anuais | type, limit |
Renderizar widgets
Crie um componente de renderização reutilizável:
---
import { PortableText } from "emdash/ui";
import { getMenu } from "emdash";
import type { Widget } from "emdash";
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 artigos recentes
---
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.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
---
interface Props {
placeholder?: string;
}
const { placeholder = "Pesquisar…" } = Astro.props;
---
<form action="/search" method="get" class="search-form">
<input
type="search"
name="q"
placeholder={placeholder}
aria-label="Pesquisar"
/>
<button type="submit">Pesquisar</button>
</form>
Áreas de widgets em layouts
O exemplo seguinte mostra um layout de blog com á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>
Listar todas as áreas de widgets
Use getWidgetAreas() para obter todas as áreas com os respetivos widgets:
import { getWidgetAreas } from "emdash";
const areas = await getWidgetAreas();
// Devolve todas as áreas com widgets preenchidos
Criar áreas de widgets
Crie áreas de widgets na interface de administração em /_emdash/admin/widgets, ou use a API admin:
POST /_emdash/api/widget-areas
Content-Type: application/json
{
"name": "footer-1",
"label": "Coluna do rodapé 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": "Artigos recentes",
"componentId": "core:recent-posts",
"componentProps": { "count": 5, "showDate": true }
}
Referência da API
getWidgetArea(name)
Obtém uma área de widgets pelo nome com todos os widgets.
Parâmetros:
name— Identificador único da área de widgets (string)
Devolve: Promise<WidgetArea | null>
getWidgetAreas()
Lista todas as áreas de widgets com os respetivos widgets.
Devolve: Promise<WidgetArea[]>
getWidgetComponents()
Lista as definições de componentes widget disponíveis para a UI de administração.
Devolve: WidgetComponentDef[]