add: multiple pages in one entry, details syntax
This commit is contained in:
parent
db63427795
commit
a127a0407d
3 changed files with 217 additions and 4 deletions
|
@ -349,3 +349,20 @@ globalThis.toggle_metadata_css = (e) => {
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
globalThis.hash_check = (hash) => {
|
||||||
|
if (hash.startsWith("#/")) {
|
||||||
|
for (const x of Array.from(document.querySelectorAll(".subpage"))) {
|
||||||
|
x.classList.add("hidden");
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById(hash).classList.remove("hidden");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener("hashchange", (_) => hash_check(window.location.hash));
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
// run initial hash check
|
||||||
|
hash_check(window.location.hash);
|
||||||
|
}, 150);
|
||||||
|
|
|
@ -709,3 +709,20 @@ table tr:not(thead *):nth-child(odd) {
|
||||||
table thead th {
|
table thead th {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* details */
|
||||||
|
details {
|
||||||
|
width: 100%;
|
||||||
|
margin: var(--pad-4) 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
details summary {
|
||||||
|
background: var(--color-super-raised);
|
||||||
|
padding: var(--pad-2) var(--pad-4);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
details .content {
|
||||||
|
padding: var(--pad-4);
|
||||||
|
background: var(--color-surface);
|
||||||
|
}
|
||||||
|
|
187
src/markdown.rs
187
src/markdown.rs
|
@ -1,11 +1,13 @@
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
pub fn render_markdown(input: &str) -> String {
|
pub fn render_markdown(input: &str) -> String {
|
||||||
let html = tetratto_shared::markdown::render_markdown_dirty(&parse_text_color(
|
let html = tetratto_shared::markdown::render_markdown_dirty(&parse_page(&parse_details(
|
||||||
&parse_highlight(&parse_link(&parse_image(&parse_image_size(
|
&parse_text_color(&parse_highlight(&parse_link(&parse_image(
|
||||||
&parse_underline(&parse_comment(&input.replace("[/]", "<br />"))),
|
&parse_image_size(&parse_underline(&parse_comment(
|
||||||
|
&input.replace("[/]", "<br />"),
|
||||||
|
))),
|
||||||
)))),
|
)))),
|
||||||
))
|
)))
|
||||||
.replace("$per", "%");
|
.replace("$per", "%");
|
||||||
|
|
||||||
let mut allowed_attributes = HashSet::new();
|
let mut allowed_attributes = HashSet::new();
|
||||||
|
@ -704,3 +706,180 @@ pub fn parse_image(input: &str) -> String {
|
||||||
pub fn parse_link(input: &str) -> String {
|
pub fn parse_link(input: &str) -> String {
|
||||||
parser_ignores_pre!(parse_link_line, input)
|
parser_ignores_pre!(parse_link_line, input)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Match page definitions.
|
||||||
|
///
|
||||||
|
/// Each page is denoted with two at symbols, followed by the name of the page.
|
||||||
|
/// The page can also have an optional second argument (separated by a semicolon)
|
||||||
|
/// which accepts the "visible" value; marking the page as visible by default.
|
||||||
|
///
|
||||||
|
/// To close a page (after you're done with the page's content), just put two
|
||||||
|
/// at symbols with nothing else on the line.
|
||||||
|
///
|
||||||
|
/// You're able to put content AFTER the page closing line. This allows you to have
|
||||||
|
/// persistant content which is shared between every page. Only content within pages
|
||||||
|
/// is hidden when navigating to another page. This means everything in the entry
|
||||||
|
/// that isn't part of a page will remian throughout navigations.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```md
|
||||||
|
/// @@ home; visible
|
||||||
|
/// this is the homepage which is shown by default!
|
||||||
|
/// @@
|
||||||
|
///
|
||||||
|
/// @@ about
|
||||||
|
/// this is the about page which is NOT shown by default! a link with an href of "#/about" will open this page
|
||||||
|
/// @@
|
||||||
|
/// ```
|
||||||
|
pub fn parse_page(input: &str) -> String {
|
||||||
|
let mut output = String::new();
|
||||||
|
let mut buffer = String::new();
|
||||||
|
let mut page_id = String::new();
|
||||||
|
|
||||||
|
let mut start_shown = false;
|
||||||
|
let mut in_page = false;
|
||||||
|
let mut in_pre = false;
|
||||||
|
|
||||||
|
for line in input.split("\n") {
|
||||||
|
if line.starts_with("```") {
|
||||||
|
in_pre = !in_pre;
|
||||||
|
|
||||||
|
if in_page {
|
||||||
|
buffer.push_str(&format!("{line}\n"));
|
||||||
|
} else {
|
||||||
|
output.push_str(&format!("{line}\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if in_pre {
|
||||||
|
if in_page {
|
||||||
|
buffer.push_str(&format!("{line}\n"));
|
||||||
|
} else {
|
||||||
|
output.push_str(&format!("{line}\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// not in pre
|
||||||
|
if line == "@@" {
|
||||||
|
// ending block
|
||||||
|
if in_page {
|
||||||
|
output.push_str(&format!(
|
||||||
|
"<div id=\"#/{page_id}\" class=\"{}subpage no_p_margin fadein\">\n{}\n</div>",
|
||||||
|
if !start_shown { "hidden " } else { "" },
|
||||||
|
render_markdown(&buffer) // recurse to render markdown since the renderer is ignoring the div content :/
|
||||||
|
));
|
||||||
|
|
||||||
|
start_shown = false;
|
||||||
|
in_page = false;
|
||||||
|
|
||||||
|
buffer.clear();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else if line.starts_with("@@") {
|
||||||
|
if !in_page {
|
||||||
|
in_page = true;
|
||||||
|
|
||||||
|
let x = line.replace("@@", "").trim().to_string();
|
||||||
|
let id_parts: Vec<&str> = x.split(";").map(|x| x.trim()).collect();
|
||||||
|
page_id = id_parts[0].to_string();
|
||||||
|
|
||||||
|
if let Some(x) = id_parts.get(1) {
|
||||||
|
if *x == "visible" {
|
||||||
|
start_shown = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise
|
||||||
|
if in_page {
|
||||||
|
buffer.push_str(&format!("{line}\n"));
|
||||||
|
} else {
|
||||||
|
output.push_str(&format!("{line}\n"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
output
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parse the markdown syntax for the expandable `<details>` element.
|
||||||
|
///
|
||||||
|
/// Similar to the [`parse_page`] page definitions, details elements are denoted
|
||||||
|
/// with two ampersand symbols. The opening line should look like `&& [summary]; [open?]`.
|
||||||
|
///
|
||||||
|
/// The block is closed with a line of exactly two ampersand symbols.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```md
|
||||||
|
/// && other summary
|
||||||
|
/// this element starts closed, but can be expanded
|
||||||
|
/// &&
|
||||||
|
/// ```
|
||||||
|
pub fn parse_details(input: &str) -> String {
|
||||||
|
let mut output = String::new();
|
||||||
|
let mut buffer = String::new();
|
||||||
|
let mut summary = String::new();
|
||||||
|
|
||||||
|
let mut in_details = false;
|
||||||
|
let mut in_pre = false;
|
||||||
|
|
||||||
|
for line in input.split("\n") {
|
||||||
|
if line.starts_with("```") {
|
||||||
|
in_pre = !in_pre;
|
||||||
|
|
||||||
|
if in_details {
|
||||||
|
buffer.push_str(&format!("{line}\n"));
|
||||||
|
} else {
|
||||||
|
output.push_str(&format!("{line}\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if in_pre {
|
||||||
|
if in_details {
|
||||||
|
buffer.push_str(&format!("{line}\n"));
|
||||||
|
} else {
|
||||||
|
output.push_str(&format!("{line}\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// not in pre
|
||||||
|
if line == "&&" {
|
||||||
|
// ending block
|
||||||
|
if in_details {
|
||||||
|
output.push_str(&format!(
|
||||||
|
"<details><summary>{summary}</summary><div class=\"content\">{}</div></details>",
|
||||||
|
render_markdown(&buffer),
|
||||||
|
));
|
||||||
|
|
||||||
|
in_details = false;
|
||||||
|
buffer.clear();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else if line.starts_with("&&") {
|
||||||
|
if !in_details {
|
||||||
|
in_details = true;
|
||||||
|
summary = line.replace("&&", "").trim().to_string();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise
|
||||||
|
if in_details {
|
||||||
|
buffer.push_str(&format!("{line}\n"));
|
||||||
|
} else {
|
||||||
|
output.push_str(&format!("{line}\n"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
output
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue