basic wiki tree
This commit is contained in:
parent
b66f168c42
commit
3e0112c206
|
@ -1,32 +1,45 @@
|
|||
use std::fmt::Debug;
|
||||
use std::fs::{self, File};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::io::Write;
|
||||
|
||||
use crate::html::LinkableData;
|
||||
use crate::Everything;
|
||||
use crate::html::Linkable;
|
||||
use crate::Sack;
|
||||
|
||||
|
||||
pub enum AssetKind {
|
||||
Html(Box<dyn Fn(&Everything) -> String>),
|
||||
Html(Box<dyn Fn(&Sack) -> String>),
|
||||
Image,
|
||||
Unknown,
|
||||
Bib(hayagriva::Library),
|
||||
}
|
||||
|
||||
impl Debug for AssetKind {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Html(ptr) => f.debug_tuple("Html").field(&"ptr").finish(),
|
||||
Self::Image => write!(f, "Image"),
|
||||
Self::Unknown => write!(f, "Unknown"),
|
||||
Self::Bib(arg0) => f.debug_tuple("Bib").field(arg0).finish(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Asset {
|
||||
pub kind: AssetKind,
|
||||
pub out: PathBuf,
|
||||
pub link: Option<LinkableData>,
|
||||
pub link: Option<Linkable>,
|
||||
pub meta: super::Source,
|
||||
}
|
||||
|
||||
pub struct Virtual(pub PathBuf, pub Box<dyn Fn(&Everything) -> String>);
|
||||
pub struct Virtual(pub PathBuf, pub Box<dyn Fn(&Sack) -> String>);
|
||||
|
||||
impl Virtual {
|
||||
pub fn new<P, F>(path: P, call: F) -> Self
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
F: Fn(&Everything) -> String + 'static
|
||||
F: Fn(&Sack) -> String + 'static
|
||||
{
|
||||
Self(path.as_ref().into(), Box::new(call))
|
||||
}
|
||||
|
@ -59,7 +72,7 @@ pub fn render(items: &[Item]) {
|
|||
})
|
||||
.collect();
|
||||
|
||||
let everything = Everything { assets: &assets };
|
||||
let everything = Sack { assets: &assets };
|
||||
|
||||
for item in items {
|
||||
match item {
|
||||
|
@ -70,7 +83,7 @@ pub fn render(items: &[Item]) {
|
|||
}
|
||||
|
||||
|
||||
fn render_real(item: &Asset, assets: &Everything) {
|
||||
fn render_real(item: &Asset, assets: &Sack) {
|
||||
match &item.kind {
|
||||
AssetKind::Html(render) => {
|
||||
let i = &item.meta.path;
|
||||
|
@ -101,7 +114,7 @@ fn render_real(item: &Asset, assets: &Everything) {
|
|||
}
|
||||
}
|
||||
|
||||
fn render_fake(item: &Virtual, assets: &Everything) {
|
||||
fn render_fake(item: &Virtual, assets: &Sack) {
|
||||
let Virtual(out, render) = item;
|
||||
|
||||
let o = Path::new("dist").join(&out);
|
||||
|
|
|
@ -15,4 +15,4 @@ pub use show::show;
|
|||
pub use special::{map, search};
|
||||
pub use wiki::wiki;
|
||||
|
||||
pub use list::LinkableData;
|
||||
pub use list::{Linkable, Link, LinkDate};
|
||||
|
|
|
@ -3,18 +3,29 @@ use hypertext::{html_elements, maud_move, GlobalAttributes, Renderable};
|
|||
use crate::html::page;
|
||||
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct LinkableData {
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Link {
|
||||
pub path: String,
|
||||
pub name: String,
|
||||
pub date: DateTime<Utc>,
|
||||
pub desc: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct LinkDate {
|
||||
pub link: Link,
|
||||
pub date: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Linkable {
|
||||
Link(Link),
|
||||
Date(LinkDate),
|
||||
}
|
||||
|
||||
|
||||
pub fn list<'data, 'list>(
|
||||
title: &'data str,
|
||||
groups: &'data [(i32, Vec<LinkableData>)]
|
||||
groups: &'data [(i32, Vec<LinkDate>)]
|
||||
) -> impl Renderable + 'list
|
||||
where
|
||||
'data: 'list
|
||||
|
@ -36,7 +47,7 @@ pub fn list<'data, 'list>(
|
|||
page(title, list)
|
||||
}
|
||||
|
||||
fn section(year: i32, group: &[LinkableData]) -> impl Renderable + '_ {
|
||||
fn section(year: i32, group: &[LinkDate]) -> impl Renderable + '_ {
|
||||
maud_move!(
|
||||
section .page-list-year {
|
||||
header .page-list-year__header {
|
||||
|
@ -49,19 +60,19 @@ fn section(year: i32, group: &[LinkableData]) -> impl Renderable + '_ {
|
|||
)
|
||||
}
|
||||
|
||||
fn link(data: &LinkableData) -> impl Renderable + '_ {
|
||||
fn link(data: &LinkDate) -> impl Renderable + '_ {
|
||||
let time = data.date.format("%m/%d");
|
||||
maud_move!(
|
||||
a .page-item href=(&data.path) {
|
||||
a .page-item href=(&data.link.path) {
|
||||
div .page-item__header {
|
||||
h3 {
|
||||
(&data.name)
|
||||
(&data.link.name)
|
||||
}
|
||||
time datetime=(data.date.to_rfc3339()) {
|
||||
(time.to_string())
|
||||
}
|
||||
}
|
||||
@if let Some(ref desc) = data.desc {
|
||||
@if let Some(ref desc) = data.link.desc {
|
||||
div .page-item__desc {
|
||||
(desc)
|
||||
}
|
||||
|
|
|
@ -4,6 +4,28 @@ use crate::html::page;
|
|||
use crate::text::md::Outline;
|
||||
|
||||
|
||||
pub fn tree(outline: Outline) -> impl Renderable {
|
||||
maud_move!(
|
||||
section .link-tree {
|
||||
h2 .link-tree__heading {
|
||||
a .link-tree__heading-text href="#top" { "Content" }
|
||||
}
|
||||
nav #table-of-contents .link-tree__nav {
|
||||
ul .link-tree__nav-list {
|
||||
@for (title, id) in outline.0 {
|
||||
li .link-tree__nav-list-item {
|
||||
a .link-tree__nav-list-text.link href=(format!("#{id}")) {
|
||||
(title)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
pub fn post<'fm, 'md, 'post, T>(
|
||||
fm: &'fm Post,
|
||||
content: T,
|
||||
|
@ -25,22 +47,7 @@ pub fn post<'fm, 'md, 'post, T>(
|
|||
label .wiki-aside__slider for="wiki-aside-shown" {
|
||||
img .wiki-icon src="/static/svg/double-arrow.svg" width="24" height="24";
|
||||
}
|
||||
section .link-tree {
|
||||
h2 .link-tree__heading {
|
||||
a .link-tree__heading-text href="#top" { "Content" }
|
||||
}
|
||||
nav #table-of-contents .link-tree__nav {
|
||||
ul .link-tree__nav-list {
|
||||
@for (title, id) in outline.0 {
|
||||
li .link-tree__nav-list-item {
|
||||
a .link-tree__nav-list-text.link href=(format!("#{id}")) {
|
||||
(title)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
(tree(outline))
|
||||
}
|
||||
|
||||
article .wiki-article /*class:list={classlist)*/ {
|
||||
|
|
104
src/html/wiki.rs
104
src/html/wiki.rs
|
@ -1,15 +1,111 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use hypertext::{html_elements, maud_move, GlobalAttributes, Renderable};
|
||||
|
||||
use crate::md::Wiki;
|
||||
use crate::html::page;
|
||||
use crate::text::md::Outline;
|
||||
use crate::Sack;
|
||||
|
||||
use super::Link;
|
||||
|
||||
|
||||
pub fn wiki<'data, 'html, T>(
|
||||
#[derive(Debug)]
|
||||
struct TreeNode {
|
||||
pub name: String,
|
||||
pub children: HashMap<String, TreeNode>,
|
||||
}
|
||||
|
||||
impl TreeNode {
|
||||
fn new(name: &str) -> Self {
|
||||
TreeNode {
|
||||
name: name.to_string(),
|
||||
children: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn add_link(&mut self, link: &Link) {
|
||||
let mut current_node = self;
|
||||
for component in link.path.split('/').filter(|s| !s.is_empty()) {
|
||||
current_node = current_node.children.entry(component.to_string())
|
||||
.or_insert(TreeNode::new(component));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn tree(sack: &Sack) -> impl Renderable {
|
||||
let mut tree = TreeNode::new("wiki");
|
||||
for link in sack.get_links_2("wiki/**/*.html") {
|
||||
tree.add_link(&link);
|
||||
};
|
||||
|
||||
maud_move!(
|
||||
h2 .link-tree__heading {
|
||||
// {pages.chain(x => x.prefix)
|
||||
// .map(pathify)
|
||||
// .mapOrDefault(href =>
|
||||
// <a class="link-tree__heading-text" href={href}>{heading}</a>,
|
||||
// <span class="link-tree__heading-text">{heading}</span>
|
||||
// )}
|
||||
}
|
||||
nav .link-tree__nav {
|
||||
// {pages.map(pages => <PagesList {...pages} />).extract()}
|
||||
(level(&tree))
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fn level(tree: &TreeNode) -> impl Renderable + '_ {
|
||||
for (key, next) in tree.children.iter() {
|
||||
println!("{key}");
|
||||
level(next);
|
||||
};
|
||||
maud_move!(
|
||||
ul .link-tree__nav-list {
|
||||
@for (key, next) in tree.children.iter() {
|
||||
li .link-tree__nav-list-item {
|
||||
span .link-tree__nav-list-text { (key) }
|
||||
@if next.children.len() > 0 {
|
||||
(level(next))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
// {tree.children
|
||||
// .map(m => Object.values(m))
|
||||
// .filter(xs => xs.length > 0)
|
||||
// .map(pages =>
|
||||
// <ul class="link-tree__nav-list">
|
||||
// {pages
|
||||
// .sort(compare)
|
||||
// .map(page => ({...page, current: checkCurrent(page.slug) }))
|
||||
// .map(page =>
|
||||
// <li class="link-tree__nav-list-item">
|
||||
// {page.slug
|
||||
// .chain(slug => prefix.map(prefix => pathify(prefix, slug)))
|
||||
// .map(href => (page.current)
|
||||
// ? <button id="current-page-button" class="link-tree__nav-list-text current">{page.title}</button>
|
||||
// : <a class="link-tree__nav-list-text link" href={href}>{page.title}</a>
|
||||
// )
|
||||
// .orDefault(<span class="link-tree__nav-list-text">{page.title}</span>)}
|
||||
// <Astro.self tree={page} slug={slug} prefix={prefix} />
|
||||
// </li>
|
||||
// )}
|
||||
// </ul>
|
||||
// ).extract()}
|
||||
|
||||
|
||||
pub fn wiki<'data, 'html, 'sack, T>(
|
||||
fm: &'data Wiki,
|
||||
content: T,
|
||||
outline: Outline,
|
||||
sack: &'sack Sack,
|
||||
) -> impl Renderable + 'html
|
||||
where
|
||||
'sack: 'html,
|
||||
'data: 'html,
|
||||
T: Renderable + 'data
|
||||
{
|
||||
|
@ -25,7 +121,11 @@ pub fn wiki<'data, 'html, T>(
|
|||
img .wiki-icon src="/static/svg/double-arrow.svg" width="24" height="24";
|
||||
}
|
||||
// Navigation tree
|
||||
// <Tree heading="Personal Wiki" pages={pages} headings={headings} />
|
||||
section .link-tree {
|
||||
div {
|
||||
(tree(sack))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
article .wiki-article /*class:list={classlist)*/ {
|
||||
|
|
109
src/main.rs
109
src/main.rs
|
@ -3,7 +3,7 @@ use std::{collections::HashMap, path::Path};
|
|||
use std::fs;
|
||||
use chrono::Datelike;
|
||||
use grass;
|
||||
use html::LinkableData;
|
||||
use html::{Link, LinkDate, Linkable};
|
||||
use hypertext::{Raw, Renderable};
|
||||
use once_cell::sync::Lazy;
|
||||
use text::md::Outline;
|
||||
|
@ -46,49 +46,78 @@ static REPO: Lazy<BuildInfo> = Lazy::new(|| {
|
|||
});
|
||||
|
||||
/// This struct allows for querying the website hierarchy
|
||||
struct Everything<'a> {
|
||||
#[derive(Debug)]
|
||||
struct Sack<'a> {
|
||||
assets: &'a [&'a gen::Asset],
|
||||
}
|
||||
|
||||
impl Everything<'_> {
|
||||
fn get_linkable(&self, path: &str) -> Vec<LinkableData> {
|
||||
impl Sack<'_> {
|
||||
fn get_links(&self, path: &str) -> Vec<LinkDate> {
|
||||
let pattern = glob::Pattern::new(path).unwrap();
|
||||
self.assets.iter()
|
||||
.filter(|f| pattern.matches_path(&f.out))
|
||||
.filter_map(|f| f.link.clone())
|
||||
.filter_map(|f| match &f.link {
|
||||
Some(Linkable::Date(link)) => Some(link.clone()),
|
||||
_ => None,
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn get_links_2(&self, path: &str) -> Vec<Link> {
|
||||
let pattern = glob::Pattern::new(path).unwrap();
|
||||
self.assets.iter()
|
||||
.filter(|f| pattern.matches_path(&f.out))
|
||||
.filter_map(|f| match &f.link {
|
||||
Some(Linkable::Link(link)) => Some(link.clone()),
|
||||
_ => None,
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
trait Transformable {
|
||||
fn transform<'f, 'm, 'html, T>(&'f self, content: T, outline: Outline) -> impl Renderable + 'html
|
||||
fn transform<'f, 'm, 'html, 'sack, T>(
|
||||
&'f self,
|
||||
content: T,
|
||||
outline: Outline,
|
||||
sack: &'sack Sack,
|
||||
) -> impl Renderable + 'html
|
||||
where
|
||||
'f: 'html,
|
||||
'm: 'html,
|
||||
'sack: 'html,
|
||||
T: Renderable + 'm;
|
||||
|
||||
fn as_link(&self, path: String) -> Option<html::LinkableData>;
|
||||
fn as_link(&self, path: String) -> Option<Linkable>;
|
||||
|
||||
fn render(data: &str) -> (Outline, String);
|
||||
}
|
||||
|
||||
impl Transformable for md::Post {
|
||||
fn transform<'f, 'm, 'html, T>(&'f self, content: T, outline: Outline) -> impl Renderable + 'html
|
||||
fn transform<'f, 'm, 'html, 'sack, T>(
|
||||
&'f self,
|
||||
content: T,
|
||||
outline: Outline,
|
||||
sack: &'sack Sack,
|
||||
) -> impl Renderable + 'html
|
||||
where
|
||||
'f: 'html,
|
||||
'm: 'html,
|
||||
'sack: 'html,
|
||||
T: Renderable + 'm {
|
||||
html::post(self, content, outline)
|
||||
}
|
||||
|
||||
fn as_link(&self, path: String) -> Option<html::LinkableData> {
|
||||
Some(html::LinkableData {
|
||||
path: path.strip_suffix("index.html").unwrap().to_owned(),
|
||||
name: self.title.to_owned(),
|
||||
fn as_link(&self, path: String) -> Option<Linkable> {
|
||||
Some(Linkable::Date(LinkDate {
|
||||
link: Link {
|
||||
path: path.strip_suffix("index.html").unwrap().to_owned(),
|
||||
name: self.title.to_owned(),
|
||||
desc: self.desc.to_owned(),
|
||||
},
|
||||
date: self.date.to_owned(),
|
||||
desc: self.desc.to_owned(),
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
fn render(data: &str) -> (Outline, String) {
|
||||
|
@ -97,21 +126,29 @@ impl Transformable for md::Post {
|
|||
}
|
||||
|
||||
impl Transformable for md::Slide {
|
||||
fn transform<'f, 'm, 'html, T>(&'f self, content: T, _: Outline) -> impl Renderable + 'html
|
||||
fn transform<'f, 'm, 'html, 'sack, T>(
|
||||
&'f self,
|
||||
content: T,
|
||||
_: Outline,
|
||||
sack: &'sack Sack,
|
||||
) -> impl Renderable + 'html
|
||||
where
|
||||
'f: 'html,
|
||||
'm: 'html,
|
||||
'sack: 'html,
|
||||
T: Renderable + 'm {
|
||||
html::show(self, content)
|
||||
}
|
||||
|
||||
fn as_link(&self, path: String) -> Option<html::LinkableData> {
|
||||
Some(html::LinkableData {
|
||||
path: path.strip_suffix("index.html").unwrap().to_owned(),
|
||||
name: self.title.to_owned(),
|
||||
fn as_link(&self, path: String) -> Option<Linkable> {
|
||||
Some(Linkable::Date(LinkDate {
|
||||
link: Link {
|
||||
path: path.strip_suffix("index.html").unwrap().to_owned(),
|
||||
name: self.title.to_owned(),
|
||||
desc: self.desc.to_owned(),
|
||||
},
|
||||
date: self.date.to_owned(),
|
||||
desc: self.desc.to_owned(),
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
fn render(data: &str) -> (Outline, String) {
|
||||
|
@ -128,16 +165,26 @@ impl Transformable for md::Slide {
|
|||
}
|
||||
|
||||
impl Transformable for md::Wiki {
|
||||
fn transform<'f, 'm, 'html, T>(&'f self, content: T, outline: Outline) -> impl Renderable + 'html
|
||||
fn transform<'f, 'm, 'html, 'sack, T>(
|
||||
&'f self,
|
||||
content: T,
|
||||
outline: Outline,
|
||||
sack: &'sack Sack,
|
||||
) -> impl Renderable + 'html
|
||||
where
|
||||
'f: 'html,
|
||||
'm: 'html,
|
||||
'sack: 'html,
|
||||
T: Renderable + 'm {
|
||||
html::wiki(self, content, outline)
|
||||
html::wiki(self, content, outline, sack)
|
||||
}
|
||||
|
||||
fn as_link(&self, _: String) -> Option<html::LinkableData> {
|
||||
None
|
||||
fn as_link(&self, path: String) -> Option<Linkable> {
|
||||
Some(Linkable::Link(Link {
|
||||
path: path.strip_suffix("index.html").unwrap().to_owned(),
|
||||
name: self.title.to_owned(),
|
||||
desc: None,
|
||||
}))
|
||||
}
|
||||
|
||||
fn render(data: &str) -> (Outline, String) {
|
||||
|
@ -146,7 +193,7 @@ impl Transformable for md::Wiki {
|
|||
}
|
||||
|
||||
|
||||
fn to_list(list: Vec<LinkableData>) -> String {
|
||||
fn to_list(list: Vec<LinkDate>) -> String {
|
||||
let mut groups = HashMap::<i32, Vec<_>>::new();
|
||||
|
||||
for page in list {
|
||||
|
@ -183,9 +230,9 @@ fn transform<T>(meta: gen::Source) -> gen::Asset
|
|||
let (fm, md) = md::preflight::<T>(&data);
|
||||
let link = T::as_link(&fm, Path::new("/").join(&loc).to_str().unwrap().to_owned());
|
||||
|
||||
let call = move |_: &Everything| {
|
||||
let call = move |everything: &Sack| {
|
||||
let (outline, html) = T::render(&md);
|
||||
T::transform(&fm, Raw(html), outline).render().into()
|
||||
T::transform(&fm, Raw(html), outline, everything).render().into()
|
||||
};
|
||||
|
||||
gen::Asset {
|
||||
|
@ -248,7 +295,7 @@ fn main() {
|
|||
gen::Asset {
|
||||
kind: gen::AssetKind::Html(Box::new(|_| {
|
||||
let data = std::fs::read_to_string("content/index.md").unwrap();
|
||||
let (outline, html) = text::md::parse(&data);
|
||||
let (_, html) = text::md::parse(&data);
|
||||
html::home(Raw(html)).render().to_owned().into()
|
||||
})),
|
||||
out: "index.html".into(),
|
||||
|
@ -261,10 +308,10 @@ fn main() {
|
|||
}
|
||||
}.into(),
|
||||
gen::Virtual("posts/index.html".into(), Box::new(|all|
|
||||
to_list(all.get_linkable("posts/**/*.html"))
|
||||
to_list(all.get_links("posts/**/*.html"))
|
||||
)).into(),
|
||||
gen::Virtual("slides/index.html".into(), Box::new(|all|
|
||||
to_list(all.get_linkable("slides/**/*.html"))
|
||||
to_list(all.get_links("slides/**/*.html"))
|
||||
)).into(),
|
||||
],
|
||||
gen::gather("content/about.md", &["md"].into())
|
||||
|
|
Loading…
Reference in a new issue