Zones de Widgets

Sur cette page

Les zones de widgets sont des régions nommées dans vos templates où les administrateurs peuvent placer des blocs de contenu. Utilisez-les pour les barres latérales, les colonnes de pied de page, les 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 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>}
        <!-- Rendre le contenu du widget -->
      </div>
    ))}
  </aside>
)}

La fonction renvoie null si la zone de widgets n’existe pas.

Structure de la Zone de Widgets

Une zone de widgets contient des métadonnées et un tableau 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>;
}

Types de Widgets

EmDash prend en charge trois types de widgets :

Widgets de Contenu

Contenu en texte enrichi stocké sous forme de Portable Text. Rendez-le en utilisant 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 Composants

Rendez un composant enregistré avec des props configurables. EmDash inclut ces composants principaux :

Component IDDescriptionProps
core:recent-postsListe des articles récentscount, showThumbnails, showDate
core:categoriesListe des catégoriesshowCount, hierarchical
core:tagsNuage de tagsshowCount, limit
core:searchFormulaire de rechercheplaceholder
core:archivesArchives mensuelles/annuellestype, limit

Rendre les Widgets

Créez un composant de rendu de widgets réutilisable :

---
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>

Exemples de Composants de Widgets

Widget Articles Récents

Le composant suivant affiche les articles les plus récents, avec des vignettes et des dates optionnelles :

---
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 Recherche

Le composant suivant affiche un formulaire de recherche qui soumet vers une page de recherche :

---
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>

Utiliser les Zones de Widgets dans les Layouts

L’exemple suivant montre un layout de blog avec une zone de widgets dans la 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 de widgets avec leurs widgets :

import { getWidgetAreas } from "emdash";

const areas = await getWidgetAreas();
// Returns all areas with widgets populated

Créer des Zones de Widgets

Créez des zones de widgets via l’interface d’administration à /_emdash/admin/widgets, ou utilisez l’API d’administration :

POST /_emdash/api/widget-areas
Content-Type: application/json

{
  "name": "footer-1",
  "label": "Footer Column 1",
  "description": "First column in the footer"
}

Ajouter un widget de contenu :

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." }]
    }
  ]
}

Ajouter un widget de composant :

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 }
}

Référence API

getWidgetArea(name)

Récupère une zone de widgets par nom avec tous les widgets.

Paramètres :

  • name — L’identifiant unique de la zone de widgets (string)

Renvoie : Promise<WidgetArea | null>

getWidgetAreas()

Liste toutes les zones de widgets avec leurs widgets.

Renvoie : Promise<WidgetArea[]>

getWidgetComponents()

Liste les définitions de composants de widgets disponibles pour l’interface d’administration.

Renvoie : WidgetComponentDef[]