Metadata and contacts #38
10 changed files with 200 additions and 252 deletions
|
@ -6,7 +6,7 @@ use serde::{Deserialize, Deserializer};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
|
||||||
#[derive(Default, Deserialize, Content, Debug)]
|
#[derive(Default, Deserialize, Content, Debug)]
|
||||||
pub struct FileMetadata {
|
pub struct FileMetadataBlog {
|
||||||
pub title: Option<String>,
|
pub title: Option<String>,
|
||||||
pub link: Option<String>,
|
pub link: Option<String>,
|
||||||
pub date: Option<Date>,
|
pub date: Option<Date>,
|
||||||
|
@ -17,6 +17,37 @@ pub struct FileMetadata {
|
||||||
pub language: Option<String>,
|
pub language: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Deserialize, Content, Debug)]
|
||||||
|
pub struct FileMetadataContact {
|
||||||
|
pub title: String,
|
||||||
|
pub custom: Option<bool>,
|
||||||
|
pub user: Option<String>,
|
||||||
|
pub link: Option<String>,
|
||||||
|
pub newtab: Option<bool>,
|
||||||
|
pub description: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Deserialize, Content, Debug)]
|
||||||
|
pub struct FileMetadataPortfolio {
|
||||||
|
pub title: Option<String>,
|
||||||
|
pub link: Option<String>,
|
||||||
|
pub description: Option<String>,
|
||||||
|
pub language: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum TypeFileMetadata {
|
||||||
|
Blog,
|
||||||
|
Contact,
|
||||||
|
Portfolio,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Deserialize, Content, Debug)]
|
||||||
|
pub struct FileMetadata {
|
||||||
|
pub blog: Option<FileMetadataBlog>,
|
||||||
|
pub contact: Option<FileMetadataContact>,
|
||||||
|
pub portfolio: Option<FileMetadataPortfolio>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Content, Debug, Clone)]
|
#[derive(Content, Debug, Clone)]
|
||||||
pub struct Tag {
|
pub struct Tag {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
@ -87,14 +118,14 @@ pub fn get_options() -> ComrakOptions {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Transform markdown string to File structure
|
/// Transform markdown string to File structure
|
||||||
fn read(raw_text: &str) -> File {
|
fn read(raw_text: &str, metadata_type: TypeFileMetadata) -> File {
|
||||||
let arena = Arena::new();
|
let arena = Arena::new();
|
||||||
|
|
||||||
let options = get_options();
|
let options = get_options();
|
||||||
let root = parse_document(&arena, raw_text, &options);
|
let root = parse_document(&arena, raw_text, &options);
|
||||||
|
|
||||||
// Find metadata
|
// Find metadata
|
||||||
let metadata = get_metadata(root);
|
let metadata = get_metadata(root, metadata_type);
|
||||||
|
|
||||||
let mermaid_name = "mermaid";
|
let mermaid_name = "mermaid";
|
||||||
hljs_replace(root, mermaid_name);
|
hljs_replace(root, mermaid_name);
|
||||||
|
@ -117,26 +148,54 @@ fn read(raw_text: &str) -> File {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read markdown file
|
/// Read markdown file
|
||||||
pub fn read_file(filename: &str) -> Option<File> {
|
pub fn read_file(filename: &str, expected_file: TypeFileMetadata) -> Option<File> {
|
||||||
match fs::read_to_string(filename) {
|
match fs::read_to_string(filename) {
|
||||||
Ok(text) => Some(read(&text)),
|
Ok(text) => Some(read(&text, expected_file)),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Deserialize metadata based on a type
|
||||||
|
fn deserialize_metadata<T: Default + serde::de::DeserializeOwned>(text: &str) -> T {
|
||||||
|
serde_yaml::from_str(text.trim_matches(&['-', '\n'] as &[_])).unwrap_or_default()
|
||||||
|
}
|
||||||
|
|
||||||
/// Fetch metadata from AST
|
/// Fetch metadata from AST
|
||||||
pub fn get_metadata<'a>(root: &'a AstNode<'a>) -> FileMetadata {
|
pub fn get_metadata<'a>(root: &'a AstNode<'a>, mtype: TypeFileMetadata) -> FileMetadata {
|
||||||
match root
|
match root
|
||||||
.children()
|
.children()
|
||||||
.find_map(|node| match &node.data.borrow().value {
|
.find_map(|node| match &node.data.borrow().value {
|
||||||
NodeValue::FrontMatter(text) => {
|
NodeValue::FrontMatter(text) => Some(match mtype {
|
||||||
// '-' correspond to `front_matter_delimiter`
|
TypeFileMetadata::Blog => FileMetadata {
|
||||||
serde_yaml::from_str(text.trim_matches(&['-', '\n'] as &[_])).unwrap_or_default()
|
blog: Some(deserialize_metadata(text)),
|
||||||
}
|
..FileMetadata::default()
|
||||||
|
},
|
||||||
|
TypeFileMetadata::Contact => FileMetadata {
|
||||||
|
contact: Some(deserialize_metadata(text)),
|
||||||
|
..FileMetadata::default()
|
||||||
|
},
|
||||||
|
TypeFileMetadata::Portfolio => FileMetadata {
|
||||||
|
portfolio: Some(deserialize_metadata(text)),
|
||||||
|
..FileMetadata::default()
|
||||||
|
},
|
||||||
|
}),
|
||||||
_ => None,
|
_ => None,
|
||||||
}) {
|
}) {
|
||||||
Some(data) => data,
|
Some(data) => data,
|
||||||
None => FileMetadata::default(),
|
None => match mtype {
|
||||||
|
TypeFileMetadata::Blog => FileMetadata {
|
||||||
|
blog: Some(FileMetadataBlog::default()),
|
||||||
|
..FileMetadata::default()
|
||||||
|
},
|
||||||
|
TypeFileMetadata::Contact => FileMetadata {
|
||||||
|
contact: Some(FileMetadataContact::default()),
|
||||||
|
..FileMetadata::default()
|
||||||
|
},
|
||||||
|
TypeFileMetadata::Portfolio => FileMetadata {
|
||||||
|
portfolio: Some(FileMetadataPortfolio::default()),
|
||||||
|
..FileMetadata::default()
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,9 @@ use crate::{
|
||||||
config::Config,
|
config::Config,
|
||||||
misc::{
|
misc::{
|
||||||
date::Date,
|
date::Date,
|
||||||
markdown::{get_metadata, get_options, read_file, File, FileMetadata},
|
markdown::{
|
||||||
|
get_metadata, get_options, read_file, File, FileMetadataBlog, TypeFileMetadata,
|
||||||
|
},
|
||||||
utils::get_url,
|
utils::get_url,
|
||||||
},
|
},
|
||||||
template::{Infos, NavBar},
|
template::{Infos, NavBar},
|
||||||
|
@ -87,7 +89,10 @@ impl Post {
|
||||||
let blog_dir = "data/blog";
|
let blog_dir = "data/blog";
|
||||||
let ext = ".md";
|
let ext = ".md";
|
||||||
|
|
||||||
if let Some(file) = read_file(&format!("{blog_dir}/{}{ext}", self.url)) {
|
if let Some(file) = read_file(
|
||||||
|
&format!("{blog_dir}/{}{ext}", self.url),
|
||||||
|
TypeFileMetadata::Blog,
|
||||||
|
) {
|
||||||
self.content = Some(file.content);
|
self.content = Some(file.content);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -126,7 +131,7 @@ fn get_posts(location: &str) -> Vec<Post> {
|
||||||
|
|
||||||
let options = get_options();
|
let options = get_options();
|
||||||
let root = parse_document(&arena, &text, &options);
|
let root = parse_document(&arena, &text, &options);
|
||||||
let mut metadata = get_metadata(root);
|
let mut metadata = get_metadata(root, TypeFileMetadata::Blog).blog.unwrap();
|
||||||
|
|
||||||
// Always have a title
|
// Always have a title
|
||||||
metadata.title = match metadata.title {
|
metadata.title = match metadata.title {
|
||||||
|
@ -136,9 +141,9 @@ fn get_posts(location: &str) -> Vec<Post> {
|
||||||
|
|
||||||
metadata
|
metadata
|
||||||
}
|
}
|
||||||
Err(_) => FileMetadata {
|
Err(_) => FileMetadataBlog {
|
||||||
title: Some(file_without_ext.into()),
|
title: Some(file_without_ext.into()),
|
||||||
..FileMetadata::default()
|
..FileMetadataBlog::default()
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -222,20 +227,23 @@ fn get_post(
|
||||||
let blog_dir = "data/blog";
|
let blog_dir = "data/blog";
|
||||||
let ext = ".md";
|
let ext = ".md";
|
||||||
|
|
||||||
*post = read_file(&format!("{blog_dir}/{filename}{ext}"));
|
*post = read_file(
|
||||||
|
&format!("{blog_dir}/{filename}{ext}"),
|
||||||
|
TypeFileMetadata::Blog,
|
||||||
|
);
|
||||||
|
|
||||||
let default = (&filename, Vec::new(), String::new());
|
let default = (&filename, Vec::new(), String::new());
|
||||||
let (title, tags, toc) = match post {
|
let (title, tags, toc) = match post {
|
||||||
Some(data) => (
|
Some(data) => (
|
||||||
match &data.metadata.info.title {
|
match &data.metadata.info.blog.as_ref().unwrap().title {
|
||||||
Some(text) => text,
|
Some(text) => text,
|
||||||
None => default.0,
|
None => default.0,
|
||||||
},
|
},
|
||||||
match &data.metadata.info.tags {
|
match &data.metadata.info.blog.as_ref().unwrap().tags {
|
||||||
Some(tags) => tags.clone(),
|
Some(tags) => tags.clone(),
|
||||||
None => default.1,
|
None => default.1,
|
||||||
},
|
},
|
||||||
match &data.metadata.info.toc {
|
match &data.metadata.info.blog.as_ref().unwrap().toc {
|
||||||
// TODO: Generate TOC
|
// TODO: Generate TOC
|
||||||
Some(true) => String::new(),
|
Some(true) => String::new(),
|
||||||
_ => default.2,
|
_ => default.2,
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
use actix_web::{get, routes, web, HttpRequest, HttpResponse, Responder};
|
use actix_web::{get, routes, web, HttpRequest, HttpResponse, Responder};
|
||||||
use cached::proc_macro::once;
|
use cached::proc_macro::once;
|
||||||
|
use glob::glob;
|
||||||
use ramhorns::Content;
|
use ramhorns::Content;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::Config,
|
config::Config,
|
||||||
misc::utils::get_url,
|
misc::{
|
||||||
|
markdown::{read_file, File, TypeFileMetadata},
|
||||||
|
utils::get_url,
|
||||||
|
},
|
||||||
template::{Infos, NavBar},
|
template::{Infos, NavBar},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -63,17 +67,65 @@ async fn service_redirection(req: HttpRequest) -> impl Responder {
|
||||||
#[derive(Content, Debug)]
|
#[derive(Content, Debug)]
|
||||||
struct NetworksTemplate {
|
struct NetworksTemplate {
|
||||||
navbar: NavBar,
|
navbar: NavBar,
|
||||||
|
|
||||||
|
socials_exists: bool,
|
||||||
|
socials: Vec<File>,
|
||||||
|
|
||||||
|
forges_exists: bool,
|
||||||
|
forges: Vec<File>,
|
||||||
|
|
||||||
|
others_exists: bool,
|
||||||
|
others: Vec<File>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove_paragraphs(list: &mut [File]) {
|
||||||
|
list.iter_mut()
|
||||||
|
.for_each(|file| file.content = file.content.replace("<p>", "").replace("</p>", ""));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[once(time = 60)]
|
#[once(time = 60)]
|
||||||
fn build_page(config: Config, url: String) -> String {
|
fn build_page(config: Config, url: String) -> String {
|
||||||
|
let contacts_dir = "data/contacts";
|
||||||
|
let ext = ".md";
|
||||||
|
|
||||||
|
let socials_dir = "socials";
|
||||||
|
let mut socials = glob(&format!("{contacts_dir}/{socials_dir}/*{ext}"))
|
||||||
|
.unwrap()
|
||||||
|
.map(|e| read_file(&e.unwrap().to_string_lossy(), TypeFileMetadata::Contact).unwrap())
|
||||||
|
.collect::<Vec<File>>();
|
||||||
|
|
||||||
|
let forges_dir = "forges";
|
||||||
|
let mut forges = glob(&format!("{contacts_dir}/{forges_dir}/*{ext}"))
|
||||||
|
.unwrap()
|
||||||
|
.map(|e| read_file(&e.unwrap().to_string_lossy(), TypeFileMetadata::Contact).unwrap())
|
||||||
|
.collect::<Vec<File>>();
|
||||||
|
|
||||||
|
let others_dir = "others";
|
||||||
|
let mut others = glob(&format!("{contacts_dir}/{others_dir}/*{ext}"))
|
||||||
|
.unwrap()
|
||||||
|
.map(|e| read_file(&e.unwrap().to_string_lossy(), TypeFileMetadata::Contact).unwrap())
|
||||||
|
.collect::<Vec<File>>();
|
||||||
|
|
||||||
|
// Remove paragraphs in custom statements
|
||||||
|
[&mut socials, &mut forges, &mut others]
|
||||||
|
.iter_mut()
|
||||||
|
.for_each(|it| remove_paragraphs(it));
|
||||||
|
|
||||||
config.tmpl.render(
|
config.tmpl.render(
|
||||||
"contact.html",
|
"contact/index.html",
|
||||||
NetworksTemplate {
|
NetworksTemplate {
|
||||||
navbar: NavBar {
|
navbar: NavBar {
|
||||||
contact: true,
|
contact: true,
|
||||||
..NavBar::default()
|
..NavBar::default()
|
||||||
},
|
},
|
||||||
|
socials_exists: !socials.is_empty(),
|
||||||
|
socials,
|
||||||
|
|
||||||
|
forges_exists: !forges.is_empty(),
|
||||||
|
forges,
|
||||||
|
|
||||||
|
others_exists: !others.is_empty(),
|
||||||
|
others,
|
||||||
},
|
},
|
||||||
Infos {
|
Infos {
|
||||||
page_title: Some("Contacts".into()),
|
page_title: Some("Contacts".into()),
|
||||||
|
|
|
@ -6,7 +6,7 @@ use ramhorns::Content;
|
||||||
use crate::{
|
use crate::{
|
||||||
config::Config,
|
config::Config,
|
||||||
misc::{
|
misc::{
|
||||||
markdown::{read_file, File},
|
markdown::{read_file, File, TypeFileMetadata},
|
||||||
utils::get_url,
|
utils::get_url,
|
||||||
},
|
},
|
||||||
template::{Infos, NavBar},
|
template::{Infos, NavBar},
|
||||||
|
@ -38,7 +38,7 @@ fn build_page(config: Config, url: String) -> String {
|
||||||
// Get apps
|
// Get apps
|
||||||
let apps = glob(&format!("{projects_dir}/*{ext}"))
|
let apps = glob(&format!("{projects_dir}/*{ext}"))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.map(|e| read_file(&e.unwrap().to_string_lossy()).unwrap())
|
.map(|e| read_file(&e.unwrap().to_string_lossy(), TypeFileMetadata::Portfolio).unwrap())
|
||||||
.collect::<Vec<File>>();
|
.collect::<Vec<File>>();
|
||||||
|
|
||||||
let appdata = if apps.is_empty() {
|
let appdata = if apps.is_empty() {
|
||||||
|
@ -50,7 +50,7 @@ fn build_page(config: Config, url: String) -> String {
|
||||||
// Get archived apps
|
// Get archived apps
|
||||||
let archived_apps = glob(&format!("{projects_dir}/archive/*{ext}"))
|
let archived_apps = glob(&format!("{projects_dir}/archive/*{ext}"))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.map(|e| read_file(&e.unwrap().to_string_lossy()).unwrap())
|
.map(|e| read_file(&e.unwrap().to_string_lossy(), TypeFileMetadata::Portfolio).unwrap())
|
||||||
.collect::<Vec<File>>();
|
.collect::<Vec<File>>();
|
||||||
|
|
||||||
let archived_appdata = if archived_apps.is_empty() {
|
let archived_appdata = if archived_apps.is_empty() {
|
||||||
|
|
|
@ -15,6 +15,10 @@ main ul {
|
||||||
column-gap: 5em;
|
column-gap: 5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
main li {
|
||||||
|
break-inside: avoid-column;
|
||||||
|
}
|
||||||
|
|
||||||
main li > p {
|
main li > p {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 3%;
|
padding: 3%;
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<header>
|
<header>
|
||||||
{{>navbar.html}} {{#info}}
|
{{>navbar.html}} {{#info}} {{#blog}}
|
||||||
<h1>{{title}}</h1>
|
<h1>{{title}}</h1>
|
||||||
{{#date}} {{>blog/date.html}} {{/date}}
|
{{#date}} {{>blog/date.html}} {{/date}}
|
||||||
<ul>
|
<ul>
|
||||||
|
@ -23,7 +23,7 @@
|
||||||
<li>{{name}}</li>
|
<li>{{name}}</li>
|
||||||
{{/tags}}
|
{{/tags}}
|
||||||
</ul>
|
</ul>
|
||||||
{{/info}} {{/metadata}} {{/post}}
|
{{/blog}} {{/info}} {{/metadata}} {{/post}}
|
||||||
</header>
|
</header>
|
||||||
<main>
|
<main>
|
||||||
{{^post}}
|
{{^post}}
|
||||||
|
|
|
@ -1,223 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="fr">
|
|
||||||
<head dir="ltr">
|
|
||||||
{{>head.html}}
|
|
||||||
<link rel="stylesheet" href="/css/contact.css" />
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<header>{{>navbar.html}}</header>
|
|
||||||
<main>
|
|
||||||
<h1>Contact</h1>
|
|
||||||
<p>Je suis présent relativement partout sur internet 😸</p>
|
|
||||||
<h2>Réseaux sociaux</h2>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<p>
|
|
||||||
Twitter :
|
|
||||||
<a
|
|
||||||
href="/contact/twitter"
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer me"
|
|
||||||
title="Compte Twitter, pour le shitposting"
|
|
||||||
>@Mylloon</a
|
|
||||||
>
|
|
||||||
</p>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<p>
|
|
||||||
Mastodon :
|
|
||||||
<a
|
|
||||||
href="/contact/mastodon"
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer me"
|
|
||||||
title="Compte Mastodon, alternative à Twitter, principalement pour l'IT"
|
|
||||||
>Mylloon@piaille.fr</a
|
|
||||||
>
|
|
||||||
</p>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<p>
|
|
||||||
Bluesky :
|
|
||||||
<a
|
|
||||||
href="/contact/bluesky"
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer me"
|
|
||||||
title="Compte Bluesky, alternative à Twitter, quand Elon aura rendu Twitter payant je serais principalement sur Bluesky"
|
|
||||||
>mylloon.fr</a
|
|
||||||
>
|
|
||||||
</p>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<p>
|
|
||||||
Discord :
|
|
||||||
<a
|
|
||||||
href="/contact/discord/user"
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer me"
|
|
||||||
title="Compte Discord perso"
|
|
||||||
>mylloon</a
|
|
||||||
>
|
|
||||||
et
|
|
||||||
<a
|
|
||||||
href="/contact/discord/guild"
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
title="Serveur Discord accessible à tous, venez !"
|
|
||||||
>mon serveur</a
|
|
||||||
>
|
|
||||||
</p>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<p>
|
|
||||||
Reddit :
|
|
||||||
<a
|
|
||||||
href="/contact/reddit"
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer me"
|
|
||||||
title="Compte Reddit, sert à rien"
|
|
||||||
>mylloon</a
|
|
||||||
>
|
|
||||||
</p>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<p>
|
|
||||||
Instagram :
|
|
||||||
<a
|
|
||||||
href="/contact/instagram"
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer me"
|
|
||||||
title="Compte Instagram, sert à rien"
|
|
||||||
>mylloon</a
|
|
||||||
>
|
|
||||||
</p>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<p>
|
|
||||||
Kitsu :
|
|
||||||
<a
|
|
||||||
href="/contact/kitsu"
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer me"
|
|
||||||
title="Compte Kitsu, pour suivre les anime/manga/webtoon que je lis/regarde"
|
|
||||||
>Mylloon</a
|
|
||||||
>
|
|
||||||
</p>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<p>
|
|
||||||
Steam :
|
|
||||||
<a
|
|
||||||
href="/contact/steam"
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer me"
|
|
||||||
title="Compte Steam pour les jeux-vidéos"
|
|
||||||
>Mylloon</a
|
|
||||||
>
|
|
||||||
</p>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<p>
|
|
||||||
Youtube :
|
|
||||||
<a
|
|
||||||
href="/contact/youtube"
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer me"
|
|
||||||
title="Compte YouTube, parfois je poste des vidéos JV ou IT"
|
|
||||||
>Mylloon</a
|
|
||||||
>
|
|
||||||
</p>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<p>
|
|
||||||
Twitch :
|
|
||||||
<a
|
|
||||||
href="/contact/twitch"
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer me"
|
|
||||||
title="Compte Twitch, parfois je stream soit des JV soit du dev"
|
|
||||||
>mylloon</a
|
|
||||||
>
|
|
||||||
</p>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<h2>Forges</h2>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<p>
|
|
||||||
Github :
|
|
||||||
<a
|
|
||||||
href="/contact/github"
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer me"
|
|
||||||
title="Compte GitHub, principalement pour les contributions"
|
|
||||||
>Mylloon</a
|
|
||||||
>
|
|
||||||
</p>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<p>
|
|
||||||
Gitlab :
|
|
||||||
<a
|
|
||||||
href="/contact/gitlab"
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer me"
|
|
||||||
title="Compte Gitlab, sert à rien"
|
|
||||||
>Mylloon</a
|
|
||||||
>
|
|
||||||
</p>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<p>
|
|
||||||
Codeberg :
|
|
||||||
<a
|
|
||||||
href="/contact/codeberg"
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer me"
|
|
||||||
title="Compte Codeberg, pas utilisé mais j'adore Codeberg !"
|
|
||||||
>Mylloon</a
|
|
||||||
>
|
|
||||||
</p>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<p>
|
|
||||||
Forgejo (mon instance) :
|
|
||||||
<a
|
|
||||||
href="/contact/forgejo"
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer me"
|
|
||||||
title="Compte Forgejo, là où il y a tout mes projets"
|
|
||||||
>Anri</a
|
|
||||||
>
|
|
||||||
</p>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<h2>Autre</h2>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<p>
|
|
||||||
Mail :
|
|
||||||
<a
|
|
||||||
href="mailto:kennel.anri%20at%20tutanota.com"
|
|
||||||
title="kennel.anri at tutanota.com"
|
|
||||||
>kennel.anri at tutanota.com</a
|
|
||||||
>
|
|
||||||
</p>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<p>
|
|
||||||
Keyoxide :
|
|
||||||
<a
|
|
||||||
href="/contact/keyoxide"
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer me"
|
|
||||||
title="Page Keyoxide, vérifie l'appartenance de la majorité des comptes mentionné ici via GPG"
|
|
||||||
>Mylloon</a
|
|
||||||
>
|
|
||||||
</p>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</main>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
17
templates/contact/element.html
Normal file
17
templates/contact/element.html
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
{{#metadata}} {{#info}} {{#contact}}
|
||||||
|
<li>
|
||||||
|
<p>
|
||||||
|
{{title}} : {{^custom}} {{#newtab}}
|
||||||
|
<a
|
||||||
|
href="{{link}} "
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer me"
|
||||||
|
title="{{description}} "
|
||||||
|
>{{user}}</a
|
||||||
|
>
|
||||||
|
{{/newtab}} {{^newtab}}
|
||||||
|
<a href="{{link}} " title="{{description}} ">{{user}}</a>
|
||||||
|
{{/newtab}} {{/custom}} {{#custom}} {{&content}} {{/custom}}
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
{{/contact}} {{/info}} {{/metadata}}
|
31
templates/contact/index.html
Normal file
31
templates/contact/index.html
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="fr">
|
||||||
|
<head dir="ltr">
|
||||||
|
{{>head.html}}
|
||||||
|
<link rel="stylesheet" href="/css/contact.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>{{>navbar.html}}</header>
|
||||||
|
<main>
|
||||||
|
<h1>Contact</h1>
|
||||||
|
<p>Je suis présent relativement partout sur internet 😸</p>
|
||||||
|
|
||||||
|
{{#data}} {{#socials_exists}}
|
||||||
|
<h2>Réseaux sociaux</h2>
|
||||||
|
<ul>
|
||||||
|
{{#socials}} {{>contact/element.html}} {{/socials}}
|
||||||
|
</ul>
|
||||||
|
{{/socials_exists}} {{#forges_exists}}
|
||||||
|
<h2>Forges</h2>
|
||||||
|
<ul>
|
||||||
|
{{#forges}} {{>contact/element.html}} {{/forges}}
|
||||||
|
</ul>
|
||||||
|
{{/forges_exists}} {{#others_exists}}
|
||||||
|
<h2>Autre</h2>
|
||||||
|
<ul>
|
||||||
|
{{#others}} {{>contact/element.html}} {{/others}}
|
||||||
|
</ul>
|
||||||
|
{{/others_exists}} {{/data}}
|
||||||
|
</main>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -1,7 +1,7 @@
|
||||||
{{#metadata}} {{#info}} {{#link}}
|
{{#metadata}} {{#info}} {{#portfolio}} {{#link}}
|
||||||
<li role="button" onclick="window.open('{{link}}', '_blank', 'noreferrer');">
|
<li role="button" onclick="window.open('{{link}}', '_blank', 'noreferrer');">
|
||||||
{{>portfolio/project.html}}
|
{{>portfolio/project.html}}
|
||||||
</li>
|
</li>
|
||||||
{{/link}} {{^link}}
|
{{/link}} {{^link}}
|
||||||
<li>{{>portfolio/project.html}}</li>
|
<li>{{>portfolio/project.html}}</li>
|
||||||
{{/link}} {{/info}} {{/metadata}}
|
{{/link}} {{/portfolio}} {{/info}} {{/metadata}}
|
||||||
|
|
Loading…
Reference in a new issue