Insert anchor as full heading (#1916)

* Add insert_anchor = "heading"

* Update CHANGELOG.md

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
This commit is contained in:
Vincent Prouillet 2022-07-10 15:02:07 +02:00 committed by GitHub
parent 065e8e64e5
commit 7208b86d77
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 45 additions and 7 deletions

View file

@ -4,11 +4,11 @@
### Breaking
- Switch to pulldown-cmark anchor rather than ours, some (very niche) edge cases are not supported anymore, you can
- Switch to pulldown-cmark anchor system rather than ours, some (very niche) edge cases are not supported anymore, you can
also specify classes on headers now
- Now outputs empty taxonomies instead of ignoring them
- Unify all pages sorting variable names in templates to `lower`/`higher` in order to make it easy to re-use templates and it
was becoming hard to come up with names
was becoming hard to come up with names to be honest
### Other
- Fix markup for fenced code with linenos
@ -24,11 +24,12 @@ any pages related to that taxonomy
- Ignore sections with `render=false` when looking for path collisions
- Add support for backlinks
- Add a warning mode for internal/external link checking in case you don't want zola to stop the build on invalid links
- Always follow symlinks
- Always follow symlinks when loading the site/assets
- Add `rel="alternate"` to Atom post links
- Fix taxonomy `current_path`
- Fix feed location for taxonomies not in the default language
- Add `title_bytes` sorting method
- Add `insert_anchor = "heading"`, which allows users to use the entire heading as a link (rather than needing a seperate icon)
## 0.15.3 (2022-01-23)

View file

@ -30,6 +30,10 @@ static EMOJI_REPLACER: Lazy<EmojiReplacer> = Lazy::new(EmojiReplacer::new);
/// [uri-schemes]: https://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml
static STARTS_WITH_SCHEMA_RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"^[0-9A-Za-z\-]+:").unwrap());
/// Matches a <a>..</a> tag, getting the opening tag in a capture group.
/// Used only with AnchorInsert::Heading to grab it from the template
static A_HTML_TAG: Lazy<Regex> = Lazy::new(|| Regex::new(r"(<\s*a[^>]*>).*?<\s*/\s*a>").unwrap());
/// Efficiently insert multiple element in their specified index.
/// The elements should sorted in ascending order by their index.
///
@ -516,7 +520,8 @@ pub fn markdown_to_html(
let anchor_idx = match context.insert_anchor {
InsertAnchor::Left => start_idx + 1,
InsertAnchor::Right => end_idx,
InsertAnchor::None => 0, // Not important
InsertAnchor::Heading => 0, // modified later to the correct value
InsertAnchor::None => unreachable!(),
};
let mut c = tera::Context::new();
c.insert("id", &id);
@ -530,7 +535,15 @@ pub fn markdown_to_html(
&None,
)
.context("Failed to render anchor link template")?;
anchors_to_insert.push((anchor_idx, Event::Html(anchor_link.into())));
if context.insert_anchor != InsertAnchor::Heading {
anchors_to_insert.push((anchor_idx, Event::Html(anchor_link.into())));
} else {
if let Some(captures) = A_HTML_TAG.captures(&anchor_link) {
let opening_tag = captures.get(1).map_or("", |m| m.as_str()).to_string();
anchors_to_insert.push((start_idx + 1, Event::Html(opening_tag.into())));
anchors_to_insert.push((end_idx, Event::Html("</a>".into())));
}
}
}
// record heading to make table of contents

View file

@ -101,6 +101,9 @@ fn can_insert_anchors() {
let body =
common::render_with_insert_anchor(&cases.join("\n"), InsertAnchor::Right).unwrap().body;
insta::assert_snapshot!(body);
let body =
common::render_with_insert_anchor(&cases.join("\n"), InsertAnchor::Heading).unwrap().body;
insta::assert_snapshot!(body);
}
#[test]

View file

@ -0,0 +1,10 @@
---
source: components/markdown/tests/markdown.rs
expression: body
---
<h1 id="hello"><a class="zola-anchor" href="#hello" aria-label="Anchor link for: hello">Hello</a></h1>
<h1 id="world"><a class="zola-anchor" href="#world" aria-label="Anchor link for: world">World</a></h1>
<h1 id="hello-1"><a class="zola-anchor" href="#hello-1" aria-label="Anchor link for: hello-1">Hello!</a></h1>
<h2 id="rust"><a class="zola-anchor" href="#rust" aria-label="Anchor link for: rust"><a href="https://rust-lang.org">Rust</a></a></h2>
<h1 id="hello-2"><a class="zola-anchor" href="#hello-2" aria-label="Anchor link for: hello-2">Hello*_()</a></h1>

View file

@ -5,5 +5,12 @@ use serde::{Deserialize, Serialize};
pub enum InsertAnchor {
Left,
Right,
Heading,
None,
}
impl InsertAnchor {
pub fn uses_template(&self) -> bool {
matches!(self, InsertAnchor::Left | InsertAnchor::Right)
}
}

View file

@ -32,7 +32,7 @@ links working.
## Anchor insertion
It is possible to have Zola automatically insert anchor links next to the heading, as you can see on this documentation
if you hover a title.
if you hover a title or covering the full heading text.
This option is set at the section level: the `insert_anchor_links` variable on the
[section front matter page](@/documentation/content/section.md#front-matter).
@ -47,6 +47,9 @@ The anchor link template has the following variables:
- `lang`: the current language, unless called from the `markdown` template filter, in which case it will always be `en`
- `level`: the heading level (between 1 and 6)
If you use `insert_anchor = "heading"`, the template will still be used but only the opening `<a>` tag will get extracted
from it, everything else will not be used.
## Internal links
Linking to other pages and their headings is so common that Zola adds a
special syntax to Markdown links to handle them: start the link with `@/` and point to the `.md` file you want

View file

@ -79,7 +79,8 @@ paginate_reversed = false
# This determines whether to insert a link for each header like the ones you can see on this site if you hover over
# a header.
# The default template can be overridden by creating an `anchor-link.html` file in the `templates` directory.
# This value can be "left", "right" or "none".
# This value can be "left", "right", "heading" or "none".
# "heading" means the full heading becomes the text of the anchor.
insert_anchor_links = "none"
# If set to "true", the section pages will be in the search index. This is only used if