diff options
| author | Alejandro Soto <alejandro@34project.org> | 2025-09-13 14:55:15 -0600 |
|---|---|---|
| committer | Alejandro Soto <alejandro@34project.org> | 2025-09-13 14:55:15 -0600 |
| commit | a2ea06d513a5802964f8f0ef5795cec7e548ed7b (patch) | |
| tree | 8afb58e3749d19bc46cffc6473f3059d647c515b /templates/macros | |
Squashed 'themes/tabi-lean/' content from commit 95c8796
git-subtree-dir: themes/tabi-lean
git-subtree-split: 95c879696445ede40daa7a30a88dae5dd74d5c0c
Diffstat (limited to 'templates/macros')
| -rw-r--r-- | templates/macros/feed_utils.html | 17 | ||||
| -rw-r--r-- | templates/macros/format_date.html | 59 | ||||
| -rw-r--r-- | templates/macros/list_posts.html | 163 | ||||
| -rw-r--r-- | templates/macros/page_header.html | 18 | ||||
| -rw-r--r-- | templates/macros/rel_attributes.html | 19 | ||||
| -rw-r--r-- | templates/macros/series_page.html | 162 | ||||
| -rw-r--r-- | templates/macros/settings.html | 68 | ||||
| -rw-r--r-- | templates/macros/table_of_contents.html | 54 | ||||
| -rw-r--r-- | templates/macros/target_attribute.html | 11 | ||||
| -rw-r--r-- | templates/macros/translate.html | 72 |
10 files changed, 643 insertions, 0 deletions
diff --git a/templates/macros/feed_utils.html b/templates/macros/feed_utils.html new file mode 100644 index 0000000..ff35194 --- /dev/null +++ b/templates/macros/feed_utils.html @@ -0,0 +1,17 @@ +{#- Feed utility macros -#} + +{#- Zola 0.19.0 uses `generate_feeds`. Prior versions use `generate_feed` -#} +{%- macro get_generate_feed() -%} + {{- config.generate_feeds | default(value=config.generate_feed) -}} +{%- endmacro get_generate_feed -%} + +{%- macro get_feed_url() -%} + {{- config.feed_filenames[0] | default(value=(config.feed_filename)) -}} +{%- endmacro get_feed_url -%} + +{#- Check footer feed icon conditions -#} +{%- macro should_show_footer_feed_icon() -%} + {%- set generate_feed = feed_utils::get_generate_feed() == "true" -%} + {%- set feed_url = feed_utils::get_feed_url() -%} + {{- generate_feed and config.extra.feed_icon and feed_url -}} +{%- endmacro should_show_footer_feed_icon -%} diff --git a/templates/macros/format_date.html b/templates/macros/format_date.html new file mode 100644 index 0000000..f747fd1 --- /dev/null +++ b/templates/macros/format_date.html @@ -0,0 +1,59 @@ +{%- macro format_date(date, short, language_strings="") -%} + +{#- Set locale -#} +{%- set date_locale = macros_translate::translate(key="date_locale", default="en_GB", language_strings=language_strings) -%} + +{#- Check for language-specific date formats -#} +{%- set language_format = "" -%} +{%- if config.extra.date_formats -%} + {%- for format_config in config.extra.date_formats -%} + {%- if format_config.lang == lang -%} + {%- if short and format_config.short -%} + {%- set_global language_format = format_config.short -%} + {%- elif not short and format_config.long -%} + {%- set_global language_format = format_config.long -%} + {%- endif -%} + {%- endif -%} + {%- endfor -%} +{%- endif -%} + +{%- if language_format -%} + {{ date | date(format=language_format, locale=date_locale) }} +{%- elif config.extra.short_date_format and short -%} + {{ date | date(format=config.extra.short_date_format, locale=date_locale) }} +{%- elif config.extra.long_date_format and not short -%} + {{ date | date(format=config.extra.long_date_format, locale=date_locale) }} +{%- elif not config.extra.short_date_format and date_locale == "en_GB" -%} + {%- set day = date | date(format='%-d') | int -%} + + {%- if day in [11, 12, 13] -%} + {%- set suffix = "th" -%} + {%- else -%} + {%- set last_digit = day % 10 -%} + {%- if last_digit == 1 -%} + {%- set suffix = "st" -%} + {%- elif last_digit == 2 -%} + {%- set suffix = "nd" -%} + {%- elif last_digit == 3 -%} + {%- set suffix = "rd" -%} + {%- else -%} + {%- set suffix = "th" -%} + {%- endif -%} + {%- endif -%} + + {#- Return the date. -#} + {{ date | date(format="%-d") }}{{ suffix }} + {%- if short == true -%} + {{ date | date(format=" %b %Y") }} + {%- else -%} + {{ date | date(format=" %B %Y") }} + {%- endif -%} +{%- else -%} + {%- if short -%} + {{ date | date(format="%-d %b %Y", locale=date_locale) }} + {%- else -%} + {{ date | date(format="%d %b %Y", locale=date_locale) }} + {%- endif -%} +{%- endif -%} + +{%- endmacro -%} diff --git a/templates/macros/list_posts.html b/templates/macros/list_posts.html new file mode 100644 index 0000000..2076194 --- /dev/null +++ b/templates/macros/list_posts.html @@ -0,0 +1,163 @@ +{# `metadata` can be "dates", "indexes" or both (e.g. "dates indexes" or "indexes dates"). #} +{# If both, the order doesn't matter and indexes will always be displayed before dates. #} +{# It would also work with arrays (e.g. ["dates"] or ["indexes"] or even ["indexes","dates"]). #} +{# Nevertheless, arrays cannot be used as a default value for a macro parameter in Tera (see https://github.com/Keats/tera/issues/710). #} +{# `paginator` is only used to compute indexes metadata and can be let empty otherwise. #} +{% macro list_posts(posts, all_posts="", max=999999, metadata="dates", language_strings="", section_path="", paginator="", pinned_first=false, current_page=1) %} + +{%- set separator = config.extra.separator | default(value="•") -%} + +{# Separate pinned and regular posts from all_posts if available, otherwise from posts #} +{% if pinned_first %} + {% set source_posts = all_posts | default(value=posts) %} + {% set pinned_posts = [] %} + {% set regular_posts = [] %} + {% for post in source_posts %} + {% if post.extra.pinned %} + {% set_global pinned_posts = pinned_posts | concat(with=post) %} + {% else %} + {% set_global regular_posts = regular_posts | concat(with=post) %} + {% endif %} + {% endfor %} + + {# On page 1 or when no pagination, show pinned then regular #} + {% if current_page == 1 %} + {% if paginator %} + {# With pagination: pinned + current page's posts #} + {% set display_posts = pinned_posts | concat(with=posts) %} + {% else %} + {# Without pagination: pinned + regular (no duplicates) #} + {% set display_posts = pinned_posts | concat(with=regular_posts) %} + {% endif %} + {% else %} + {% set display_posts = posts %} + {% endif %} +{% else %} + {% set display_posts = posts %} +{% endif %} + +<div class="bloglist-container"> + {# Display posts #} + {% for post in display_posts %} + {% if loop.index <= max %} + {% if loop.index == max or loop.last %} + {% set bottom_divider = false %} + {% else %} + {% set bottom_divider = true %} + {% endif %} + + <section class="bloglist-meta {% if bottom_divider -%}bottom-divider{%- endif -%}"> + <ul> + {%- if "indexes" in metadata -%} + {%- set post_index = loop.index -%} + {%- set number_of_posts = posts | length -%} + {# in case we have a pager, the index has been computed for the current page. #} + {%- if paginator -%} + {%- set number_of_posts = paginator.total_pages -%} + {%- set number_of_other_pages = paginator.current_index - 1 -%} + {%- set posts_per_page = paginator.paginate_by -%} + {%- set posts_in_other_pages = number_of_other_pages * posts_per_page -%} + {%- set post_index = posts_in_other_pages + post_index -%} + {%- endif -%} + {%- if macros_settings::evaluate_setting_priority(setting="post_listing_index_reversed", page=section, default_global_value=false) == "true" -%} + {# index starts at 1 instead of 0 #} + {%- set post_index = number_of_posts + 1 - post_index -%} + {%- endif -%} + <li class="index-label">{{ post_index }}</li> + {%- endif -%} + + {%- if "dates" in metadata -%} + {%- set allowed_post_listing_dates = ["date", "updated", "both"] -%} + {#- Calling the hierarchy macro here causes an error due to the "get parents" part of the macro. -#} + {#- This seems cleaner. -#} + {%- set post_listing_date = section.extra.post_listing_date | default(value=config.extra.post_listing_date) | default(value="date") -%} + {%- if post_listing_date not in allowed_post_listing_dates -%} + {{ throw(message="ERROR: Invalid value for config.extra.post_listing_date. Allowed values are 'date', 'updated', or 'both'.") }} + {%- endif -%} + + {%- set show_date = post.date and post_listing_date == "date" or post.date and post_listing_date == "both" or post.date and post_listing_date == "updated" and not post.updated -%} + {%- set show_updated = post.updated and post_listing_date == "updated" or post.updated and post_listing_date == "both" -%} + + {%- if show_date or show_updated -%} + {%- if show_date -%} + <li class="date">{{- macros_format_date::format_date(date=post.date, short=false, language_strings=language_strings) -}}</li> + {%- endif -%} + {%- if show_date and show_updated -%} + <li class="mobile-only separator">{{- separator -}}</li> + {%- endif -%} + {%- if show_updated -%} + {%- set last_updated_str = macros_translate::translate(key="last_updated_on", default="Updated on $DATE", language_strings=language_strings) -%} + {%- set formatted_date = macros_format_date::format_date(date=post.updated, short=true, language_strings=language_strings) -%} + {%- set updated_str = last_updated_str | replace(from="$DATE", to=formatted_date) -%} + <li class="date">{{ updated_str }}</li> + {%- endif -%} + {%- endif -%} + {%- endif -%} + + {% if post.extra.local_image or post.extra.remote_image %} + <li class="post-thumbnail"> + <a href="{{ post.permalink }}"> + {% if post.extra.local_image %} + {% set meta = get_image_metadata(path=post.extra.local_image, allow_missing=true) %} + <img class="thumbnail-image" + alt="{{ post.extra.local_image }}" + src="{{ get_url(path=post.extra.local_image) }}" + {% if meta.width %}width="{{ meta.width }}"{% endif %} + {% if meta.height %}height="{{ meta.height }}"{% endif %}> + {% elif post.extra.remote_image %} + <img class="thumbnail-image" + alt="{{ post.extra.remote_image }}" + src="{{ post.extra.remote_image }}"> + {% endif %} + </a> + </li> + {% endif %} + + {% if post.draft %} + <li class="draft-label">{{ macros_translate::translate(key="draft", default="DRAFT", language_strings=language_strings) }}</li> + {% endif %} + </ul> + </section> + + <section class="bloglist-content {% if bottom_divider -%}bottom-divider{%- endif -%}"> + <div> + {% if pinned_first and post.extra.pinned %} + <div class="pinned-label"> + <svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill="currentColor" fill-rule="evenodd" d="M10.5 2.255v-.01c.003-.03.013-.157-.361-.35C9.703 1.668 8.967 1.5 8 1.5s-1.703.169-2.138.394c-.375.194-.365.32-.362.351v.01c-.003.03-.013.157.362.35C6.297 2.832 7.033 3 8 3s1.703-.169 2.139-.394c.374-.194.364-.32.361-.351M12 2.25c0 .738-.433 1.294-1.136 1.669l.825 2.31c1.553.48 2.561 1.32 2.561 2.52c0 1.854-2.402 2.848-5.5 2.985V15a.75.75 0 0 1-1.5 0v-3.266c-3.098-.136-5.5-1.131-5.5-2.984c0-1.2 1.008-2.04 2.561-2.52l.825-2.311C4.433 3.544 4 2.988 4 2.25C4 .75 5.79 0 8 0s4 .75 4 2.25" clip-rule="evenodd"/></svg> + <span>{{ macros_translate::translate(key="pinned", default="Pinned", language_strings=language_strings) }}</span> + </div> + {% endif %} + + <h2 class="bloglist-title"> + <a href="{{ post.permalink }}">{{ post.title }}</a> + </h2> + + {% if post.taxonomies.tags %} + <div class="bloglist-tags"> + {% for tag in post.taxonomies.tags %} + <a class="tag" href="{{ get_taxonomy_url(kind='tags', name=tag, lang=lang) | safe }}">{{ tag }}</a> + {% endfor %} + </div> + {% endif %} + + <div class="description"> + {% if post.description %} + <p>{{ post.description | markdown(inline=true) | safe }}</p> + {% elif post.summary %} + <p>{{ post.summary | markdown(inline=true) | trim_end_matches(pat=".") | safe }}…</p> + {% endif %} + </div> + <a class="readmore" href="{{ post.permalink }}">{{ macros_translate::translate(key="read_more", default="Read more", language_strings=language_strings) }} <span class="arrow">→</span></a> + </div> + </section> + {% endif %} + {% if not loop.last %} + {% if loop.index == max %} + <div class="all-posts"> + <a href="{{ get_url(path=section_path, lang=lang) }}/">{{ macros_translate::translate(key="all_posts", default="All posts", language_strings=language_strings) }} <span class="arrow">⟶</span></a> + </div> + {% endif %} + {% endif %} + {% endfor %} +</div> +{% endmacro %} diff --git a/templates/macros/page_header.html b/templates/macros/page_header.html new file mode 100644 index 0000000..daa8d02 --- /dev/null +++ b/templates/macros/page_header.html @@ -0,0 +1,18 @@ +{% macro page_header(title, show_feed_icon=false) %} + +{% set rel_attributes = macros_rel_attributes::rel_attributes() | trim %} + + +{%- set blank_target = macros_target_attribute::target_attribute(new_tab=config.markdown.external_links_target_blank) -%} + +<h1 class="title-container section-title bottom-divider"> + {{ title -}} + {% if show_feed_icon %} + {%- set feed_url = feed_utils::get_feed_url() -%} + <a class="no-hover-padding social" rel="{{ rel_attributes }}" {{ blank_target }} href="{{ get_url(path=term.path ~ feed_url, lang=lang, trailing_slash=false) | safe }}"> + <img loading="lazy" alt="feed" title="feed" src="{{ get_url(path='/social_icons/rss.svg') }}"> + </a> + {% endif %} +</h1> + +{% endmacro page_header %} diff --git a/templates/macros/rel_attributes.html b/templates/macros/rel_attributes.html new file mode 100644 index 0000000..71672c7 --- /dev/null +++ b/templates/macros/rel_attributes.html @@ -0,0 +1,19 @@ +{% macro rel_attributes() %} + +{%- set rel_attributes = [] -%} +{%- if config.markdown.external_links_target_blank -%} + {%- set rel_attributes = rel_attributes | concat(with="noopener") -%} +{%- endif -%} +{# https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel#nofollow #} +{# This is ignored, as it doesn't make sense to set `nofollow` on projects or social links. #} +{# {%- if config.markdown.external_links_no_follow -%} + {%- set rel_attributes = rel_attributes | concat(with="nofollow") -%} +{%- endif -%} #} +{%- if config.markdown.external_links_no_referrer -%} + {%- set rel_attributes = rel_attributes | concat(with="noreferrer") -%} +{%- endif -%} + +{# Return the array of rel attributes joined by a space #} +{{- rel_attributes | join(sep=" ") -}} + +{% endmacro rel_attributes %} diff --git a/templates/macros/series_page.html b/templates/macros/series_page.html new file mode 100644 index 0000000..d5704a1 --- /dev/null +++ b/templates/macros/series_page.html @@ -0,0 +1,162 @@ +{# +Those macros deal with introduction and navigation for series pages. +Using macros have been prefered over partial inclusion or inline code to make sure series_ordered_pages is forced to be used. +A section's pages natural order is invalid in case of reversed pagination which would lead to invalid series' pages order. +To prevent this, pages are ordered correctly in a separate variable which must be used instead of the series section pages. +#} + +{# +Computes the introduction of a series's page. + +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 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 = '<a href="' ~ series_section.permalink ~ '" aria_label="' ~ series_section.title ~ '">' ~ series_section.title ~ '</a>' -%} + {# 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 = '<li>' ~ series_page.title ~ '</li>' -%} + {%- else -%} + {%- set series_pages_list_item = '<li><a href="' ~ series_page.permalink ~ '" aria_label="' ~ series_page.title ~ '">' ~ series_page.title ~ '</a></li>' -%} + {%- 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 = '<ol reversed>' ~ series_pages_list ~ '</ol>' -%} + {%- else -%} + {%- set series_pages_ordered_list = '<ol>' ~ series_pages_list ~ '</ol>' -%} + {%- endif -%} + {%- set series_pages_unordered_list = '<ul>' ~ series_pages_list ~ '</ul>' -%} + + {# 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 -%} + + {# 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 -%} + + {# Prepare navigation variables #} + {%- if prev_page is defined -%} + {%- set prev_title = prev_page.title -%} + {%- set prev_permalink = prev_page.permalink -%} + {%- set prev_html_link = '<a href="' ~ prev_page.permalink ~ '" aria_label="' ~ prev_page.title ~ '">' ~ prev_page.title ~ '</a>' -%} + {%- 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 = '<a href="' ~ next_page.permalink ~ '" aria_label="' ~ next_page.title ~ '">' ~ next_page.title ~ '</a>' -%} + {%- 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='<a href="' ~ first_page.permalink ~ '">' ~ first_page.title ~ '</a>') + | 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 -%} + + {%- 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 -%} + + {# 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 -%} + <section class="series-page-{{ template_type }}"> + {{ template | markdown | safe }} + </section> + {%- endif -%} + {%- endif -%} +{% endmacro %} + +{# 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 %} + +{# 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/macros/settings.html b/templates/macros/settings.html new file mode 100644 index 0000000..d237d7a --- /dev/null +++ b/templates/macros/settings.html @@ -0,0 +1,68 @@ +{# +Evaluates the priority of a particular setting across different scopes. + +The priority is as follows: page > section > config. + +Parameters: + - setting: The name of the setting to evaluate. + - page: The page object containing settings. + - default_global_value: The setting's default value. +#} + +{% macro evaluate_setting_priority(setting, page, section="", default_global_value="") %} + +{%- if section -%} + {%- set current_section = section -%} +{%- elif page -%} + {%- set current_section = "" -%} + {#- Retrieve last ancestor to determine current section, if applicable -#} + {%- if page.ancestors | length > 0 -%} + {%- set last_ancestor = page.ancestors | slice(start=-1) -%} + {%- set_global current_section = get_section(path=last_ancestor.0, metadata_only=true) -%} + {%- else -%} + {#- We're likely in a nested page. Try to find the parent page or nearest section. -#} + {%- set components = page.components -%} + {%- for i in range(start=1, end=components | length) -%} + {%- if lang == config.default_language -%} + {%- set potential_path = components | slice(end=components | length - i) | join(sep="/") -%} + {%- set potential_page = potential_path ~ "/index.md" -%} + {%- set potential_section = potential_path ~ "/_index.md" -%} + {%- else -%} + {%- set potential_path = components | slice(start=1, end=components | length - i) | join(sep="/") -%} + {%- set potential_page = potential_path ~ "/index." ~ lang ~ ".md" -%} + {%- set potential_section = potential_path ~ "/_index." ~ lang ~ ".md" -%} + {%- endif -%} + {#- Check for parent page first. -#} + {%- set page_data = load_data(path=potential_page, required=false) -%} + {%- if page_data -%} + {%- set_global current_section = get_page(path=potential_page) -%} + {%- break -%} + {%- endif -%} + {#- No parent page, check for section. -#} + {%- set section_data = load_data(path=potential_section, required=false) -%} + {%- if section_data -%} + {%- set_global current_section = get_section(path=potential_section, metadata_only=true) -%} + {%- break -%} + {%- endif -%} + {%- endfor -%} + {%- endif -%} +{%- endif -%} + +{%- set priority_order = [ + page.extra[setting] | default(value=""), + current_section.extra[setting] | default(value=""), + config.extra[setting] | default(value="") +] -%} + +{%- set output = default_global_value -%} + +{%- for value in priority_order -%} + {%- if value != "" -%} + {%- set_global output = value -%} + {%- break -%} + {%- endif -%} +{%- endfor -%} + +{{- output -}} + +{% endmacro %} diff --git a/templates/macros/table_of_contents.html b/templates/macros/table_of_contents.html new file mode 100644 index 0000000..18a3ab6 --- /dev/null +++ b/templates/macros/table_of_contents.html @@ -0,0 +1,54 @@ +{% macro toc(page, header, language_strings="") %} + +{%- set toc_levels = page.extra.toc_levels | default(value=3) -%} + +{% if page.extra.toc_ignore_pattern %} + {%- set toc_ignore_pattern = page.extra.toc_ignore_pattern -%} +{% endif %} + +<div class="toc-container"> + {% if header %} + <h3>{{ macros_translate::translate(key="table_of_contents", default="Table of Contents", language_strings=language_strings) }}</h3> + {% endif %} + + <ul> + {% for h1 in page.toc %} + {# Only render headers if there's no ignore pattern, or if the header text doesn't match the pattern. #} + {% if not toc_ignore_pattern or not (h1.title is matching(toc_ignore_pattern)) %} + <li><a href="{{ h1.permalink | safe }}">{{ h1.title }}</a> + {% if h1.children and toc_levels > 1 %} + <ul> + {% for h2 in h1.children %} + {% if not toc_ignore_pattern or not (h2.title is matching(toc_ignore_pattern)) %} + <li><a href="{{ h2.permalink | safe }}">{{ h2.title }}</a> + {% if h2.children and toc_levels > 2 %} + <ul> + {% for h3 in h2.children %} + {% if not toc_ignore_pattern or not (h3.title is matching(toc_ignore_pattern)) %} + <li><a href="{{ h3.permalink | safe }}">{{ h3.title }}</a> + {% if h3.children and toc_levels > 3 %} + <ul> + {% for h4 in h3.children %} + {% if not toc_ignore_pattern or not (h4.title is matching(toc_ignore_pattern)) %} + <li><a href="{{ h4.permalink | safe }}">{{ h4.title }}</a></li> + {% endif %} + {% endfor %} + </ul> + {% endif %} + </li> + {% endif %} + {% endfor %} + </ul> + {% endif %} + </li> + {% endif %} + {% endfor %} + </ul> + {% endif %} + </li> + {% endif %} + {% endfor %} + </ul> +</div> + +{% endmacro toc %} diff --git a/templates/macros/target_attribute.html b/templates/macros/target_attribute.html new file mode 100644 index 0000000..2da5b9d --- /dev/null +++ b/templates/macros/target_attribute.html @@ -0,0 +1,11 @@ +{% macro target_attribute(new_tab) %} + +{%- set blank_target = "" -%} + +{%- if new_tab -%} + {%- set blank_target = "target=_blank" -%} +{%- endif -%} + +{{ blank_target }} + +{% endmacro target_attribute %} diff --git a/templates/macros/translate.html b/templates/macros/translate.html new file mode 100644 index 0000000..1b138dd --- /dev/null +++ b/templates/macros/translate.html @@ -0,0 +1,72 @@ +{#- Dynamically selects the appropriate translation key based on the provided `number` and `lang` context. +If a `number` is provided, the macro will attempt to pluralize the translation key based on the language's rules. + +Parameters: +- `key`: The base key for the translation string, matching the i18n files. Example: `results` to get `zero_results`, `one_results`, `many_results`, etc. +- `number`: Optional. The numerical value associated with the key. +- `language_strings`: A dictionary containing the translation strings. +- `default`: A default string to use if no translation is found for the key. +- `replace`: Optional. If `true`, the macro will replace the `$NUMBER` placeholder in the translation string with the provided `number`. + +The macro supports special pluralization rules for: +- Arabic (`ar`): Has unique forms for zero, one, two, few, and many. +- Slavic languages: Pluralization depends on the last digit of the number, with exceptions for numbers ending in 11-14. + +NOTE: If the logic for pluralization is modified, it needs to be replicated on the JavaScript search. +Files: static/js/searchElasticlunr.js and its minified version at static/js/searchElasticlunr.min.js +Function name: getPluralizationKey -#} +{% macro translate(key, number=-1, language_strings="", default="", replace=true) %} + {%- set slavic_plural_languages = ["uk", "be", "bs", "hr", "ru", "sr"] -%} + + {%- set key_prefix = "" -%} + {#- `zero_` and `one_` are common cases. We handle "many" (plural) later, after language-specific pluralization -#} + {%- if number == 0 -%} + {%- set key_prefix = "zero_" -%} + {%- elif number == 1 -%} + {%- set key_prefix = "one_" -%} + {%- endif -%} + + {#- Pluralization -#} + {%- if number != -1 and key_prefix == "" -%} + {#- Arabic -#} + {%- if lang == "ar" -%} + {%- set modulo = number % 100 -%} + {%- if number == 2 -%} + {%- set key_prefix = "two_" -%} + {%- elif modulo >= 3 and modulo <= 10 -%} + {%- set key_prefix = "few_" -%} + {%- else -%} + {%- set key_prefix = "many_" -%} + {%- endif -%} + {#- Slavic languages like Russian or Ukrainian -#} + {%- elif lang in slavic_plural_languages -%} + {%- set modulo10 = number % 10 -%} + {%- set modulo100 = number % 100 -%} + {%- if modulo10 == 1 and modulo100 != 11 -%} + {%- set key_prefix = "one_" -%} + {%- elif modulo10 >= 2 and modulo10 <= 4 -%} + {%- if modulo100 >= 12 and modulo100 <= 14 -%} + {%- set key_prefix = "many_" -%} + {%- else -%} + {%- set key_prefix = "few_" -%} + {%- endif -%} + {%- else -%} + {%- set key_prefix = "many_" -%} + {%- endif -%} + {%- else -%} + {#- Default pluralization -#} + {#- Zero and one are already handled -#} + {%- set key_prefix = "many_" -%} + {%- endif -%} + {%- endif -%} + + {#- Translated string -#} + {%- set final_key = key_prefix ~ key -%} + {%- set translated_text = language_strings[final_key] | default(value=default) | safe -%} + + {#- Replace $NUMBER with the number -#} + {%- if replace -%} + {%- set translated_text = translated_text | replace(from="$NUMBER", to=number | as_str) -%} + {%- endif -%} + {{- translated_text -}} +{% endmacro %} |
