Basic cours support #44
6 changed files with 88 additions and 25 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -930,6 +930,7 @@ dependencies = [
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"rss",
|
"rss",
|
||||||
"serde",
|
"serde",
|
||||||
|
"serde_json",
|
||||||
"serde_yaml",
|
"serde_yaml",
|
||||||
"toml",
|
"toml",
|
||||||
]
|
]
|
||||||
|
|
|
@ -17,6 +17,7 @@ ramhorns = "0.14"
|
||||||
toml = "0.8"
|
toml = "0.8"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_yaml = "0.9"
|
serde_yaml = "0.9"
|
||||||
|
serde_json = "1.0"
|
||||||
minify-html = "0.11"
|
minify-html = "0.11"
|
||||||
minify-js = "0.5"
|
minify-js = "0.5"
|
||||||
glob = "0.3"
|
glob = "0.3"
|
||||||
|
|
|
@ -6,7 +6,11 @@ use ramhorns::Content;
|
||||||
use serde::{Deserialize, Deserializer};
|
use serde::{Deserialize, Deserializer};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
|
||||||
#[derive(Default, Deserialize, Content, Debug)]
|
/// Regular markdown files, no metadata
|
||||||
|
#[derive(Content, Debug, Default, Deserialize)]
|
||||||
|
pub struct FileNoMetadata {}
|
||||||
|
|
||||||
|
#[derive(Content, Debug, Default, Deserialize)]
|
||||||
pub struct FileMetadataBlog {
|
pub struct FileMetadataBlog {
|
||||||
pub title: Option<String>,
|
pub title: Option<String>,
|
||||||
pub date: Option<Date>,
|
pub date: Option<Date>,
|
||||||
|
@ -16,7 +20,7 @@ pub struct FileMetadataBlog {
|
||||||
pub toc: Option<bool>,
|
pub toc: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Deserialize, Content, Debug)]
|
#[derive(Content, Debug, Default, Deserialize)]
|
||||||
pub struct FileMetadataContact {
|
pub struct FileMetadataContact {
|
||||||
pub title: String,
|
pub title: String,
|
||||||
pub custom: Option<bool>,
|
pub custom: Option<bool>,
|
||||||
|
@ -26,7 +30,7 @@ pub struct FileMetadataContact {
|
||||||
pub description: Option<String>,
|
pub description: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Deserialize, Content, Debug)]
|
#[derive(Content, Debug, Default, Deserialize)]
|
||||||
pub struct FileMetadataPortfolio {
|
pub struct FileMetadataPortfolio {
|
||||||
pub title: Option<String>,
|
pub title: Option<String>,
|
||||||
pub link: Option<String>,
|
pub link: Option<String>,
|
||||||
|
@ -34,9 +38,6 @@ pub struct FileMetadataPortfolio {
|
||||||
pub language: Option<String>,
|
pub language: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Deserialize, Content, Debug)]
|
|
||||||
pub struct FileMetadataCours {}
|
|
||||||
|
|
||||||
pub enum TypeFileMetadata {
|
pub enum TypeFileMetadata {
|
||||||
Blog,
|
Blog,
|
||||||
Contact,
|
Contact,
|
||||||
|
@ -44,12 +45,12 @@ pub enum TypeFileMetadata {
|
||||||
Cours,
|
Cours,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Deserialize, Content, Debug)]
|
#[derive(Content, Debug, Default, Deserialize)]
|
||||||
pub struct FileMetadata {
|
pub struct FileMetadata {
|
||||||
pub blog: Option<FileMetadataBlog>,
|
pub blog: Option<FileMetadataBlog>,
|
||||||
pub contact: Option<FileMetadataContact>,
|
pub contact: Option<FileMetadataContact>,
|
||||||
pub portfolio: Option<FileMetadataPortfolio>,
|
pub portfolio: Option<FileMetadataPortfolio>,
|
||||||
pub cours: Option<FileMetadataCours>,
|
pub cours: Option<FileNoMetadata>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Content, Debug, Clone)]
|
#[derive(Content, Debug, Clone)]
|
||||||
|
@ -254,7 +255,7 @@ pub fn get_metadata<'a>(root: &'a AstNode<'a>, mtype: TypeFileMetadata) -> FileM
|
||||||
..FileMetadata::default()
|
..FileMetadata::default()
|
||||||
},
|
},
|
||||||
TypeFileMetadata::Cours => FileMetadata {
|
TypeFileMetadata::Cours => FileMetadata {
|
||||||
cours: Some(FileMetadataCours::default()),
|
cours: Some(FileNoMetadata::default()),
|
||||||
..FileMetadata::default()
|
..FileMetadata::default()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,43 +1,91 @@
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
use actix_web::{get, web, Responder};
|
use actix_web::{get, web, Responder};
|
||||||
use glob::glob;
|
|
||||||
use ramhorns::Content;
|
use ramhorns::Content;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::Config,
|
config::Config,
|
||||||
misc::{
|
misc::{
|
||||||
markdown::{read_file, TypeFileMetadata},
|
markdown::{read_file, File, TypeFileMetadata},
|
||||||
utils::{make_kw, Html},
|
utils::{make_kw, Html},
|
||||||
},
|
},
|
||||||
template::{Infos, NavBar},
|
template::{Infos, NavBar},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub struct PathRequest {
|
||||||
|
q: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
#[get("/cours")]
|
#[get("/cours")]
|
||||||
async fn page(config: web::Data<Config>) -> impl Responder {
|
async fn page(info: web::Query<PathRequest>, config: web::Data<Config>) -> impl Responder {
|
||||||
Html(build_page(config.get_ref().to_owned()))
|
Html(build_page(info, config.get_ref().to_owned()))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Content, Debug)]
|
#[derive(Content, Debug)]
|
||||||
struct CoursTemplate {
|
struct CoursTemplate {
|
||||||
navbar: NavBar,
|
navbar: NavBar,
|
||||||
/* filetree: Truc, */
|
filetree: String,
|
||||||
|
content: Option<File>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the filetree
|
#[derive(Serialize)]
|
||||||
fn get_filetree() {
|
struct FileNode {
|
||||||
let cours_dir = "data/cours";
|
name: String,
|
||||||
glob(&format!("{cours_dir}/*")).unwrap();
|
is_dir: bool,
|
||||||
|
children: Vec<FileNode>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a page
|
/// Build the filetree
|
||||||
fn get_page(filename: &str) {
|
fn get_filetree(dir_path: &str, exclusion_list: &[&str]) -> FileNode {
|
||||||
let cours_dir = "data/cours";
|
let entries = std::fs::read_dir(dir_path).unwrap();
|
||||||
|
|
||||||
let post = read_file(&format!("{cours_dir}/{filename}"), TypeFileMetadata::Cours);
|
let mut children = Vec::new();
|
||||||
|
for entry in entries.filter_map(Result::ok) {
|
||||||
|
let entry_path = entry.path();
|
||||||
|
let entry_name = entry_path.file_name().and_then(|n| n.to_str()).unwrap();
|
||||||
|
if !exclusion_list.contains(&entry_name) {
|
||||||
|
let filename = entry_name.to_string();
|
||||||
|
if entry_path.is_file() {
|
||||||
|
children.push(FileNode {
|
||||||
|
name: filename,
|
||||||
|
is_dir: false,
|
||||||
|
children: vec![],
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
children.push(get_filetree(entry_path.to_str().unwrap(), exclusion_list));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FileNode {
|
||||||
|
name: Path::new(dir_path)
|
||||||
|
.file_name()
|
||||||
|
.unwrap()
|
||||||
|
.to_string_lossy()
|
||||||
|
.to_string(),
|
||||||
|
is_dir: true,
|
||||||
|
children,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a page content
|
||||||
|
fn get_content(cours_dir: &str, path: &web::Query<PathRequest>) -> Option<File> {
|
||||||
|
let filename = match &path.q {
|
||||||
|
Some(q) => q,
|
||||||
|
None => "index.md",
|
||||||
|
};
|
||||||
|
|
||||||
|
read_file(&format!("{cours_dir}/{filename}"), TypeFileMetadata::Cours)
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[once(time = 60)]
|
// #[once(time = 60)]
|
||||||
// TODO: Uncomment before release
|
// TODO: Uncomment before release
|
||||||
fn build_page(config: Config) -> String {
|
fn build_page(info: web::Query<PathRequest>, config: Config) -> String {
|
||||||
|
let cours_dir = "data/cours";
|
||||||
|
let filetree = get_filetree(cours_dir, &[]);
|
||||||
|
|
||||||
config.tmpl.render(
|
config.tmpl.render(
|
||||||
"cours.html",
|
"cours.html",
|
||||||
CoursTemplate {
|
CoursTemplate {
|
||||||
|
@ -45,6 +93,8 @@ fn build_page(config: Config) -> String {
|
||||||
cours: true,
|
cours: true,
|
||||||
..NavBar::default()
|
..NavBar::default()
|
||||||
},
|
},
|
||||||
|
filetree: serde_json::to_string(&filetree).unwrap(),
|
||||||
|
content: get_content(cours_dir, &info),
|
||||||
},
|
},
|
||||||
Infos {
|
Infos {
|
||||||
page_title: Some("Cours".into()),
|
page_title: Some("Cours".into()),
|
||||||
|
|
4
static/js/cours.js
Normal file
4
static/js/cours.js
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
window.addEventListener("load", () => {
|
||||||
|
/* Ici on va récuperer le JSON envoyer par le serveur et le transformer
|
||||||
|
* en un jolie filetree */
|
||||||
|
});
|
|
@ -9,9 +9,15 @@
|
||||||
<main>
|
<main>
|
||||||
{{#data}}
|
{{#data}}
|
||||||
|
|
||||||
<p>Coucou</p>
|
<aside>
|
||||||
|
<div id="data" data-json="{{filetree}} "></div>
|
||||||
|
</aside>
|
||||||
|
|
||||||
{{/data}}
|
{{^content}}
|
||||||
|
<p>Fichier introuvable</p>
|
||||||
|
{{/content}} {{#content}}
|
||||||
|
<article>{{&content}}</article>
|
||||||
|
{{/content}} {{/data}}
|
||||||
</main>
|
</main>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
Loading…
Reference in a new issue