1
Fork 0

Implement base table of contents logic

This commit is contained in:
prescientmoon 2024-11-08 07:45:00 +01:00
parent d604ca637d
commit 17f49c2107
Signed by: prescientmoon
SSH key fingerprint: SHA256:WFp/cO76nbarETAoQcQXuV+0h7XJsEsOCI0UsyPIy6U
4 changed files with 89 additions and 2 deletions

View file

@ -10,8 +10,14 @@ A discussion on pretty much every aspect of the mobile rhythm game "Arcaea".
# Why I love arcaea
## What is arcaea
- explain the base mechanics
## Introduction
- What is arcaea
- What this article is
- How to read this article
::: toc
:::
## What makes a good rhythm game
- I don't need to reinvent the wheel here, I can link that one `mental checkpoint` video

View file

@ -1,3 +1,4 @@
use std::cmp::Ordering;
use std::collections::HashMap;
use std::fmt::Display;
@ -311,6 +312,64 @@ impl<'s> Writer<'s> {
self.states.push(State::Ignore);
}
// }}}
// {{{ Table of contents
Container::Div { class: "toc" } => {
template!("templates/table-of-contents.html", out)?.feed_fully(
out,
|label, out| {
if label == "content" {
let mut level_stack = Vec::with_capacity(6);
level_stack.push(1);
for (i, heading) in self.metadata.toc.iter().enumerate() {
loop {
let level = level_stack.last().unwrap();
match heading.level.cmp(level) {
Ordering::Greater => {
writeln!(out, "<ol>")?;
level_stack.push(heading.level);
break;
}
Ordering::Equal => {
if i != 0 {
writeln!(out, "</li>")?;
}
break;
}
Ordering::Less => {
writeln!(out, "</li></ol>")?;
level_stack.pop();
}
}
}
write!(out, r##"<li><a href="#{}">"##, heading.id)?;
for event in &heading.events {
self.render_event(event, out)?;
}
writeln!(out, "</a>")?;
}
for _ in 0..level_stack.len() - 1 {
writeln!(out, "</li></ol>")?;
}
writeln!(out, "</li>")?;
Ok(true)
} else {
Ok(false)
}
},
)?;
// We don't care about the contents of this block
self.states.push(State::Ignore);
}
// }}}
// {{{ Div
Container::Div { class } => {
if has_role(attrs, "description") {

View file

@ -129,6 +129,7 @@ impl<'a> TemplateRenderer<'a> {
}
// }}}
/// Automatically fill in placeholders until the provided lambda returns false.
pub fn feed<W: std::fmt::Write>(
&mut self,
out: &mut W,
@ -144,6 +145,18 @@ impl<'a> TemplateRenderer<'a> {
Ok(())
}
/// Equivalent to running [Self::feed] and then [Self::finish].
pub fn feed_fully<W: std::fmt::Write>(
mut self,
out: &mut W,
f: impl FnMut(&str, &mut W) -> anyhow::Result<bool>,
) -> anyhow::Result<()> {
self.feed(out, f)?;
self.finish(out)?;
Ok(())
}
}
// }}}
// {{{ Macro

View file

@ -0,0 +1,9 @@
<details>
<summary>Toggle table of contents</summary>
<nav role="doc-toc" aria-labelledby="toc-title">
<h2 id="toc-title">Table of Contents</h2>
<ol>
{{content}}
</ol>
</nav>
</details>