Les zones de widgets sont des régions nommées dans vos modèles où les administrateurs peuvent placer des blocs de contenu. Servez-vous-en pour les barres latérales, colonnes de pied de page, bannières promotionnelles ou toute section que les éditeurs doivent contrôler sans toucher au code.
Interroger les zones de widgets
Utilisez getWidgetArea() pour récupérer une zone de widgets par son nom :
---
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>}
<!-- Rendu du contenu du widget -->
</div>
))}
</aside>
)}
La fonction renvoie null si la zone n’existe pas.
Structure d’une zone de widgets
Une zone de widgets contient des métadonnées et un tableau de widgets :
interface WidgetArea {
id: string;
name: string; // Identifiant unique ("sidebar", "footer-1")
label: string; // Libellé affiché ("Barre latérale principale")
description?: string;
widgets: Widget[];
}
interface Widget {
id: string;
type: "content" | "menu" | "component";
title?: string;
// Champs spécifiques au type
content?: PortableTextBlock[]; // Widgets de contenu
menuName?: string; // Widgets de menu
componentId?: string; // Widgets de composant
componentProps?: Record<string, unknown>;
}
Types de widgets
EmDash prend en charge trois types de widgets :
Widgets de contenu
Texte enrichi stocké en Portable Text. Rendez-le avec le composant PortableText :
---
import { PortableText } from "emdash/ui";
---
{widget.type === "content" && widget.content && (
<div class="widget-content">
<PortableText value={widget.content} />
</div>
)}
Widgets de menu
Affichez un menu de navigation dans une zone 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 composant
Rendez un composant enregistré avec des props configurables. EmDash inclut ces composants de base :
| ID de composant | Description | Props |
|---|---|---|
core:recent-posts | Liste des articles récents | count, showThumbnails, showDate |
core:categories | Liste des catégories | showCount, hierarchical |
core:tags | Nuage de tags | showCount, limit |
core:search | Formulaire de recherche | placeholder |
core:archives | Archives mensuelles/annuelles | type, limit |
Rendre les widgets
Créez un composant de rendu réutilisable :
---
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>
Exemples de composants widget
Widget articles récents
---
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 recherche
---
interface Props {
placeholder?: string;
}
const { placeholder = "Rechercher…" } = Astro.props;
---
<form action="/search" method="get" class="search-form">
<input
type="search"
name="q"
placeholder={placeholder}
aria-label="Recherche"
/>
<button type="submit">Rechercher</button>
</form>
Zones de widgets dans les layouts
Exemple de mise en page blog avec barre latérale :
---
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>
Lister toutes les zones de widgets
Utilisez getWidgetAreas() pour récupérer toutes les zones avec leurs widgets :
import { getWidgetAreas } from "emdash";
const areas = await getWidgetAreas();
// Renvoie toutes les zones avec widgets peuplés
Créer des zones de widgets
Créez-les dans l’admin à /_emdash/admin/widgets, ou via l’API d’administration :
POST /_emdash/api/widget-areas
Content-Type: application/json
{
"name": "footer-1",
"label": "Pied de page colonne 1",
"description": "Première colonne du pied de page"
}
Ajouter un widget de contenu :
POST /_emdash/api/widget-areas/footer-1/widgets
Content-Type: application/json
{
"type": "content",
"title": "À propos",
"content": [
{
"_type": "block",
"style": "normal",
"children": [{ "_type": "span", "text": "Bienvenue sur notre site." }]
}
]
}
Ajouter un widget de composant :
POST /_emdash/api/widget-areas/sidebar/widgets
Content-Type: application/json
{
"type": "component",
"title": "Articles récents",
"componentId": "core:recent-posts",
"componentProps": { "count": 5, "showDate": true }
}
Référence API
getWidgetArea(name)
Récupère une zone de widgets par nom avec tous ses widgets.
Paramètres :
name— Identifiant unique de la zone (chaîne)
Retour : Promise<WidgetArea | null>
getWidgetAreas()
Liste toutes les zones de widgets avec leurs widgets.
Retour : Promise<WidgetArea[]>
getWidgetComponents()
Liste les définitions de composants widget disponibles pour l’admin.
Retour : WidgetComponentDef[]