Capítulo 3.14 · Parte II · O ofício
Configuração: páginas compostas
Modelos de página para as páginas compostas: quadros, grupos, decoração, herança e variantes de recto e verso, os estilos de rótulo das âncoras de uma imagem e os avisos que um modelo pode dar
Em poucas palavras
Esta página trata dos modelos de página. Um modelo é uma página desenhada nos ajustes: caixas com nome, chamadas quadros, com o lugar de cada uma, o tamanho até o qual podem crescer e a aparência. O Markdown de uma página composta depois preenche esses quadros pelo nome, então o texto nunca guarda posições e os ajustes nunca guardam texto. Um modelo pode partir de outro e mudar só alguns quadros, e pode ser diferente nas páginas pares e nas ímpares. A página também traz os estilos de rótulo para as palavras colocadas sobre uma imagem, e cada aviso que um modelo pode dar com o jeito de corrigi-lo.
#Modelos de página
Uma página composta é uma página que tira a forma de um modelo de página da configuração e o conteúdo do Markdown de um bloco ::::page{template="…"}. O modelo dá nome a retângulos, chamados quadros; o Markdown manda cada parte do conteúdo para um quadro pelo nome (o seu encaixe). A geometria nunca aparece no Markdown, e o texto do conteúdo nunca aparece no modelo. A propriedade pageTemplates guarda os modelos do livro:
const config: PostextConfig = {
calloutStyles: [{ id: 'caja-azul' }, { id: 'tab-titulo' }],
pageTemplates: [
{
id: 'tema-cajas',
decoration: {
elements: [
{ kind: 'image', id: 'fondo', resourceId: '{attr.fondo}', decorative: true,
placement: { anchor: { to: 'bleed', edge: 'top-left' }, size: { width: 'fill', height: 'fill' } } },
],
},
frames: [
{ name: 'titulo', takes: 'h1', style: 'tab-titulo' },
{ name: 'texto', flow: true },
{ name: 'dinero', style: 'caja-azul', padding: { right: { value: 62, unit: 'mm' } } },
{ name: 'dinero-fotos', layer: 2, width: { value: 60, unit: 'mm' },
placement: { anchor: { to: '#dinero', edge: 'top-right' } } },
],
groups: [
{ name: 'pagina', kind: 'stack', gap: { value: 6, unit: 'mm' }, frames: ['titulo', 'texto', 'dinero'] },
],
},
],
};Um modelo que define só o seu id e um quadro é uma página inteira com esse quadro ocupando a área de texto. Todos os outros campos são opcionais:
| Propriedade | Tipo | Padrão | Descrição |
|---|---|---|---|
id | string | obrigatório | O nome que um bloco de página pede (template="tema-cajas"). Único entre os modelos: um segundo com o mesmo id é ignorado. |
name | string | o id | O nome exibido no Sandbox. A diagramação nunca o lê. |
extends | string | nenhum | O id de um modelo do qual este parte. Veja Herança e variantes. |
area | 'content' | 'trim' | 'bleed' | 'content' | O retângulo ao qual as posições dos quadros se referem. 'content' é a área de texto da página, espelhada nas pares e ímpares como o texto corrido; 'trim' é a página refilada; 'bleed', a página com a sangria. |
grid | { columns, rows, columnGap?, rowGap? } | nenhuma | Divide a área em células, de modo que um quadro ou um grupo pode ser posicionado por célula (grid: { col: 2, row: 1, cols: 2 }, contando a partir de 1) em vez de por placement. Os espaços valem 0 por padrão. |
frames | FrameConfig[] | [] | Os quadros, na ordem do modelo: a ordem em que são medidos e a que desempata. Veja Quadros. |
groups | FrameGroupConfig[] | [] | Pilhas e fileiras de quadros que dividem o espaço. Veja Grupos. |
decoration | DesignSlot | nenhuma | Imagens, fios e caixas pintados com a página, na linguagem de elementos dos cabeços e rodapés. Os elementos de texto só levam marcadores ({pageNumber}, {chapterTitle}, {attr.x} para um atributo do bloco de página). Um elemento pode se ancorar a um quadro ou a um grupo ('#dinero') e então se move com ele. A decoração é posicionada depois dos quadros e nunca empurra o texto. |
header, footer | DesignSlot | false | herdados | O cabeço e o fólio da página. Sem valor, a página mantém os do seu capítulo; false os esconde. |
spread | boolean | false | O modelo descreve duas páginas espelhadas diagramadas como uma só folha. Uma página dupla sempre começa numa página par num livro da esquerda para a direita (numa ímpar num da direita para a esquerda), com uma página em branco antes dela quando necessário. |
gutter | Dimension | 0 | Numa página dupla, a faixa junto à lombada que os quadros deixam livre, a menos que definam crossGutter: true. |
variants | { recto?, verso? } | nenhuma | Mudanças para uma página ímpar (recto) ou uma par (verso), escritas como o próprio modelo. O lado é o físico, então funcionam tanto os livros da esquerda para a direita quanto os da direita para a esquerda. |
overflowTemplate | string | este modelo | O modelo das páginas acrescentadas quando um quadro continua na página seguinte (overflow.). Sem valor, a página acrescentada usa este modelo com apenas os quadros que continuam preenchidos. |
bodyStyle | string | nenhum | Um estilo de parágrafo para o texto da página, como os estilos de título têm. |
palette | string | nenhuma | Uma paleta própria para a página, como os estilos de título e as partes têm. |
role | string | 'composed' | O papel de página que os elementos de design com um filtro pages enxergam. |
#Quadros
Um quadro é um retângulo com nome que recebe conteúdo diagramado. O seu name é o encaixe que o Markdown pede, e é único no seu modelo (um grupo também não pode ter o nome de um quadro, já que as âncoras nomeiam os dois do mesmo jeito).
Um quadro é posicionado pela sua célula de grid quando o modelo tem grade e, senão, pelo seu placement, que funciona como o de um elemento de design: uma âncora ('container' é a área, 'page', 'bleed', ou '#name' para outro quadro ou grupo), uma borda, um deslocamento e um tamanho. Um quadro ancorado a outro se move com ele. Sem nenhum dos dois, o quadro ocupa a área inteira.
| Propriedade | Tipo | Padrão | Descrição |
|---|---|---|---|
name | string | obrigatório | O nome do encaixe. |
placement | ElementPlacement | a área inteira | Âncora, borda, deslocamento e tamanho, como no posicionamento de elementos. Ignorado quando uma célula da grade posiciona o quadro. |
grid | { col, row, cols?, rows? } | nenhuma | Uma célula da grade do modelo, contando a partir de 1, que ocupa cols × rows células (1 por padrão). Uma célula que passa da grade é trazida de volta para dentro dela. Ignorado quando o modelo não tem grade. |
width, height | Dimension | { percent } | 'auto' | 'fill' | 'fill', 'auto' | Um comprimento fixo, uma porcentagem da área (de 0 a 100), 'auto' (o tamanho próprio do conteúdo) ou 'fill' (o que sobra até a borda à qual o quadro está ancorado). Sem valor, o quadro lê placement.size e depois o padrão: a largura inteira e a altura do seu conteúdo. Um quadro de texto precisa de uma medida, então uma largura 'auto' só faz sentido num quadro que contém uma única imagem (a largura da imagem na altura do quadro). Um valor que o motor não consegue usar (um comprimento negativo, uma unidade desconhecida) é lido como o padrão. |
minWidth, maxWidth, minHeight, maxHeight | Dimension | nenhum | Limites para um tamanho 'auto' ou 'fill' e para o espaço que um grupo dá ou tira. O mínimo prevalece sobre o máximo, e um tamanho fixo fora deles é trazido para dentro (frameMinMax avisa dos dois casos). |
style | string | sem caixa | O id de um estilo de boxe: os quadros são desenhados com estilos de boxe (fundo, borda, preenchimento, faixa, ícone, aba de rótulo, título). As palavras de uma aba vêm do Markdown (:::frame{slot="dinero" label="El dinero"}). Os ajustes de boxe sobre onde uma caixa vai no texto corrido (placement, span, columns, width, fixed…) não se aplicam a um quadro. |
padding | { top?, right?, bottom?, left? } | o do estilo | Substitui o preenchimento do estilo lado a lado: espaço para as fotos que ficam sobre uma caixa, por exemplo. |
layer | number | 1 | Ordem de pintura. A decoração é a camada 0; uma camada negativa é pintada por baixo dela. |
rotate | number | 0 | Graus, no sentido horário. A caixa e o seu conteúdo giram juntos. |
verticalAlign | 'top' | 'middle' | 'bottom' | 'justify' | 'top' | Onde o conteúdo fica num quadro mais alto que ele. |
columns, columnGap | number, Dimension | 1, o do estilo | Colunas dentro do quadro. |
exclude | 'none' | 'push' | 'none' | 'push': o texto dos outros quadros contorna o retângulo deste. |
flow | boolean | false | O quadro recebe o conteúdo que não nomeia nenhum encaixe. |
takes | 'h1' … 'h6' | nenhum | O quadro recebe o primeiro título desse nível que não nomeia nenhum encaixe, então o título de uma página é só um # Título no começo do bloco. |
next | string | nenhum | Uma cadeia: o conteúdo que não cabe continua no quadro com esse nome, na mesma página. |
overflow.continueIn | string | nenhum | Onde continua o conteúdo que não cabe: '#frame' (outro quadro da página, como next), 'next-page' (o mesmo quadro numa página acrescentada depois desta) ou 'template:<id>' (uma página desse modelo). |
overflow.mark | string | false | a do idioma | A marca no fim de um trecho cortado. Sem valor, a palavra de continuação do idioma do documento (a mesma das tabelas divididas); false não põe nenhuma. |
fit.shrinkText | boolean | true | Quando nada mais faz o conteúdo caber, o texto pode ser diagramado menor. |
fit.minScale | number | 0.9 | A menor escala de texto, acima de 0 e no máximo 1 (um valor maior é lido como 1). |
fit.scaleImages, fit.imageMinScale | boolean, number | true, 0.8 | Se as imagens do quadro podem ser diagramadas menores, e até que escala. |
pin | boolean | false | O quadro nunca se move nem muda de tamanho, para uma caixa que precisa ficar alinhada com a arte. Um grupo se arranja em volta dele. |
grow, shrink, priority | number | 0 | Como o quadro divide o espaço do seu grupo: grow fica com uma parte do espaço que sobra, shrink deixa o quadro devolver espaço, e os quadros com priority mais baixa cedem primeiro. |
optional | boolean | false | Nenhum aviso quando o Markdown não manda nada para o quadro. |
crossGutter | boolean | false | Numa página dupla, o quadro pode atravessar a faixa da lombada. |
writingMode, direction | 'horizontal-tb' | 'vertical-rl', 'ltr' | 'rtl' | os da página | Uma caixa vertical numa página horizontal, ou o contrário. |
remove | boolean | false | Num modelo que estende outro, ou numa variante: remove o quadro herdado com esse nome. |
#Grupos
Um grupo é uma pilha (de cima para baixo) ou uma fileira (do início ao fim) de quadros que dividem o espaço e se movem juntos. Dentro de um grupo, a posição própria dos quadros na direção do grupo é ignorada: o grupo os arranja em ordem, com gap entre eles. Quando o texto de um quadro cresce, os quadros que vêm depois se deslocam. Um grupo é uma caixa à qual quadros e decoração podem se ancorar ('#pagina').
| Propriedade | Tipo | Padrão | Descrição |
|---|---|---|---|
name | string | obrigatório | Único entre os quadros e grupos do modelo. |
kind | 'stack' | 'row' | 'stack' | De cima para baixo, ou do início ao fim. |
frames | string[] | [] | Os quadros do grupo, na sua ordem na página. Um quadro pertence a um grupo no máximo; um nome que não é nenhum quadro do modelo, ou um quadro já listado, é pulado. |
gap | Dimension | 0 | O espaço entre dois quadros do grupo. |
placement, grid | como nos quadros | a caixa dos seus quadros | A caixa própria do grupo. Sem valor, a caixa em volta das caixas declaradas dos seus quadros. |
align | 'start' | 'center' | 'end' | 'space-between' | 'start' | Para onde vai o espaço que sobra quando nenhum quadro do grupo cresce. |
remove | boolean | false | Num modelo que estende outro, ou numa variante: remove o grupo herdado. |
#Herança e variantes
Um modelo com extends parte do modelo que nomeia (que por sua vez pode estender outro) e muda só o que escreve:
- Um campo como
area,headerouoverflowTemplatesubstitui o do pai.gridé mesclado chave a chave.spread,guttereroletambém são herdados;id,nameeextendssão do próprio modelo. framesegroupssão mesclados pelo nome: uma entrada com o nome de uma herdada muda os campos que escreve e mantém o resto (fit,overflowepaddingsão mesclados chave a chave;placementé substituído inteiro);remove: truea remove; um nome novo é acrescentado depois dos herdados.- Os elementos de decoração são mesclados por
iddo mesmo jeito; um elemento com um id novo, ou sem id, é acrescentado.
variants.recto e variants.verso são escritos como um modelo e mesclados do mesmo jeito, numa página ímpar ou numa par. Eles se aplicam depois de toda a cadeia de extends, primeiro a variante da raiz. Uma página dupla tem os dois lados, então nenhuma variante se aplica a ela.
pageTemplates: [
{ id: 'tema', frames: [{ name: 'texto', flow: true }, { name: 'margen', width: { value: 30, unit: 'mm' },
placement: { anchor: { to: 'container', edge: 'top-left' } } }],
variants: { recto: { frames: [{ name: 'margen', placement: { anchor: { to: 'container', edge: 'top-right' } } }] } } },
{ id: 'tema-sin-margen', extends: 'tema', frames: [{ name: 'margen', remove: true }] },
]Quando o Sandbox salva um modelo, um valor igual ao padrão nunca é descartado: num modelo que estende outro, ou numa variante, esse valor substitui o do pai.
No código, resolvePageTemplate(config, id, { parity }) devolve um modelo com a cadeia mesclada, a variante do lado aplicada, todos os padrões preenchidos e cada referência resolvida como os avisos abaixo descrevem; validatePageTemplates(config) devolve os avisos.
#Estilos de rótulo
A propriedade labelStyles dá nome às aparências dos rótulos colocados sobre uma imagem: os mares e as cidades de um mapa, as partes de um esquema. Um rótulo fica numa âncora da imagem (um ponto guardado com o recurso, como os falantes de quadrinhos) e usa o estilo que a âncora ou o rótulo nomeia.
labelStyles: [
{ id: 'mar', fontStyle: 'italic', textTransform: 'uppercase', letterSpacing: 0.12,
color: { hex: '#2b6ca3', model: 'hex' } },
{ id: 'ciudad', fontWeight: 600, halo: { color: { hex: '#ffffff', model: 'hex' }, width: { value: 0.6, unit: 'pt' } } },
]| Propriedade | Tipo | Padrão | Descrição |
|---|---|---|---|
id | string | obrigatório | O nome que âncoras e rótulos usam. |
name | string | o id | O nome exibido no Sandbox. |
paragraphStyle | string | nenhum | Um estilo de parágrafo do qual o rótulo toma a fonte; os campos abaixo o substituem. |
fontFamily, fontSize, fontWeight | string, Dimension, number | os do texto principal | A fonte do rótulo. |
fontStyle | 'normal' | 'italic' | 'normal' | Redondo ou itálico. |
color | ColorValue | a do texto principal | A cor das letras. |
textTransform | 'none' | 'uppercase' | 'none' | Maiúsculas, como os mapas usam para mares e países. |
letterSpacing | number | 0 | Espaço extra entre as letras, em ems. |
halo | { color, width } | nenhum | Um contorno atrás das letras, para que elas se leiam sobre uma imagem carregada. |
background, padding | ColorValue, Dimension | nenhum | Uma placa atrás do rótulo, e o espaço em volta do seu texto. |
minScale | number | 0.85 | Até que tamanho um rótulo pode ser reduzido quando não cabe na sua largura. |
#Campos de rótulo de uma âncora
As âncoras de uma imagem (Resource.anchors, os pontos que os quadrinhos usam para os falantes) aceitam alguns campos opcionais para rótulos. São frações da imagem, então valem em todos os idiomas e com qualquer recorte da imagem. Os quadrinhos os ignoram.
| Campo | Tipo | Padrão | Descrição |
|---|---|---|---|
width | number | a própria do rótulo | A medida do rótulo, como fração da largura da imagem: um nome longo quebra em duas linhas dentro dela. |
align | 'start' | 'center' | 'end' | 'center' | Qual lado do rótulo fica no ponto da âncora. |
verticalAlign | 'top' | 'middle' | 'bottom' | 'middle' | Qual borda do rótulo fica na altura da âncora. |
rotate | number | 0 | Graus, no sentido horário, em volta do ponto da âncora: o nome de um rio ao longo do seu curso. |
style | string | nenhum | Um id de labelStyles. Um rótulo que nomeia o seu próprio estilo o substitui. |
#Avisos dos modelos de página
No resto da configuração, o motor ignora uma chave que não conhece. Os modelos de página e os estilos de rótulo, por outro lado, são verificados, e cada problema é um aviso de configuração no postext check e no painel Verificações do Sandbox. O campo path desses avisos é um ponteiro JSON para o campo com problema: /pageTemplates/3/frames/2/style, /pageTemplates/0/variants/recto/frames/1/next, /resources/4/anchors/0/style. Quando o campo foi herdado, o ponteiro nomeia o modelo que o escreveu. Um aviso que nomeia um id ou um nome inexistente também sugere o existente mais parecido.
Uma chave digitada errado de um modelo, quadro, grupo, grade, fit, overflow, variante ou estilo de rótulo é um unknownConfigKey; uma palavra fora das opções de um ajuste (area, verticalAlign, exclude, takes, kind, align, writingMode, direction, fontStyle, textTransform) é um unknownConfigValue, e o ajuste mantém o seu padrão. Um modelo sem id, ou um quadro ou grupo sem name, é ignorado com um unknownConfigValue nesse campo.
| Aviso | Causa | Solução |
|---|---|---|
templateDuplicate | Dois modelos têm o mesmo id. O primeiro é usado e o posterior é ignorado. | Renomeie um deles, ou apague a cópia. |
templateExtendsCycle | Seguindo extends se volta ao mesmo modelo (a → b → a). Todos os modelos do ciclo, e todos os que estendem algum deles, são descartados: nenhuma página pode usá-los. | Remova o extends de um modelo do ciclo. |
templateExtendsUnknown | extends nomeia um id que nenhum modelo tem. O modelo é usado sozinho, sem herdar nada. | Corrija o id (o aviso sugere o mais parecido), ou acrescente o modelo pai. |
frameDuplicate | Dois quadros, ou dois grupos, de uma mesma lista têm o mesmo name, ou um grupo tem o nome de um quadro. A entrada posterior é ignorada; uma âncora para esse nome lê o quadro. | Dê a cada quadro e a cada grupo um nome próprio. Para mudar um quadro herdado, escreva uma única entrada com o nome dele. |
frameStyleUnknown | O style de um quadro não nomeia nenhum estilo de boxe. O quadro é desenhado sem caixa. | Corrija o id, ou acrescente o estilo a calloutStyles. |
frameAnchorUnknown | Um quadro, um grupo ou um elemento de decoração está ancorado a '#name' e o modelo não tem nenhum quadro, grupo ou elemento com esse nome; ou quadros e grupos estão ancorados uns nos outros num ciclo (também através de um grupo sem âncora própria, cuja caixa é a dos seus quadros). A âncora é lida como 'container', a área. | Ancore a um quadro ou grupo que exista, ou quebre o ciclo ancorando um deles à área. |
frameMinMax | Um mínimo é maior que o seu máximo (minHeight 40mm > maxHeight 30mm), ou um width ou height fixo fica fora deles. O mínimo prevalece, um tamanho fixo é trazido para dentro dos limites e used diz o que o quadro ocupa. Comprimentos em unidades diferentes são comparados na resolução da página, e os ems no corpo do texto principal. | Faça o mínimo não passar do máximo, ou tire o limite que o tamanho fixo contradiz. |
groupFrameUnknown | Os frames de um grupo listam um nome que não é nenhum quadro do modelo (talvez removido por um modelo filho ou por uma variante). O grupo o pula. | Corrija o nome, ou tire-o da lista. |
groupFrameTwice | Um quadro aparece em dois grupos, ou duas vezes no mesmo. Um quadro pertence a um só grupo: a aparição posterior é pulada. | Deixe o quadro no grupo com o qual ele se move. |
frameChainLoop | Quadros continuam uns nos outros num ciclo através de next ou de overflow. (a → b → a). O elo que fecha o ciclo é descartado, então a cadeia termina no quadro anterior a ele. | Termine a cadeia no seu último quadro: remova o next dele, ou faça-o continuar na página seguinte. |
overflowTargetUnknown | Um next não nomeia nenhum quadro do modelo; um overflow.continueIn não nomeia nenhum quadro ('#x') nem nenhum modelo ('template:x'), ou não está em nenhuma das formas '#frame', 'next-page' e 'template:<id>'; ou overflowTemplate não nomeia nenhum modelo. O conteúdo que não cabe não continua ali. | Corrija o nome ou o id, ou escreva uma das três formas. |
labelStyleUnknown | Uma âncora de uma imagem nomeia um style que labelStyles não tem. O aviso nomeia o recurso. Os rótulos dessa âncora usam a aparência padrão. | Corrija o id do estilo na âncora, ou acrescente o estilo a labelStyles. |
A versão da configuração é a 15 desde os modelos de página (pacotes escritos antes continuam carregando sem mudanças: nada do que uma configuração anterior diz muda de sentido).