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();
|
||||
}
|
||||
};
|
||||
|
||||
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 {
|
||||
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;
|
||||
|
||||
pub fn render_markdown(input: &str) -> String {
|
||||
let html = tetratto_shared::markdown::render_markdown_dirty(&parse_text_color(
|
||||
&parse_highlight(&parse_link(&parse_image(&parse_image_size(
|
||||
&parse_underline(&parse_comment(&input.replace("[/]", "<br />"))),
|
||||
let html = tetratto_shared::markdown::render_markdown_dirty(&parse_page(&parse_details(
|
||||
&parse_text_color(&parse_highlight(&parse_link(&parse_image(
|
||||
&parse_image_size(&parse_underline(&parse_comment(
|
||||
&input.replace("[/]", "<br />"),
|
||||
))),
|
||||
)))),
|
||||
))
|
||||
)))
|
||||
.replace("$per", "%");
|
||||
|
||||
let mut allowed_attributes = HashSet::new();
|
||||
|
@ -704,3 +706,180 @@ pub fn parse_image(input: &str) -> String {
|
|||
pub fn parse_link(input: &str) -> String {
|
||||
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