Áreas de Widgets

Nesta página

Áreas de widgets são regiões nomeadas em seus templates onde os administradores podem colocar blocos de conteúdo. Use-as para barras laterais, colunas de rodapé, banners promocionais ou qualquer seção que os editores devam controlar sem tocar no código.

Consultando Áreas de Widgets

Use getWidgetArea() para buscar uma área de widgets 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 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; // 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>;
}

Tipos de Widgets

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

Exiba um menu de navegação dentro de uma á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 Componentes

Renderize um componente registrado com props configuráveis. EmDash inclui estes componentes principais:

Component IDDescriçãoProps
core:recent-postsLista de posts recentescount, showThumbnails, showDate
core:categoriesLista de categoriasshowCount, hierarchical
core:tagsNuvem de tagsshowCount, limit
core:searchFormulário de pesquisaplaceholder
core:archivesArquivos mensais/anuaistype, limit

Renderizando Widgets

Crie um componente de renderização de widgets reutilizável:

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

Exemplos de Componentes de Widgets

Widget de Posts Recentes

O componente a seguir renderiza os posts mais recentes, com miniaturas e datas opcionais:

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

O componente a seguir renderiza um formulário de pesquisa que envia para uma página de pesquisa:

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

Usando Áreas de Widgets em Layouts

O exemplo a seguir mostra um layout de blog com uma á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>

Listando Todas as Áreas de Widgets

Use getWidgetAreas() para recuperar todas as áreas de widgets com seus widgets:

import { getWidgetAreas } from "emdash";

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

Criando Áreas de Widgets

Crie áreas de widgets através da interface de administração em /_emdash/admin/widgets, ou use a API de administração:

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

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

Adicionar um widget de conteúdo:

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

Adicionar um widget de componente:

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

Referência da API

getWidgetArea(name)

Busca uma área de widgets por nome com todos os widgets.

Parâmetros:

  • name — O identificador único da área de widgets (string)

Retorna: Promise<WidgetArea | null>

getWidgetAreas()

Lista todas as áreas de widgets com seus widgets.

Retorna: Promise<WidgetArea[]>

getWidgetComponents()

Lista definições de componentes de widgets disponíveis para a interface de administração.

Retorna: WidgetComponentDef[]