Sintaxe de Template do Facet
Sintaxe de Template do Facet
Facet é a linguagem de templates usada pelo FaceFlow para renderização dinâmica.
Use esta página como o guia primário de sintaxe. Ela cobre os padrões que usuários técnicos realmente precisam ao escrever templates de Componentes, templates de Variáveis, saída de itens de Lista e outros fragmentos em tempo de execução dentro do FaceFlow.
Esta página é intencionalmente detalhada. Não é apenas um guia rápido. É o documento principal de sintaxe para autoria de templates oficiais do FaceFlow.
Famílias de Sintaxe
Facet templates normalmente combinam cinco famílias de sintaxe:
| Sintaxe | Função | Uso Típico |
|---|---|---|
{field} | Saída de campo do Componente | saída direta de um campo do Componente |
{{ expr }} | saída de expressão escapada | dados da página, objetos de contexto, filtros |
{{{ expr }}} | saída bruta | conteúdo rico confiável e marcação controlada |
{{#block}}...{{/block}} | fluxo de controle | condições, loops, consultas de página, saída diferida |
[[variable-name]] | incorporação de fragmento reutilizável | fragmentos de template compartilhados com atributos opcionais |
A fonte mais comum de confusão é misturar a forma abreviada de campo de Componente com expressões Facet gerais. Mantenha essa separação clara:
- use
{field}quando o contrato do campo do Componente suportar saída direta de campo ou helpers de campo - use
{{ ... }}ao renderizar expressões gerais sensíveis ao contexto - use
[[variable-name]]quando a solução correta for reuso, não mais lógica de template
Início Rápido
O modelo mental mínimo útil do Facet é:
<section class="hero">
<h1>{{ page.title }}</h1>
{{#if summary}}
<p>{{ summary }}</p>
{{/if}}
[[sales-contact-badge]]
</section>Esse único exemplo já mostra os três blocos de construção mais importantes:
- saída de valor
- estrutura condicional
- composição de fragmento reutilizável
Sintaxe de Saída
Saída de Campo do Componente
Em templates de Componente, a saída direta de campo frequentemente usa a sintaxe com colchete simples:
<h2>{title}</h2>
<p>{summary}</p>Use isso quando o contrato do campo do Componente for simples e orientado a campo.
Para campos com suporte a helpers, a mesma família se estende na sintaxe de helpers:
<img src="{heroImage.webp}" alt="{heroImage.description}">
<div data-form-embed="{contactForm}"></div>
<div data-review-embed="{serviceReview}"></div>Não presuma que todo campo suporte encadeamento de helpers. Verifique a referência do campo proprietário primeiro.
Saída de Expressão Escapada
Use colchetes duplos para saída escapada normal:
<h1>{{ page.title }}</h1>
<p>{{ summary | default("No summary available.") }}</p>Esta é a escolha padrão para texto simples, rótulos, URLs, valores escalares dinâmicos e todos os casos em que o HTML deve ser escapado.
Saída Bruta
Use colchetes triplos quando a fonte for confiável e deva renderizar como HTML:
<div class="prose">
{{{ body }}}
</div>Isto é apropriado para:
- texto rico gerenciado
- fragmentos HTML controlados
- conteúdo editorial confiável
Não use saída bruta para strings arbitrárias não confiáveis.
Comentários
Facet suporta comentários curtos e longos:
{{! short comment }}
{{!--
long comment
spanning multiple lines
--}}Comentários nunca são renderizados na saída.
Sintaxe de Expressão
Expressões são a base da saída dinâmica do template. Elas permitem acessar propriedades aninhadas, chamar métodos no estilo helper, aplicar filtros e usar lógica condicional inline.
Notação de Caminho com Ponto
Acesse propriedades aninhadas com notação por ponto:
{{ page.title }}
{{ page.parent.title }}
{{ page.parent.parent.name }}
{{ user.language.title }}A notação com seta também é aceita em lugares onde autores naturalmente digitam acesso a objetos:
{{ page->parent->title }}
{{#if page->parent->hasChildren}}
...
{{/if}}
{{#each page->children as="child"}}
...
{{/each}}Use o estilo que for mais claro dentro do template atual, mas mantenha consistência dentro de um arquivo.
Chamadas do tipo método
Alguns objetos expõem transformações ou buscas no estilo de método:
{{ page.image.width(800) }}
{{ page.image.size(600, 400) }}
{{ page.image.size(600, 400).webp.url }}Isto é comum para:
- imagens
- coleções
- URLs localizadas por página
- helpers de consulta conscientes da página
Chamadas no estilo método fazem parte do modelo de objeto do Facet, não de execução arbitrária de código em tempo de execução.
Parâmetros Chave-Valor
Alguns helpers aceitam parâmetros nomeados:
{{ page.field name="summary" }}
{{ page.children selector="limit=5" }}
{{ pages.count selector="template=blog-post" }}Use parâmetros nomeados quando o contrato do helper explicitamente os esperar. Isso mantém os templates legíveis e evita sobrecarregar argumentos posicionais.
Expressões Ternárias
Facet suporta lógica ternária de saída:
{{ user.isLoggedin ? "Welcome back!" : "Please sign in." }}
{{ page.summary ? page.summary : "No summary provided." }}Use ternárias para decisões de saída curtas. Se o branching ficar estrutural, prefira um helper de bloco como {{#if}}.
Cadeias de Filtros
Use o operador pipe para transformar valores:
{{ page.title | upper }}
{{ page.body | striptags | truncate(200, "...") }}
{{ published | date("F j, Y") }}
{{ price | currency("$", 2) }}Filtros encadeiam da esquerda para a direita.
Estilos de Argumento de Filtro
Facet aceita argumentos no estilo de parênteses e no estilo de dois-pontos:
{{ page.title | truncate(100, "...") }}
{{ page.title | truncate:100:... }}Ambas as formas são suportadas. Prefira o estilo com parênteses em templates oficiais porque é mais claro e mais fácil de revisar.
Helpers de Bloco
Helpers de bloco fornecem estrutura, não apenas saída escalar.
Facet suporta estes tipos de bloco principais:
| Bloco | Propósito |
|---|---|
{{#if}} | renderização condicional |
{{#each}} | loop sobre arrays ou coleções existentes |
{{#pages}} | consulta um conjunto de páginas |
{{#page}} | consulta uma página |
{{#languages}} | iterar idiomas disponíveis |
{{#deferred}} | renderização diferida compatível com cache |
{{#if}}
Use {{#if}} para renderização condicional:
{{#if summary}}
<p>{{ summary }}</p>
{{/if}}Com else:
{{#if user.isLoggedin}}
<p>Hello, {{ user.name }}.</p>
{{else}}
<p>Please sign in.</p>
{{/if}}Com elseif:
{{#if page.template == "blog-post"}}
<span class="badge">Blog</span>
{{elseif page.template == "case-study"}}
<span class="badge">Case Study</span>
{{else}}
<span class="badge">Page</span>
{{/if}}A variante else if também é aceita:
{{#if page.numChildren > 10}}
<p>Many children</p>
{{else if page.numChildren > 0}}
<p>Some children</p>
{{else}}
<p>No children</p>
{{/if}}Operadores de Comparação
| Operador | Significado | Exemplo |
|---|---|---|
== | igual | page.template == "blog-post" |
!= | diferente | page.status != 1 |
> | maior que | page.numChildren > 5 |
< | menor que | page.numChildren < 3 |
>= | maior ou igual | page.sort >= 0 |
<= | menor ou igual | page.sort <= 10 |
Operadores Lógicos
| Operador | Significado | Exemplo |
|---|---|---|
&& | E | user.isLoggedin && user.isSuperuser |
|| | OU | page.template == "blog-post" || page.template == "news" |
! | NÃO | !user.isGuest |
Regras de Truthiness
Facet segue um modelo prático orientado a templates para truthiness:
| Valor | Verdadeiro? |
|---|---|
null | falso |
false | falso |
"" | falso |
0 | falso |
"0" | falso |
| array vazio ou coleção vazia | falso |
| todo o resto | verdadeiro |
Se a lógica de condição começar a carregar regras de negócio em vez de regras simples de exibição, retorne ao modelo de objeto. Não esconda um design de conteúdo fraco atrás de blocos if aninhados.
{{#each}}
Use {{#each}} quando a coleção já existir no contexto atual:
{{#each page.children as="child"}}
<a href="{{ child.url }}">{{ child.title }}</a>
{{/each}}Com o atalho this:
{{#each page.images}}
<img src="{{ this.url }}" alt="{{ this.description }}">
{{/each}}Com else:
{{#each page.children as="child"}}
<div>{{ child.title }}</div>
{{else}}
<p>No child pages found.</p>
{{/each}}Variáveis de Contexto do Loop
Dentro de blocos de loop, estes valores estão disponíveis:
| Variável | Descrição |
|---|---|
loop.index | índice baseado em zero |
loop.index1 | índice baseado em um |
loop.first | true na primeira iteração |
loop.last | true na última iteração |
loop.length | contagem total de itens |
loop.even | true em índices pares |
loop.odd | true em índices ímpares |
@index | alias abreviado de loop.index |
Exemplo:
{{#each page.children as="child"}}
<div class="{{#if loop.odd}}row-alt{{/if}}">
<span>{{ loop.index1 }}.</span>
{{ child.title }}
</div>
{{/each}}this vs apelidos nomeados
Dentro de {{#each}}, this sempre aponta para o item atual.
{{#each page.children}}
<a href="{{ this.url }}">{{ this.title }}</a>
{{/each}}Se a legibilidade importar, prefira um apelido explícito:
{{#each page.children as="child"}}
<a href="{{ child.url }}">{{ child.title }}</a>
{{/each}}{{#pages}}
Use {{#pages}} quando o template precisar consultar conteúdo em vez de renderizar uma coleção já presente no escopo.
{{#pages selector="template=blog-post, sort=-created, limit=5" as="post"}}
<article>
<h2><a href="{{ post.url }}">{{ post.title }}</a></h2>
<time>{{ post.created | date("F j, Y") }}</time>
<p>{{ post.summary | truncate(200) }}</p>
</article>
{{else}}
<p>No posts found.</p>
{{/pages}}Parâmetros típicos:
| Parâmetro | Descrição |
|---|---|
selector | string seletora de consulta |
as | nome da variável de loop |
Use {{#pages}} para:
- arquivos (archives)
- páginas de listagem
- widgets de conteúdo recente
- coleções de navegação
- blocos de conteúdo dirigidos por consulta
Use {{#each}} quando a coleção já existir. Use {{#pages}} quando o template precisar buscá-la.
{{#page}}
Use {{#page}} quando apenas uma página deve ser consultada:
{{#page path="/about/"}}
<a href="{{ page.url }}">{{ page.title }}</a>
{{/page}}Padrões de busca suportados incluem:
{{#page id="1024"}}...{{/page}}
{{#page path="/about/"}}...{{/page}}
{{#page name="contact"}}...{{/page}}
{{#page selector="template=homepage"}}...{{/page}}Dentro de um bloco {{#page}}, page refere-se à página consultada pela duração desse bloco.
{{#languages}}
Use {{#languages}} para construir UI sensível ao idioma, como seletores de idioma:
<nav class="lang-switch">
{{#languages as="lang"}}
<a href="{{ lang.url }}" {{#if lang.isCurrent}}class="active"{{/if}}>
{{ lang.title }}
</a>
{{/languages}}
</nav>Com um fallback vazio:
{{#languages as="lang"}}
<a href="{{ lang.url }}">{{ lang.title }}</a>
{{else}}
{{! single-language site }}
{{/languages}}Propriedades de idioma úteis incluem:
lang.idlang.namelang.titlelang.isDefaultlang.isCurrentlang.urllang.httpUrllang.locale
{{#deferred}}
Use {{#deferred}} quando a página for pesada em cache, mas parte do conteúdo depender de dados por usuário ou de rápida mudança em tempo de execução.
{{#deferred}}
<span>Welcome, {{ user.name }}!</span>
{{/deferred}}Com dimensionamento de esqueleto (skeleton) customizado:
{{#deferred skeleton-width="12rem" skeleton-height="2em"}}
<div class="user-panel">
<span>{{ user.displayName }}</span>
</div>
{{/deferred}}Use para:
- saudações sensíveis ao usuário
- painéis de conta
- personalização segura para cache
- outros conteúdos que não devem ficar fixos em uma resposta HTML de página totalmente cacheada
deferred deve ser usado de forma intencional. Não envolva tudo dinâmico por padrão.
Objetos de Contexto
Facet expõe um conjunto de objetos de contexto de nível raiz em todas as superfícies de renderização suportadas.
Objetos comuns incluem:
pagepagesuserlanguages/langsitenowattrloopthis
Dentro de templates de Componente, valores de campos do Componente também são expostos no nível raiz:
<h1>{{ title }}</h1>
{{#if showGallery}}
<div class="gallery">
{{#each images as="img"}}
<img src="{{ img.url }}">
{{/each}}
</div>
{{/if}}A referência detalhada de objetos está documentada em:
Limite de Saída de Imagem
A sintaxe de imagem depende de onde o objeto de imagem vem.
Sintaxe de helper do campo image do Componente
<img src="{heroImage.width(1200).webp}" alt="{heroImage.description}">Sintaxe de objeto de imagem de página ou consulta
{{#each page.images as="img"}}
<img src="{{ img.width(800).webp.url }}" alt="{{ img.description }}">
{{/each}}Sintaxe de loop do campo images do Componente
{{#each gallery}}
<img src="{{this.width(1200).webp}}" alt="{{this.description}}">
{{/each}}Não misture essas formas casualmente. O campo proprietário ou o objeto em tempo de execução decide qual sintaxe é correta.
Saída de Helper de Mapa
Campos no estilo mapa podem expor saída orientada a helpers:
{officeLocation}
{officeLocation.width(600)}
{officeLocation.height(400)}
{officeLocation.size(800,500)}Use isso apenas quando o contrato do campo documentá-lo explicitamente.
Incorporação de Variáveis
Variáveis são incorporadas com a sintaxe de colchetes duplos:
[[site-announcement]]
[[cta-badge label="New" tone="accent"]]Dentro do template da Variável, os valores passados estão disponíveis através de attr.
Variáveis são para fragmentos reutilizáveis, não para substituir um design de objeto apropriado. Se o fragmento crescer para um contrato de seção, volte ao design de Componentes.
Marcadores de Incorporação Gerenciados
Formulários e Avaliações (Reviews) tipicamente são renderizados através de marcadores de incorporação gerenciados.
Embed de modelo fixo:
<div data-form-embed="enterprise-demo-request"></div>
<div data-review-embed="customer-success-reviews"></div>Embed respaldado por campo dentro de um Componente reutilizável:
<div data-form-embed="{contactForm}"></div>
<div data-review-embed="{serviceReview}"></div>Regra de decisão:
- embed fixo quando o template possui um fluxo de trabalho gerenciado estável
- embed respaldado por campo quando autores devem escolher o modelo gerenciado durante a autoria
Orientações de Uso
- mantenha a lógica do template legível
- prefira contratos de campo fortes em vez de truques inteligentes no template
- use
{{#if}}para estrutura, não para esconder um design de conteúdo fraco - use
{{#each}}quando a coleção já existir - use
{{#pages}}quando o template precisar consultar a coleção - use Variáveis para pequenos fragmentos reutilizáveis
- retorne ao design de Componente ou Lista quando a lógica do template ficar muito complexa
Erros Comuns
Evite estes padrões:
- usar saída bruta onde a saída escapada é mais segura
- misturar a forma abreviada de campo de Componente e expressões Facet genéricas sem entender a diferença
- resolver um problema de modelo de conteúdo apenas com condicionais
- construir um único template gigantesco e aninhado em vez de clarificar limites de objeto
- repetir o mesmo fragmento em vários templates em vez de extrair uma Variável
- usar sintaxe de helper de campo em campos que não a suportam
Guia Rápido de Decisão
need to show one value -> {field} or {{ expr }}
need trusted HTML output -> {{{ expr }}}
need to show content conditionally -> {{#if}}
need to loop existing items -> {{#each}}
need to query content -> {{#pages}} or {{#page}}
need language-aware navigation -> {{#languages}}
need cache-safe dynamic personalization -> {{#deferred}}
need one reusable fragment -> [[variable-name]]
need a field-specific helper output -> {field.helper}
need a full reusable section contract -> return to Component design