diff --git a/config.toml b/config.toml index cd7f0535d..fa637b722 100644 --- a/config.toml +++ b/config.toml @@ -160,7 +160,7 @@ post_listing_date = "date" # Determines if indexes should be increasing (false) or decreasing (true) in series' posts list. # It has only effect if the section uses indexes metadata (which is only the case for series as of now). # Can be set at section levels, following the hierarchy: section > config. See: https://welpo.github.io/tabi/blog/mastering-tabi-settings/#settings-hierarchy -post_listing_index_reversed = false # Defaults to false. +post_listing_index_reversed = false # Defaults to false. # DEPRECATED! # Use Zola's built-in `bottom_footnotes = true` in the [markdown] section instead. (Available since v0.19.0) @@ -186,10 +186,6 @@ serve_local_mermaid = true # Can be set at page or section levels, following the hierarchy: page > section > config. See: https://welpo.github.io/tabi/blog/mastering-tabi-settings/#settings-hierarchy show_previous_next_article_links = false -# Show links to previous and next series articles at the bottom of posts which is part of a series. -# Can be set at page or section levels, following the hierarchy: page > section > config. See: https://welpo.github.io/tabi/blog/mastering-tabi-settings/#settings-hierarchy -show_previous_next_series_article_links = false - # Invert order of the links to previous and next articles at the bottom of posts. # By default, next articles are on the left side of the page and previous articles are on the right side. # To reverse the order (next articles on the right and previous articles on the left), set it to true. diff --git a/content/blog/_index.ca.md b/content/blog/_index.ca.md index 3ef05bb3b..7a722314c 100644 --- a/content/blog/_index.ca.md +++ b/content/blog/_index.ca.md @@ -8,5 +8,4 @@ insert_anchor_links = "left" [extra] social_media_card = "blog/social_cards/ca_blog.jpg" show_previous_next_article_links = true -show_previous_next_series_article_links = true +++ diff --git a/content/blog/_index.es.md b/content/blog/_index.es.md index b3d11d7e6..a367dbbad 100644 --- a/content/blog/_index.es.md +++ b/content/blog/_index.es.md @@ -8,5 +8,4 @@ insert_anchor_links = "left" [extra] social_media_card = "blog/social_cards/es_blog.jpg" show_previous_next_article_links = true -show_previous_next_series_article_links = true +++ diff --git a/content/blog/_index.md b/content/blog/_index.md index c12c66a7b..036db4df5 100644 --- a/content/blog/_index.md +++ b/content/blog/_index.md @@ -8,5 +8,4 @@ insert_anchor_links = "left" [extra] social_media_card = "blog/social_cards/blog.jpg" show_previous_next_article_links = true -show_previous_next_series_article_links = true +++ diff --git a/content/blog/series/01-series-introduction/index.md b/content/blog/series/01-series-introduction/index.md index 3a1d691ce..4764e8ee8 100644 --- a/content/blog/series/01-series-introduction/index.md +++ b/content/blog/series/01-series-introduction/index.md @@ -7,13 +7,15 @@ description = "This first article introduces how does series works and how to co tags = ["showcase", "tutorial"] [extra] -series_page_introduction_variables = { position = "first", foo = "FOO!!!"} +series_template_variables = { position = "first", foo = "FOO!!!"} +++ {{ admonition(type="warning", icon="warning", title="IMPORTANT", text="This article has been introduced retroactively to showcase series.") }} Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. -Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. +Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. [^1] Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. + +[^1]: Lorem. diff --git a/content/blog/series/02-series-pages-organization/index.md b/content/blog/series/02-series-pages-organization/index.md index ebbb153fb..149dc8c0b 100644 --- a/content/blog/series/02-series-pages-organization/index.md +++ b/content/blog/series/02-series-pages-organization/index.md @@ -7,7 +7,9 @@ description = "This second article focuses on how to organisation the pages of a tags = ["showcase", "tutorial"] [extra] -series_page_introduction_variables = { position = "second", foo = "FOO FOO!!!"} +[extra.series_template_variables] +position = "second" +foo = "FOO FOO!!!" +++ diff --git a/content/blog/series/03-series-cheat-sheet/index.md b/content/blog/series/03-series-cheat-sheet/index.md index 56bfe16aa..4326c715f 100644 --- a/content/blog/series/03-series-cheat-sheet/index.md +++ b/content/blog/series/03-series-cheat-sheet/index.md @@ -7,14 +7,265 @@ description = "This last article provides an overview of series and describe all tags = ["showcase", "tutorial", "FAQ"] [extra] -series_page_introduction_variables = { position = "third", foo = "FOO FOO FOO!!!"} +series_template_variables = { position = "third", foo = "FOO FOO FOO!!!"} +toc = true +++ -## Jump to Posts Feature +## 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: + + ```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! + +## Jump to Posts When a series has a description over 2000 characters, a "Jump to posts" link automatically appears next to the series title: ##### TODO: Add screenshot with final design To force the feature on or off, use the `show_jump_to_posts` option in the `[extra]` section of your section (series) or in `config.toml`. 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`: + +```toml +[extra.series_intro_templates] # Shown at the start of each article. +default = "This article is part of the $SERIES_HTML_LINK series." + +[extra.series_outro_templates] # Shown at the end of each article. +default = "Thanks for reading part $SERIES_PAGE_INDEX of $SERIES_HTML_LINK!" +``` + +### 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 `` and `` in your Markdown: + +```markdown +This paragraph appears before the series introduction. + + + +Main content of the article. + + + +## 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 Learn Rust! | +| `$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:
  1. Current article
  2. Other articles
| +| `$SERIES_PAGES_ULIST` | Always | HTML | Unordered list of all articles | `Articles in series: $SERIES_PAGES_ULIST` | Articles in series: | + +{% 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 Setting Up Your Environment 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 Advanced Patterns | +| `$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 Introduction to Rust | +{% 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.") }} + +```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. Define your placeholders once in the series configuration with `series_template_placeholders`. +2. Provide their values in each article with `series_template_variables` (note the different name). + +3. First, define your **placeholders** in your series configuration (`_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`: + +```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: + +```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 + +Here's a complete example showing how to use custom variables in a series: + +```toml +# In series _index.md +[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 +""" + +# In an article of the series +[extra.series_template_variables] +learning_time = "30 minutes" +key_concepts = "Functions, Error Handling, Pattern Matching" +``` + +This will output: + +```text +📚 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.") }} diff --git a/content/blog/series/_index.md b/content/blog/series/_index.md index 092926757..84405c9aa 100644 --- a/content/blog/series/_index.md +++ b/content/blog/series/_index.md @@ -13,7 +13,7 @@ quick_navigation_buttons = true show_jump_to_posts = true post_listing_index_reversed = false -series_page_introduction_placeholders = ["$POSITION", "$FOO", "$BAR"] +series_template_placeholders = ["$POSITION", "$FOO", "$BAR"] series_page_introduction = """ You can put whatever you want in a custom description. @@ -21,7 +21,20 @@ You can put whatever you want in a custom description. Markdown is rendered. """ + +[extra.series_intro_templates] +prev_only = "Welcome back to $SERIES_HTML_LINK! This is article the $POSITION of $SERIES_PAGES_NUMBER, following $PREV_HTML_LINK." +next_only = "Welcome to $SERIES_HTML_LINK! This is the $POSITION article in a $SERIES_PAGES_NUMBER-part series." +middle = "Welcome to the $POSITION of $SERIES_PAGES_NUMBER articles in $SERIES_HTML_LINK. We previously covered $PREV_HTML_LINK." +default = "This article is part $SERIES_PAGE_INDEX of $SERIES_PAGES_NUMBER in the $SERIES_HTML_LINK series." + +[extra.series_outro_templates] +prev_only = "Check out the previous post in the $SERIES_HTML_LINK series: [$PREV_TITLE]($PREV_PERMALINK)." +next_only = "This is the start of the [series]($SERIES_PERMALINK). Continue with $NEXT_HTML_LINK!" +middle = "Previously: $PREV_HTML_LINK. Up next: $NEXT_HTML_LINK." +default = "This article is part of the $SERIES_HTML_LINK series." +++ + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. diff --git a/templates/macros/series_page.html b/templates/macros/series_page.html index 6be39fb6d..d5704a15a 100644 --- a/templates/macros/series_page.html +++ b/templates/macros/series_page.html @@ -14,140 +14,149 @@ - `series_ordered_pages`: The series' pages properly ordered (see at the top of this file for an explanation). - `language_strings`: A dictionary containing the translation strings. #} -{% macro get_introduction(page, series_section, series_ordered_pages, language_strings) %} - {%- if "series" in series_section.extra and series_section.extra.series -%} - {# Prepare variables for substitution #} - {%- set series_title = series_section.title -%} - {%- set series_permalink = series_section.permalink -%} - {%- set series_html_link = '' ~ series_section.title ~ '' -%} - {%- set series_pages_list = [] -%} - {%- set series_pages_number = 0 -%} - {%- set series_page_index = 0 -%} - {%- for series_page in series_ordered_pages -%} - {%- set_global series_pages_number = series_pages_number + 1 -%} - {%- if series_page.relative_path == page.relative_path -%} - {%- set_global series_page_index = series_pages_number -%} - {%- set series_pages_list_item = '
  • ' ~ series_page.title ~ '
  • ' -%} - {%- else -%} - {%- set series_pages_list_item = '
  • ' ~ series_page.title ~ '
  • ' -%} - {%- endif -%} - {%- set_global series_pages_list = series_pages_list | concat(with=series_pages_list_item) -%} - {%- endfor -%} - {%- set series_pages_number = series_pages_number | as_str -%} - {%- set series_page_index = series_page_index | as_str -%} - {%- set series_pages_list = series_pages_list | join(sep="") -%} +{% macro process_series_template(template_type, page, series_section, series_ordered_pages, language_strings) %} + {%- if "series" in series_section.extra and series_section.extra.series -%} + {# Prepare variables for substitution #} + {%- set series_title = series_section.title -%} + {%- set series_permalink = series_section.permalink -%} + {%- set series_html_link = '' ~ series_section.title ~ '' -%} + {# Build series pages list #} + {%- set series_pages_list = [] -%} + {%- for series_page in series_ordered_pages -%} + {%- if series_page.relative_path == page.relative_path -%} + {%- set series_pages_list_item = '
  • ' ~ series_page.title ~ '
  • ' -%} + {%- else -%} + {%- set series_pages_list_item = '
  • ' ~ series_page.title ~ '
  • ' -%} + {%- endif -%} + {%- set_global series_pages_list = series_pages_list | concat(with=series_pages_list_item) -%} + {%- endfor -%} + {%- set series_pages_list = series_pages_list | join(sep="") -%} + {%- if macros_settings::evaluate_setting_priority(setting="post_listing_index_reversed", page=series_section, default_global_value=false) == "true" -%} + {%- set series_pages_ordered_list = '
      ' ~ series_pages_list ~ '
    ' -%} + {%- else -%} + {%- set series_pages_ordered_list = '
      ' ~ series_pages_list ~ '
    ' -%} + {%- endif -%} + {%- set series_pages_unordered_list = '' -%} + + {# Get page position and navigation info #} + {%- set series_pages_number = 0 -%} + {%- set series_page_index = 0 -%} + {%- set first_page = series_ordered_pages | first -%} + {%- set is_found = false -%} + + {%- for series_page in series_ordered_pages -%} + {%- set_global series_pages_number = series_pages_number + 1 -%} + {%- if series_page.relative_path == page.relative_path -%} + {%- set_global series_page_index = series_pages_number -%} + {%- set_global is_found = true -%} + {%- else -%} + {%- if not is_found -%} + {%- set_global prev_page = series_page -%} + {%- elif not next_page is defined -%} + {%- set_global next_page = series_page -%} + {%- endif -%} + {%- endif -%} + {%- endfor -%} + + {# Determine template to use based on available navigation #} + {%- set position = "middle" -%} + {%- if prev_page is defined and not next_page is defined -%} + {%- set_global position = "prev_only" -%} + {%- elif next_page is defined and not prev_page is defined -%} + {%- set_global position = "next_only" -%} + {%- endif -%} - {%- if macros_settings::evaluate_setting_priority(setting="post_listing_index_reversed", page=series_section, default_global_value=false) == "true" -%} - {%- set series_pages_ordered_list = '
      ' ~ series_pages_list ~ '
    ' -%} - {%- else -%} - {%- set series_pages_ordered_list = '
      ' ~ series_pages_list ~ '
    ' -%} - {%- endif -%} - {%- set series_pages_unordered_list = '' -%} + {# Get template from config #} + {%- set templates_key = "series_" ~ template_type ~ "_templates" -%} + {%- set template = "" -%} + {%- if series_section.extra[templates_key] is defined -%} + {%- if series_section.extra[templates_key][position] is defined -%} + {%- set_global template = series_section.extra[templates_key][position] -%} + {%- elif series_section.extra[templates_key].default is defined -%} + {%- set_global template = series_section.extra[templates_key].default -%} + {%- endif -%} + {%- endif -%} - {# Define introduction #} - {%- set series_page_introduction = series_section.extra.series_page_introduction | default(value="") -%} - {%- set series_page_introduction = series_page_introduction | replace(from="$SERIES_TITLE", to=series_title) | replace(from="$SERIES_PERMALINK", to=series_permalink) | replace(from="$SERIES_HTML_LINK", to=series_html_link) -%} - {%- set series_page_introduction = series_page_introduction | replace(from="$SERIES_PAGES_NUMBER", to=series_pages_number) | replace(from="$SERIES_PAGE_INDEX", to=series_page_index) | replace(from="$SERIES_PAGES_OLIST", to=series_pages_ordered_list) | replace(from="$SERIES_PAGES_ULIST", to=series_pages_unordered_list) -%} + {# Prepare navigation variables #} + {%- if prev_page is defined -%} + {%- set prev_title = prev_page.title -%} + {%- set prev_permalink = prev_page.permalink -%} + {%- set prev_html_link = '' ~ prev_page.title ~ '' -%} + {%- set prev_description = prev_page.description | default(value="") -%} + {%- endif -%} + {%- if next_page is defined -%} + {%- set next_title = next_page.title -%} + {%- set next_permalink = next_page.permalink -%} + {%- set next_html_link = '' ~ next_page.title ~ '' -%} + {%- set next_description = next_page.description | default(value="") -%} + {%- endif -%} + + {# Replace standard variables #} + {%- set template = template + | replace(from="$SERIES_TITLE", to=series_title) + | replace(from="$SERIES_PERMALINK", to=series_permalink) + | replace(from="$SERIES_HTML_LINK", to=series_html_link) + | replace(from="$FIRST_TITLE", to=first_page.title) + | replace(from="$FIRST_HTML_LINK", to='' ~ first_page.title ~ '') + | replace(from="$SERIES_PAGES_NUMBER", to=series_pages_number | as_str) + | replace(from="$SERIES_PAGE_INDEX", to=series_page_index | as_str) + | replace(from="$SERIES_PAGES_OLIST", to=series_pages_ordered_list) + | replace(from="$SERIES_PAGES_ULIST", to=series_pages_unordered_list) + -%} + + {# Replace navigation variables if they exist #} + {%- if prev_page is defined -%} + {%- set template = template + | replace(from="$PREV_TITLE", to=prev_title) + | replace(from="$PREV_PERMALINK", to=prev_permalink) + | replace(from="$PREV_HTML_LINK", to=prev_html_link) + | replace(from="$PREV_DESCRIPTION", to=prev_description) + -%} + {%- endif -%} - {# Replace introduction custom placeholders #} - {%- if series_section.extra.series_page_introduction_placeholders is defined -%} - {%- set missing_vars = [] -%} - {%- for placeholder in series_section.extra.series_page_introduction_placeholders -%} - {%- if placeholder in series_page_introduction -%} - {# Attempt to retrieve the corresponding variable by trimming the $ sign and converting to lowercase #} - {%- set var_name = placeholder | replace(from="$", to="") | lower -%} - {%- if page.extra.series_page_introduction_variables[var_name] -%} - {%- set_global series_page_introduction = series_page_introduction | replace(from=placeholder, to=page.extra.series_page_introduction_variables[var_name]) -%} - {%- else -%} - {# Append the variable name to the list of missing variables #} - {% set_global missing_vars = missing_vars | concat(with=var_name) -%} - {%- endif -%} - {%- endif -%} - {%- endfor -%} - {%- if missing_vars | length > 0 -%} - {%- set missing_vars_str = missing_vars | join(sep=", ") -%} - {{ throw(message="ERROR: The following variables are included in this page's series introduction (`series_page_introduction_placeholders`) but have not been set in the `series_page_introduction_variables` of this page: " ~ missing_vars_str) }} - {%- endif -%} - {%- endif -%} + {%- if next_page is defined -%} + {%- set template = template + | replace(from="$NEXT_TITLE", to=next_title) + | replace(from="$NEXT_PERMALINK", to=next_permalink) + | replace(from="$NEXT_HTML_LINK", to=next_html_link) + | replace(from="$NEXT_DESCRIPTION", to=next_description) + -%} + {%- endif -%} - {%- if series_page_introduction | length > 0 -%} -
    - {{ series_page_introduction | markdown | safe }} -
    + {# Custom placeholders #} + {%- if series_section.extra.series_template_placeholders is defined -%} + {%- set missing_vars = [] -%} + {%- for placeholder in series_section.extra.series_template_placeholders -%} + {%- if placeholder in template -%} + {%- set var_name = placeholder | replace(from="$", to="") | lower -%} + {%- if page.extra.series_template_variables is defined and page.extra.series_template_variables[var_name] is defined -%} + {%- set_global template = template | replace(from=placeholder, to=page.extra.series_template_variables[var_name]) -%} + {%- else -%} + {%- set_global missing_vars = missing_vars | concat(with=var_name) -%} + {%- endif -%} {%- endif -%} + {%- endfor -%} + {%- if missing_vars | length > 0 -%} + {%- set missing_vars_str = missing_vars | join(sep=", ") -%} + {{ throw(message="ERROR: The following variables are included in this page's series templates (`series_template_placeholders`) but have not been set in the `series_template_variables` of this page: " ~ missing_vars_str) }} + {%- endif -%} {%- endif -%} + + {# Output the processed template if not empty #} + {%- if template | length > 0 -%} +
    + {{ template | markdown | safe }} +
    + {%- endif -%} + {%- endif -%} {% endmacro %} -{# -Computes the series navigation of a series's page. +{# Macro for series introduction #} +{% macro get_introduction(page, series_section, series_ordered_pages, language_strings) %} + {{ macros_series_page::process_series_template(template_type="intro", page=page, series_section=series_section, series_ordered_pages=series_ordered_pages, language_strings=language_strings) }} +{% endmacro %} -Parameters: - - `page`: The page object being part of the series. - - `series_section`: The series' section the page belongs to. - - `series_ordered_pages`: The series' pages properly ordered (see at the top of this file for an explanation). - - `language_strings`: A dictionary containing the translation strings. -#} -{% macro get_navigation(page, series_section, series_ordered_pages, language_strings) %} - {%- if macros_settings::evaluate_setting_priority(setting="show_previous_next_series_article_links", page=page, default_global_value=false) == "true" -%} - {%- if series_ordered_pages | length > 1 -%} - {% set next_series_label = macros_translate::translate(key="next_series", default="Next (series)", language_strings=language_strings) %} - {% set prev_series_label = macros_translate::translate(key="prev_series", default="Prev (series)", language_strings=language_strings) %} - {% set is_previous = true %} - {% set is_next = false %} - {%- for series_page in series_ordered_pages -%} - {%- if series_page.relative_path == page.relative_path -%} - {%- set_global is_previous = false -%} - {%- set_global is_next = true -%} - {%- else -%} - {%- if is_previous -%} - {%- set_global prev_series_page = series_page -%} - {%- endif -%} - {%- if is_next -%} - {%- set_global next_series_page = series_page -%} - {%- set_global is_next = false-%} - {%- endif -%} - {%- endif -%} - {%- endfor -%} - {% if macros_settings::evaluate_setting_priority(setting="invert_previous_next_article_links", page=page, default_global_value=true) == "true" %} - {% if prev_series_page %} - {% set left_series_link = prev_series_page.permalink %} - {% set left_series_label = prev_series_label %} - {% set left_series_title = prev_series_page.title %} - {% endif %} - {% if next_series_page %} - {% set right_series_link = next_series_page.permalink %} - {% set right_series_label = next_series_label %} - {% set right_series_title = next_series_page.title %} - {% endif %} - {% else %} - {% if next_series_page %} - {% set left_series_link = next_series_page.permalink %} - {% set left_series_label = next_series_label %} - {% set left_series_title = next_series_page.title %} - {% endif %} - {% if prev_series_page %} - {% set right_series_link = prev_series_page.permalink %} - {% set right_series_label = prev_series_label %} - {% set right_series_title = prev_series_page.title %} - {% endif %} - {% endif %} - {% if macros_settings::evaluate_setting_priority(setting="previous_next_article_links_full_width", page=page, default_global_value=true) == "true" %} - {%- set full_width_class = "full-width" -%} - {% endif %} - - {%- endif -%} - {%- endif -%} +{# Macro for series outro #} +{% macro get_outro(page, series_section, series_ordered_pages, language_strings) %} + {{ macros_series_page::process_series_template(template_type="outro", page=page, series_section=series_section, series_ordered_pages=series_ordered_pages, language_strings=language_strings) }} {% endmacro %} diff --git a/templates/page.html b/templates/page.html index 99440d2e0..8486d2edb 100644 --- a/templates/page.html +++ b/templates/page.html @@ -171,7 +171,7 @@

    {%- set formatted_date = macros_format_date::format_date(date=page.updated, short=true, language_strings=language_strings) -%} {%- set updated_str = last_updated_str | replace(from="$DATE", to=formatted_date) -%} - {# A page is part of a series if one of the sections above (whether it is transparent or not) has the `extra.series` parameter set to true. #} - {# As a series might be a transparent section in order to mix up its articles with those of the section just above or the root, #} - {# there is no other way but to compute the potential path of each ancestor section related to the page and look for the first one being a series. #} - {# Using the `ancestors` field of a section is not possible because transparent sections are not present in this field. #} + {#- A page is part of a series if one of the sections above (whether it is transparent or not) has the `extra.series` parameter set to true. -#} + {#- As a series might be a transparent section in order to mix up its articles with those of the section just above or the root, -#} + {#- there is no other way but to compute the potential path of each ancestor section related to the page and look for the first one being a series. -#} + {#- Using the `ancestors` field of a section is not possible because transparent sections are not present in this field. -#} {%- set current_path = [] -%} {%- set section_paths = [] -%} {%- for path in page.relative_path | split(pat="/") | slice(end=-1) -%} @@ -190,7 +190,7 @@

    {%- set section_path = current_path | concat(with="_index.md") | join(sep="/") -%} {%- set_global section_paths = section_paths | concat(with=section_path) -%} {%- endfor -%} - {# The series the page is part of is the closest section flagged as a series, if any #} + {#- The series the page is part of is the closest section flagged as a series, if any -#} {%- for section_path in section_paths | reverse -%} {%- set section_file_exists = load_data(path=section_path, required=false) -%} {%- if section_file_exists -%} @@ -206,10 +206,6 @@

    {%- endif -%} {%- endfor -%} - {% if series_section %} - {{ macros_series_page::get_introduction(page=page, series_section=series_section, series_ordered_pages=series_ordered_pages, language_strings=language_strings)}} - {% endif %} - {% if page.extra.tldr %}
    @@ -222,18 +218,48 @@

    {% endif %} - {# Optional table of contents below the header #} + {#- Optional table of contents below the header -#} {% if page.toc and macros_settings::evaluate_setting_priority(setting="toc", page=page, default_global_value=false) == "true" %} {{ macros_toc::toc(page=page, header=true, language_strings=language_strings) }} {% endif %}
    - {# The replace pattern is used to enable arbitrary locations for the Table of Contents #} - {# This is Philipp Oppermann's workaround: https://github.com/getzola/zola/issues/584#issuecomment-474329637 #} - {{ page.content | replace(from="", to=macros_toc::toc(page=page, header=false, language_strings=language_strings)) | safe }} + {#- Replace series_intro placeholder -#} + {%- set content_with_intro = page.content -%} + {%- if "" in page.content -%} + {%- set series_intro_html = macros_series_page::get_introduction(page=page, series_section=series_section, series_ordered_pages=series_ordered_pages, language_strings=language_strings) -%} + {%- set content_with_intro = content_with_intro | replace(from="", to=series_intro_html) -%} + {%- elif series_section -%} + {%- set series_intro_html = macros_series_page::get_introduction(page=page, series_section=series_section, series_ordered_pages=series_ordered_pages, language_strings=language_strings) -%} + {%- set content_with_intro = series_intro_html ~ content_with_intro -%} + {%- endif -%} + + {#- Handle series_outro placeholder -#} + {%- set processed_content = content_with_intro -%} + {%- if "" in content_with_intro -%} + {%- set series_outro_html = macros_series_page::get_outro(page=page, series_section=series_section, series_ordered_pages=series_ordered_pages, language_strings=language_strings) -%} + {%- set processed_content = processed_content | replace(from="", to=series_outro_html) -%} + {%- elif series_section -%} + {%- set series_outro_html = macros_series_page::get_outro(page=page, series_section=series_section, series_ordered_pages=series_ordered_pages, language_strings=language_strings) -%} + {#- We want the outro at the end of the article, but before footnote definitions -#} + {%- set footnotes_marker = '
      ' -%} + {%- if footnotes_marker in content_with_intro -%} + {%- set content_sections = processed_content | split(pat=footnotes_marker) -%} + {%- set main_content = content_sections | first -%} + {%- set footnotes_content = content_sections | slice(start=1) | join(sep=footnotes_marker) -%} + {%- set processed_content = main_content ~ series_outro_html ~ footnotes_marker ~ footnotes_content -%} + {%- else -%} + {%- set processed_content = processed_content ~ series_outro_html -%} + {%- endif -%} + {%- endif -%} + + {#- Replace TOC and render final content -#} + {#- The replace pattern is used to enable arbitrary locations for the Table of Contents -#} + {#- This is Philipp Oppermann's workaround: https://github.com/getzola/zola/issues/584#issuecomment-474329637 -#} + {{ processed_content | replace(from="", to=macros_toc::toc(page=page, header=false, language_strings=language_strings)) | safe }}
    - {# Check if comments are enabled, checking that they are not disabled on the specific page #} + {#- Check if comments are enabled, checking that they are not disabled on the specific page -#} {% set systems = ["giscus", "utterances", "hyvortalk", "isso"] %} {% set enabled_systems = 0 %} {% set comment_system = "" %} @@ -249,9 +275,6 @@

    {% endif %} {% endfor %} - {% if series_section %} - {{ macros_series_page::get_navigation(page=page, series_section=series_section, series_ordered_pages=series_ordered_pages, language_strings=language_strings)}} - {%- endif -%} {% if macros_settings::evaluate_setting_priority(setting="show_previous_next_article_links", page=page, default_global_value=true) == "true" %} {%- if page.lower or page.higher -%} {% set next_label = macros_translate::translate(key="next", default="Next", language_strings=language_strings) %} @@ -299,12 +322,12 @@

    {%- endif -%} {%- endif -%} - {# Ensure only one comment system is enabled #} + {#- Ensure only one comment system is enabled -#} {% if enabled_systems > 1 %} {{ throw(message="ERROR: Multiple comment systems have been enabled for the same page. Check your config.toml and individual page settings to ensure only one comment system is activated at a time.") }} {% endif %} - {# Comments #} + {#- Comments -#} {% if comment_system %} {% include "partials/comments.html" %} {% endif %} diff --git a/theme.toml b/theme.toml index cf527e35b..42516fa1a 100644 --- a/theme.toml +++ b/theme.toml @@ -117,7 +117,7 @@ post_listing_date = "date" # Determines if indexes should be increasing (false) or decreasing (true) in series' posts list. # It has only effect if the section uses indexes metadata (which is only the case for series as of now). # Can be set at section levels, following the hierarchy: section > config. See: https://welpo.github.io/tabi/blog/mastering-tabi-settings/#settings-hierarchy -post_listing_index_reversed = false # Defaults to false. +post_listing_index_reversed = false # Defaults to false. # DEPRECATED! # Use Zola's built-in `bottom_footnotes = true` in the [markdown] section instead. (Available since v0.19.0) @@ -143,10 +143,6 @@ serve_local_mermaid = true # Can be set at page or section levels, following the hierarchy: page > section > config. See: https://welpo.github.io/tabi/blog/mastering-tabi-settings/#settings-hierarchy show_previous_next_article_links = false -# Show links to previous and next series articles at the bottom of posts which is part of a series. -# Can be set at page or section levels, following the hierarchy: page > section > config. See: https://welpo.github.io/tabi/blog/mastering-tabi-settings/#settings-hierarchy -show_previous_next_series_article_links = false - # Invert order of the links to previous and next articles at the bottom of posts. # By default, next articles are on the left side of the page and previous articles are on the right side. # To reverse the order (next articles on the right and previous articles on the left), set it to true.