feat: add series functionality (#406)

Co-authored-by: welpo <welpo@users.noreply.github.com>
This commit is contained in:
ZzMzaw
2024-11-08 00:01:30 +01:00
committed by GitHub
parent 57a0a8e1a0
commit 0253799f23
52 changed files with 1824 additions and 75 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

View File

@@ -267,6 +267,34 @@ Si configures `tag_sorting = "frequency"`, s'ordenaran segons el nombre de publi
---
### Sèries
Per a una explicació detallada, consulta la [documentació de sèries](@/blog/series/index.ca.md).
#### Enllaç per saltar a les publicacions
| Pàgina | Secció | `config.toml` | Segueix la jerarquia | Requereix JavaScript |
|:------:|:-------:|:-------------:|:------------------:|:-------------------:|
| ❌ | ✅ | ✅ | ✅ | ❌ |
Per defecte, apareix automàticament un enllaç "Salta a les publicacions" al costat del títol de la sèrie quan una sèrie té un contingut de més de 2000 caràcters:
{{ dual_theme_image(light_src="blog/series/img/jump_to_series_posts_light.webp", dark_src="blog/series/img/jump_to_series_posts_dark.webp" alt="enllaç per saltar a les publicacions de la sèrie", full_width=true) }}
Estableix `show_jump_to_posts = true` per forçar l'activació de la funció i `show_jump_to_posts = false` per desactivar-la.
#### Indexació de pàgines de sèries
| Pàgina | Secció | `config.toml` | Segueix la jerarquia | Requereix JavaScript |
|:------:|:-------:|:-------------:|:------------------:|:-------------------:|
| ❌ | ✅ | ✅ | ✅ | ❌ |
Per defecte, les pàgines de sèries s'indexen (usant una indexació basada en 1) segons el `sort_by` de la secció de sèries.
Estableix `post_listing_index_reversed = true` per invertir aquest índex.
---
## Integració amb repositoris Git
| Pàgina | Secció | `config.toml` | Segueix la jerarquia | Requereix JavaScript |

View File

@@ -267,6 +267,34 @@ Si configuras `tag_sorting = "frequency"`, se ordenarán según el número de pu
---
### Series
Para una explicación detallada, consulta la [documentación de series](@/blog/series/index.es.md).
#### Enlace para saltar a las publicaciones
| Página | Sección | `config.toml` | Sigue jerarquía | Requiere JavaScript |
|:------:|:-------:|:-------------:|:------------------:|:-------------------:|
| ❌ | ✅ | ✅ | ✅ | ❌ |
Por defecto, aparece automáticamente un enlace "Saltar a publicaciones" junto al título de la serie cuando una serie tiene un contenido de más de 2000 caracteres:
{{ dual_theme_image(light_src="blog/series/img/jump_to_series_posts_light.webp", dark_src="blog/series/img/jump_to_series_posts_dark.webp" alt="enlace para saltar a las publicaciones de la serie", full_width=true) }}
Establece `show_jump_to_posts = true` para forzar la activación de la función y `show_jump_to_posts = false` para desactivarla.
#### Indexación de páginas de series
| Página | Sección | `config.toml` | Sigue la jerarquía | Requiere JavaScript |
|:------:|:-------:|:-------------:|:------------------:|:-------------------:|
| ❌ | ✅ | ✅ | ✅ | ❌ |
Por defecto, las páginas de series se indexan (usando una indexación basada en 1) según el `sort_by` de la sección de series.
Establece `post_listing_index_reversed = true` para invertir el índice.
---
## Integración con repositorios Git
| Página | Sección | `config.toml` | Sigue la jerarquía | Requiere JavaScript |

View File

@@ -272,6 +272,34 @@ Setting `tag_sorting = "frequency"` will sort them by number-of-posts (descendin
---
### Series
For a detailed explanation of the series feature, see the [series documentation](@/blog/series/index.md).
#### Jump to posts link
| Page | Section | `config.toml` | Follows Hierarchy | Requires JavaScript |
|:----:|:-------:|:-------------:|:-----------------:|:-------------------:|
| ❌ | ✅ | ✅ | ✅ | ❌ |
By default, a "Jump to posts" link automatically appears next to the series title when a series has a content over 2000 characters:
{{ dual_theme_image(light_src="blog/series/img/jump_to_series_posts_light.webp", dark_src="blog/series/img/jump_to_series_posts_dark.webp" alt="jump to series posts link", full_width=true) }}
Set `show_jump_to_posts = true` to force the feature on and `show_jump_to_posts = false` to force it off.
#### Series pages indexation
| Page | Section | `config.toml` | Follows Hierarchy | Requires JavaScript |
|:----:|:-------:|:-------------:|:-----------------:|:-------------------:|
| ❌ | ✅ | ✅ | ✅ | ❌ |
By default, series page are indexed (using a 1-based indexing) as per the series section `sort_by`.
Set `post_listing_index_reversed = true` to reverse this index.
---
## Git Repository Integration
| Page | Section | `config.toml` | Follows Hierarchy | Requires JavaScript |

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@@ -0,0 +1,424 @@
+++
title = "Guia completa sobre sèries"
date = 2024-11-08
description = "Aprèn a organitzar les teves publicacions en sèries seqüencials, perfectes per a tutorials, cursos i històries de diverses parts."
[taxonomies]
tags = ["funcionalitat", "tutorial", "preguntes freqüents", "sèries"]
[extra]
quick_navigation_buttons = true
toc = true
mermaid = true
social_media_card = "social_cards/ca_blog_series.jpg"
+++
Una sèrie organitza publicacions relacionades en ordre seqüencial, similar als capítols d'un llibre. A diferència de les etiquetes, que simplement agrupen contingut relacionat, les sèries suggereixen un ordre específic de lectura de principi a fi.
Les publicacions dins d'una sèrie no necessiten publicar-se de forma consecutiva; la funció de sèries reuneix publicacions temàticament vinculades en una seqüència coherent.
El següent diagrama il·lustra com les publicacions de la sèrie (3, 5 i 8) existeixen dins del flux principal del blog mentre mantenen la seva pròpia seqüència ordenada dins de Sèrie 1.
{% mermaid(full_width=true) %}
flowchart
subgraph main[BLOG]
P1[Post 1]
P2[P2]
P3[P3]
P4[P4]
P5[P5]
P6[P6]
P7[P7]
P8[P8]
P9[P9]
end
subgraph series1[SÈRIE 1]
PS1["Post Sèrie 1 (=P3)"]
PS2["Post Sèrie 2 (=P5)"]
PS3["Post Sèrie 3 (=P8)"]
end
P3 o-.-o PS1
P5 o-.-o PS2
P8 o-.-o PS3
{% end %}
## Inici ràpid
1. Crea un directori per a la teva sèrie
2. Crea `_index.md` al directori de la sèrie
3. Configura el front matter de `_index.md`:
{{ add_src_to_code_block(src="series/_index.md") }}
```toml
title = "Aprenent Rust"
template = "series.html"
sort_by = "slug"
transparent = true
[extra]
series = true
```
4. Crea els teus articles de la sèrie en aquest directori
Vols saber-ne més? Continua llegint!
## Com funcionen les sèries?
Una sèrie és simplement una secció que tabi gestiona de manera especial. Per a més detalls sobre seccions, consulta la [documentació de Zola](https://www.getzola.org/documentation/content/section/).
Prenent l'exemple del diagrama anterior, l'estructura de directoris seria així:
```txt
content/
_index.md
blog/
_index.md
post1/
index.md
post2/
index.md
post4/
index.md
post6/
index.md
post7/
index.md
post9/
index.md
serie1/
_index.md
post3/
index.md
post5/
index.md
post8/
index.md
```
Per crear una sèrie, necessites:
1. Utilitzar la plantilla `series.html`
2. Establir `series = true` a la configuració `[extra]` de la secció
3. Activar `transparent = true` per integrar les publicacions de la sèrie amb la secció del blog principal
La pàgina principal de la sèrie mostra un resum seguit d'una llista de totes les publicacions a la sèrie:
{{ dual_theme_image(light_src="blog/series/img/series_light.webp", dark_src="blog/series/img/series_dark.webp" alt="una sèrie", full_width=true) }}
## Saltar a les publicacions
Si el contingut d'una sèrie (el Markdown després del frontmatter a `_index.md`) supera els 2000 caràcters, apareix un enllaç "Salta a les publicacions" al costat del títol de la sèrie.
{{ dual_theme_image(light_src="blog/series/img/jump_to_series_posts_light.webp", dark_src="blog/series/img/jump_to_series_posts_dark.webp" alt="enllaç per saltar a les publicacions de la sèrie", full_width=true) }}
Per forçar l'activació o desactivació d'aquesta funció, configura `show_jump_to_posts` a la secció `[extra]` de la teva secció de sèries o a `config.toml`. Aquesta configuració segueix [la jerarquia](@/blog/mastering-tabi-settings/index.ca.md#jerarquia-de-configuracio).
## Pàgines de sèries i ordre
Totes les pàgines a la secció de sèries seran pàgines de sèrie. Les pàgines s'ordenaran segons el `sort_by` de la secció.
Tot i que les sèries mantenen el seu propi ordre intern, romanen independents del flux cronològic de la secció principal (per exemple, `blog/`) gràcies a la configuració `transparent`.
### Opcions d'ordre
Tria entre aquests mètodes d'ordre, cadascun amb els seus avantatges:
{% wide_container() %}
`sort_by` | avantatges | desavantatges
---------|------------|---------------
`slug` | L'ordre de les pàgines és explícit a la ruta (per exemple, `example.com/blog/series1/01-series-post-un`). | Cada pàgina de la sèrie ha de tenir el prefix corresponent.
`weight` | L'ordre de les pàgines és fàcil de configurar de forma transparent.<br>La primera publicació té pes `1`, la segona pes `2` i així successivament. | Cada pàgina de la sèrie ha de tenir el seu pes configurat.
`date` | L'ordre de les pàgines es pot configurar una sola vegada a la configuració de la secció. No cal fer res a cada pàgina. | L'ordre de les pàgines s'ha d'invertir perquè la primera pàgina sol ser la més antiga. Això només es pot aconseguir paginant la secció (`paginate_by = 9999`) i invertint el seu ordre (`paginate_reversed = true`).
{% end %}
{{ admonition(type="danger", title="Versió de Zola per ordenar per data", text="Per invertir correctament les dates, es requereix Zola v0.19.3+ (no publicada) perquè la informació de paginació estigui disponible a través de la funció `get_section`. En cas contrari, qualsevol cosa que depengui de l'ordre de les pàgines de la sèrie no serà correcta (per exemple, pàgina anterior/següent, llistes ordenades i no ordenades...) Vegeu [Zola PR #2653](https://github.com/getzola/zola/pull/2653).") }}
### Indexació de pàgines
Les pàgines en una sèrie s'indexen començant des d'1, seguint el seu ordre `sort_by`. Per invertir la indexació (fent que la primera pàgina tingui l'índex més alt), afegeix aquesta configuració a `_index.md` o `config.toml`:
```toml
[extra]
post_listing_index_reversed = true # Per defecte és false si no es configura
```
{{ dual_theme_image(light_src="blog/series/img/series_reversed_light.webp", dark_src="blog/series/img/series_reversed_dark.webp" alt="una sèrie amb índexs invertits", full_width=true) }}
Aquesta configuració segueix [la jerarquia](@/blog/mastering-tabi-settings/index.ca.md#jerarquia-de-configuracio).
## Plantilles d'introducció i conclusió
Els articles d'una sèrie poden tenir seccions automàtiques d'introducció i conclusió. Aquestes es configuren al `_index.md` de la teva sèrie. Un exemple bàsic:
{{ add_src_to_code_block(src="series/_index.md") }}
```toml
[extra.series_intro_templates]
default = "Aquest article és part de la sèrie $SERIES_HTML_LINK."
[extra.series_outro_templates]
default = "Gràcies per llegir la part $SERIES_PAGE_INDEX de $SERIES_HTML_LINK!"
```
Les seccions d'introducció i conclusió tenen les seves pròpies classes CSS (`series-page-intro` i `series-page-outro`), que et permeten personalitzar la seva aparença mitjançant [CSS personalitzat](@/blog/mastering-tabi-settings/index.ca.md#estils-css-personalitzats).
### Tipus de plantilles
El sistema de sèries utilitza diferents plantilles segons la posició de l'article a la sèrie:
- `next_only` - Utilitzat per al primer article (té article següent però no anterior)
- `middle` - Utilitzat per a articles amb articles anterior i següent
- `prev_only` - Utilitzat per a l'últim article (té article anterior però no següent)
- `default` - Plantilla per defecte utilitzada quan no existeix una plantilla específica per a la posició
El sistema determina automàticament quina plantilla utilitzar segons la posició de l'article. Les plantilles es defineixen a la configuració de la sèrie (`_index.md`), com `extra.series_intro_templates` i `extra.series_outro_templates`:
{{ add_src_to_code_block(src="series/_index.md") }}
```toml
[extra.series_intro_templates]
next_only = "Benvingut a la part 1! Següent: $NEXT_HTML_LINK"
middle = "Anterior: $PREV_HTML_LINK | Següent: $NEXT_HTML_LINK"
prev_only = "El capítol final! Anteriorment: $PREV_HTML_LINK"
default = "Part $SERIES_PAGE_INDEX de $SERIES_PAGES_NUMBER"
```
Totes les plantilles són opcionals. La selecció de plantilles segueix un sistema de prioritat:
1. Si existeix una plantilla específica per a la posició (`next_only`, `middle`, o `prev_only`), s'utilitzarà aquesta
2. Si no, s'utilitza la plantilla `default`
3. Si no es defineix cap plantilla, no es mostrarà informació de la sèrie
Mira l'[exemple de plantilla](#exemple-de-plantilla) per veure un exemple més elaborat.
### Ubicació al contingut
Per defecte:
- Les introduccions de sèrie apareixen a l'inici del teu article
- La conclusió apareix al final (abans de les notes al peu, si n'hi ha)
Pots controlar exactament on apareixen utilitzant `<!-- series_intro -->` i `<!-- series_outro -->` al teu Markdown:
```markdown
Aquest paràgraf apareix abans de la introducció de la sèrie.
<!-- series_intro -->
Contingut principal de l'article.
<!-- series_outro -->
## Recursos d'aprenentatge
Contingut addicional...
[^1]: Les notes al peu sempre apareixeran al final.
```
## Variables
Les plantilles de sèries utilitzen un sistema flexible de variables que et permet:
1. Fer referència a informació de la sèrie (títol, enllaços)
2. Afegir navegació entre articles
3. Mostrar indicadors de progrés
4. Incloure informació personalitzada utilitzant les teves pròpies variables
Les variables són marcadors que comencen amb `$` i es reemplacen amb contingut real quan es construeix el teu lloc. Per exemple, `$SERIES_HTML_LINK` es converteix en un enllaç clicable a la pàgina índex de la teva sèrie.
Hi ha tres tipus de variables:
- [Variables bàsiques de sèrie](#variables-basiques-de-serie): Informació general sobre la sèrie
- [Variables de navegació](#variables-de-navegacio): Enllaços a articles anterior/següent
- [Variables personalitzades](#variables-personalitzades): Els teus propis marcadors per a informació addicional
### Variables bàsiques de sèrie
{% wide_container() %}
| Variable | Disponibilitat | Retorna | Descripció | Exemple d'ús | Exemple de sortida |
|----------|---------------|----------|------------|--------------|-------------------|
| `$SERIES_TITLE` | Sempre | Text | Títol de la sèrie en text pla | `Part de $SERIES_TITLE` | Part d'Aprenent Rust |
| `$SERIES_PERMALINK` | Sempre | Text | URL a l'índex de la sèrie | `[Veure totes les publicacions]($SERIES_PERMALINK)` | [Veure totes les publicacions](/series/learn-rust) |
| `$SERIES_HTML_LINK` | Sempre | HTML | Enllaç llest per usar a la sèrie | `Benvingut a $SERIES_HTML_LINK!` | Benvingut a <a href="/series/learn-rust">Aprenent Rust</a>! |
| `$SERIES_PAGES_NUMBER` | Sempre | Nombre | Total d'articles a la sèrie | `Una sèrie de $SERIES_PAGES_NUMBER parts` | Una sèrie de 5 parts |
| `$SERIES_PAGE_INDEX` | Sempre | Nombre | Posició de l'article actual | `Part $SERIES_PAGE_INDEX de $SERIES_PAGES_NUMBER` | Part 3 de 5 |
| `$SERIES_PAGES_OLIST` | Sempre | HTML | Llista ordenada de tots els articles | `Articles a la sèrie: $SERIES_PAGES_OLIST` | Articles a la sèrie: <ol><li>Article actual</li><li><a href="...">Altres articles</a></li></ol> |
| `$SERIES_PAGES_ULIST` | Sempre | HTML | Llista desordenada de tots els articles | `Articles a la sèrie: $SERIES_PAGES_ULIST` | Articles a la sèrie: <ul><li>Article actual</li><li><a href="...">Altres articles</a></li></ul> |
{% end %}
### Variables de navegació
{% wide_container() %}
| Variable | Disponibilitat | Retorna | Descripció | Exemple d'ús | Exemple de sortida |
|----------|---------------|----------|------------|--------------|-------------------|
| `$PREV_TITLE` | Existeix anterior | Text | Títol de l'article anterior | `Anteriorment: $PREV_TITLE` | Anteriorment: Configurant el teu entorn |
| `$PREV_PERMALINK` | Existeix anterior | Text | URL a l'article anterior | `[← Enrere]($PREV_PERMALINK)` | [← Enrere](/series/learn-rust/setup) |
| `$PREV_HTML_LINK` | Existeix anterior | HTML | Enllaç llest per usar a l'anterior | `Llegeix primer $PREV_HTML_LINK` | Llegeix primer <a href="/series/learn-rust/setup">Configurant el teu entorn</a> |
| `$PREV_DESCRIPTION` | Existeix anterior | Text | Descripció de l'article anterior | `Resum: $PREV_DESCRIPTION` | Resum: Configurant Rust |
| `$NEXT_TITLE` | Existeix següent | Text | Títol del següent article | `Següent: $NEXT_TITLE` | Següent: Patrons avançats |
| `$NEXT_PERMALINK` | Existeix següent | Text | URL al següent article | `[Continuar →]($NEXT_PERMALINK)` | [Continuar →](/series/learn-rust/patterns) |
| `$NEXT_HTML_LINK` | Existeix següent | HTML | Enllaç llest per usar al següent | `Continua amb $NEXT_HTML_LINK` | Continua amb <a href="/series/learn-rust/patterns">Patrons avançats</a> |
| `$NEXT_DESCRIPTION` | Existeix següent | Text | Descripció del següent article | `Properament: $NEXT_DESCRIPTION` | Properament: Aprèn sobre les característiques avançades de pattern matching en Rust |
{% end %}
### Referència al primer article
{% wide_container() %}
| Variable | Disponibilitat | Retorna | Descripció | Exemple d'ús | Exemple de sortida |
|----------|---------------|----------|------------|--------------|-------------------|
| `$FIRST_TITLE` | Sempre | Text | Títol del primer article | `Comença amb $FIRST_TITLE` | Comença amb Introducció a Rust |
| `$FIRST_HTML_LINK` | Sempre | HTML | Enllaç llest per usar al primer article | `Comença a $FIRST_HTML_LINK` | Comença a <a href="/series/learn-rust/intro">Introducció a Rust</a> |
{% end %}
### Exemple de plantilla
{{ admonition(type="tip", title="Variables HTML vs text", text="Utilitza variables HTML (que acaben en `_HTML_LINK`) quan vulguis enllaços preparats per usar. Utilitza variables de text (que acaben en `_TITLE` o `_PERMALINK`) quan vulguis més control sobre el format.") }}
{{ add_src_to_code_block(src="series/_index.md") }}
```toml
# Introducció
[extra.series_intro_templates]
next_only = """
Benvingut a $SERIES_HTML_LINK! Aquesta sèrie de $SERIES_PAGES_NUMBER parts t'ensenyarà Rust des de zero.
Següent: $NEXT_HTML_LINK - $NEXT_DESCRIPTION
"""
middle = """
📚 Part $SERIES_PAGE_INDEX de $SERIES_PAGES_NUMBER a $SERIES_HTML_LINK
Anterior: $PREV_HTML_LINK
Següent: $NEXT_HTML_LINK
"""
prev_only = """
Benvingut a l'última part de $SERIES_HTML_LINK!
Ets nou? Comença amb $FIRST_HTML_LINK per construir una base sòlida.
Anterior: $PREV_HTML_LINK
"""
# Plantilla de respatller
default = "Aquest article és part de la sèrie $SERIES_HTML_LINK."
# Conclusió
[extra.series_outro_templates]
next_only = """
Gràcies per llegir! 🙌
Continua el teu viatge amb $NEXT_HTML_LINK, on $NEXT_DESCRIPTION
O revisa l'esquema complet de la sèrie [$SERIES_TITLE]($SERIES_PERMALINK).
"""
middle = """
---
📝 Navegació de la sèrie
- Anterior: $PREV_HTML_LINK
- Següent: $NEXT_HTML_LINK
- [Resum de la sèrie]($SERIES_PERMALINK)
"""
prev_only = """
🎉 Felicitats! Has completat $SERIES_HTML_LINK.
Vols repassar? Aquí vam començar: $FIRST_HTML_LINK
O revisa el que acabem de veure a $PREV_HTML_LINK.
"""
# Respatller.
default = """
---
Aquest article és la part $SERIES_PAGE_INDEX de $SERIES_PAGES_NUMBER a $SERIES_HTML_LINK.
"""
```
### Variables personalitzades
Les plantilles de sèries admeten variables personalitzades per incloure informació addicional a tota la teva sèrie. El procés té dos passos:
1. Primer, defineix els teus **marcadors** a la configuració de la teva sèrie (`_index.md`):
{{ add_src_to_code_block(src="series/_index.md") }}
```toml
[extra]
series = true
series_template_placeholders = ["$POSITION", "$TOPIC", "$DIFFICULTY"]
```
2. Després, a cada article de la sèrie, proporciona els valors per a aquests marcadors a `series_template_variables`:
{{ add_src_to_code_block(src="series/article.md") }}
```toml
[extra.series_template_variables]
position = "primer"
topic = "Variables i tipus"
difficulty = "Principiant"
```
### Ús de variables personalitzades
Pots usar les teves variables personalitzades a qualsevol plantilla, juntament amb les variables integrades:
{{ add_src_to_code_block(src="series/_index.md") }}
```toml
[extra.series_intro_templates]
default = """
Aquest és l'article $POSITION a $SERIES_HTML_LINK.
Tema d'avui: $TOPIC
Nivell de dificultat: $DIFFICULTY
"""
```
{{ admonition(type="warning", text="Encara que els marcadors es defineixen en majúscules (`$POSITION`), els noms de variables a `series_template_variables` han d'estar en minúscules (`position`).") }}
### Exemple amb variables personalitzades
{{ add_src_to_code_block(src="series/_index.md") }}
```toml
# A la configuració de la sèrie.
[extra]
series = true
series_template_placeholders = ["$LEARNING_TIME", "$KEY_CONCEPTS"]
series_intro_templates.default = """
📚 Part $SERIES_PAGE_INDEX de $SERIES_PAGES_NUMBER
⏱️ Temps estimat: $LEARNING_TIME
🔑 Conceptes clau: $KEY_CONCEPTS
"""
```
{{ add_src_to_code_block(src="series/02-learning-rust/index.md") }}
```toml
# En un article de la sèrie.
[extra.series_template_variables]
learning_time = "30 minuts"
key_concepts = "Funcions, gestió d'errors, coincidència de patrons"
```
Això generarà:
```txt
📚 Part 2 de 5
⏱️ Temps estimat: 30 minuts
🔑 Conceptes clau: Funcions, gestió d'errors, coincidència de patrons
```
{{ admonition(type="warning", title="Variables que falten", text="Si uses un marcador a les teves plantilles però no proporciones el seu valor a `series_template_variables`, la compilació fallarà amb un error que llista les variables que falten.") }}

View File

@@ -0,0 +1,424 @@
+++
title = "Guía completa sobre series"
date = 2024-11-08
description = "Aprende a organizar tus publicaciones en series secuenciales, perfectas para tutoriales, cursos e historias de varias partes."
[taxonomies]
tags = ["funcionalidad", "tutorial", "preguntas frecuentes", "series"]
[extra]
quick_navigation_buttons = true
toc = true
mermaid = true
social_media_card = "social_cards/es_blog_series.jpg"
+++
Una serie organiza publicaciones relacionadas en orden secuencial, similar a los capítulos de un libro. A diferencia de las etiquetas, que simplemente agrupan contenido relacionado, las series sugieren un orden específico de lectura de principio a fin.
Las publicaciones dentro de una serie no necesitan publicarse de forma consecutiva; la función de series reúne publicaciones temáticamente vinculadas en una secuencia coherente.
El siguiente diagrama ilustra cómo las publicaciones de la serie (3, 5 y 8) existen dentro del flujo principal del blog mientras mantienen su propia secuencia ordenada dentro de Serie 1.
{% mermaid(full_width=true) %}
flowchart
subgraph main[BLOG]
P1[Post 1]
P2[P2]
P3[P3]
P4[P4]
P5[P5]
P6[P6]
P7[P7]
P8[P8]
P9[P9]
end
subgraph series1[SERIE 1]
PS1["Post Serie 1 (=P3)"]
PS2["Post Serie 2 (=P5)"]
PS3["Post Serie 3 (=P8)"]
end
P3 o-.-o PS1
P5 o-.-o PS2
P8 o-.-o PS3
{% end %}
## Inicio rápido
1. Crea un directorio para tu serie
2. Crea `_index.md` en el directorio de la serie
3. Configura el front matter de `_index.md`:
{{ add_src_to_code_block(src="series/_index.md") }}
```toml
title = "Aprendiendo Rust"
template = "series.html"
sort_by = "slug"
transparent = true
[extra]
series = true
```
4. Crea tus artículos de la serie en este directorio
¿Quieres saber más? ¡Sigue leyendo!
## ¿Cómo funcionan las series?
Una serie es simplemente una sección que tabi maneja de manera especial. Para más detalles sobre secciones, consulta la [documentación de Zola](https://www.getzola.org/documentation/content/section/).
Tomando el ejemplo del diagrama anterior, la estructura de directorios sería así:
```txt
content/
_index.md
blog/
_index.md
post1/
index.md
post2/
index.md
post4/
index.md
post6/
index.md
post7/
index.md
post9/
index.md
serie1/
_index.md
post3/
index.md
post5/
index.md
post8/
index.md
```
Para crear una serie, necesitas:
1. Usar la plantilla `series.html`
2. Establecer `series = true` en la configuración `[extra]` de la sección
3. Activar `transparent = true` para integrar las publicaciones de la serie con la sección del blog principal
La página principal de la serie muestra un resumen seguido de una lista de todas las publicaciones en la serie:
{{ dual_theme_image(light_src="blog/series/img/series_light.webp", dark_src="blog/series/img/series_dark.webp" alt="una serie", full_width=true) }}
## Saltar a las publicaciones
Si el contenido de una serie (el Markdown después del frontmatter en `_index.md`) supera los 2000 caracteres, aparece un enlace "Saltar a publicaciones" junto al título de la serie.
{{ dual_theme_image(light_src="blog/series/img/jump_to_series_posts_light.webp", dark_src="blog/series/img/jump_to_series_posts_dark.webp" alt="enlace para saltar a las publicaciones de la serie", full_width=true) }}
Para forzar la activación o desactivación de esta función, configura `show_jump_to_posts` en la sección `[extra]` de tu sección de series o en `config.toml`. Esta configuración sigue [la jerarquía](@/blog/mastering-tabi-settings/index.es.md#jerarquia-de-configuracion).
## Páginas de series y orden
Todas las páginas en la sección de series serán páginas de serie. Las páginas se ordenarán según el `sort_by` de la sección.
Aunque las series mantienen su propio orden interno, permanecen independientes del flujo cronológico de la sección principal (por ejemplo, `blog/`) gracias a la configuración `transparent`.
### Opciones de orden
Elige entre estos métodos de orden, cada uno con sus ventajas:
{% wide_container() %}
`sort_by` | ventajas | desventajas
---------|-------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
`slug` | El orden de las páginas es explícito en la ruta (por ejemplo, `example.com/blog/series1/01-series-post-uno`). | Cada página de la serie debe tener el prefijo correspondiente.
`weight` | El orden de las páginas es fácil de configurar de forma transparente.<br>La primera publicación tiene peso `1`, la segunda peso `2` y así sucesivamente. | Cada página de la serie debe tener su peso configurado.
`date` | El orden de las páginas se puede configurar una sola vez en la configuración de la sección. No hay que hacer nada en cada página. | El orden de las páginas debe invertirse porque la primera página suele ser la más antigua. Esto solo se puede lograr paginando la sección (`paginate_by = 9999`) e invirtiendo su orden (`paginate_reversed = true`).
{% end %}
{{ admonition(type="danger", title="Versión de Zola para ordenar por fecha", text="Para invertir correctamente las fechas, se requiere Zola v0.19.3+ (no publicada) para que la información de paginación esté disponible a través de la función `get_section`. De lo contrario, cualquier cosa que dependa del orden de las páginas de la serie no será correcta (por ejemplo, página anterior/siguiente, listas ordenadas y no ordenadas...) Ver [Zola PR #2653](https://github.com/getzola/zola/pull/2653).") }}
### Indexación de páginas
Las páginas en una serie se indexan empezando desde 1, siguiendo su orden `sort_by`. Para invertir la indexación (haciendo que la primera página tenga el índice más alto), añade esta configuración a `_index.md` o `config.toml`:
```toml
[extra]
post_listing_index_reversed = true # Por defecto es false si no se configura
```
{{ dual_theme_image(light_src="blog/series/img/series_reversed_light.webp", dark_src="blog/series/img/series_reversed_dark.webp" alt="una serie con índices invertidos", full_width=true) }}
Esta configuración sigue [la jerarquía](@/blog/mastering-tabi-settings/index.es.md#jerarquia-de-configuracion).
## Plantillas de introducción y conclusión
Los artículos de una serie pueden tener secciones automáticas de introducción y conclusión. Estas se configuran en el `_index.md` de tu serie. Un ejemplo básico:
{{ add_src_to_code_block(src="series/_index.md") }}
```toml
[extra.series_intro_templates]
default = "Este artículo es parte de la serie $SERIES_HTML_LINK."
[extra.series_outro_templates]
default = "¡Gracias por leer la parte $SERIES_PAGE_INDEX de $SERIES_HTML_LINK!"
```
Las secciones de introducción y conclusión tienen sus propias clases CSS (`series-page-intro` y `series-page-outro`), lo que te permite personalizar su apariencia mediante [CSS personalizado](@/blog/mastering-tabi-settings/index.es.md#estilos-css-personalizados).
### Tipos de plantillas
El sistema de series usa diferentes plantillas según la posición del artículo en la serie:
- `next_only` - Usado para el primer artículo (tiene artículo siguiente pero no anterior)
- `middle` - Usado para artículos con artículos anterior y siguiente
- `prev_only` - Usado para el último artículo (tiene artículo anterior pero no siguiente)
- `default` - Plantilla por defecto usada cuando no existe una plantilla específica para la posición
El sistema determina automáticamente qué plantilla usar según la posición del artículo. Las plantillas se definen en la configuración de la serie (`_index.md`), como `extra.series_intro_templates` y `extra.series_outro_templates`:
{{ add_src_to_code_block(src="series/_index.md") }}
```toml
[extra.series_intro_templates]
next_only = "¡Bienvenido a la parte 1! Siguiente: $NEXT_HTML_LINK"
middle = "Anterior: $PREV_HTML_LINK | Siguiente: $NEXT_HTML_LINK"
prev_only = "¡El capítulo final! Anteriormente: $PREV_HTML_LINK"
default = "Parte $SERIES_PAGE_INDEX de $SERIES_PAGES_NUMBER"
```
Todas las plantillas son opcionales. La selección de plantillas sigue un sistema de prioridad:
1. Si existe una plantilla específica para la posición (`next_only`, `middle`, o `prev_only`), se usará esa
2. Si no, se usa la plantilla `default`
3. Si no se define ninguna plantilla, no se mostrará información de la serie
Mira el [ejemplo de plantilla](#ejemplo-de-plantilla) para ver un ejemplo más elaborado.
### Ubicación en el contenido
Por defecto:
- Las introducciones de serie aparecen al inicio de tu artículo
- La conclusión aparece al final (antes de las notas al pie, si las hay)
Puedes controlar exactamente dónde aparecen usando `<!-- series_intro -->` y `<!-- series_outro -->` en tu Markdown:
```markdown
Este párrafo aparece antes de la introducción de la serie.
<!-- series_intro -->
Contenido principal del artículo.
<!-- series_outro -->
## Recursos de aprendizaje
Contenido adicional...
[^1]: Las notas al pie siempre aparecerán al final.
```
## Variables
Las plantillas de series usan un sistema flexible de variables que te permite:
1. Hacer referencia a información de la serie (título, enlaces)
2. Añadir navegación entre artículos
3. Mostrar indicadores de progreso
4. Incluir información personalizada usando tus propias variables
Las variables son marcadores que comienzan con `$` y se reemplazan con contenido real cuando se construye tu sitio. Por ejemplo, `$SERIES_HTML_LINK` se convierte en un enlace clicable a la página índice de tu serie.
Hay tres tipos de variables:
- [Variables básicas de serie](#variables-basicas-de-serie): Información general sobre la serie
- [Variables de navegación](#variables-de-navegacion): Enlaces a artículos anterior/siguiente
- [Variables personalizadas](#variables-personalizadas): Tus propios marcadores para información adicional
### Variables básicas de serie
{% wide_container() %}
| Variable | Disponibilidad | Devuelve | Descripción | Ejemplo de uso | Ejemplo de salida |
|----------|---------------|-----------|-------------|----------------|-------------------|
| `$SERIES_TITLE` | Siempre | Texto | Título de la serie en texto plano | `Parte de $SERIES_TITLE` | Parte de Aprendiendo Rust |
| `$SERIES_PERMALINK` | Siempre | Texto | URL al índice de la serie | `[Ver todas las publicaciones]($SERIES_PERMALINK)` | [Ver todas las publicaciones](/series/learn-rust) |
| `$SERIES_HTML_LINK` | Siempre | HTML | Enlace listo para usar a la serie | `¡Bienvenido a $SERIES_HTML_LINK!` | ¡Bienvenido a <a href="/series/learn-rust">Aprendiendo Rust</a>! |
| `$SERIES_PAGES_NUMBER` | Siempre | Número | Total de artículos en la serie | `Una serie de $SERIES_PAGES_NUMBER partes` | Una serie de 5 partes |
| `$SERIES_PAGE_INDEX` | Siempre | Número | Posición del artículo actual | `Parte $SERIES_PAGE_INDEX de $SERIES_PAGES_NUMBER` | Parte 3 de 5 |
| `$SERIES_PAGES_OLIST` | Siempre | HTML | Lista ordenada de todos los artículos | `Artículos en la serie: $SERIES_PAGES_OLIST` | Artículos en la serie: <ol><li>Artículo actual</li><li><a href="...">Otros artículos</a></li></ol> |
| `$SERIES_PAGES_ULIST` | Siempre | HTML | Lista desordenada de todos los artículos | `Artículos en la serie: $SERIES_PAGES_ULIST` | Artículos en la serie: <ul><li>Artículo actual</li><li><a href="...">Otros artículos</a></li></ul> |
{% end %}
### Variables de navegación
{% wide_container() %}
| Variable | Disponibilidad | Devuelve | Descripción | Ejemplo de uso | Ejemplo de salida |
|----------|---------------|-----------|-------------|----------------|-------------------|
| `$PREV_TITLE` | Existe anterior | Texto | Título del artículo anterior | `Anteriormente: $PREV_TITLE` | Anteriormente: Configurando tu entorno |
| `$PREV_PERMALINK` | Existe anterior | Texto | URL al artículo anterior | `[← Atrás]($PREV_PERMALINK)` | [← Atrás](/series/learn-rust/setup) |
| `$PREV_HTML_LINK` | Existe anterior | HTML | Enlace listo para usar al anterior | `Lee primero $PREV_HTML_LINK` | Lee primero <a href="/series/learn-rust/setup">Configurando tu entorno</a> |
| `$PREV_DESCRIPTION` | Existe anterior | Texto | Descripción del artículo anterior | `Resumen: $PREV_DESCRIPTION` | Resumen: Configurando Rust |
| `$NEXT_TITLE` | Existe siguiente | Texto | Título del siguiente artículo | `Siguiente: $NEXT_TITLE` | Siguiente: Patrones avanzados |
| `$NEXT_PERMALINK` | Existe siguiente | Texto | URL al siguiente artículo | `[Continuar →]($NEXT_PERMALINK)` | [Continuar →](/series/learn-rust/patterns) |
| `$NEXT_HTML_LINK` | Existe siguiente | HTML | Enlace listo para usar al siguiente | `Continúa con $NEXT_HTML_LINK` | Continúa con <a href="/series/learn-rust/patterns">Patrones avanzados</a> |
| `$NEXT_DESCRIPTION` | Existe siguiente | Texto | Descripción del siguiente artículo | `Próximamente: $NEXT_DESCRIPTION` | Próximamente: Aprende sobre las características avanzadas de pattern matching en Rust |
{% end %}
### Referencia al primer artículo
{% wide_container() %}
| Variable | Disponibilidad | Devuelve | Descripción | Ejemplo de uso | Ejemplo de salida |
|----------|---------------|-----------|-------------|----------------|-------------------|
| `$FIRST_TITLE` | Siempre | Texto | Título del primer artículo | `Comienza con $FIRST_TITLE` | Comienza con Introducción a Rust |
| `$FIRST_HTML_LINK` | Siempre | HTML | Enlace listo para usar al primer artículo | `Empieza en $FIRST_HTML_LINK` | Empieza en <a href="/series/learn-rust/intro">Introducción a Rust</a> |
{% end %}
### Ejemplo de plantilla
{{ admonition(type="tip", title="Variables HTML vs texto", text="Usa variables HTML (que terminan en `_HTML_LINK`) cuando quieras enlaces listos para usar. Usa variables de texto (que terminan en `_TITLE` o `_PERMALINK`) cuando quieras más control sobre el formato.") }}
{{ add_src_to_code_block(src="series/_index.md") }}
```toml
# Introducción.
[extra.series_intro_templates]
next_only = """
¡Bienvenido a $SERIES_HTML_LINK! Esta serie de $SERIES_PAGES_NUMBER partes te enseñará Rust desde cero.
Siguiente: $NEXT_HTML_LINK - $NEXT_DESCRIPTION
"""
middle = """
📚 Parte $SERIES_PAGE_INDEX de $SERIES_PAGES_NUMBER en $SERIES_HTML_LINK
Anterior: $PREV_HTML_LINK
Siguiente: $NEXT_HTML_LINK
"""
prev_only = """
¡Bienvenido a la última parte de $SERIES_HTML_LINK!
¿Eres nuevo? Comienza con $FIRST_HTML_LINK para construir una base sólida.
Anterior: $PREV_HTML_LINK
"""
# Plantilla de respaldo.
default = "Este artículo es parte de la serie $SERIES_HTML_LINK."
# Conclusión.
[extra.series_outro_templates]
next_only = """
¡Gracias por leer! 🙌
Continúa tu viaje con $NEXT_HTML_LINK, donde $NEXT_DESCRIPTION
O revisa el esquema completo de la serie [$SERIES_TITLE]($SERIES_PERMALINK).
"""
middle = """
---
📝 Navegación de la serie
- Anterior: $PREV_HTML_LINK
- Siguiente: $NEXT_HTML_LINK
- [Resumen de la serie]($SERIES_PERMALINK)
"""
prev_only = """
🎉 ¡Felicidades! Has completado $SERIES_HTML_LINK.
¿Quieres repasar? Aquí comenzamos: $FIRST_HTML_LINK
O revisa lo que acabamos de ver en $PREV_HTML_LINK.
"""
# Respaldo.
default = """
---
Este artículo es la parte $SERIES_PAGE_INDEX de $SERIES_PAGES_NUMBER en $SERIES_HTML_LINK.
"""
```
### Variables personalizadas
Las plantillas de series admiten variables personalizadas para incluir información adicional en toda tu serie. El proceso tiene dos pasos:
1. Primero, define tus **marcadores** en la configuración de tu serie (`_index.md`):
{{ add_src_to_code_block(src="series/_index.md") }}
```toml
[extra]
series = true
series_template_placeholders = ["$POSITION", "$TOPIC", "$DIFFICULTY"]
```
2. Luego, en cada artículo de la serie, proporciona los valores para estos marcadores en `series_template_variables`:
{{ add_src_to_code_block(src="series/article.md") }}
```toml
[extra.series_template_variables]
position = "primero"
topic = "Variables y tipos"
difficulty = "Principiante"
```
### Uso de variables personalizadas
Puedes usar tus variables personalizadas en cualquier plantilla, junto con las variables integradas:
{{ add_src_to_code_block(src="series/_index.md") }}
```toml
[extra.series_intro_templates]
default = """
Este es el artículo $POSITION en $SERIES_HTML_LINK.
Tema de hoy: $TOPIC
Nivel de dificultad: $DIFFICULTY
"""
```
{{ admonition(type="warning", text="Aunque los marcadores se definen en mayúsculas (`$POSITION`), los nombres de variables en `series_template_variables` deben estar en minúsculas (`position`).") }}
### Ejemplo con variables personalizadas
{{ add_src_to_code_block(src="series/_index.md") }}
```toml
# En la configuración de la serie.
[extra]
series = true
series_template_placeholders = ["$LEARNING_TIME", "$KEY_CONCEPTS"]
series_intro_templates.default = """
📚 Parte $SERIES_PAGE_INDEX de $SERIES_PAGES_NUMBER
⏱️ Tiempo estimado: $LEARNING_TIME
🔑 Conceptos clave: $KEY_CONCEPTS
"""
```
{{ add_src_to_code_block(src="series/02-learning-rust/index.md") }}
```toml
# En un artículo de la serie.
[extra.series_template_variables]
learning_time = "30 minutos"
key_concepts = "Funciones, manejo de errores, coincidencia de patrones"
```
Esto generará:
```txt
📚 Parte 2 de 5
⏱️ Tiempo estimado: 30 minutos
🔑 Conceptos clave: Funciones, manejo de errores, coincidencia de patrones
```
{{ admonition(type="warning", title="Variables faltantes", text="Si usas un marcador en tus plantillas pero no proporcionas su valor en `series_template_variables`, la compilación fallará con un error que lista las variables faltantes.") }}

View File

@@ -0,0 +1,424 @@
+++
title = "A Complete Guide to Series"
date = 2024-11-08
description = "Learn how to organize your posts into sequential series, perfect for tutorials, courses, and multi-part stories."
[taxonomies]
tags = ["showcase", "tutorial", "FAQ", "series"]
[extra]
quick_navigation_buttons = true
toc = true
mermaid = true
social_media_card = "social_cards/es_blog_series.jpg"
+++
A series organizes related posts in a sequential order, similar to chapters in a book. Unlike tags, which simply group related content, series suggest a specific reading order from start to finish.
Posts within a series do not need to be published consecutively; the series feature brings together thematically linked posts in a coherent sequence.
The diagram below illustrates how series posts (3, 5, and 8) exist within the main blog flow while maintaining their own ordered sequence within Series 1.
{% mermaid(full_width=true) %}
flowchart
subgraph main[BLOG]
P1[Post 1]
P2[P2]
P3[P3]
P4[P4]
P5[P5]
P6[P6]
P7[P7]
P8[P8]
P9[P9]
end
subgraph series1[SERIES 1]
PS1["Series Post 1 (=P3)"]
PS2["Series Post 2 (=P5)"]
PS3["Series Post 3 (=P8)"]
end
P3 o-.-o PS1
P5 o-.-o PS2
P8 o-.-o PS3
{% end %}
## Quick Start
1. Create a directory for your series.
2. Create `_index.md` in the series directory.
3. Set up the `_index.md` front matter:
{{ add_src_to_code_block(src="series/_index.md") }}
```toml
title = "Learning Rust"
template = "series.html"
sort_by = "slug"
transparent = true
[extra]
series = true
```
4. Create your series articles in this directory.
Want more? Keep reading!
## How Do Series Work?
A series is just a section which is handled in a special way by tabi. For more details on sections, see the [Zola documentation](https://www.getzola.org/documentation/content/section/).
Taking the example from the diagram above, the directory structure would be as follow:
```txt
content/
_index.md
blog/
_index.md
post1/
index.md
post2/
index.md
post4/
index.md
post6/
index.md
post7/
index.md
post9/
index.md
series1/
_index.md
post3/
index.md
post5/
index.md
post8/
index.md
```
To create a series, you need to:
1. Use the `series.html` template
2. Set `series = true` in the section's `[extra]` configuration
3. Enable `transparent = true` to integrate series posts with the parent blog section
The series main page displays an overview followed by a list of all posts in the series:
{{ dual_theme_image(light_src="blog/series/img/series_light.webp", dark_src="blog/series/img/series_dark.webp" alt="a series", full_width=true) }}
## Jump to Posts
If the content of a series (the Markdown after the front matter in `_index.md`) is over 2000 characters, a "Jump to posts" link appears next to the series title.
{{ dual_theme_image(light_src="blog/series/img/jump_to_series_posts_light.webp", dark_src="blog/series/img/jump_to_series_posts_dark.webp" alt="jump to series posts link", full_width=true) }}
To force the feature on or off, set `show_jump_to_posts` in the `[extra]` section of your series section or in `config.toml`. This setting follows [the hierarchy](@/blog/mastering-tabi-settings/index.md#settings-hierarchy).
## Series Pages and Order
All pages in the series section will be a series page. The series pages will be ordered as per the series section `sort_by`.
While series maintain their own internal order, they remain independent from the main section's (e.g. `blog/`) chronological flow thanks to the `transparent` setting.
### Sorting Options
Choose from these sorting methods, each with its own advantages:
{% wide_container() %}
`sort_by` | pros | cons
---------|-------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
`slug` | The series pages order is made explicit in the path (e.g. `example.com/blog/series1/01-series-post-one`). | Each series page must be prefixed accordingly.
`weight` | The series pages order is easy to set up transparently.<br>First series post has weight `1`, second series post has weight `2` and so on. | Each series page must have its weight set accordingly.
`date` | The series pages order can be configured once in the series section configuration. No need to do anything on each series page. | The series pages order has to be reversed because the first page is usually the oldest. This can only be achieved by paginating the series section (`paginate_by = 9999`) and reversing its order (`paginate_reversed = true`).
{% end %}
{{ admonition(type="danger", title="Zola version to sort by date", text="In order to properly reverse dates, Zola v0.19.3+ (unreleased) is required so that pagination information is available through the `get_section` function. Anything relying on the series pages order won't be correct in a series page otherwise (e.g. previous/next series page, ordered and unordered list…) See [Zola PR #2653](https://github.com/getzola/zola/pull/2653).") }}
### Page Indexing
Pages in a series are indexed starting from 1, following their `sort_by` order. To reverse the indexing (making the first page have the highest index instead), add this setting to `_index.md` or `config.toml`:
```toml
[extra]
post_listing_index_reversed = true # Defaults to false if unset.
```
{{ dual_theme_image(light_src="blog/series/img/series_reversed_light.webp", dark_src="blog/series/img/series_reversed_dark.webp" alt="a series with indexes reversed", full_width=true) }}
This setting follows [the hierarchy](@/blog/mastering-tabi-settings/index.md#settings-hierarchy).
## Intro and Outro Templates
Series articles can have automatic introduction and conclusion sections. These are configured in your series' `_index.md`. A basic example:
{{ add_src_to_code_block(src="series/_index.md") }}
```toml
[extra.series_intro_templates]
default = "This article is part of the $SERIES_HTML_LINK series."
[extra.series_outro_templates]
default = "Thanks for reading part $SERIES_PAGE_INDEX of $SERIES_HTML_LINK!"
```
The intro and outro sections each have their own CSS classes (`series-page-intro` and `series-page-outro`), allowing you to customize their appearance through [custom CSS](@/blog/mastering-tabi-settings/index.md#custom-css).
### Template Types
The series system uses different templates based on an article's position in the series:
- `next_only` - Used for the first article (has next article but no previous)
- `middle` - Used for articles with both previous and next articles
- `prev_only` - Used for the last article (has previous article but no next)
- `default` - Fallback template used when a specific position template isn't defined
The system automatically determines which template to use based on the article's position. The templates are defined in the series configuration (`_index.md`), as `extra.series_intro_templates` and `extra.series_outro_templates`.:
{{ add_src_to_code_block(src="series/_index.md") }}
```toml
[extra.series_intro_templates]
next_only = "Welcome to part 1! Next up: $NEXT_HTML_LINK"
middle = "Previous: $PREV_HTML_LINK | Next: $NEXT_HTML_LINK"
prev_only = "The final chapter! Previously: $PREV_HTML_LINK"
default = "Part $SERIES_PAGE_INDEX of $SERIES_PAGES_NUMBER"
```
All templates are optional. Template selection follows a priority system:
1. If a position-specific template exists (`next_only`, `middle`, or `prev_only`), it will be used
2. Otherwise, the `default` template is used
3. If no templates are defined at all, no series information will be displayed
See the [template example](#template-example) for a more elaborate example.
### Placement in Content
By default:
- Series introductions appear at the start of your article
- Series outro appears at the end (before footnotes, if any)
You can control exactly where these appear using `<!-- series_intro -->` and `<!-- series_outro -->` in your Markdown:
```markdown
This paragraph appears before the series introduction.
<!-- series_intro -->
Main content of the article.
<!-- series_outro -->
## Learning Resources
Extra content…
[^1]: Footnotes will always appear at the end.
```
## Variables
Series templates use a flexible variable system that lets you:
1. Reference series information (title, links)
2. Add navigation between articles
3. Show progress indicators
4. Include custom information using your own variables
Variables are placeholders starting with `$` that get replaced with actual content when your site builds. For example, `$SERIES_HTML_LINK` becomes a clickable link to your series index page.
There are three types of variables:
- [**Basic Series Variables**](#basic-series-variables): General information about the series
- [**Navigation Variables**](#navigation-variables): Links to previous/next articles
- [**Custom Variables**](#custom-variables): Your own placeholders for additional information
### Basic Series Variables
{% wide_container() %}
| Variable | Availability | Returns | Description | Example Usage | Example Output |
|----------|-------------|---------|-------------|---------------|----------------|
| `$SERIES_TITLE` | Always | Text | Plain text title of the series | `Part of $SERIES_TITLE` | Part of Learn Rust |
| `$SERIES_PERMALINK` | Always | Text | URL to series index | `[See all posts]($SERIES_PERMALINK)` | [See all posts](/series/learn-rust) |
| `$SERIES_HTML_LINK` | Always | HTML | Ready-to-use link to series | `Welcome to $SERIES_HTML_LINK!` | Welcome to <a href="/series/learn-rust">Learn Rust</a>! |
| `$SERIES_PAGES_NUMBER` | Always | Number | Total articles in series | `A $SERIES_PAGES_NUMBER part series` | A 5 part series |
| `$SERIES_PAGE_INDEX` | Always | Number | Current article's position | `Part $SERIES_PAGE_INDEX of $SERIES_PAGES_NUMBER` | Part 3 of 5 |
| `$SERIES_PAGES_OLIST` | Always | HTML | Ordered list of all articles | `Articles in series: $SERIES_PAGES_OLIST` | Articles in series: <ol><li>Current article</li><li><a href="...">Other articles</a></li></ol> |
| `$SERIES_PAGES_ULIST` | Always | HTML | Unordered list of all articles | `Articles in series: $SERIES_PAGES_ULIST` | Articles in series: <ul><li>Current article</li><li><a href="...">Other articles</a></li></ul> |
{% end %}
### Navigation Variables
{% wide_container() %}
| Variable | Availability | Returns | Description | Example Usage | Example Output |
|----------|-------------|---------|-------------|---------------|----------------|
| `$PREV_TITLE` | Previous exists | Text | Previous article's title | `Previously: $PREV_TITLE` | Previously: Setting Up Your Environment |
| `$PREV_PERMALINK` | Previous exists | Text | URL to previous article | `[← Back]($PREV_PERMALINK)` | [← Back](/series/learn-rust/setup) |
| `$PREV_HTML_LINK` | Previous exists | HTML | Ready-to-use link to previous | `Read $PREV_HTML_LINK first` | Read <a href="/series/learn-rust/setup">Setting Up Your Environment</a> first |
| `$PREV_DESCRIPTION` | Previous exists | Text | Description of previous article | `Recap: $PREV_DESCRIPTION` | Recap: Setting up Rust |
| `$NEXT_TITLE` | Next exists | Text | Next article's title | `Next up: $NEXT_TITLE` | Next up: Advanced Patterns |
| `$NEXT_PERMALINK` | Next exists | Text | URL to next article | `[Continue →]($NEXT_PERMALINK)` | [Continue →](/series/learn-rust/patterns) |
| `$NEXT_HTML_LINK` | Next exists | HTML | Ready-to-use link to next | `Continue with $NEXT_HTML_LINK` | Continue with <a href="/series/learn-rust/patterns">Advanced Patterns</a> |
| `$NEXT_DESCRIPTION` | Next exists | Text | Description of next article | `Coming up: $NEXT_DESCRIPTION` | Coming up: Learn about Rust's advanced pattern matching features |
{% end %}
### First Article Reference
{% wide_container() %}
| Variable | Availability | Returns | Description | Example Usage | Example Output |
|----------|-------------|---------|-------------|---------------|----------------|
| `$FIRST_TITLE` | Always | Text | First article's title | `Start with $FIRST_TITLE` | Start with Introduction to Rust |
| `$FIRST_HTML_LINK` | Always | HTML | Ready-to-use link to first article | `Begin at $FIRST_HTML_LINK` | Begin at <a href="/series/learn-rust/intro">Introduction to Rust</a> |
{% end %}
### Template Example
{{ admonition(type="tip", title="HTML vs text variables", text="Use HTML variables (ending in `_HTML_LINK`) when you want ready-made links. Use text variables (ending in `_TITLE` or `_PERMALINK`) when you want more control over the formatting.") }}
{{ add_src_to_code_block(src="series/_index.md") }}
```toml
# Introduction.
[extra.series_intro_templates]
next_only = """
Welcome to $SERIES_HTML_LINK! This $SERIES_PAGES_NUMBER-part series will teach you Rust from scratch.
Up next: $NEXT_HTML_LINK - $NEXT_DESCRIPTION
"""
middle = """
📚 Part $SERIES_PAGE_INDEX of $SERIES_PAGES_NUMBER in $SERIES_HTML_LINK
Previously: $PREV_HTML_LINK
Next up: $NEXT_HTML_LINK
"""
prev_only = """
Welcome to the final part of $SERIES_HTML_LINK!
New here? Start with $FIRST_HTML_LINK to build a strong foundation.
Previously: $PREV_HTML_LINK
"""
# Fallback template.
default = "This article is part of the $SERIES_HTML_LINK series."
# Outro.
[extra.series_outro_templates]
next_only = """
Thanks for reading! 🙌
Continue your journey with $NEXT_HTML_LINK, where $NEXT_DESCRIPTION
Or check out the complete [$SERIES_TITLE]($SERIES_PERMALINK) series outline.
"""
middle = """
---
📝 Series Navigation
- Previous: $PREV_HTML_LINK
- Next: $NEXT_HTML_LINK
- [Series Overview]($SERIES_PERMALINK)
"""
prev_only = """
🎉 Congratulations! You've completed $SERIES_HTML_LINK.
Want to review? Here's where we started: $FIRST_HTML_LINK
Or check what we just covered in $PREV_HTML_LINK.
"""
# Fallback.
default = """
---
This article is part $SERIES_PAGE_INDEX of $SERIES_PAGES_NUMBER in $SERIES_HTML_LINK.
"""
```
### Custom Variables
Series templates support custom variables for additional information you want to include across your series. The process takes two steps:
1. First, define your **placeholders** in your series configuration (`_index.md`):
{{ add_src_to_code_block(src="series/_index.md") }}
```toml
[extra]
series = true
series_template_placeholders = ["$POSITION", "$TOPIC", "$DIFFICULTY"]
```
2. Then, in each series article, provide the values for these placeholders in `series_template_variables`:
{{ add_src_to_code_block(src="series/article.md") }}
```toml
[extra.series_template_variables]
position = "first"
topic = "Variables and Types"
difficulty = "Beginner"
```
### Using Custom Variables
You can use your custom variables in any template, alongside the built-in variables:
{{ add_src_to_code_block(src="series/_index.md") }}
```toml
[extra.series_intro_templates]
default = """
This is the $POSITION article in $SERIES_HTML_LINK.
Today's topic: $TOPIC
Difficulty level: $DIFFICULTY
"""
```
{{ admonition(type="warning", text="While placeholders are defined with uppercase (`$POSITION`), the variable names in `series_template_variables` must be lowercase (`position`).") }}
### Example with Custom Variables
{{ add_src_to_code_block(src="series/_index.md") }}
```toml
# In the series configuration.
[extra]
series = true
series_template_placeholders = ["$LEARNING_TIME", "$KEY_CONCEPTS"]
series_intro_templates.default = """
📚 Part $SERIES_PAGE_INDEX of $SERIES_PAGES_NUMBER
⏱️ Estimated time: $LEARNING_TIME
🔑 Key concepts: $KEY_CONCEPTS
"""
```
{{ add_src_to_code_block(src="series/02-learning-rust/index.md") }}
```toml
# In an article of the series.
[extra.series_template_variables]
learning_time = "30 minutes"
key_concepts = "Functions, Error Handling, Pattern Matching"
```
This will output:
```txt
📚 Part 2 of 5
⏱️ Estimated time: 30 minutes
🔑 Key concepts: Functions, Error Handling, Pattern Matching
```
{{ admonition(type="warning", title="Missing Variables", text="If you use a placeholder in your templates but don't provide its value in `series_template_variables`, the build will fail with an error listing the missing variables.") }}

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB