diff --git a/rustfmt.toml b/rustfmt.toml
new file mode 100644
index 0000000..6a34f55
--- /dev/null
+++ b/rustfmt.toml
@@ -0,0 +1,2 @@
+tab_spaces = 4
+hard_tabs = true
diff --git a/src/html/home.rs b/src/html/home.rs
index edd602f..34ded98 100644
--- a/src/html/home.rs
+++ b/src/html/home.rs
@@ -1,6 +1,6 @@
use hypertext::{html_elements, maud, maud_move, GlobalAttributes, Raw, Renderable};
-use crate::text::md::parse;
+use crate::{pipeline::Sack, text::md::parse};
const INTRO: &str = r#"
## かもし
@@ -15,59 +15,62 @@ const INTRO: &str = r#"
"#;
fn intro() -> impl Renderable {
- let (_, html, _) = parse(INTRO, None);
- maud!(
- section .p-card.intro-jp lang="ja-JP" {
- (Raw(html))
- }
- )
+ let (_, html, _) = parse(INTRO.into(), None);
+ maud!(
+ section .p-card.intro-jp lang="ja-JP" {
+ (Raw(html))
+ }
+ )
}
-fn kanji() -> impl Renderable {
- maud!(
- section .p-card {
- h2 .p-card__heading {
- "Kanji of the Day"
- }
- div {
- //
- }
- }
- )
-}
+// fn kanji() -> impl Renderable {
+// maud!(
+// section .p-card {
+// h2 .p-card__heading {
+// "Kanji of the Day"
+// }
+// div {
+// //
+// }
+// }
+// )
+// }
fn photo() -> impl Renderable {
- maud!(
- section .p-card.home-card-image {
- h2 .p-card__heading {
- "Image of the Month"
- }
- a .home-card-image__link href="/static/IMG_20231029_111650.jpg" {
- img .home-card-image__image
- src="/static/IMG_20231029_111650.jpg"
- alt="Autumn park with colorful trees and fallen leaves";
- }
- }
- )
+ maud!(
+ section .p-card.home-card-image {
+ h2 .p-card__heading {
+ "Image of the Month"
+ }
+ a .home-card-image__link href="/static/IMG_20231029_111650.jpg" {
+ img .home-card-image__image
+ src="/static/IMG_20231029_111650.jpg"
+ alt="Autumn park with colorful trees and fallen leaves";
+ }
+ }
+ )
}
-pub fn home<'data, 'home, R>(main: R) -> impl Renderable + 'home
+pub(crate) fn home<'s, 'p, 'html>(
+ sack: &'s Sack,
+ main: impl Renderable + 'p,
+) -> impl Renderable + 'html
where
- 'data: 'home,
- R: Renderable + 'data,
+ 's: 'html,
+ 'p: 'html,
{
- let main = maud_move!(
- main .l-home {
- article .l-home__article.markdown {
- (main)
- }
- aside .l-home__aside {
- (intro())
- // (kanji())
- (photo())
- }
- }
- );
+ let main = maud_move!(
+ main .l-home {
+ article .l-home__article.markdown {
+ (main)
+ }
+ aside .l-home__aside {
+ (intro())
+ // (kanji())
+ (photo())
+ }
+ }
+ );
- crate::html::page("Home", main, None)
+ crate::html::page(sack, main, "Home".into())
}
diff --git a/src/html/list.rs b/src/html/list.rs
index 1536d02..52eca77 100644
--- a/src/html/list.rs
+++ b/src/html/list.rs
@@ -1,62 +1,66 @@
-use crate::{html::page, LinkDate};
-use camino::Utf8PathBuf;
-use chrono::{DateTime, Utc};
use hypertext::{html_elements, maud_move, GlobalAttributes, Renderable};
-pub fn list<'data, 'list>(
- title: &'data str,
- groups: &'data [(i32, Vec)],
-) -> impl Renderable + 'list
+use crate::html::page;
+use crate::pipeline::Sack;
+use crate::LinkDate;
+
+pub fn list<'s, 'g, 'html>(
+ sack: &'s Sack,
+ groups: &'g [(i32, Vec)],
+ title: String,
+) -> impl Renderable + 'html
where
- 'data: 'list,
+ 's: 'html,
+ 'g: 'html,
{
- let list = maud_move!(
- main .page-list-main {
- article .page-list {
- header .markdown {
- h1 { (title) }
- }
+ let heading = title.clone();
+ let list = maud_move!(
+ main .page-list-main {
+ article .page-list {
+ header .markdown {
+ h1 { (heading) }
+ }
- @for (year, group) in groups {
- (section(*year, group))
- }
- }
- }
- );
+ @for (year, group) in groups {
+ (section(*year, group))
+ }
+ }
+ }
+ );
- page(title, list, None)
+ page(sack, list, title)
}
fn section(year: i32, group: &[LinkDate]) -> impl Renderable + '_ {
- maud_move!(
- section .page-list-year {
- header .page-list-year__header {
- h2 { (year) }
- }
- @for item in group.iter() {
- (link(item))
- }
- }
- )
+ maud_move!(
+ section .page-list-year {
+ header .page-list-year__header {
+ h2 { (year) }
+ }
+ @for item in group.iter() {
+ (link(item))
+ }
+ }
+ )
}
fn link(data: &LinkDate) -> impl Renderable + '_ {
- let time = data.date.format("%m/%d");
- maud_move!(
- a .page-item href=(data.link.path.as_str()) {
- div .page-item__header {
- h3 {
- (&data.link.name)
- }
- time datetime=(data.date.to_rfc3339()) {
- (time.to_string())
- }
- }
- @if let Some(ref desc) = data.link.desc {
- div .page-item__desc {
- (desc)
- }
- }
- }
- )
+ let time = data.date.format("%m/%d");
+ maud_move!(
+ a .page-item href=(data.link.path.as_str()) {
+ div .page-item__header {
+ h3 {
+ (&data.link.name)
+ }
+ time datetime=(data.date.to_rfc3339()) {
+ (time.to_string())
+ }
+ }
+ @if let Some(ref desc) = data.link.desc {
+ div .page-item__desc {
+ (desc)
+ }
+ }
+ }
+ )
}
diff --git a/src/html/misc.rs b/src/html/misc.rs
index f0dd44b..f8758e6 100644
--- a/src/html/misc.rs
+++ b/src/html/misc.rs
@@ -3,93 +3,92 @@ use hypertext::{html_elements, maud_move, GlobalAttributes, Raw, Renderable};
use crate::pipeline::{Sack, TreePage};
use crate::text::md::Outline;
-
/// Render the outline for a document
pub(crate) fn show_outline(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)
- }
- }
- }
- }
- }
- }
- )
+ 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)
+ }
+ }
+ }
+ }
+ }
+ }
+ )
}
/// Render the bibliography for a document
pub(crate) fn show_bibliography(bib: Vec) -> impl Renderable {
- maud_move!(
- section .markdown {
- h2 {
- "Bibliography"
- }
- ol .bibliography {
- @for item in bib {
- li {
- (Raw(item))
- }
- }
- }
- }
- )
+ maud_move!(
+ section .markdown {
+ h2 {
+ "Bibliography"
+ }
+ ol .bibliography {
+ @for item in bib {
+ li {
+ (Raw(item))
+ }
+ }
+ }
+ }
+ )
}
/// Render the page tree
pub(crate) fn show_page_tree(sack: &Sack, glob: &str) -> impl Renderable {
- let tree = sack.get_tree(glob);
+ let tree = sack.get_tree(glob);
- maud_move!(
- h2 .link-tree__heading {
- // {pages.chain(x => x.prefix)
- // .map(pathify)
- // .mapOrDefault(href =>
- // {heading},
- // {heading}
- // )}
- }
- nav .link-tree__nav {
- (show_page_tree_level(&tree))
- }
- )
+ maud_move!(
+ h2 .link-tree__heading {
+ // {pages.chain(x => x.prefix)
+ // .map(pathify)
+ // .mapOrDefault(href =>
+ // {heading},
+ // {heading}
+ // )}
+ }
+ nav .link-tree__nav {
+ (show_page_tree_level(&tree))
+ }
+ )
}
fn show_page_tree_level(tree: &TreePage) -> impl Renderable + '_ {
- let subs = {
- let mut subs: Vec<_> = tree.subs.iter().collect();
- subs.sort_by(|a, b| a.0.cmp(b.0));
- subs
- };
+ let subs = {
+ let mut subs: Vec<_> = tree.subs.iter().collect();
+ subs.sort_by(|a, b| a.0.cmp(b.0));
+ subs
+ };
- maud_move!(
- ul .link-tree__nav-list {
- @for (key, next) in subs {
- li .link-tree__nav-list-item {
- span .link-tree__nav-list-text {
- @if let Some(ref link) = next.link {
- a .link-tree__nav-list-text.link href=(link.path.as_str()) {
- (&link.name)
- }
- } @else {
- span .link-tree__nav-list-text {
- (key)
- }
- }
- }
- @if !next.subs.is_empty() {
- (show_page_tree_level(next))
- }
- }
- }
- }
- )
+ maud_move!(
+ ul .link-tree__nav-list {
+ @for (key, next) in subs {
+ li .link-tree__nav-list-item {
+ span .link-tree__nav-list-text {
+ @if let Some(ref link) = next.link {
+ a .link-tree__nav-list-text.link href=(link.path.as_str()) {
+ (&link.name)
+ }
+ } @else {
+ span .link-tree__nav-list-text {
+ (key)
+ }
+ }
+ }
+ @if !next.subs.is_empty() {
+ (show_page_tree_level(next))
+ }
+ }
+ }
+ }
+ )
}
diff --git a/src/html/mod.rs b/src/html/mod.rs
index d64cfc9..11bec4a 100644
--- a/src/html/mod.rs
+++ b/src/html/mod.rs
@@ -13,223 +13,240 @@ use camino::Utf8Path;
use chrono::Datelike;
use hypertext::{html_elements, maud, maud_move, GlobalAttributes, Raw, Renderable};
-use crate::REPO;
-
pub(crate) use home::home;
pub(crate) use post::Post;
pub(crate) use slideshow::Slideshow;
pub(crate) use wiki::Wiki;
+use crate::{pipeline::Sack, Mode};
+
const JS_RELOAD: &str = r#"
const socket = new WebSocket("ws://localhost:1337");
socket.addEventListener("message", (event) => {
- console.log(event);
- window.location.reload();
+ console.log(event);
+ window.location.reload();
});
"#;
const JS_IMPORTS: &str = r#"
{
- "imports": {
- "reveal": "/js/vanilla/reveal.js",
- "photos": "/js/vanilla/photos.js"
- }
+ "imports": {
+ "reveal": "/js/vanilla/reveal.js",
+ "photos": "/js/vanilla/photos.js"
+ }
}
"#;
-fn head(title: &str) -> impl Renderable + '_ {
- let title = format!("{} | kamoshi.org", title);
+fn head<'s, 'html>(sack: &'s Sack, title: String) -> impl Renderable + 'html
+where
+ 's: 'html,
+{
+ let title = format!("{} | kamoshi.org", title);
- maud_move!(
- meta charset="utf-8";
- meta name="viewport" content="width=device-width, initial-scale=1";
- title {
- (title)
- }
+ maud_move!(
+ meta charset="utf-8";
+ meta name="viewport" content="width=device-width, initial-scale=1";
+ title {
+ (title)
+ }
- // link rel="sitemap" href="/sitemap.xml";
+ // link rel="sitemap" href="/sitemap.xml";
- link rel="stylesheet" href="/styles.css";
- link rel="stylesheet" href="/static/css/reveal.css";
- link rel="stylesheet" href="/static/css/leaflet.css";
- link rel="stylesheet" href="/static/css/MarkerCluster.css";
- link rel="stylesheet" href="/static/css/MarkerCluster.Default.css";
- link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png";
- link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png";
- link rel="icon" href="/favicon.ico" sizes="any";
+ link rel="stylesheet" href="/styles.css";
+ link rel="stylesheet" href="/static/css/reveal.css";
+ link rel="stylesheet" href="/static/css/leaflet.css";
+ link rel="stylesheet" href="/static/css/MarkerCluster.css";
+ link rel="stylesheet" href="/static/css/MarkerCluster.Default.css";
+ link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png";
+ link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png";
+ link rel="icon" href="/favicon.ico" sizes="any";
- script type="importmap" {(Raw(JS_IMPORTS))}
+ script type="importmap" {(Raw(JS_IMPORTS))}
- script { (Raw(JS_RELOAD)) }
- )
+ @if matches!(sack.ctx.mode, Mode::Watch) {
+ script { (Raw(JS_RELOAD)) }
+ }
+ )
}
fn navbar() -> impl Renderable {
- static ITEMS: &[(&str, &str)] = &[
- ("Posts", "/posts/"),
- ("Slides", "/slides/"),
- ("Wiki", "/wiki/"),
- ("Map", "/map/"),
- ("About", "/about/"),
- ("Search", "/search/"),
- ];
+ static ITEMS: &[(&str, &str)] = &[
+ ("Posts", "/posts/"),
+ ("Slides", "/slides/"),
+ ("Wiki", "/wiki/"),
+ ("Map", "/map/"),
+ ("About", "/about/"),
+ ("Search", "/search/"),
+ ];
- maud!(
- nav .p-nav {
- input #p-nav-toggle type="checkbox" hidden;
+ maud!(
+ nav .p-nav {
+ input #p-nav-toggle type="checkbox" hidden;
- div .p-nav__bar {
- a .p-nav__logo href="/" {
- img .p-nav__logo-icon height="48px" width="51px" src="/static/svg/aya.svg" alt="";
- div .p-nav__logo-text {
- div .p-nav__logo-main {
- (Raw(include_str!("logotype.svg")))
- }
- div #p-nav-splash .p-nav__logo-sub {
- "夢現の遥か彼方"
- }
- }
- }
+ div .p-nav__bar {
+ a .p-nav__logo href="/" {
+ img .p-nav__logo-icon height="48px" width="51px" src="/static/svg/aya.svg" alt="";
+ div .p-nav__logo-text {
+ div .p-nav__logo-main {
+ (Raw(include_str!("logotype.svg")))
+ }
+ div #p-nav-splash .p-nav__logo-sub {
+ "夢現の遥か彼方"
+ }
+ }
+ }
- label .p-nav__burger for="p-nav-toggle" tabindex="0" {
- span .p-nav__burger-icon {}
- }
- }
+ label .p-nav__burger for="p-nav-toggle" tabindex="0" {
+ span .p-nav__burger-icon {}
+ }
+ }
- menu .p-nav__menu {
- @for (name, url) in ITEMS {
- li .p-nav__menu-item {
- a .p-nav__menu-link href=(*url) {
- (*name)
- }
- }
- }
- }
- }
- )
+ menu .p-nav__menu {
+ @for (name, url) in ITEMS {
+ li .p-nav__menu-item {
+ a .p-nav__menu-link href=(*url) {
+ (*name)
+ }
+ }
+ }
+ }
+ }
+ )
}
-pub fn footer(path: Option<&Utf8Path>) -> impl Renderable {
- let copy = format!("Copyright © {} Maciej Jur", &REPO.year);
- let mail = "maciej@kamoshi.org";
- let href = format!("mailto:{}", mail);
- let link = Utf8Path::new(&REPO.link)
- .join("src/commit")
- .join(&REPO.hash);
- let link = match path {
- Some(path) => link.join(path),
- None => link,
- };
-
- maud_move!(
- footer .footer {
- div .left {
- div {
- (Raw(copy))
- }
- a href=(href) {
- (mail)
- }
- }
- div .repo {
- a href=(link.as_str()) {
- (&REPO.hash)
- }
- div {
- (&REPO.date)
- }
- }
- a .right.footer__cc-wrap rel="license" href="http://creativecommons.org/licenses/by/4.0/" {
- img .footer__cc-stamp alt="Creative Commons License" width="88" height="31" src="/static/svg/by.svg";
- }
- }
- )
-}
-
-fn bare<'data, 'html, R>(title: &'data str, main: R) -> impl Renderable + 'html
- where
- 'data : 'html,
- R: Renderable + 'data
+pub fn footer<'s, 'html>(sack: &'s Sack) -> impl Renderable + 'html
+where
+ 's: 'html,
{
- maud_move!(
- (Raw(""))
- html lang="en" {
- (head(title))
+ let copy = format!("Copyright © {} Maciej Jur", &sack.ctx.year);
+ let mail = "maciej@kamoshi.org";
+ let href = format!("mailto:{}", mail);
+ let link = Utf8Path::new(&sack.ctx.link)
+ .join("src/commit")
+ .join(&sack.ctx.hash);
+ let link = match sack.get_file() {
+ Some(path) => link.join(path),
+ None => link,
+ };
- body {
- (main)
- }
- }
- )
+ maud_move!(
+ footer .footer {
+ div .left {
+ div {
+ (Raw(copy))
+ }
+ a href=(href) {
+ (mail)
+ }
+ }
+ div .repo {
+ a href=(link.as_str()) {
+ (&sack.ctx.hash)
+ }
+ div {
+ (&sack.ctx.date)
+ }
+ }
+ a .right.footer__cc-wrap rel="license" href="http://creativecommons.org/licenses/by/4.0/" {
+ img .footer__cc-stamp alt="Creative Commons License" width="88" height="31" src="/static/svg/by.svg";
+ }
+ }
+ )
}
-fn page<'data, 'main, 'html, T>(
- title: &'data str,
- main: T,
- path: Option<&'data Utf8Path>,
+fn bare<'s, 'p, 'html>(
+ sack: &'s Sack,
+ main: impl Renderable + 'p,
+ title: String,
) -> impl Renderable + 'html
- where
- 'main : 'html,
- 'data : 'html,
- T: Renderable + 'main
+where
+ 's: 'html,
+ 'p: 'html,
{
- maud_move!(
- (Raw(""))
- html lang="en" {
- (head(title))
+ maud_move!(
+ (Raw(""))
+ html lang="en" {
+ (head(sack, title))
- body {
- (navbar())
- (main)
- (footer(path))
- }
- }
- )
+ body {
+ (main)
+ }
+ }
+ )
}
-pub(crate) fn to_list(list: Vec) -> String {
- let mut groups = HashMap::>::new();
+fn page<'s, 'p, 'html>(
+ sack: &'s Sack,
+ main: impl Renderable + 'p,
+ title: String,
+) -> impl Renderable + 'html
+where
+ 's: 'html,
+ 'p: 'html,
+{
+ maud_move!(
+ (Raw(""))
+ html lang="en" {
+ (head(sack, title))
- for page in list {
- groups.entry(page.date.year()).or_default().push(page);
- }
-
- let mut groups: Vec<_> = groups
- .into_iter()
- .map(|(k, mut v)| {
- v.sort_by(|a, b| b.date.cmp(&a.date));
- (k, v)
- })
- .collect();
-
- groups.sort_by(|a, b| b.0.cmp(&a.0));
-
- list::list("", &groups).render().into()
+ body {
+ (navbar())
+ (main)
+ (footer(sack))
+ }
+ }
+ )
}
-pub(crate) fn map() -> impl Renderable {
- page(
- "Map",
- maud!(
- main {
- div #map style="height: 100%; width: 100%" {}
+pub(crate) fn to_list(sack: &Sack, list: Vec, title: String) -> String {
+ let mut groups = HashMap::>::new();
- script type="module" {
- (Raw("import 'photos';"))
- }
- }
- ),
- None,
- )
+ for page in list {
+ groups.entry(page.date.year()).or_default().push(page);
+ }
+
+ let mut groups: Vec<_> = groups
+ .into_iter()
+ .map(|(k, mut v)| {
+ v.sort_by(|a, b| b.date.cmp(&a.date));
+ (k, v)
+ })
+ .collect();
+
+ groups.sort_by(|a, b| b.0.cmp(&a.0));
+
+ list::list(sack, &groups, title).render().into()
}
-pub(crate) fn search() -> impl Renderable {
- page(
- "Search",
- maud!(
- main #app {}
- script type="module" src="/js/search/dist/search.js" {}
- ),
- None,
- )
+pub(crate) fn map<'s, 'html>(sack: &'s Sack) -> impl Renderable + 'html
+where
+ 's: 'html,
+{
+ page(
+ sack,
+ maud!(
+ main {
+ div #map style="height: 100%; width: 100%" {}
+
+ script type="module" {
+ (Raw("import 'photos';"))
+ }
+ }
+ ),
+ String::from("Map"),
+ )
+}
+
+pub(crate) fn search<'s, 'html>(sack: &'s Sack) -> impl Renderable + 'html
+where
+ 's: 'html,
+{
+ page(
+ sack,
+ maud!(
+ main #app {}
+ script type="module" src="/js/search/dist/search.js" {}
+ ),
+ String::from("Search"),
+ )
}
diff --git a/src/html/post.rs b/src/html/post.rs
index 29dfa9d..3cff100 100644
--- a/src/html/post.rs
+++ b/src/html/post.rs
@@ -6,91 +6,88 @@ use serde::Deserialize;
use crate::pipeline::{Content, Sack};
use crate::text::md::Outline;
-use crate::{Linkable, LinkDate};
+use crate::{LinkDate, Linkable};
/// Represents a simple post.
#[derive(Deserialize, Debug, Clone)]
pub(crate) struct Post {
- pub(crate) title: String,
- #[serde(with = "super::isodate")]
- pub(crate) date: DateTime,
- pub(crate) desc: Option,
+ pub(crate) title: String,
+ #[serde(with = "super::isodate")]
+ pub(crate) date: DateTime,
+ pub(crate) desc: Option,
}
impl Content for Post {
- fn parse(data: &str, lib: Option<&Library>) -> (Outline, String, Option>) {
- crate::text::md::parse(data, lib)
- }
+ fn parse(data: String, lib: Option<&Library>) -> (Outline, String, Option>) {
+ crate::text::md::parse(data, lib)
+ }
- fn transform<'f, 'm, 's, 'html, T>(
- &'f self,
- content: T,
- outline: Outline,
- sack: &'s Sack,
- bib: Option>,
- ) -> impl Renderable + 'html
- where
- 'f: 'html,
- 'm: 'html,
- 's: 'html,
- T: Renderable + 'm,
- {
- post(self, content, outline, bib, sack)
- }
+ fn render<'s, 'p, 'html>(
+ self,
+ sack: &'s Sack,
+ parsed: impl Renderable + 'p,
+ outline: Outline,
+ bib: Option>,
+ ) -> impl Renderable + 'html
+ where
+ 's: 'html,
+ 'p: 'html,
+ {
+ post(self, sack, parsed, outline, bib)
+ }
- fn as_link(&self, path: Utf8PathBuf) -> Option {
- Some(Linkable::Date(LinkDate {
- link: crate::Link {
- path,
- name: self.title.to_owned(),
- desc: self.desc.to_owned(),
- },
- date: self.date.to_owned(),
- }))
- }
+ fn as_link(&self, path: Utf8PathBuf) -> Option {
+ Some(Linkable::Date(LinkDate {
+ link: crate::Link {
+ path,
+ name: self.title.to_owned(),
+ desc: self.desc.to_owned(),
+ },
+ date: self.date.to_owned(),
+ }))
+ }
}
-pub fn post<'f, 'm, 's, 'html, T>(
- fm: &'f Post,
- content: T,
- outline: Outline,
- bib: Option>,
- sack: &'s Sack,
+pub fn post<'s, 'p, 'html>(
+ fm: Post,
+ sack: &'s Sack,
+ content: impl Renderable + 'p,
+ outline: Outline,
+ bib: Option>,
) -> impl Renderable + 'html
- where
- 'f: 'html,
- 'm: 'html,
- 's: 'html,
- T: Renderable + 'm
+where
+ 's: 'html,
+ 'p: 'html,
{
- let main = maud_move!(
- main .wiki-main {
+ let heading = fm.title.clone();
+ let main = maud_move!(
+ main .wiki-main {
- // Slide in/out for mobile
- input #wiki-aside-shown type="checkbox" hidden;
+ // Slide in/out for mobile
+ input #wiki-aside-shown type="checkbox" hidden;
- aside .wiki-aside {
- // Slide button
- label .wiki-aside__slider for="wiki-aside-shown" {
- img .wiki-icon src="/static/svg/double-arrow.svg" width="24" height="24";
- }
- (crate::html::misc::show_outline(outline))
- }
+ aside .wiki-aside {
+ // Slide button
+ label .wiki-aside__slider for="wiki-aside-shown" {
+ img .wiki-icon src="/static/svg/double-arrow.svg" width="24" height="24";
+ }
+ (crate::html::misc::show_outline(outline))
+ }
- article .wiki-article /*class:list={classlist)*/ {
- header class="markdown" {
- h1 #top { (fm.title.clone()) }
- }
- section .wiki-article__markdown.markdown {
- (content)
- }
+ article .wiki-article /*class:list={classlist)*/ {
+ header class="markdown" {
+ h1 #top { (heading) }
+ }
+ section .wiki-article__markdown.markdown {
+ (content)
+ }
- @if let Some(bib) = bib {
- (crate::html::misc::show_bibliography(bib))
- }
- }
- }
- );
+ @if let Some(bib) = bib {
+ (crate::html::misc::show_bibliography(bib))
+ }
+ }
+ }
+ );
- crate::html::page(&fm.title, main, sack.get_file())
+ crate::html::page(sack, main, fm.title.clone())
}
diff --git a/src/html/slideshow.rs b/src/html/slideshow.rs
index effae9c..ebdd920 100644
--- a/src/html/slideshow.rs
+++ b/src/html/slideshow.rs
@@ -1,87 +1,105 @@
use camino::Utf8PathBuf;
use chrono::{DateTime, Utc};
use hayagriva::Library;
-use hypertext::{html_elements, maud_move, Renderable, GlobalAttributes, Raw};
+use hypertext::{html_elements, maud_move, GlobalAttributes, Raw, Renderable};
use serde::Deserialize;
use crate::pipeline::{Content, Sack};
use crate::text::md::Outline;
use crate::{Link, LinkDate, Linkable};
+const CSS: &str = r#"
+.slides img {
+ margin-left: auto;
+ margin-right: auto;
+ max-height: 60vh;
+}
+"#;
/// Represents a slideshow
#[derive(Deserialize, Debug, Clone)]
pub(crate) struct Slideshow {
- pub title: String,
- #[serde(with = "super::isodate")]
- pub date: DateTime,
- pub desc: Option,
+ pub title: String,
+ #[serde(with = "super::isodate")]
+ pub date: DateTime,
+ pub desc: Option,
}
impl Content for Slideshow {
- fn transform<'f, 'm, 's, 'html, T>(
- &'f self,
- content: T,
- _: Outline,
- _: &'s Sack,
- _bib: Option>,
- ) -> impl Renderable + 'html
- where
- 'f: 'html,
- 'm: 'html,
- 's: 'html,
- T: Renderable + 'm {
- show(self, content)
- }
+ fn parse(data: String, _: Option<&Library>) -> (Outline, String, Option>) {
+ let html = data
+ .split("\n-----\n")
+ .map(|chunk| {
+ chunk
+ .split("\n---\n")
+ .map(|s| crate::text::md::parse(s.to_owned(), None))
+ .map(|e| e.1)
+ .collect::>()
+ })
+ .map(|stack| match stack.len() > 1 {
+ true => format!(
+ "",
+ stack
+ .into_iter()
+ .map(|slide| format!(""))
+ .collect::()
+ ),
+ false => format!("", stack[0]),
+ })
+ .collect::();
+ (Outline(vec![]), html, None)
+ }
- fn as_link(&self, path: Utf8PathBuf) -> Option {
- Some(Linkable::Date(LinkDate {
- link: Link {
- path,
- name: self.title.to_owned(),
- desc: self.desc.to_owned(),
- },
- date: self.date.to_owned(),
- }))
- }
+ fn render<'s, 'p, 'html>(
+ self,
+ sack: &'s Sack,
+ parsed: impl Renderable + 'p,
+ _: Outline,
+ _: Option>,
+ ) -> impl Renderable + 'html
+ where
+ 's: 'html,
+ 'p: 'html,
+ {
+ show(self, sack, parsed)
+ }
- fn parse(data: &str, _: Option<&Library>) -> (Outline, String, Option>) {
- let html = data
- .split("\n-----\n")
- .map(|chunk| chunk.split("\n---\n").map(|s| crate::text::md::parse(s, None)).map(|e| e.1).collect::>())
- .map(|stack| match stack.len() > 1 {
- true => format!("", stack.into_iter().map(|slide| format!("")).collect::()),
- false => format!("", stack[0])
- })
- .collect::();
- (Outline(vec![]), html, None)
- }
+ fn as_link(&self, path: Utf8PathBuf) -> Option {
+ Some(Linkable::Date(LinkDate {
+ link: Link {
+ path,
+ name: self.title.to_owned(),
+ desc: self.desc.to_owned(),
+ },
+ date: self.date.to_owned(),
+ }))
+ }
}
-pub fn show<'data, 'show>(
- fm: &'data Slideshow,
- slides: impl Renderable + 'data
-) -> impl Renderable + 'show
- where
- 'data: 'show
+pub fn show<'s, 'p, 'html>(
+ fm: Slideshow,
+ sack: &'s Sack,
+ slides: impl Renderable + 'p,
+) -> impl Renderable + 'html
+where
+ 's: 'html,
+ 'p: 'html,
{
- crate::html::bare(&fm.title, maud_move!(
- div .reveal {
- div .slides {
- (slides)
- }
- }
+ crate::html::bare(
+ sack,
+ maud_move!(
+ div .reveal {
+ div .slides {
+ (slides)
+ }
+ }
- script type="module" {
- (Raw("import 'reveal';"))
- }
+ script type="module" {
+ (Raw("import 'reveal';"))
+ }
- style {r#"
- .slides img {
- margin-left: auto;
- margin-right: auto;
- max-height: 60vh;
- }
- "#}
- ))
+ style { (Raw(CSS)) }
+ ),
+ fm.title.clone(),
+ )
}
diff --git a/src/html/wiki.rs b/src/html/wiki.rs
index f11869e..762ac83 100644
--- a/src/html/wiki.rs
+++ b/src/html/wiki.rs
@@ -10,83 +10,82 @@ use crate::{Link, Linkable};
/// Represents a wiki page
#[derive(Deserialize, Debug, Clone)]
pub struct Wiki {
- pub title: String,
+ pub title: String,
}
impl Content for Wiki {
- fn transform<'f, 'm, 's, 'html, T>(
- &'f self,
- content: T,
- outline: Outline,
- sack: &'s Sack,
- bib: Option>,
- ) -> impl Renderable + 'html
- where
- 'f: 'html,
- 'm: 'html,
- 's: 'html,
- T: Renderable + 'm {
- wiki(self, content, outline, sack, bib)
- }
+ fn parse(data: String, lib: Option<&Library>) -> (Outline, String, Option>) {
+ crate::text::md::parse(data, lib)
+ }
- fn as_link(&self, path: Utf8PathBuf) -> Option {
- Some(Linkable::Link(Link {
- path,
- name: self.title.to_owned(),
- desc: None,
- }))
- }
+ fn render<'s, 'p, 'html>(
+ self,
+ sack: &'s Sack,
+ parsed: impl Renderable + 'p,
+ outline: Outline,
+ bib: Option>,
+ ) -> impl Renderable + 'html
+ where
+ 's: 'html,
+ 'p: 'html,
+ {
+ wiki(self, sack, parsed, outline, bib)
+ }
- fn parse(data: &str, lib: Option<&Library>) -> (Outline, String, Option>) {
- crate::text::md::parse(data, lib)
- }
+ fn as_link(&self, path: Utf8PathBuf) -> Option {
+ Some(Linkable::Link(Link {
+ path,
+ name: self.title.to_owned(),
+ desc: None,
+ }))
+ }
}
-fn wiki<'data, 'html, 'sack, T>(
- fm: &'data Wiki,
- content: T,
- _: Outline,
- sack: &'sack Sack,
- bib: Option>,
+fn wiki<'s, 'p, 'html>(
+ matter: Wiki,
+ sack: &'s Sack,
+ parsed: impl Renderable + 'p,
+ _: Outline,
+ bib: Option>,
) -> impl Renderable + 'html
- where
- 'sack: 'html,
- 'data: 'html,
- T: Renderable + 'data
+where
+ 's: 'html,
+ 'p: 'html,
{
- let main = maud_move!(
- main .wiki-main {
+ let heading = matter.title.clone();
+ let main = maud_move!(
+ main .wiki-main {
- // Slide in/out for mobile
- input #wiki-aside-shown type="checkbox" hidden;
+ // Slide in/out for mobile
+ input #wiki-aside-shown type="checkbox" hidden;
- aside .wiki-aside {
- // Slide button
- label .wiki-aside__slider for="wiki-aside-shown" {
- img .wiki-icon src="/static/svg/double-arrow.svg" width="24" height="24";
- }
- // Navigation tree
- section .link-tree {
- div {
- (crate::html::misc::show_page_tree(sack, "wiki/**/*.html"))
- }
- }
- }
+ aside .wiki-aside {
+ // Slide button
+ label .wiki-aside__slider for="wiki-aside-shown" {
+ img .wiki-icon src="/static/svg/double-arrow.svg" width="24" height="24";
+ }
+ // Navigation tree
+ section .link-tree {
+ div {
+ (crate::html::misc::show_page_tree(sack, "wiki/**/*.html"))
+ }
+ }
+ }
- article .wiki-article /*class:list={classlist)*/ {
- header class="markdown" {
- h1 #top { (fm.title.clone()) }
- }
- section .wiki-article__markdown.markdown {
- (content)
- }
+ article .wiki-article /*class:list={classlist)*/ {
+ header class="markdown" {
+ h1 #top { (heading) }
+ }
+ section .wiki-article__markdown.markdown {
+ (parsed)
+ }
- @if let Some(bib) = bib {
- (crate::html::misc::show_bibliography(bib))
- }
- }
- }
- );
+ @if let Some(bib) = bib {
+ (crate::html::misc::show_bibliography(bib))
+ }
+ }
+ }
+ );
- crate::html::page(&fm.title, main, sack.get_file())
+ crate::html::page(sack, main, matter.title.to_owned())
}
diff --git a/src/main.rs b/src/main.rs
index fd86cb7..5373a2c 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,286 +1,339 @@
mod build;
mod html;
-mod md;
mod pipeline;
mod text;
mod ts;
mod utils;
mod watch;
+use std::collections::HashSet;
use std::fs;
use std::process::Command;
use camino::{Utf8Path, Utf8PathBuf};
use chrono::{DateTime, Datelike, Utc};
use clap::{Parser, ValueEnum};
-use pipeline::{Asset, AssetKind, Content, FileItemKind, Output, PipelineItem, Sack};
+use gray_matter::engine::YAML;
+use gray_matter::Matter;
use hypertext::{Raw, Renderable};
-use once_cell::sync::Lazy;
+use pipeline::{Asset, AssetKind, Content, FileItemKind, Output, PipelineItem};
use serde::Deserialize;
-use crate::pipeline::Virtual;
use crate::build::build_styles;
+use crate::pipeline::Virtual;
#[derive(Parser, Debug, Clone)]
struct Args {
- #[clap(value_enum, index = 1, default_value = "build")]
- mode: Mode,
+ #[clap(value_enum, index = 1, default_value = "build")]
+ mode: Mode,
}
#[derive(ValueEnum, Debug, Clone, Copy)]
enum Mode {
- Build,
- Watch,
+ Build,
+ Watch,
}
#[derive(Debug)]
-struct BuildInfo {
- pub year: i32,
- pub date: String,
- pub link: String,
- pub hash: String,
+struct BuildContext {
+ pub mode: Mode,
+ pub year: i32,
+ pub date: String,
+ pub link: String,
+ pub hash: String,
}
-
-static REPO: Lazy = Lazy::new(|| {
- let time = chrono::Utc::now();
-
- BuildInfo {
- year: time.year(),
- date: time.format("%Y/%m/%d %H:%M").to_string(),
- link: "https://git.kamoshi.org/kamov/website".into(),
- hash: String::from_utf8(
- Command::new("git")
- .args(["rev-parse", "--short", "HEAD"])
- .output()
- .unwrap()
- .stdout
- )
- .unwrap()
- .trim()
- .into()
- }
-});
-
-
#[derive(Debug, Clone)]
pub struct Link {
- pub path: Utf8PathBuf,
- pub name: String,
- pub desc: Option,
+ pub path: Utf8PathBuf,
+ pub name: String,
+ pub desc: Option,
}
#[derive(Debug, Clone)]
pub struct LinkDate {
- pub link: Link,
- pub date: DateTime,
+ pub link: Link,
+ pub date: DateTime,
}
#[derive(Debug, Clone)]
pub enum Linkable {
- Link(Link),
- Date(LinkDate),
-}
-
-
-fn to_index(item: PipelineItem) -> PipelineItem
- where
- T: for<'de> Deserialize<'de> + Content + 'static,
-{
- let meta = match item {
- PipelineItem::Skip(meta) if matches!(meta.kind, FileItemKind::Index) => meta,
- _ => return item,
- };
-
- let dir = meta.path.parent().unwrap().strip_prefix("content").unwrap();
- let dir = match meta.path.file_stem().unwrap() {
- "index" => dir.to_owned(),
- name => dir.join(name),
- };
- let path = dir.join("index.html");
-
- match meta.path.extension() {
- Some("md" | "mdx" | "lhs") => {
- let data = fs::read_to_string(&meta.path).unwrap();
- let (fm, md) = md::preflight::(&data);
- let link = T::as_link(&fm, Utf8Path::new("/").join(dir));
-
- let call = move |sack: &Sack| {
- let lib = sack.get_library();
- let (outline, html, bib) = T::parse(&md, lib);
- T::transform(&fm, Raw(html), outline, sack, bib).render().into()
- };
-
- Output {
- kind: Asset {
- kind: pipeline::AssetKind::Html(Box::new(call)),
- meta,
- }.into(),
- path,
- link,
- }.into()
- },
- _ => meta.into(),
- }
-}
-
-fn to_bundle(item: PipelineItem) -> PipelineItem {
- let meta = match item {
- PipelineItem::Skip(meta) if matches!(meta.kind, FileItemKind::Bundle) => meta,
- _ => return item,
- };
-
- let path = meta.path.strip_prefix("content").unwrap().to_owned();
-
- match meta.path.extension() {
- // any image
- Some("jpg" | "png" | "gif") => {
- Output {
- kind: Asset {
- kind: AssetKind::Image,
- meta,
- }.into(),
- path,
- link: None,
- }.into()
- },
- // bibliography
- Some("bib") => {
- let data = fs::read_to_string(&meta.path).unwrap();
- let data = hayagriva::io::from_biblatex_str(&data).unwrap();
-
- Output {
- kind: Asset {
- kind: AssetKind::Bibtex(data),
- meta,
- }.into(),
- path,
- link: None,
- }.into()
- },
- _ => meta.into(),
- }
-}
-
-
-fn build() {
- if fs::metadata("dist").is_ok() {
- println!("Cleaning dist");
- fs::remove_dir_all("dist").unwrap();
- }
-
- fs::create_dir("dist").unwrap();
-
- let assets: Vec