178 lines
4.6 KiB
Rust
178 lines
4.6 KiB
Rust
use super::posts::parse::Tag;
|
|
use super::util::slugify::slugify;
|
|
use super::util::templates::{filters, TemplateCommon};
|
|
use super::util::{from_frontmatter, output_rendered_template, word_count};
|
|
use super::{content_path, markdown};
|
|
use askama::Template;
|
|
use chrono::{DateTime, FixedOffset};
|
|
use serde::Deserialize;
|
|
use std::{fs, io::Read, path::PathBuf};
|
|
|
|
pub fn generate() {
|
|
let series = vec![
|
|
generate_series("forge-modding-1102", "Forge Mods for 1.10.2"),
|
|
generate_series("forge-modding-1112", "Forge Mods for 1.11.2"),
|
|
generate_series("forge-modding-112", "Forge Mods for 1.12"),
|
|
];
|
|
|
|
generate_index(&series);
|
|
}
|
|
|
|
fn generate_index(series: &[TutorialSeries]) {
|
|
output_rendered_template(
|
|
&TutorialsIndexTemplate { all_series: series },
|
|
"/tutorials/index.html",
|
|
)
|
|
.unwrap();
|
|
}
|
|
|
|
fn generate_series(slug: &'static str, name: &'static str) -> TutorialSeries {
|
|
let mut path = content_path("tutorials");
|
|
path.push(slug);
|
|
let posts = fs::read_dir(path)
|
|
.unwrap()
|
|
.map(|entry| {
|
|
let entry = entry.unwrap();
|
|
assert!(entry.file_type().unwrap().is_file());
|
|
parse_post(entry.path(), slug, name)
|
|
})
|
|
.collect::<Vec<_>>();
|
|
|
|
let series = TutorialSeries { slug, name, posts };
|
|
|
|
for post in series.posts.iter() {
|
|
generate_post(&series, post);
|
|
}
|
|
generate_series_index(&series);
|
|
|
|
series
|
|
}
|
|
|
|
fn generate_post(series: &TutorialSeries, post: &TutorialPost) {
|
|
output_rendered_template(
|
|
&TutorialPostTemplate { series, post },
|
|
format!("/tutorials/{}/{}/index.html", series.slug, post.slug),
|
|
)
|
|
.unwrap();
|
|
}
|
|
|
|
fn generate_series_index(series: &TutorialSeries) {
|
|
output_rendered_template(
|
|
&TutorialSeriesTemplate { series },
|
|
format!("/tutorials/{}/index.html", series.slug),
|
|
)
|
|
.unwrap();
|
|
}
|
|
|
|
fn parse_post(path: PathBuf, series_slug: &str, series_name: &str) -> TutorialPost {
|
|
let mut f = fs::File::open(&path).unwrap();
|
|
let mut buffer = String::new();
|
|
f.read_to_string(&mut buffer).unwrap();
|
|
TutorialPost::new(path, &buffer, series_slug, series_name)
|
|
}
|
|
|
|
struct TutorialSeries {
|
|
slug: &'static str,
|
|
name: &'static str,
|
|
posts: Vec<TutorialPost>,
|
|
}
|
|
|
|
impl TutorialSeries {
|
|
fn last_updated(&self) -> &DateTime<FixedOffset> {
|
|
&self
|
|
.posts
|
|
.iter()
|
|
.max_by_key(|p| p.metadata.date)
|
|
.unwrap()
|
|
.metadata
|
|
.date
|
|
}
|
|
}
|
|
|
|
struct TutorialPost {
|
|
content: String,
|
|
slug: String,
|
|
word_count: Option<u32>,
|
|
metadata: TutorialPostMetadata,
|
|
}
|
|
|
|
impl TutorialPost {
|
|
fn new(path: PathBuf, contents: &str, series_slug: &str, series_name: &str) -> Self {
|
|
let (mut metadata, rest_contents) =
|
|
from_frontmatter::<'_, TutorialPostMetadata>(contents).unwrap();
|
|
|
|
metadata.tags = Some(vec![Tag {
|
|
name: series_name.to_owned(),
|
|
slug: format!("tutorials/{}", series_slug),
|
|
}]);
|
|
|
|
let slug = metadata
|
|
.slug
|
|
.clone()
|
|
.unwrap_or_else(|| slugify(&metadata.title));
|
|
|
|
assert!(path.extension().unwrap().eq_ignore_ascii_case("md"));
|
|
|
|
let wc = word_count::markdown(rest_contents);
|
|
|
|
let mut buf = vec![];
|
|
markdown::render(rest_contents, &mut buf);
|
|
let html = String::from_utf8(buf).unwrap();
|
|
|
|
TutorialPost {
|
|
content: html,
|
|
slug,
|
|
word_count: Some(wc),
|
|
metadata,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Deserialize)]
|
|
struct TutorialPostMetadata {
|
|
title: String,
|
|
date: DateTime<FixedOffset>,
|
|
slug: Option<String>,
|
|
tags: Option<Vec<Tag>>,
|
|
}
|
|
|
|
#[derive(Template)]
|
|
#[template(path = "layout/tutorial.html")]
|
|
struct TutorialPostTemplate<'a> {
|
|
series: &'a TutorialSeries,
|
|
post: &'a TutorialPost,
|
|
}
|
|
|
|
impl<'a> TemplateCommon for TutorialPostTemplate<'a> {}
|
|
impl<'a> TutorialPostTemplate<'a> {
|
|
fn permalink(&self) -> String {
|
|
format!("/tutorials/{}/{}/", self.series.slug, self.post.slug)
|
|
}
|
|
}
|
|
|
|
#[derive(Template)]
|
|
#[template(path = "layout/tutorial-series.html")]
|
|
struct TutorialSeriesTemplate<'a> {
|
|
series: &'a TutorialSeries,
|
|
}
|
|
|
|
impl<'a> TemplateCommon for TutorialSeriesTemplate<'a> {}
|
|
impl<'a> TutorialSeriesTemplate<'a> {
|
|
fn permalink(&self) -> String {
|
|
format!("/tutorials/{}/", self.series.slug)
|
|
}
|
|
}
|
|
|
|
#[derive(Template)]
|
|
#[template(path = "tutorials.html")]
|
|
struct TutorialsIndexTemplate<'a> {
|
|
all_series: &'a [TutorialSeries],
|
|
}
|
|
|
|
impl<'a> TemplateCommon for TutorialsIndexTemplate<'a> {}
|
|
impl<'a> TutorialsIndexTemplate<'a> {
|
|
fn permalink(&self) -> &'static str {
|
|
"/tutorials/"
|
|
}
|
|
}
|