Hello everybody!
I’d like to propose a feature which I call Arbitrary Content Tables (I don’t know if there is another, preexisting name for it). However, I think I should start with the use case.
Use Case
TL;DR: I want to create multiple "toc"s with somewhat dynamically added, user defined entries.
I am writing my personal blog, on which I want to publish relatively long texts (2500 words and up). In these texts, I’d like to state my sources with a list of all sources at the end (similarly to how Wikipedia does it). Also, I want to create lists of figures and stuff like that.
It would also be quite nice to be able to refer to things in such lists. This is really nice in LaTeX, because there you can refer to e.g. images with a title you can define.
Implementation Idea
The best method of doing that, which I can think of, is to have Zola keep track of an arbitrary amount of tables that users can freely fill with arbitrary content (hence the name). Later, the user would be able to refer back to previously added items and iterate over it.
This could be done by exposing some new functions to templates (interface expressed in rust, for syntax highlighting):
type Text = Option<String>;
type URL = Option<String>;
/// This adds a new entry to the specified _act_ (arbitrary content table).
///
/// - The key can be used to refer to the entry later.
/// - The text and url can be retrieved later, e.g. to render a list of all entries.
/// - The returned number is the length of the specified _act_ after adding the new entry.
fn act_add_entry(
table_name: String,
key: String,
text: Text,
url: URL,
) -> usize;
/// This checks if an entry already exists in an _act_.
fn act_has_entry(table_name: String, key: String) -> bool;
/// This gets a whole _act_ (to iterate over it).
fn act_get_table(table_name: String) -> &HashMap<String, (Text, URL)>;
/// This gets a single entry from an _act_ (e.g. to render references in text).
///
/// The returned `usize` would be the index of the entry.
fn act_get_entry(table_name: String, key: String) -> (usize, Text, URL);
Limitation of this approach
As the tables would be built up while rendering, this would make the position of calling act_get_table
important (a significant difference to how the toc works). In particular, it would be impossible to render an act in front of the content it is referring to.
However, for the given use case, this would not be a problem. Also, CSS could be used to make the act appear in front of its content.
Other approaches
Doing it in Tera
My first idea was to implement this myself using templates and Tera. However, looking at the tera documentation I was unable to find the required expressions. To me it seems to be not possible to create structures (like an entry from above) or append elements to an array.
Also, I don’t think there is a way to pass variables to shortcodes, which I would also need to do.
Doing it by hand
This could also be done by hand, of course. I think the reasons for why this is a bad idea are obvious, but I will still list a few of them:
- it is really easy to mess up the numbers of the references (hence the return value for
act_add_entry(…)
). - it is really easy to miss a reference (hence the user defined
key
). - A list needs to be maintained at the bottom, which would need to be updated whenever something changes.
- Also, the author would need to jump between the bit of the page where the reference is and where the table is.
Other thoughts
- While this feature would of course increase the complexity of Zola a bit, I think it’d be a really powerful tool. In my mind, the trade-off would be worth it.
- I’ve looked at the documentations for a few other SSGs and as far as I can tell, nothings seems to have such a feature. It’d be a unique advantage of Zola.
So now my questions are:
- Do I miss a better/simpler solution for this use case? (without decreasing functionality)
- Would such a feature be accepted into Zola?
- Could this feature somehow be improved?
- Is there some major issue I can’t see?
If the answer to question 2 is “yes”, I’d be willing to implement this myself and submit it as a PR.
Thank you in advance!