Tudo o que se segue vive sob `duxt` no teu `app/app.config.ts`. Como a
combinação funciona, e porque os arrays substituem em vez de acrescentar, está
em [Configuração](/getting-started/configuration).

## Site

| Chave              | Por omissão          | O que controla                                          |
| :----------------- | :------------------- | :-------------------------------------------------------- |
| `title`            | **nenhum**           | O nome na barra de navegação e no título de SEO           |
| `logo`              | **nenhum**           | Um logótipo em vez do par de ícone e nome — ver abaixo       |
| `version`          | **nenhuma**          | O distintivo ao lado                                      |
| `organization`     | **nenhuma**          | Quem publica o site, para schema.org — ver abaixo         |
| `locales`          | os sete              | Que idiomas da camada este site serve                     |
| `breadcrumb`       | `true`               | `false` retira o trilho por cima do título da página      |
| `pageIcon`          | **nenhum**           | Ícone para páginas sem um próprio — o da secção ganha     |
| `packageManagers`  | pnpm, npm, yarn, bun | Que gestores um bloco de comando oferece, por essa ordem  |
| `requestSamples`   | sete de doze       | Que amostras de código o cliente de ensaio oferece — ver [Amostras de pedido](/reference/openapi/request-samples) |
| `sampleLanguages`  | **nenhuma**        | Gramáticas Shiki adicionais, para `x-codeSamples` numa linguagem que nenhuma amostra nomeia |
| `poweredBy`        | ligado               | `false` retira a linha «Powered by duxt» do rodapé        |

## Comportamento

| Chave | Por omissão | Efeito |
| :-- | :-- | :-- |
| `copy.models` | ChatGPT, Claude | Destinos pela ordem do menu; a lista substitui o padrão |
| `contributors.avatarUrl` | template GitHub | `{username}` é substituído por contribuidor |
| `toc.depth` | `3` | Título mais profundo no índice |
| `toc.scrollOffset` | `96` | Linha de ativação sob o topo da janela |
| `search.fuzzy` | `0.35`, `3`, `20` | Limiar Fuse, comprimento mínimo e limite |
| `search.recentPages` | `5` | Páginas recentes; `0` oculta a lista |
| `openapi.exampleDepth` | `6` | Profundidade máxima dos exemplos derivados |
| `openapi.schemaDepth` | `8` | Profundidade máxima da árvore de schema |
| `shortcuts.singleCharacter` | `true` | Teclas globais `?`, `[` e `]`; `⌘/Ctrl+K` permanece |
| `analytics.track` | **nenhum** | Callback neutro quanto ao provider por interação |

```ts [app/app.config.ts]
export default defineAppConfig({
  duxt: {
    copy: {
      models: [
        {
          label: 'O meu assistente',
          icon: 'simple-icons:openai',
          url: 'https://example.com/new?prompt='
        }
      ]
    },
    contributors: {
      avatarUrl: 'https://github.com/{username}.png?size=96'
    },
    toc: { depth: 4, scrollOffset: 112 },
    search: {
      fuzzy: { threshold: 0.3, minMatchCharLength: 3, limit: 15 },
      recentPages: 8
    },
    openapi: { exampleDepth: 6, schemaDepth: 8 },
    shortcuts: { singleCharacter: false }
  }
})
```

As listas substituem os padrões. Uma lista `copy.models` vazia remove destinos
externos, não as ações de copiar e ver a fonte. `search.recentPages: 0` não
guarda entradas novas. As opções fuzzy só afetam aproximações depois de uma
pesquisa Content vazia. Sem callback de analytics nada é enviado;
consentimento, provider e armazenamento pertencem ao site consumidor.

### `logo`

| Campo     | Tipo     | Notas                                                        |
| :-------- | :------- | :------------------------------------------------------------ |
| `src`     | `string` | A marca. Sem valor fica o ícone genérico ao lado de `title`  |
| `srcDark` | `string` | Trocado por CSS sob a classe `dark`, não por script          |
| `alt`     | texto    | Recai em `title`                                             |

Definir um é [Dá identidade ao teu site](/guides/brand-your-site).

### `organization`

O nó `Organization` que os motores de busca e os resumos de IA leem para nomear
uma fonte. Ausente até o definires: o duxt renderiza a documentação de outros e
não adivinha de quem.

| Campo  | Tipo     | Notas                                                           |
| :----- | :------- | :---------------------------------------------------------------- |
| `name` | texto    | O nome de quem publica. Sem ele não se publica nada             |
| `url`  | `string` | O site dessa entidade. Recorre a `site.url`                     |
| `logo` | `string` | Absoluto, ou um caminho desde a raiz; quadrado e com 112px ou mais |


## Anúncios

Um aviso para todo o site — uma versão, uma migração ou uma manutenção. Nada é
renderizado nem ocupa espaço até escreveres uma entrada.

```ts [app/app.config.ts]
announcements: [
  {
    text: { 'en-GB': 'Version 2 is out.', 'pt-PT': 'A versão 2 foi lançada.' },
    link: { label: 'Ler as notas', to: '/releases/v2' }
  },
  {
    id: 'march-maintenance',
    text: 'Manutenção agendada no domingo a partir das 09:00 UTC.',
    placement: 'below-header',
    startsAt: '2026-03-01T09:00:00Z',
    endsAt: '2026-03-08T09:00:00Z'
  }
],
announcementOptions: { maxVisible: 1 }
```

A lista é desenhada por ordem: uma versão e uma indisponibilidade são dois
anúncios, e o fim de um não deve retirar o outro.

| Campo       | Tipo                                               | Notas                                                            |
| :---------- | :------------------------------------------------- | :--------------------------------------------------------------- |
| `text`      | texto                                              | Literal, chave i18n ou registo por locale                        |
| `link`      | ligação                                            | Uma ação; as restantes pertencem à página ligada             |
| `placement` | `above-header`, `below-header` ou `above-content`   | Posição; `above-header` por omissão                           |
| `startsAt`  | `string`                                           | Início; qualquer valor que `Date` analise                       |
| `endsAt`    | `string`                                           | Fim                                                              |
| `id`        | `string`                                           | Identidade de fecho; derivada do conteúdo e da ligação se faltar |

### Onde são apresentados

| Posição          | Local                                                            |
| :--------------- | :--------------------------------------------------------------- |
| `above-header`   | Largura total no topo, acima da navegação — o padrão          |
| `below-header`   | Largura total sob a navegação e acima das barras laterais      |
| `above-content`  | Na coluna do documento, com avisos de versão e tradução       |

`above-content` pertence à coluna do documento, por isso aparece em páginas
de documentação e não numa landing page sem essa coluna.

`announcementOptions.maxVisible` limita quantos anúncios uma posição mostra
ao mesmo tempo. Um número limita **cada** posição, um objeto limita-as
separadamente (`{ 'above-header': 1 }`), e `null`, uma chave omitida ou a
ausência de `maxVisible` significa ilimitado. Fechar o aviso superior promove o
seguinte.

### Quando são apresentados

`startsAt` e `endsAt` são lidos no **browser** contra o relógio do leitor. O
anúncio começa e termina sem deploy nem recarregar a página. A janela é
semiaberta: visível desde `startsAt` e até `endsAt`.

Escreve um offset quando o instante exato importa
(`2026-03-01T09:00:00Z`). Sem fuso horário usa-se a hora local do leitor. Uma
data inválida é tratada como ausente, para que um erro não esconda o aviso em
silêncio.

### Fecho

Um anúncio fechado permanece fechado durante navegação, reloads e mudanças de
idioma. É a sua **identidade** que fica guardada:

- com `id`, exatamente essa string independente do locale; mudá-la volta a
  mostrar o anúncio a todos,
- sem `id`, um valor derivado de todas as variantes de `text` e `link`; mudar o
  texto cria um anúncio novo, reordenar as chaves de locale não.

Define `id` para corrigir o texto sem voltar a apresentá-lo. Os fechos vivem
apenas em `localStorage`; chaves de anúncios removidos são descartadas. Como o
relógio e os fechos pertencem ao browser, a faixa é desenhada depois da
hidratação.

A superfície do componente está em
[DuxtAnnouncements](/reference/components/layout/duxt-announcements).

## Navegação e ligações

Uma entrada de secção é uma ligação mais um campo próprio:

| Campo      | Tipo     | Notas                                                              |
| :--------- | :------- | :------------------------------------------------------------------ |
| `pageIcon` | `string` | Ícone para as páginas desta secção que não definam um. Prevalece sobre `duxt.pageIcon`; o frontmatter de uma página continua a ganhar |

Útil onde as páginas não podem levar ícone — o frontmatter de um ADR está fixo em
`title`, `description`, `status` e `date`, pelo que o registo de decisões seria
apresentado sem nenhum.

| Chave        | Por omissão      | O que controla                                                |
| :----------- | :--------------- | :-------------------------------------------------------------- |
| `navigation` | uma entrada      | Ligações da barra; uma entrada com `children` vira um menu       |
| `sections`   | **vazio**        | A segunda linha da barra — as partes de topo da documentação     |
| `links`      | **vazio**        | Ligações com ícone à direita da barra                            |
| `aside`      | só o título      | `title` e `links` sob o índice                                   |
| `footer`     | **vazio**        | `copyright` e `legal`                                            |
| `landing`    | uma ação | A página em `/`           |

A maioria é entregue vazia, por duas razões diferentes. `links`, `aside.links`,
`footer.legal`, `title`, `version` e o texto da página inicial nomeiam um projeto
concreto — um repositório, uma comunidade, um aviso legal, um nome, uma versão
publicada, uma frase sobre o que faz — e pertencem a quem gere o site. `sections` nomeia as partes de
uma **árvore** de documentação, e a árvore é tua: quatro separadores a apontar
para nomes de pasta que a camada adivinhasse não levariam a lado nenhum.
Define-o quando a tua documentação tiver secções; até lá a linha não é
apresentada e a barra lateral mostra a árvore inteira, que é a forma certa para
documentação sem secções.

**Uma linha por fonte.** Uma entrada pertence à fonte sob cujo prefixo de URL
está, e a linha mostra as entradas da fonte em que o leitor se encontra — um
site com a documentação na raiz e outra coisa em `/demo` escreve assim uma só
lista `sections`, e cada área desenha a sua parte dela. Uma secção gerada por
baixo de uma área (`/demo/openapi`) pertence a essa área em vez de ser uma. Um site
com uma única fonte tem uma área, cada entrada está lá dentro, e a linha é
exactamente a lista tal como foi escrita.

### A página inicial

A página em `/` desenha três faixas, e cada uma está ausente até a sua chave
estar definida.

| Chave         | Por omissão              | O que desenha                                       |
| :------------ | :----------------------- | :---------------------------------------------------- |
| `badge`       | **nenhum**               | A pastilha por cima do título — texto, ou um objeto de distintivo |
| `headline`    | **nenhum**               | O `h1`; recai sobre `title`                            |
| `description` | **nenhuma**              | O parágrafo por baixo, e a meta description da página  |
| `actions`     | uma, «Ler a documentação» | Os botões do bloco principal; uma ação sem `to` resolve para a primeira secção |
| `command`     | **nenhum**               | Um comando de instalação copiável sob os botões        |
| `preview`     | **nenhum**               | Uma página deste site, incorporada numa janela de browser |
| `features`    | **vazio**                | A grelha de cartões                                    |

`command` é uma `string` simples, não texto: um comando de shell é igual em
todos os idiomas, e um traduzido por engano é um que não corre. A camada não
entrega nenhum — não sabe como se chama o teu projeto, pela mesma razão por que
`links` está vazio.

Não há chamada à ação final, deliberadamente. Os botões do bloco principal são a
chamada; repeti-los sob uma grelha de cartões pede a um leitor acabado de chegar que
decida duas vezes.

`badge` é entregue vazio pela mesma razão que `links`: uma pastilha por cima do
título diz algo sobre o estado de um projeto — «beta», «a v2 saiu» — e a camada
nada sabe sobre o estado do teu. Um texto é a forma curta; o objeto acrescenta
ícone, cor e destino.

| Campo de `badge` | Tipo      | Notas                                                     |
| :--------------- | :-------- | :--------------------------------------------------------- |
| `label`          | texto     | Obrigatório. `{version}` é substituído pela `version` do site |
| `icon`           | `string`  | Qualquer nome do Iconify                                    |
| `variant`        | `string`  | `default`, `secondary`, `outline`, `success`, `destructive` |
| `to`             | `string`  | Faz de toda a pastilha uma ligação                          |
| `external`       | `boolean` | O separador novo                                            |

```ts [app/app.config.ts]
badge: {
  label: '{version} lançada',
  icon: 'lucide:rocket',
  variant: 'success',
  to: 'https://github.com/acme/sdk/releases/latest',
  external: true
}
```

`preview` é uma janela viva, não uma imagem. Incorpora uma página **deste** site
num enquadramento de browser que o leitor pode percorrer, navegar e cujo tema
pode mudar sem sair da página inicial. O enquadramento só é montado quando a
faixa entra no ecrã, e nunca durante a renderização no servidor — um iframe no
HTML inicial é um segundo carregamento completo a competir com o primeiro.

| Campo de `preview` | Tipo     | Notas                                                     |
| :----------------- | :------- | :---------------------------------------------------------- |
| `to`               | `string` | A página a incorporar; por omissão, a primeira secção        |
| `height`           | `string` | Qualquer comprimento CSS. Por omissão `32rem`, `24rem` sob `sm` |
| `src`              | `string` | Uma captura EM VEZ da página viva                            |
| `srcDark`          | `string` | Serve o modo escuro; sem ele, `src` serve ambos              |
| `alt`              | texto    | O texto alternativo da imagem e o nome acessível do enquadramento |

::callout{type="tip" title="Uma captura é a opção mais barata"}
O enquadramento vivo carrega a aplicação uma segunda vez. Um site que prefira
não pagar isso define `src` e obtém a mesma janela à volta de uma imagem fixa.
::

### Forma de uma ligação

| Campo         | Tipo                | Notas                                            |
| :------------ | :------------------ | :------------------------------------------------ |
| `label`       | texto               | Obrigatório                                       |
| `to`          | `string`            | Um caminho de documentação é localizado; um URL não |
| `icon`        | `string`            | Qualquer nome do Iconify, p. ex. `lucide:rocket`   |
| `description` | texto               | Mostrada num menu suspenso da barra                |
| `external`    | `boolean`           | O separador novo e a seta — nunca o roteamento     |
| `children`    | `DuxtLink[]`        | Transforma uma entrada da barra num menu suspenso  |
| `variant`     | variante de botão   | Só `landing.actions`                               |

Todos os campos marcados como _texto_ aceitam um literal, uma chave i18n ou um
registo por locale — ver [Localização](/concepts/localisation).

## Fontes

| Chave           | Lida em              | O que controla                              |
| :-------------- | :------------------- | :------------------------------------------ |
| `sources`       | tempo de compilação  | As fontes de documentação                    |
| `sourceOptions` | tempo de compilação  | Como essas fontes se tornam prefixos de URL  |
| `versions`      | execução             | Substitui as versões derivadas quando precisam de rótulos ou descrições |

Ambas as chaves de fonte têm [uma página própria](/reference/sources).
`locales` é a terceira chave de compilação: alterar qualquer uma das três exige
nova compilação.

## O feed

`/rss.xml` está vazio até `feed.path` nomear uma secção:

```ts
feed: { path: '/changelog', title: 'o meu projeto — lançamentos' }
```

Desligado por omissão, de propósito. Um feed é uma lista de coisas que
**aconteceram**, e uma página de referência editada não é um acontecimento — um
site que publica cada edição como item ensina os seus leitores a cancelar a
subscrição. Os itens são ordenados pela `date` da própria página, recorrendo ao
último commit que lhe tocou, e só a versão predefinida de cada fonte contribui,
por isso um changelog versionado não repete cada entrada uma vez por versão.


A secção para a qual costuma apontar é um
[histórico de versões](/reference/changelog), cujas páginas trazem cada uma a sua
`date`.

## Gerado, não escrito

| Chave              | Escrito por        | Contém                                           |
| :----------------- | :----------------- | :----------------------------------------------- |
| `resolvedSources`  | a compilação       | O manifesto: que coleção serve que prefixo        |
| `layerVersion`     | a compilação       | A versão do duxt, para o rodapé                   |
| `layerRepository`  | a compilação       | O repositório do duxt, para o rodapé              |

Definir qualquer um dos três à mão é sobrescrito na compilação seguinte.