Coleções e @each
Coleções permitem iterar sobre listas de conteúdo diretamente no template .seed usando o componente @each. Defina no seed.yaml, crie um diretório com arquivos .seed, e use @each para listar os itens.
O que é uma coleção
Uma coleção é um diretório de arquivos .seed dentro de src/. Cada arquivo representa um item, e o front matter de cada arquivo define os campos acessíveis no template via {prefixo-campo}.
Exemplos de uso:
- Blog — lista de posts (coleção embutida, veja Blog)
- Equipe — membros do time
- Portfólio — projetos
- Depoimentos — feedback de clientes
- Produtos — catálogo de itens
Configuração no seed.yaml
Declare suas coleções na chave collections do seed.yaml:
```yaml
collections:
team: # nome da coleção → @each team
dir: team # diretório: src/team/
sort: name # campo de ordenação (default: title)
order: asc # asc | desc (default: asc)
projects:
dir: projects # src/projects/
sort: publish_date
order: desc
```Estrutura do projeto
``` src/ ├── team/ │ ├── list.layout ← layout da listagem (opcional) │ ├── item.layout ← layout de cada membro (opcional) │ ├── ana.seed │ ├── lucas.seed │ └── maria.seed ├── projects/ │ ├── list.layout │ ├── item.layout │ ├── ada.seed │ └── seed.seed └── index.seed ```
Cada arquivo .seed dentro do diretório da coleção é um item. O front matter define os campos:
```seed --- name: Ana Silva role: CTO photo: /static/img/ana.jpg --- @p Ana lidera a engenharia com 15 anos de experiência em fintechs. ```
Usando @each no template
O componente @each itera sobre uma coleção registrada. Tudo que está indentado abaixo dele é repetido para cada item:
```seed
@each team
@div class=flex items-center gap-4 p-4 border rounded-lg
@img src={team-photo}, class=w-12 h-12 rounded-full
@div
@h3
{team-name}
@p class=text-sm text-gray-500
{team-role}
```Se a coleção team tiver 3 membros, o bloco acima gera 3 cards — um para cada pessoa.
Prefixo de variáveis
As variáveis dentro de @each usam o padrão {prefixo-campo}. O prefixo é derivado automaticamente do nome da coleção, removendo o s final quando houver:
| Coleção | Prefixo | Variáveis de exemplo |
|---|---|---|
posts | post | {post-title}, {post-url}, {post-publish_date} |
projects | project | {project-name}, {project-url} |
team | team | {team-name}, {team-role} |
testimonials | testimonial | {testimonial-text}, {testimonial-author} |
Cada campo do front matter do .seed vira uma variável com {prefixo-campo}.
Layouts
Cada coleção pode ter dois layouts opcionais no seu diretório:
| Arquivo | Propósito |
|---|---|
list.layout | Página de listagem da coleção (/team/index.html), com @each para iterar |
item.layout | Layout aplicado a cada .seed individual da coleção |
Os nomes são configuráveis no seed.yaml:
```yaml
collections:
cases:
dir: cases
list_layout: gallery # → src/cases/gallery.layout
item_layout: case # → src/cases/case.layout
```Resolução (prioridade)
- Projeto →
src/<dir>/<nome>.layout - Tema →
themes/<tema>/<dir>/<nome>.layout - Fallback →
src/default.layout(para item) ou listagem embutida (para list)
Exemplo: list.layout
```seed
---
title: Nossa Equipe
---
@section class=max-w-5xl mx-auto py-20
@h1
Equipe
@div class=grid gap-8 md:grid-cols-3
@each team
@div class=text-center
@img src={team-photo}, class=w-24 h-24 rounded-full mx-auto
@h3
{team-name}
@p class=text-gray-500
{team-role}
```Exemplo: item.layout
```seed
---
title: Equipe
---
@article class=max-w-3xl mx-auto py-20 px-6
@h1
{title}
@p class=text-gray-500
{role}
@div class=prose
{content}
```Convenções
| Regra | Exemplo | Resultado |
|---|---|---|
Campos com _ são internos | Campo _file num item | Não é exposto no template |
| Listas viram string | tags: [a, b] | {post-tags} → "a, b" |
| Campo inexistente | {post-inexistente} | Permanece literal no HTML |
Datas, arquivos e autoria
Coleções que ordenam ou agrupam por data usam o campo publish_date do front matter (não date — veja Front Matter). Se a coleção define sort: publish_date ou dates: day/dates: month, todo item precisa ter publish_date — sem ele, o build falha apontando o arquivo.
```yaml
collections:
blog:
dir: blog
sort: publish_date
order: desc
tags: true # gera /blog/tags/<slug>/ com @each tags
dates: month # gera /blog/<YYYY-MM>/ com @each dates
author:
name: Jane Doe # autor padrão de todo item — ver abaixo
```Com tags: true, cada item pode declarar tags: [a, b] no front matter; o Seed gera uma página de arquivo por tag e registra @each tags com {tag-name}, {tag-url}, {tag-count}, {tag-active}. Com dates: day ou dates: month, o Seed gera páginas de arquivo por dia/mês (noindex, follow) e registra @each dates com {date-name}, {date-url}, {date-count}, {date-active} (mais recente primeiro).
author: na coleção define o autor padrão de todo item — tanto no JSON-LD quanto na variável {author_name} usada em item.layout/list.layout. Uma página pode sobrescrever com seu próprio author_name, ou remover a autoria com author: false. Detalhes completos da precedência em SEO & Metadados.
Paginação de Coleções
Quando uma coleção cresce, exibir todos os itens em uma única página pode prejudicar a performance e a experiência do usuário. O Seed oferece um sistema de paginação automática que divide o conteúdo em múltiplas páginas físicas.
1. Configuração
Para ativar a paginação, adicione a chave per_page na configuração da coleção no seed.yaml:
```yaml
collections:
blog:
per_page: 10 # Exibe 10 itens por página
```O valor padrão é 0, que mantém todos os itens em uma única página (sem paginação).
2. Estrutura de URLs
Ao ativar a paginação, o Seed gera automaticamente uma estrutura de diretórios para as páginas subsequentes:
- Primeira Página:
/blog/index.html(ou o caminho base da coleção) - Páginas Seguintes:
/blog/page/2/index.html,/blog/page/3/index.html, etc.
Essa estrutura é ideal para SEO e permite que os usuários naveguem diretamente para páginas específicas.
3. Variáveis de Navegação
Dentro do seu list.layout (ou arquivo que contém o @each), o Seed injeta variáveis especiais de metadados. Você pode usá-las para criar controles de navegação (anterior/próximo, contador de páginas, etc.):
| Variável | Descrição |
|---|---|
{page} | Número da página atual (inteiro: 1, 2, 3...) |
{total_pages} | Quantidade total de páginas geradas |
{total_items} | Número total de itens na coleção (antes de filtrar por página) |
{prev_url} | Caminho da página anterior. Fica vaziO na primeira página. |
{next_url} | Caminho da próxima página. Fica vazia na última página. |
{prev_title} | Sugestão de título amigável: "Página 1" (ou o número da página anterior). |
{next_title} | Sugestão de título amigável: "Página 3" (ou o número da próxima página). |
4. Guia de Implementação (Exemplo Completo)
Abaixo, um exemplo de como implementar uma paginação robusta usando componentes utilitários para condicionalmente exibir os links:
```seed
// No seu list.layout
@section
@h1
Artigos
@div class=grid gap-6
@each blog
@article
@h2
{blog-title}
@p
{blog-description}
// Navegação
@nav class=flex items-center justify-between mt-12 py-8 border-t
@div
@if {prev_url}
@a href={prev_url}, class=btn-pagination
← {prev_title}
@span class=text-gray-500
Página {page} de {total_pages}
@div
@if {next_url}
@a href={next_url}, class=btn-pagination
{next_title} →
```O Seed é inteligente: se você definir per_page: 10 mas tiver apenas 8 itens, ele gerará apenas a página principal e as variáveis de navegação (next_url, etc.) ficarão vazias, ocultando os botões automaticamente se você usar o padrão @if.
Se a coleção estiver vazia, o bloco @each não gera nenhum HTML — sem erros, sem output.
Se a coleção não foi registrada (o nome não existe no seed.yaml), o Seed exibe um erro inline visível na página para facilitar depuração.
Múltiplas coleções na mesma página
Você pode usar quantos @each quiser na mesma página, cada um com uma coleção diferente:
```seed
@section
@h2
Equipe
@each team
@p
{team-name} — {team-role}
@section
@h2
Projetos
@each projects
@p
{project-name} — {project-description}
```O blog é uma coleção especial com funcionalidades extras (listing page automática, filtragem de drafts, campos pré-definidos). Veja Blog.
Feito com ❤️ e Seed