Receitas / Recipes

Common patterns for real-world templates

Receitas curtas para problemas reais que aparecem ao escrever templates: listas de opcoes que se repetem, colunas de imagem em tabelas, achatamento de querystring, e quando preferir tabela vs campos repetidos.

Short recipes for real problems you hit while authoring templates: repeated option lists, image columns in tables, querystring flattening, and when to prefer a table over repeated fields.

1. Listas de opcoes compartilhadas / Shared option lists

Quando o mesmo conjunto de opcoes aparece em varios campos (ex: lista de partidos politicos, lista de paises, lista de canais), o padrao atual e repetir o array options inline em cada campo. Verbose mas explicito e compativel com qualquer ferramenta que leia o JSON.

When the same option set appears in many fields (e.g. political parties, countries, channels), the current pattern is to repeat the inline options array on every field. Verbose but explicit, and compatible with any tool that reads the JSON.

{
  "key": "b1p", "name": "bar1Party", "label": "Bar 1 — party",
  "type": "dropdown",
  "default": "PL",
  "options": [
    { "value": "PL",   "text": "PL" },
    { "value": "PT",   "text": "PT" },
    { "value": "PSDB", "text": "PSDB" }
    /* ... 27 mais ... */
  ]
}
Roadmap: uma sintaxe de referencia ("options": "@parties" resolvida contra schema.optionLists.parties) esta planejada mas nao implementada ainda. Por enquanto, repita o array.
Roadmap: a reference syntax ("options": "@parties" resolved against schema.optionLists.parties) is planned but not implemented yet. For now, repeat the array.

Dica de autoria: gere o config.json a partir de uma fonte unica (script Node, template Jinja, etc.) para evitar erro de copia/colagem. O editor le apenas o JSON final.

Authoring tip: generate config.json from a single source (Node script, Jinja template, etc.) to avoid copy-paste drift. The editor reads only the final JSON.

2. Coluna de imagem com MAM picker / Image column with MAM picker

Em uma tabela, defina a coluna como type: "image" e adicione accept. Ao clicar na celula, o editor abre o mesmo picker de assets do MAM usado pelo campo file raiz.

In a table, set the column to type: "image" and add accept. Clicking the cell opens the same MAM asset picker used by the top-level file field.

{
  "key": "bars", "name": "bars", "label": "Barras",
  "type": "table",
  "maxRows": 4,
  "columns": [
    { "key": "n", "label": "Candidato", "type": "text" },
    { "key": "f", "label": "Foto",      "type": "image", "accept": "image", "width": 90 },
    { "key": "v", "label": "Valor",     "type": "number", "min": 0, "max": 100 }
  ]
}

O valor armazenado por linha e o caminho do asset (string), por exemplo assets/lula.avif. O template recebe esse caminho ja resolvido na querystring.

The stored per-row value is the asset path (string), e.g. assets/lula.avif. The template receives this resolved path in the querystring.

3. Achatamento de tabela na querystring / Table querystring flattening

Cada celula vira um parametro com o padrao key + indice. Um parametro lider nomeDoCampo=N indica a quantidade de linhas. Para o exemplo do item 2, com 2 linhas:

Each cell becomes a parameter with the pattern key + index. A leading fieldName=N indicates the row count. For the example in section 2, with 2 rows:

?bars=2&n1=Lula&f1=assets/lula.avif&v1=42&n2=Bolsonaro&f2=assets/bolso.avif&v2=39

No template, leia com URLSearchParams:

In the template, read with URLSearchParams:

const p = new URLSearchParams(location.search);
const count = parseInt(p.get('bars') || '0', 10);

const rows = [];
for (let i = 1; i <= count; i++) {
  rows.push({
    name:  p.get(`n${i}`) || '',
    photo: p.get(`f${i}`) || '',
    value: parseFloat(p.get(`v${i}`) || '0')
  });
}

console.log(rows);
// [{ name: 'Lula', photo: 'assets/lula.avif', value: 42 }, { ... }]

4. Tabela vs campos repetidos / Table vs repeated fields

Quando o template tem N entidades parecidas (8 barras, 5 candidatos, 3 colunas), ha duas formas de modelar:

When the template has N similar entities (8 bars, 5 candidates, 3 columns), there are two ways to model it:

Padrao / PatternQuando usar / When to use
Tabela / Table — um campo type: "table" com columns Numero de linhas e variavel (1 a N). Cada linha tem mesmas colunas. Editor mostra UI tabular escalavel.
Row count is variable (1 to N). Each row has the same columns. Editor shows a scalable tabular UI.
Campos repetidos / Repeated fieldsb1n, b1v, b2n, b2v... Numero fixo (sempre 8 barras), ou cada "linha" tem schema unico, ou voce precisa de tips/labels diferentes por entidade.
Fixed count (always 8 bars), or each "row" has a unique schema, or you need different tips/labels per entity.

Recomendacao: use tabela quando possivel — e mais facil de manter, mais facil de preencher e reduz a duplicacao no schema.

Recommendation: use a table when possible — easier to maintain, easier to fill in, and reduces schema duplication.

5. Consumidor minimo de widget / Minimal widget consumer

Padrao recomendado para o app.js de um template: ler URLSearchParams, normalizar valores, renderizar uma vez.

Recommended pattern for a template's app.js: read URLSearchParams, normalize values, render once.

const p = new URLSearchParams(location.search);

// helpers
const str  = (k, d = '') => p.get(k) ?? d;
const bool = (k, d = false) => (p.get(k) ?? (d ? '1' : '0')) === '1';
const num  = (k, d = 0) => parseFloat(p.get(k) ?? String(d));

// values (use the field "name", not the "key" — that's just a convention)
const data = {
  title:    str('t', 'Hello'),
  bgColor:  str('bg', '#000'),
  showTime: bool('show', true),
  ratio:    num('pct', 0)
};

// render
document.body.style.background = data.bgColor;
document.body.querySelector('h1').textContent = data.title;
if (!data.showTime) document.body.querySelector('.time').remove();

6. Defaults inteligentes / Smart defaults

Templates rodam em standalone (sem editor). Nesse caso, todos os defaults do schema entram em jogo. Escolha defaults visualmente plausiveis para que o template renderize bem ao ser aberto sem nenhum parametro.

Templates run standalone (without an editor). In that case, all schema defaults come into play. Choose visually plausible defaults so the template renders well when opened with no params.

7. Versionamento do schema / Schema versioning

meta.version deve seguir semver-ish: aumente o major quando a forma do schema mudar de modo incompativel (renomeou um campo, mudou um tipo). O backend pode usar essa versao para aplicar migracoes em configuracoes salvas.

meta.version should follow semver-ish: bump major when the schema shape changes in an incompatible way (renamed a field, changed a type). The backend can use this version to migrate saved configurations.

Mudancas seguras (adicionar um campo opcional, mudar um tip, expandir options) podem aumentar apenas o patch (1.2.0 → 1.2.1). Mudancas de comportamento aumentam o minor; mudancas de schema que quebram, o major.
Safe changes (add an optional field, change a tip, expand options) can bump only the patch (1.2.0 → 1.2.1). Behavior changes bump the minor; breaking schema changes bump the major.

← Schema metadata  ·  Back to Overview