Rework (#35)
All checks were successful
ci/woodpecker/push/publish Pipeline was successful

- Style rework
- Update dependencies to latest

Close #33
Close #34

Reviewed-on: #35
Co-authored-by: Mylloon <kennel.anri@tutanota.com>
Co-committed-by: Mylloon <kennel.anri@tutanota.com>
This commit is contained in:
Mylloon 2023-10-15 20:58:20 +02:00 committed by Anri Kennel
parent 127c7cfd29
commit 9f95eb2b6b
Signed by: Forgejo
GPG key ID: E72245C752A07631
49 changed files with 1322 additions and 802 deletions

1
.gitattributes vendored
View file

@ -1,3 +1,4 @@
*.png filter=lfs diff=lfs merge=lfs -text
*.gif filter=lfs diff=lfs merge=lfs -text
*.jpg filter=lfs diff=lfs merge=lfs -text
*.webp filter=lfs diff=lfs merge=lfs -text

74
Cargo.lock generated
View file

@ -256,6 +256,12 @@ dependencies = [
"alloc-no-stdlib",
]
[[package]]
name = "allocator-api2"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5"
[[package]]
name = "android-tzdata"
version = "0.1.1"
@ -476,15 +482,16 @@ dependencies = [
[[package]]
name = "cached"
version = "0.45.1"
version = "0.46.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90eb5776f28a149524d1d8623035760b4454ec881e8cf3838fa8d7e1b11254b3"
checksum = "8cead8ece0da6b744b2ad8ef9c58a4cdc7ef2921e60a6ddfb9eaaa86839b5fc5"
dependencies = [
"ahash",
"async-trait",
"cached_proc_macro",
"cached_proc_macro_types",
"futures",
"hashbrown 0.13.2",
"hashbrown 0.14.1",
"instant",
"once_cell",
"thiserror",
@ -611,11 +618,12 @@ checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]]
name = "comrak"
version = "0.18.0"
version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "482aa5695bca086022be453c700a40c02893f1ba7098a2c88351de55341ae894"
checksum = "82c995deda3bfdebd07d0e2af79e9da13e4b1be652b21a746f3f5b24bf0a49ef"
dependencies = [
"clap",
"derive_builder",
"entities",
"memchr",
"once_cell",
@ -696,7 +704,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "874c6e2d19f8d4a285083b11a3241bfbe01ac3ed85f26e1e6b34888d960552bd"
dependencies = [
"derive_more",
"indexmap",
"indexmap 1.9.3",
"nom",
]
@ -819,6 +827,12 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5320ae4c3782150d900b79807611a59a99fc9a1d61d686faafc24b93fc8d7ca"
[[package]]
name = "equivalent"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]]
name = "errno"
version = "0.3.1"
@ -1020,7 +1034,7 @@ dependencies = [
"futures-sink",
"futures-util",
"http",
"indexmap",
"indexmap 1.9.3",
"slab",
"tokio",
"tokio-util",
@ -1043,6 +1057,16 @@ dependencies = [
"bumpalo",
]
[[package]]
name = "hashbrown"
version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7dfda62a12f55daeae5015f81b0baea145391cb4520f86c248fc615d72640d12"
dependencies = [
"ahash",
"allocator-api2",
]
[[package]]
name = "heck"
version = "0.3.3"
@ -1208,6 +1232,16 @@ dependencies = [
"hashbrown 0.12.3",
]
[[package]]
name = "indexmap"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897"
dependencies = [
"equivalent",
"hashbrown 0.14.1",
]
[[package]]
name = "instant"
version = "0.1.12"
@ -1708,7 +1742,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9bd9647b268a3d3e14ff09c23201133a62589c658db02bb7388c7246aafe0590"
dependencies = [
"base64",
"indexmap",
"indexmap 1.9.3",
"line-wrap",
"quick-xml",
"serde",
@ -2058,9 +2092,9 @@ dependencies = [
[[package]]
name = "serde_spanned"
version = "0.6.2"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93107647184f6027e3b7dcb2e11034cf95ffa1e3a682c67951963ac69c1c007d"
checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186"
dependencies = [
"serde",
]
@ -2083,7 +2117,7 @@ version = "0.9.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9d684e3ec7de3bf5466b32bd75303ac16f0736426e5a4e0d6e489559ce1249c"
dependencies = [
"indexmap",
"indexmap 1.9.3",
"itoa",
"ryu",
"serde",
@ -2358,9 +2392,9 @@ dependencies = [
[[package]]
name = "toml"
version = "0.7.4"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6135d499e69981f9ff0ef2167955a5333c35e36f6937d382974566b3d5b94ec"
checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d"
dependencies = [
"serde",
"serde_spanned",
@ -2370,20 +2404,20 @@ dependencies = [
[[package]]
name = "toml_datetime"
version = "0.6.2"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a76a9312f5ba4c2dec6b9161fdf25d87ad8a09256ccea5a556fef03c706a10f"
checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b"
dependencies = [
"serde",
]
[[package]]
name = "toml_edit"
version = "0.19.9"
version = "0.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92d964908cec0d030b812013af25a0e57fddfadb1e066ecc6681d86253129d4f"
checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338"
dependencies = [
"indexmap",
"indexmap 2.0.2",
"serde",
"serde_spanned",
"toml_datetime",
@ -2803,9 +2837,9 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
[[package]]
name = "winnow"
version = "0.4.6"
version = "0.5.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61de7bac303dc551fe038e2b3cef0f571087a47571ea6e79a87692ac99b99699"
checksum = "037711d82167854aff2018dfd193aa0fef5370f456732f0d5a0c59b0f1b4b907"
dependencies = [
"memchr",
]

View file

@ -12,15 +12,15 @@ license = "AGPL-3.0-or-later"
[dependencies]
actix-web = "4.4"
actix-files = "0.6"
cached = { version = "0.45", features = ["async"] }
cached = { version = "0.46", features = ["async"] }
ramhorns = "0.14"
toml = "0.7"
toml = "0.8"
serde = { version = "1.0", features = ["derive"] }
serde_yaml = "0.9"
minify-html = "0.11"
minify-js = "0.5"
glob = "0.3"
comrak = "0.18"
comrak = "0.19"
reqwest = { version = "0.11", features = ["json"] }
chrono = "0.4.30"
chrono-tz = "0.8"

View file

@ -82,7 +82,7 @@ onion = "http://youraddress.onion/"
## Example of [`config.toml`](./config/config.toml)
```toml
mail = your.mail at host.com"
mail = "your.mail at host.com"
lang = "lang"
onion = "http://youraddress.onion/"
app_name = "Nickname"

View file

@ -124,6 +124,7 @@ fn init(dist_dir: String, static_dir: String, templates_dir: String) -> String {
keep_closing_tags: true,
minify_css: true,
minify_js: true,
remove_bangs: false,
..minify_html::Cfg::spec_compliant()
};

View file

@ -3,7 +3,7 @@ use actix_web::{middleware::DefaultHeaders, web, App, HttpServer};
use std::io::Result;
use crate::routes::{
agreements, api_v1, blog, contrib, cours, cv, gaming, index, memorial, networks, not_found,
agreements, api_v1, blog, contact, contrib, cours, cv, gaming, index, memorial, not_found,
portfolio, setup, web3,
};
@ -29,10 +29,15 @@ async fn main() -> Result<()> {
HttpServer::new(move || {
App::new()
.app_data(web::Data::new(config.to_owned()))
.wrap(DefaultHeaders::new().add((
"Onion-Location",
config.fc.onion.as_deref().unwrap_or_default(),
)))
.wrap(
DefaultHeaders::new()
.add((
"Onion-Location",
config.fc.onion.as_deref().unwrap_or_default(),
))
.add(("Server", format!("ewp/{}", env!("CARGO_PKG_VERSION"))))
.add(("Permissions-Policy", "interest-cohort=()")),
)
.service(web::scope("/api").service(web::scope("v1").service(api_v1::love)))
.service(index::page)
.service(agreements::security)
@ -47,7 +52,8 @@ async fn main() -> Result<()> {
.service(cv::page)
.service(gaming::page)
.service(memorial::page)
.service(networks::page)
.service(contact::page)
.service(contact::service_redirection)
.service(portfolio::page)
.service(setup::page)
.service(web3::page)

View file

@ -1,9 +1,6 @@
use crate::misc::date::Date;
use comrak::nodes::{AstNode, NodeValue};
use comrak::{
format_html, parse_document, Arena, ComrakExtensionOptions, ComrakOptions, ComrakParseOptions,
ComrakRenderOptions, ListStyleType,
};
use comrak::{format_html, parse_document, Arena, ComrakOptions, ListStyleType};
use ramhorns::Content;
use serde::{Deserialize, Deserializer};
use std::fs;
@ -17,6 +14,7 @@ pub struct FileMetadata {
pub publish: Option<bool>,
pub tags: Option<Vec<Tag>>,
pub toc: Option<bool>,
pub language: Option<String>,
}
#[derive(Content, Debug, Clone)]
@ -55,39 +53,41 @@ pub struct File {
/// Options used for parser and compiler MD --> HTML
pub fn get_options() -> ComrakOptions {
ComrakOptions {
extension: ComrakExtensionOptions {
strikethrough: true,
tagfilter: true,
table: true,
autolink: true,
tasklist: true,
superscript: true,
header_ids: Some(String::new()),
footnotes: true,
description_lists: true,
front_matter_delimiter: Some("---".into()),
},
parse: ComrakParseOptions {
smart: true, // could be boring
default_info_string: Some("plaintext".into()),
relaxed_tasklist_matching: true,
},
render: ComrakRenderOptions {
hardbreaks: false, // could be true? change by metadata could be good for compatibility
github_pre_lang: false,
full_info_string: true,
width: 0, // 0 mean disabled?
unsafe_: true,
escape: false,
list_style: ListStyleType::Dash,
sourcepos: false,
},
}
let mut options = comrak::Options::default();
// Extension
options.extension.strikethrough = true;
options.extension.tagfilter = true;
options.extension.table = true;
options.extension.autolink = true;
options.extension.tasklist = true;
options.extension.superscript = true;
options.extension.header_ids = Some(String::new());
options.extension.footnotes = true;
options.extension.description_lists = true;
options.extension.front_matter_delimiter = Some("---".into());
// Parser
options.parse.smart = true; // could be boring
options.parse.default_info_string = Some("plaintext".into());
options.parse.relaxed_tasklist_matching = true;
options.parse.relaxed_autolinks = true;
// Renderer
options.render.hardbreaks = false; // could be true? change by metadata could be good for compatibility
options.render.github_pre_lang = false;
options.render.full_info_string = true;
options.render.width = 0; // 0 mean disabled?
options.render.unsafe_ = true;
options.render.escape = false;
options.render.list_style = ListStyleType::Dash;
options.render.sourcepos = false;
options
}
/// Transform markdown string to File structure
pub fn read(raw_text: &str) -> File {
fn read(raw_text: &str) -> File {
let arena = Arena::new();
let options = get_options();

View file

@ -6,7 +6,7 @@ use ramhorns::Content;
#[routes]
#[get("/.well-known/security.txt")]
#[get("/security.txt")]
pub async fn security(req: HttpRequest, config: web::Data<Config>) -> impl Responder {
async fn security(req: HttpRequest, config: web::Data<Config>) -> impl Responder {
HttpResponse::Ok().body(build_securitytxt(
config.get_ref().to_owned(),
get_url(req.connection_info()),
@ -34,7 +34,7 @@ fn build_securitytxt(config: Config, url: String) -> String {
}
#[get("/humans.txt")]
pub async fn humans(config: web::Data<Config>) -> impl Responder {
async fn humans(config: web::Data<Config>) -> impl Responder {
HttpResponse::Ok().body(build_humanstxt(config.get_ref().to_owned()))
}
@ -59,7 +59,7 @@ fn build_humanstxt(config: Config) -> String {
}
#[get("/robots.txt")]
pub async fn robots() -> impl Responder {
async fn robots() -> impl Responder {
HttpResponse::Ok().body(build_robotstxt())
}
@ -69,7 +69,7 @@ fn build_robotstxt() -> String {
}
#[get("/sitemap.xml")]
pub async fn sitemap() -> impl Responder {
async fn sitemap() -> impl Responder {
// TODO
actix_web::web::Redirect::to("/")
}

View file

@ -7,7 +7,7 @@ struct Info {
}
#[get("/love")]
pub async fn love() -> impl Responder {
async fn love() -> impl Responder {
HttpResponse::Ok().json(Info {
unix_epoch: 1605576600,
})

View file

@ -21,13 +21,13 @@ use crate::{
markdown::{get_metadata, get_options, read_file, File, FileMetadata},
utils::get_url,
},
template::Infos,
template::{Infos, NavBar},
};
const MIME_TYPE_RSS: &str = "application/rss+xml";
#[get("/blog")]
pub async fn index(req: HttpRequest, config: web::Data<Config>) -> impl Responder {
async fn index(req: HttpRequest, config: web::Data<Config>) -> impl Responder {
HttpResponse::Ok().body(build_index(
config.get_ref().to_owned(),
get_url(req.connection_info()),
@ -36,12 +36,13 @@ pub async fn index(req: HttpRequest, config: web::Data<Config>) -> impl Responde
#[derive(Content, Debug)]
struct BlogIndexTemplate {
navbar: NavBar,
posts: Vec<Post>,
no_posts: bool,
}
#[once(time = 120)]
pub fn build_index(config: Config, url: String) -> String {
fn build_index(config: Config, url: String) -> String {
let mut posts = get_posts("data/blog");
// Sort from newest to oldest
@ -51,6 +52,10 @@ pub fn build_index(config: Config, url: String) -> String {
config.tmpl.render(
"blog/index.html",
BlogIndexTemplate {
navbar: NavBar {
blog: true,
..NavBar::default()
},
no_posts: posts.is_empty(),
posts,
},
@ -172,12 +177,13 @@ fn get_posts(location: &str) -> Vec<Post> {
#[derive(Content, Debug)]
struct BlogPostTemplate {
navbar: NavBar,
post: Option<File>,
toc: String,
}
#[get("/blog/p/{id}")]
pub async fn page(
async fn page(
req: HttpRequest,
path: web::Path<(String,)>,
config: web::Data<Config>,
@ -193,9 +199,18 @@ fn build_post(file: String, config: Config, url: String) -> String {
let mut post = None;
let (infos, toc) = get_post(&mut post, file, config.fc.name.unwrap_or_default(), url);
config
.tmpl
.render("blog/post.html", BlogPostTemplate { post, toc }, infos)
config.tmpl.render(
"blog/post.html",
BlogPostTemplate {
navbar: NavBar {
blog: true,
..NavBar::default()
},
post,
toc,
},
infos,
)
}
fn get_post(
@ -234,7 +249,7 @@ fn get_post(
page_title: Some(format!("Post: {}", title)),
page_desc: Some(format!("Blog d'{name}")),
page_kw: Some(
vec!["blog", "blogging", "write", "writing"]
["blog", "blogging", "write", "writing"]
.iter()
.map(|&tag| tag.to_owned())
.chain(tags.into_iter().map(|t| t.name))
@ -248,7 +263,7 @@ fn get_post(
}
#[get("/blog/rss")]
pub async fn rss(req: HttpRequest, config: web::Data<Config>) -> impl Responder {
async fn rss(req: HttpRequest, config: web::Data<Config>) -> impl Responder {
HttpResponse::Ok()
.append_header(("content-type", MIME_TYPE_RSS))
.body(build_rss(

84
src/routes/contact.rs Normal file
View file

@ -0,0 +1,84 @@
use actix_web::{get, routes, web, HttpRequest, HttpResponse, Responder};
use cached::proc_macro::once;
use ramhorns::Content;
use crate::{
config::Config,
misc::utils::get_url,
template::{Infos, NavBar},
};
#[get("/contact")]
async fn page(req: HttpRequest, config: web::Data<Config>) -> impl Responder {
HttpResponse::Ok().body(build_page(
config.get_ref().to_owned(),
get_url(req.connection_info()),
))
}
#[routes]
#[get("/contact/{service}")]
#[get("/contact/{service}/{scope}")]
async fn service_redirection(req: HttpRequest) -> impl Responder {
let info = req.match_info();
let find_redirection = match info.query("service") {
/* Socials links */
"twitter" => Some("https://twitter.com/Mylloon".to_owned()),
"mastodon" => Some("https://piaille.fr/@mylloon".to_owned()),
"discord" => match info.get("scope") {
Some("user") => Some("https://discord.com/users/158260864623968257/".to_owned()),
Some("guild") => Some("https://discord.gg/Z5ePxH4".to_owned()),
_ => None,
},
"reddit" => Some("https://www.reddit.com/user/mylloon".to_owned()),
"instagram" => Some("https://www.instagram.com/mylloon/".to_owned()),
"kitsu" => Some("https://kitsu.io/users/Mylloon/library?status=completed".to_owned()),
"steam" => Some("https://steamcommunity.com/id/mylloon/".to_owned()),
"youtube" => Some("https://www.youtube.com/c/Mylloon".to_owned()),
"twitch" => Some("https://www.twitch.tv/mylloon".to_owned()),
/* Forges */
"github" => Some("https://github.com/Mylloon".to_owned()),
"gitlab" => Some("https://gitlab.com/Mylloon".to_owned()),
"codeberg" => Some("https://codeberg.org/Mylloon".to_owned()),
"forgejo" => Some("https://git.mylloon.fr/Anri".to_owned()),
/* Others */
"keyoxide" => {
Some("https://keyoxide.org/27024A99057E58B8087A5022A82D63DFF8D1317F".to_owned())
}
_ => None,
};
if let Some(redirection) = find_redirection {
// Redirect to the desired service
actix_web::web::Redirect::to(redirection)
} else {
// By default, returns to the contact page
actix_web::web::Redirect::to("/contact")
}
}
#[derive(Content, Debug)]
struct NetworksTemplate {
navbar: NavBar,
}
#[once(time = 60)]
fn build_page(config: Config, url: String) -> String {
config.tmpl.render(
"contact.html",
NetworksTemplate {
navbar: NavBar {
contact: true,
..NavBar::default()
},
},
Infos {
page_title: Some("Contacts".into()),
page_desc: Some(format!("Réseaux d'{}", config.fc.name.unwrap_or_default())),
page_kw: None,
url,
},
)
}

View file

@ -6,20 +6,21 @@ use crate::{
github::{fetch_pr, ProjectState},
utils::get_url,
},
template::Infos,
template::{Infos, NavBar},
};
use actix_web::{get, web, HttpRequest, HttpResponse, Responder};
use cached::proc_macro::once;
use ramhorns::Content;
#[get("/contrib")]
pub async fn page(req: HttpRequest, config: web::Data<Config>) -> impl Responder {
async fn page(req: HttpRequest, config: web::Data<Config>) -> impl Responder {
let url = get_url(req.connection_info());
HttpResponse::Ok().body(build_page(config.get_ref().to_owned(), url).await)
}
#[derive(Content, Debug)]
struct PortfolioTemplate {
navbar: NavBar,
error: bool,
projects: Option<Vec<Project>>,
waiting: Option<Vec<Project>>,
@ -45,7 +46,12 @@ struct Pull {
}
#[once(time = 120)]
pub async fn build_page(config: Config, url: String) -> String {
async fn build_page(config: Config, url: String) -> String {
let navbar = NavBar {
contrib: true,
..NavBar::default()
};
// Fetch latest data from github
let data = match fetch_pr().await {
Ok(projects) => {
@ -107,6 +113,7 @@ pub async fn build_page(config: Config, url: String) -> String {
});
PortfolioTemplate {
navbar,
error: false,
projects: Some(
data.iter()
@ -132,6 +139,7 @@ pub async fn build_page(config: Config, url: String) -> String {
eprintln!("{}", e);
PortfolioTemplate {
navbar,
error: true,
projects: None,
waiting: None,

View file

@ -1,7 +1,7 @@
use actix_web::{get, Responder};
#[get("/cours")]
pub async fn page() -> impl Responder {
async fn page() -> impl Responder {
// TODO
actix_web::web::Redirect::to("/")
}

View file

@ -1,7 +1,7 @@
use actix_web::{get, Responder};
#[get("/cv")]
pub async fn page() -> impl Responder {
async fn page() -> impl Responder {
// TODO
actix_web::web::Redirect::to("/")
}

View file

@ -1,7 +1,7 @@
use actix_web::{get, Responder};
#[get("/gaming")]
pub async fn page() -> impl Responder {
async fn page() -> impl Responder {
// TODO
actix_web::web::Redirect::to("/")
}

View file

@ -1,21 +1,42 @@
use actix_web::{get, web, HttpRequest, HttpResponse, Responder};
use cached::proc_macro::once;
use ramhorns::Content;
use crate::{config::Config, misc::utils::get_url, template::Infos};
use crate::{
config::Config,
misc::utils::get_url,
template::{Infos, NavBar},
};
#[get("/")]
pub async fn page(req: HttpRequest, config: web::Data<Config>) -> impl Responder {
async fn page(req: HttpRequest, config: web::Data<Config>) -> impl Responder {
HttpResponse::Ok().body(build_page(
config.get_ref().to_owned(),
get_url(req.connection_info()),
))
}
#[derive(Content, Debug)]
struct IndexTemplate {
navbar: NavBar,
fullname: String,
}
#[once(time = 60)]
pub fn build_page(config: Config, url: String) -> String {
fn build_page(config: Config, url: String) -> String {
config.tmpl.render(
"index.html",
(),
IndexTemplate {
navbar: NavBar {
index: true,
..NavBar::default()
},
fullname: config
.fc
.fullname
.to_owned()
.unwrap_or("Fullname".to_owned()),
},
Infos {
page_title: config.fc.fullname,
page_desc: Some("Page principale".into()),

View file

@ -1,7 +1,7 @@
use actix_web::{get, Responder};
#[get("/memorial")]
pub async fn page() -> impl Responder {
async fn page() -> impl Responder {
// Memorial? J'espere ne jamais faire cette page lol
actix_web::web::Redirect::to("/")
}

View file

@ -1,13 +1,13 @@
pub mod agreements;
pub mod api_v1;
pub mod blog;
pub mod contact;
pub mod contrib;
pub mod cours;
pub mod cv;
pub mod gaming;
pub mod index;
pub mod memorial;
pub mod networks;
pub mod not_found;
pub mod portfolio;
pub mod setup;

View file

@ -1,26 +0,0 @@
use actix_web::{get, web, HttpRequest, HttpResponse, Responder};
use cached::proc_macro::once;
use crate::{config::Config, misc::utils::get_url, template::Infos};
#[get("/networks")]
pub async fn page(req: HttpRequest, config: web::Data<Config>) -> impl Responder {
HttpResponse::Ok().body(build_page(
config.get_ref().to_owned(),
get_url(req.connection_info()),
))
}
#[once(time = 60)]
pub fn build_page(config: Config, url: String) -> String {
config.tmpl.render(
"networks.html",
(),
Infos {
page_title: Some("Mes réseaux".into()),
page_desc: Some(format!("Réseaux d'{}", config.fc.name.unwrap_or_default())),
page_kw: None,
url,
},
)
}

View file

@ -1,13 +1,39 @@
use actix_web::{web, HttpResponse, Responder};
use actix_web::{web, HttpRequest, HttpResponse, Responder};
use cached::proc_macro::once;
use ramhorns::Content;
use crate::{config::Config, template::Infos};
use crate::{
config::Config,
misc::utils::get_url,
template::{Infos, NavBar},
};
pub async fn page(config: web::Data<Config>) -> impl Responder {
HttpResponse::NotFound().body(build_page(config.get_ref().to_owned()))
pub async fn page(req: HttpRequest, config: web::Data<Config>) -> impl Responder {
HttpResponse::NotFound().body(build_page(
config.get_ref().to_owned(),
get_url(req.connection_info()),
))
}
#[derive(Content, Debug)]
struct NotFoundTemplate {
navbar: NavBar,
www: String,
onion: Option<String>,
}
#[once(time = 60)]
pub fn build_page(config: Config) -> String {
config.tmpl.render("404.html", (), Infos::default())
fn build_page(config: Config, url: String) -> String {
config.tmpl.render(
"404.html",
NotFoundTemplate {
navbar: NavBar::default(),
www: url,
onion: config.fc.onion,
},
Infos {
page_desc: Some("Une page perdu du web".into()),
..Infos::default()
},
)
}

View file

@ -9,11 +9,11 @@ use crate::{
markdown::{read_file, File},
utils::get_url,
},
template::Infos,
template::{Infos, NavBar},
};
#[get("/portfolio")]
pub async fn page(req: HttpRequest, config: web::Data<Config>) -> impl Responder {
async fn page(req: HttpRequest, config: web::Data<Config>) -> impl Responder {
HttpResponse::Ok().body(build_page(
config.get_ref().to_owned(),
get_url(req.connection_info()),
@ -22,62 +22,38 @@ pub async fn page(req: HttpRequest, config: web::Data<Config>) -> impl Responder
#[derive(Content, Debug)]
struct PortfolioTemplate<'a> {
bots_app: Option<Vec<File>>,
bots_loc: Option<String>,
persos_app: Option<Vec<File>>,
persos_loc: Option<String>,
univ_content: Option<String>,
univ_loc: Option<String>,
navbar: NavBar,
location_apps: Option<&'a str>,
apps: Option<Vec<File>>,
err_msg: &'a str,
}
#[once(time = 60)]
pub fn build_page(config: Config, url: String) -> String {
fn build_page(config: Config, url: String) -> String {
let projects_dir = "data/projects";
let ext = ".md";
// Get bots apps
let bots_apps_loc = format!("{projects_dir}/bots");
let bots_apps = glob(&format!("{bots_apps_loc}/*{ext}"))
// Get apps
let apps = glob(&format!("{projects_dir}/*{ext}"))
.unwrap()
.map(|e| read_file(&e.unwrap().to_string_lossy()).unwrap())
.collect::<Vec<File>>();
// Get perso apps
let perso_apps_loc = format!("{projects_dir}/perso");
let perso_apps = glob(&format!("{perso_apps_loc}/*{ext}"))
.unwrap()
.map(|e| read_file(&e.unwrap().to_string_lossy()).unwrap())
.collect::<Vec<File>>();
let univ_loc = format!("{projects_dir}/univ{ext}");
let (bots_app, bots_loc) = if bots_apps.is_empty() {
(None, Some(bots_apps_loc))
let bots_app = if apps.is_empty() {
(None, Some(projects_dir))
} else {
(Some(bots_apps), None)
};
let (persos_app, persos_loc) = if perso_apps.is_empty() {
(None, Some(perso_apps_loc))
} else {
(Some(perso_apps), None)
};
let (univ_content, univ_loc) = match read_file(&univ_loc) {
Some(data) => (Some(data.content), None),
_ => (None, Some(univ_loc)),
(Some(apps), None)
};
config.tmpl.render(
"portfolio.html",
PortfolioTemplate {
bots_app,
bots_loc,
persos_app,
persos_loc,
univ_content,
univ_loc,
navbar: NavBar {
portfolio: true,
..NavBar::default()
},
apps: bots_app.0,
location_apps: bots_app.1,
err_msg: "is empty",
},
Infos {

View file

@ -1,7 +1,7 @@
use actix_web::{get, Responder};
#[get("/setup")]
pub async fn page() -> impl Responder {
async fn page() -> impl Responder {
// Explication de l'histoire de par exemple wiki/cat et le follow up
// avec les futures video youtube probablement un shortcut
// vers un billet de blog

View file

@ -4,7 +4,7 @@ use cached::proc_macro::once;
use crate::{config::Config, misc::utils::get_url, template::Infos};
#[get("/web3")]
pub async fn page(req: HttpRequest, config: web::Data<Config>) -> impl Responder {
async fn page(req: HttpRequest, config: web::Data<Config>) -> impl Responder {
HttpResponse::Ok().body(build_page(
config.get_ref().to_owned(),
get_url(req.connection_info()),
@ -12,7 +12,7 @@ pub async fn page(req: HttpRequest, config: web::Data<Config>) -> impl Responder
}
#[once(time = 60)]
pub fn build_page(config: Config, url: String) -> String {
fn build_page(config: Config, url: String) -> String {
config.tmpl.render(
"web3.html",
(),

View file

@ -22,6 +22,16 @@ pub struct Infos {
pub url: String,
}
#[derive(Content, Debug, Default)]
pub struct NavBar {
pub index: bool,
pub blog: bool,
pub portfolio: bool,
pub contact: bool,
pub contrib: bool,
pub cours: bool,
}
/// Final structure given to template
#[derive(Content, Debug)]
struct Data<T> {

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View file

@ -1,127 +1,54 @@
@media (prefers-color-scheme: light) {
:root {
--selection: #36837db3;
--bg: #ffffff;
--line: #aebed0;
--date: #d2e0f0;
--point: #8c9daf;
--bg-hover: #cedce2;
--point-hover: #ff00ff;
--font-color: #18181b;
--title-color: #a14cb3;
--rss-inverse: 0%;
}
}
@media (prefers-color-scheme: dark) {
:root {
--selection: #4bad9480;
--bg: #171e26;
--line: #374351;
--date: #242e38;
--point: #515f70;
--bg-hover: #1f2730;
--point-hover: #ff00ff;
--font-color: #a1a1aa;
--title-color: #a25add;
--rss-inverse: 80%;
}
}
:root {
--font-size: 20px;
}
::selection {
color: rgb(255, 255, 255);
background: var(--selection);
}
html {
background-color: var(--bg);
font-family: "Segoe UI", Arial, sans-serif, "Segoe UI Emoji",
"Segoe UI Symbol";
}
/* Scrollbar - Firefox */
* {
scrollbar-color: var(--font-color) var(--bg);
}
/* Scrollbar - Chrome */
*::-webkit-scrollbar {
width: 7px;
height: 9px;
background: var(--bg);
}
*::-webkit-scrollbar-thumb {
background-color: var(--font-color);
border-radius: 10px;
}
/* Title of page */
/* Title */
h1 {
color: var(--font-color);
text-transform: uppercase;
letter-spacing: 0.3cap;
margin-bottom: 0;
}
h2,
p {
margin: 0px;
}
h1,
footer {
text-align: center;
font-size: calc(var(--font-size) * 2);
}
footer > * {
color: var(--font-color);
font-weight: bold;
text-decoration: none;
font-size: calc(var(--font-size) / 1.5);
text-transform: uppercase;
opacity: 0.7;
letter-spacing: 0.15rem;
}
footer > *::before {
content: "> ";
}
a:hover {
color: var(--title-color);
}
.timeline {
box-sizing: border-box;
color: var(--font-color);
padding: 30px 20px;
display: flex;
width: 100%;
justify-content: center;
}
/* Barre */
.timeline > ul {
list-style-type: none;
border-left: 2px solid var(--line);
padding: 0px 5px;
/* RSS link */
#rss::before {
content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='20' width='20' viewBox='0 0 24 24' %3E%3Cpath d='M6.18 15.64a2.18 2.18 0 0 1 2.18 2.18C8.36 19 7.38 20 6.18 20 5 20 4 19 4 17.82a2.18 2.18 0 0 1 2.18-2.18M4 4.44A15.56 15.56 0 0 1 19.56 20h-2.83A12.73 12.73 0 0 0 4 7.27V4.44m0 5.66a9.9 9.9 0 0 1 9.9 9.9h-2.83A7.07 7.07 0 0 0 4 12.93V10.1Z' %3E%3C/path%3E%3C/svg%3E");
padding-right: 2px;
vertical-align: middle;
filter: invert(var(--rss-inverse));
}
/* Card */
.timeline > ul > li {
main li {
padding: 20px 20px;
position: relative;
cursor: pointer;
border-radius: 5px;
}
/* Dates */
.timeline > ul > li > span {
display: inline-block;
main li:hover {
background: var(--bg-hover);
}
/* Card dates */
main span {
background-color: var(--date);
border-radius: 5px;
padding: 2px 5px;
@ -129,82 +56,48 @@ a:hover {
font-family: monospace;
}
/* Titles */
.timeline > ul > li > .content > h2 {
/* Card text */
li h2,
li p {
margin: 0px;
padding-top: 5px;
}
/* Card titles */
li h2 {
color: var(--title-color);
font-size: var(--font-size);
padding-top: 5px;
text-decoration: none;
}
/* Descriptions */
.timeline > ul > li > .content > p {
padding-top: 5px;
/* Card descriptions */
li p {
font-size: calc(var(--font-size) - 2px);
max-width: 25em;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
/* Points côté */
.timeline > ul > li::before {
/* Timeline bar */
main ul {
list-style-type: none;
border-left: 2px solid var(--line);
padding: 0px 5px;
}
/* Timeline dot */
main li::before {
position: absolute;
content: "";
width: 10px;
height: 10px;
background-color: var(--point);
border-radius: 50%;
left: -11px;
top: 59px;
transition: 0.2s;
}
/* Card hover */
.timeline > ul > li:hover {
background-color: var(--bg-hover);
}
/* Point côté hover */
.timeline > ul > li:hover::before {
main li:hover::before {
background-color: var(--point-hover);
box-shadow: 0px 0px 10px 2px var(--point-hover);
}
nav {
display: flex;
justify-content: center;
}
#rss {
text-transform: lowercase;
color: var(--font-color);
text-decoration: none;
}
hr {
border: 0;
margin: 0;
height: 1px;
background: var(--line);
margin: 2rem auto;
width: 20%;
}
#rss:hover {
color: var(--title-color);
text-decoration: underline;
}
@media only screen and (max-width: 300px) {
.timeline {
padding: 30px 5px 30px 10px;
}
.timeline > ul > li > .content > h2 > a {
color: var(--title-color);
font-size: calc(var(--font-size) - 2px);
}
}

View file

@ -1,13 +1,9 @@
@media (prefers-color-scheme: light) {
:root {
--selection: rgba(92, 54, 131, 0.7);
--bg: #ffffff;
--font-color: #18181b;
--code-font-color: #333333;
--code-bg-color: #eeeeee;
--quote-border-color: #9852fa;
--quote-bg-color: #d8d6d6;
--link-hover-color: #fd62af;
--separator-color: #cccccc;
--tag-bg-color: #d2e0f0;
}
@ -15,103 +11,68 @@
@media (prefers-color-scheme: dark) {
:root {
--selection: rgba(124, 75, 173, 0.5);
--bg: #171e26;
--font-color: #bcbcc5;
--code-font-color: #eeeeee;
--code-bg-color: #333333;
--quote-border-color: #bd93f9;
--quote-bg-color: #273341;
--link-hover-color: #ff80bf;
--separator-color: #414558;