Aree widget

In questa pagina

Le aree widget sono regioni nominate nei template in cui gli amministratori possono posizionare blocchi di contenuto. Usale per barre laterali, colonne del footer, banner promozionali o qualsiasi sezione che gli editor devono gestire senza toccare il codice.

Interrogare le aree widget

Usa getWidgetArea() per ottenere un’area widget per 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>}
        <!-- Renderizza il contenuto del widget -->
      </div>
    ))}
  </aside>
)}

La funzione restituisce null se l’area widget non esiste.

Struttura dell’area widget

Un’area widget contiene metadati e un array di widget:

interface WidgetArea {
	id: string;
	name: string; // Identificatore univoco ("sidebar", "footer-1")
	label: string; // Nome visualizzato ("Barra laterale principale")
	description?: string;
	widgets: Widget[];
}

interface Widget {
	id: string;
	type: "content" | "menu" | "component";
	title?: string;
	// Campi specifici del tipo
	content?: PortableTextBlock[]; // Per widget di contenuto
	menuName?: string; // Per widget menu
	componentId?: string; // Per widget componente
	componentProps?: Record<string, unknown>;
}

Tipi di widget

EmDash supporta tre tipi di widget:

Widget di contenuto

Testo formattato salvato come Portable Text. Renderizza con il componente PortableText:

---
import { PortableText } from "emdash/ui";
---

{widget.type === "content" && widget.content && (
  <div class="widget-content">
    <PortableText value={widget.content} />
  </div>
)}

Widget menu

Mostra un menu di navigazione nell’area 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>
)}

Widget componente

Renderizza un componente registrato con props configurabili. EmDash include questi componenti di base:

ID componenteDescrizioneProps
core:recent-postsElenco degli articoli recenticount, showThumbnails, showDate
core:categoriesElenco categorieshowCount, hierarchical
core:tagsNuvola di tagshowCount, limit
core:searchModulo di ricercaplaceholder
core:archivesArchivi mensili/annualitype, limit

Renderizzare i widget

Crea un componente renderer riutilizzabile:

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

Esempi di componenti widget

Widget articoli recenti

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

---
interface Props {
  placeholder?: string;
}

const { placeholder = "Cerca…" } = Astro.props;
---

<form action="/search" method="get" class="search-form">
  <input
    type="search"
    name="q"
    placeholder={placeholder}
    aria-label="Cerca"
  />
  <button type="submit">Cerca</button>
</form>

Aree widget nei layout

L’esempio seguente mostra un layout blog con area widget nella barra laterale:

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

Elencare tutte le aree widget

Usa getWidgetAreas() per recuperare tutte le aree con i relativi widget:

import { getWidgetAreas } from "emdash";

const areas = await getWidgetAreas();
// Restituisce tutte le aree con i widget popolati

Creare aree widget

Crea aree widget dall’interfaccia admin su /_emdash/admin/widgets, oppure usa l’API admin:

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

{
  "name": "footer-1",
  "label": "Colonna footer 1",
  "description": "Prima colonna nel piè di pagina"
}

Aggiungi un widget di contenuto:

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

{
  "type": "content",
  "title": "Chi siamo",
  "content": [
    {
      "_type": "block",
      "style": "normal",
      "children": [{ "_type": "span", "text": "Benvenuti sul nostro sito." }]
    }
  ]
}

Aggiungi un widget componente:

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

{
  "type": "component",
  "title": "Articoli recenti",
  "componentId": "core:recent-posts",
  "componentProps": { "count": 5, "showDate": true }
}

Riferimento API

getWidgetArea(name)

Carica un’area widget per nome con tutti i widget.

Parametri:

  • name — Identificatore univoco dell’area widget (stringa)

Restituisce: Promise<WidgetArea | null>

getWidgetAreas()

Elenca tutte le aree widget con i relativi widget.

Restituisce: Promise<WidgetArea[]>

getWidgetComponents()

Elenca le definizioni dei componenti widget disponibili per l’admin.

Restituisce: WidgetComponentDef[]