Merge branch 'chore/portfolio'
Some checks failed
ci/woodpecker/push/publish Pipeline failed

This commit is contained in:
Mylloon 2023-04-11 02:13:54 +02:00
commit 7f01fe98db
Signed by: Anri
GPG key ID: A82D63DFF8D1317F
13 changed files with 258 additions and 314 deletions

View file

@ -0,0 +1,6 @@
---
title: Botanique
link: https://git.mylloon.fr/ConfrerieDuKassoulait/Botanique
---
✨ Bot Discord libre et écrit en Typescript.

View file

@ -0,0 +1,6 @@
---
title: feurBot
link: https://git.mylloon.fr/Anri/feurBot
---
Réponds à certains tweets (exemple : si un tweet fini par _quoi_, le bot répondra _feur_).

View file

@ -0,0 +1,6 @@
---
title: cal8tor
link: https://git.mylloon.fr/Anri/cal8tor
---
Lecteur de l'emploi du temps pour la licence d'informatique de Paris 8, avec possibilité d'exporter le calendrier en ICS.

View file

@ -0,0 +1,6 @@
---
title: confOS
link: https://git.mylloon.fr/Anri/confOS
---
Scripts et fichiers de configuration pour me simplifier la vie quand je réinstalle mes systèmes d'exploitation.

View file

@ -0,0 +1,6 @@
---
title: Constnium
link: https://git.mylloon.fr/Anri/Constnium
---
Calculez votre propre constante sur la base de votre prénom en multipliant de vraies constantes mathématiques entre elles. Une [démo est disponible ici](https://constnium.mylloon.fr/).

View file

@ -0,0 +1,6 @@
---
title: csh
link: https://git.mylloon.fr/Anri/csh
---
Application python pour tricher dans le jeu compétitif Counter-Strike : Global Offensive. Repose sur le principe de cheat externe. C'était marrant à faire.

View file

@ -0,0 +1,6 @@
---
title: prose_dl
link: https://git.mylloon.fr/Anri/prose_dl
---
Permets de télécharger tous les posts d'un utilisateur depuis [prose.sh](https://prose.sh/). J'ai [écrit ici](https://anri.prose.sh/prose_dl) sur son développement.

5
data/projects/univ.md Normal file
View file

@ -0,0 +1,5 @@
---
title: Projet de l'université
---
✨ Parce que j'ai fait plusieurs projets dont je suis fier mais qui ne mérite pas une place entière sur cette page comme mon [premier pendu](https://git.mylloon.fr/Paris8/penduEnC) ou une jolie [interface manager/caisser](https://git.mylloon.fr/Paris8/GesMag), vous pouvez simplement aller voir la liste des projets en vrac qui sont disponibles sur mon [git](https://git.mylloon.fr/Paris8/).

View file

@ -1,7 +1,11 @@
use actix_web::{get, web, HttpResponse, Responder}; use actix_web::{get, web, HttpResponse, Responder};
use glob::glob;
use ramhorns::Content; use ramhorns::Content;
use crate::config::Config; use crate::{
config::Config,
template::{read_md, File},
};
#[get("/portfolio")] #[get("/portfolio")]
pub async fn page(config: web::Data<Config>) -> impl Responder { pub async fn page(config: web::Data<Config>) -> impl Responder {
@ -9,8 +13,36 @@ pub async fn page(config: web::Data<Config>) -> impl Responder {
} }
#[derive(Content)] #[derive(Content)]
struct PortfolioTemplate {} struct PortfolioTemplate {
page_title: String,
bots_app: Vec<File>,
persos_app: Vec<File>,
univ_content: String,
}
pub fn get_page(config: Config) -> std::string::String { pub fn get_page(config: Config) -> std::string::String {
config.tmpl.render("portfolio.html", PortfolioTemplate {}) let projects_dir = "data/projects";
let ext = ".md";
// Get bots apps
let mut bots_apps = Vec::new();
for entry in glob(&format!("{projects_dir}/bots/*{ext}")).unwrap() {
bots_apps.push(read_md(&entry.unwrap().to_string_lossy()));
}
// Get perso apps
let mut perso_apps = Vec::new();
for entry in glob(&format!("{projects_dir}/perso/*{ext}")).unwrap() {
perso_apps.push(read_md(&entry.unwrap().to_string_lossy()));
}
config.tmpl.render(
"portfolio.html",
PortfolioTemplate {
page_title: "Portfolio".to_string(),
bots_app: bots_apps,
persos_app: perso_apps,
univ_content: read_md(&format!("{projects_dir}/univ{ext}")).content,
},
)
} }

View file

@ -54,7 +54,13 @@ pub struct Metadata {
pub syntax_highlight: bool, pub syntax_highlight: bool,
} }
pub fn read_md(filename: &str) -> (Metadata, String) { #[derive(Content)]
pub struct File {
pub metadata: Metadata,
pub content: String,
}
pub fn read_md(filename: &str) -> File {
// Read markdown file // Read markdown file
let mut text = std::fs::read_to_string(filename).unwrap(); let mut text = std::fs::read_to_string(filename).unwrap();
@ -106,12 +112,12 @@ pub fn read_md(filename: &str) -> (Metadata, String) {
_ => false, _ => false,
}); });
( File {
Metadata { metadata: Metadata {
info: metadata, info: metadata,
mermaid: presence_mermaid, mermaid: presence_mermaid,
syntax_highlight: presence_code, syntax_highlight: presence_code,
}, },
html, content: html,
) }
} }

View file

@ -1,60 +1,60 @@
/* Title font */ /* Title font */
@import url("https://fonts.googleapis.com/css2?family=Overpass:wght@200&display=swap"); @import url("https://api.fonts.coollabs.io/css2?family=Overpass:wght@200&display=swap");
/* Normal font */ /* Normal font */
@font-face { @font-face {
font-family: "Luciole"; font-family: "Luciole";
font-style: normal; font-style: normal;
font-weight: normal; font-weight: normal;
src: url(/css/fonts/Luciole-Regular.ttf); src: url(/css/fonts/Luciole-Regular.ttf);
} }
/* Italic font */ /* Italic font */
@font-face { @font-face {
font-family: "Luciole"; font-family: "Luciole";
font-style: italic; font-style: italic;
font-weight: normal; font-weight: normal;
src: url(/css/fonts/Luciole-Regular-Italic.ttf); src: url(/css/fonts/Luciole-Regular-Italic.ttf);
} }
/* Bold fond */ /* Bold fond */
@font-face { @font-face {
font-family: "Luciole"; font-family: "Luciole";
font-style: normal; font-style: normal;
font-weight: bold; font-weight: bold;
src: url(/css/fonts/Luciole-Bold.ttf); src: url(/css/fonts/Luciole-Bold.ttf);
} }
/* Bold italic font */ /* Bold italic font */
@font-face { @font-face {
font-family: "Luciole"; font-family: "Luciole";
font-style: italic; font-style: italic;
font-weight: bold; font-weight: bold;
src: url(/css/fonts/Luciole-Bold-Italic.ttf); src: url(/css/fonts/Luciole-Bold-Italic.ttf);
} }
/* Page bottom */ /* Page bottom */
footer { footer {
position: absolute; position: absolute;
bottom: 0; bottom: 0;
margin: -8px; margin: -8px;
width: 100%; width: 100%;
height: 2.5rem; height: 2.5rem;
} }
/* Regular tags */ /* Regular tags */
html { html {
position: relative; position: relative;
min-height: 100vh; min-height: 100vh;
height: 100%; height: 100%;
scroll-behavior: smooth; scroll-behavior: smooth;
} }
body { body {
position: relative; position: relative;
padding-bottom: 3em; padding-bottom: 3em;
min-height: 90%; min-height: 90%;
background-color: rgb(24, 24, 24); background-color: rgb(24, 24, 24);
} }
p, p,
@ -63,186 +63,186 @@ h2,
h3, h3,
li, li,
a { a {
font-family: "Luciole", sans-serif; font-family: "Luciole", sans-serif;
} }
::selection { ::selection {
color: rgb(255, 255, 255); color: rgb(255, 255, 255);
background: rgba(124, 75, 173, 0.486); background: rgba(124, 75, 173, 0.486);
} }
/* Frames */ /* Frames */
h1.subtitle { h1.subtitle {
text-decoration: none; text-decoration: none;
color: rgb(28, 118, 236); color: rgb(28, 118, 236);
} }
h1#title { h1#title {
text-align: center; text-align: center;
color: rgb(28, 236, 174); color: rgb(28, 236, 174);
} }
h2.subtitle, h2.subtitle,
h2.subtitle a { h2.subtitle a {
color: rgb(28, 118, 236) !important; color: rgb(28, 118, 236) !important;
} }
h3.subsubtitle, h3.subsubtitle,
#content h3.subsubtitle a { #content h3.subsubtitle a {
text-align: left; text-align: left;
color: rgb(149, 87, 201); color: rgb(149, 87, 201);
} }
#content h3.subsubtitle a:hover { #content h3.subsubtitle a:hover {
color: rgb(0, 181, 236); color: rgb(0, 181, 236);
transition: color 0.1s; transition: color 0.1s;
} }
div#content { div#content {
margin-left: auto; margin-left: auto;
margin-right: auto; margin-right: auto;
margin-top: 2%; margin-top: 2%;
padding: 0.9% 0.9% 0.9% 0.9%; padding: 0.9% 0.9% 0.9% 0.9%;
width: 42%; width: 42%;
border-radius: 6px; border-radius: 6px;
border: 1px solid rgb(170, 170, 170); border: 1px solid rgb(170, 170, 170);
text-align: center; text-align: center;
} }
@media only screen and (max-width: 850px) { @media only screen and (max-width: 850px) {
/* Mobile display */ /* Mobile display */
div#content { div#content {
width: 90%; width: 90%;
} }
} }
#content a, #content a,
#content a:visited, #content a:visited,
#content ul { #content ul {
text-decoration: none; text-decoration: none;
color: rgb(201, 201, 201); color: rgb(201, 201, 201);
text-align: center; text-align: center;
} }
#content p { #content p {
text-decoration: none; text-decoration: none;
color: rgb(201, 201, 201); color: rgb(201, 201, 201);
text-align: center; text-align: center;
padding: 0.7em; padding: 0.7em;
} }
#content a:hover { #content a:hover {
color: rgb(0, 181, 236); color: rgb(0, 181, 236);
transition: color 0.1s; transition: color 0.1s;
} }
/* https://stackoverflow.com/a/40244401/15436737 */ /* https://stackoverflow.com/a/40244401/15436737 */
#content a { #content a {
position: relative; position: relative;
text-decoration: none; text-decoration: none;
display: inline-block; display: inline-block;
} }
#content a:after { #content a:after {
display: block; display: block;
content: ""; content: "";
border-bottom: solid 3px; border-bottom: solid 3px;
transform: scaleX(0); transform: scaleX(0);
transition: transform 250ms ease-in-out; transition: transform 250ms ease-in-out;
transform-origin: 100% 50%; transform-origin: 100% 50%;
} }
#content a:hover:after { #content a:hover:after {
transform: scaleX(1); transform: scaleX(1);
transform-origin: 0 50%; transform-origin: 0 50%;
} }
/* ------------------------------------------- */ /* ------------------------------------------- */
div.subcontent { div.subcontent {
margin-left: auto; margin-left: auto;
margin-right: auto; margin-right: auto;
margin-top: 5%; margin-top: 5%;
padding: 1.2% 1.2% 1.2% 1.2%; padding: 1.2% 1.2% 1.2% 1.2%;
width: 78%; width: 78%;
border-radius: 6px; border-radius: 6px;
border: 1px solid rgb(170, 170, 170); border: 1px solid rgb(170, 170, 170);
text-align: center; text-align: center;
} }
#listecontent li { #listecontent li {
margin-bottom: 0.5em; margin-bottom: 0.5em;
} }
/* Index */ /* Index */
.index { .index {
height: 100%; height: 100%;
padding: 0; padding: 0;
margin: 0; margin: 0;
} }
.divIndex { .divIndex {
width: 50%; width: 50%;
height: 50%; height: 50%;
float: left; float: left;
} }
button.buttonIndex { button.buttonIndex {
width: 100%; width: 100%;
height: 100%; height: 100%;
border: none; border: none;
opacity: 0.6; opacity: 0.6;
transition: all 0.1s; transition: all 0.1s;
cursor: pointer; cursor: pointer;
} }
span.buttonIndex { span.buttonIndex {
font-family: "Overpass", sans-serif; font-family: "Overpass", sans-serif;
font-size: 500%; font-size: 500%;
cursor: pointer; cursor: pointer;
display: inline-block; display: inline-block;
position: relative; position: relative;
transition: 0.5s; transition: 0.5s;
} }
.buttonIndex:hover, .buttonIndex:hover,
span.buttonIndex:after { span.buttonIndex:after {
opacity: 1; opacity: 1;
padding-right: 2%; padding-right: 2%;
} }
#buttonIndexTL { #buttonIndexTL {
background-color: rgb(0, 255, 255); background-color: rgb(0, 255, 255);
} }
#buttonIndexTR { #buttonIndexTR {
background-color: rgb(21, 255, 0); background-color: rgb(21, 255, 0);
} }
#buttonIndexBL { #buttonIndexBL {
background-color: rgb(187, 255, 0); background-color: rgb(187, 255, 0);
} }
#buttonIndexBR { #buttonIndexBR {
background-color: rgb(208, 88, 255); background-color: rgb(208, 88, 255);
} }
/* Back links going to the index */ /* Back links going to the index */
footer.backToIndexPage { footer.backToIndexPage {
text-align: center; text-align: center;
} }
footer.backToIndexPage a { footer.backToIndexPage a {
color: rgb(114, 180, 76); color: rgb(114, 180, 76);
text-decoration: none; text-decoration: none;
} }
footer.backToIndexPage a:hover { footer.backToIndexPage a:hover {
color: rgb(152, 187, 132); color: rgb(152, 187, 132);
} }
/* Hide content */ /* Hide content */
.hide { .hide {
display: none; display: none;
} }

37
templates/header.html Normal file
View file

@ -0,0 +1,37 @@
<head dir="rtl">
<title>{{#data}}{{page_title}}{{/data}} - {{app_name}}</title>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="css/style.css" />
<meta name="author" content="Mylloon" />
<meta name="description" content="{{ desc }}" />
<base target="_blank" />
<link
rel="apple-touch-icon"
sizes="180x180"
href="icons/apple-touch-icon.png"
/>
<link
rel="icon"
type="image/png"
sizes="32x32"
href="icons/favicon-32x32.png"
/>
<link
rel="icon"
type="image/png"
sizes="16x16"
href="icons/favicon-16x16.png"
/>
<link rel="manifest" href="icons/site.webmanifest" />
<link rel="mask-icon" href="icons/safari-pinned-tab.svg" color="#5bbad5" />
<link rel="shortcut icon" href="icons/favicon.ico" />
<meta name="msapplication-TileColor" content="#ffffff" />
<meta name="msapplication-config" content="icons/browserconfig.xml" />
<meta name="theme-color" content="#2a2424" />
<meta content="{{ title }}" property="og:title" />
<meta content="{{ desc }}" property="og:description" />
<meta content="icons/apple-touch-icon.png" property="og:image" />
<meta content="#43B581" data-react-helmet="true" name="theme-color" />
</head>

View file

@ -1,218 +1,40 @@
<!DOCTYPE html> <!DOCTYPE html>
<html class="index" lang="fr"> <html class="index" lang="fr">
<head dir="rtl"> {{> header.html }}
<title>Mon portfolio - Anri</title>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="css/style.css" />
<meta name="author" content="Mylloon" />
<meta name="description" content="Portfolio d'Anri Kennel" />
<base target="_blank" />
<link
rel="apple-touch-icon"
sizes="180x180"
href="icons/apple-touch-icon.png"
/>
<link
rel="icon"
type="image/png"
sizes="32x32"
href="icons/favicon-32x32.png"
/>
<link
rel="icon"
type="image/png"
sizes="16x16"
href="icons/favicon-16x16.png"
/>
<link rel="manifest" href="icons/site.webmanifest" />
<link rel="mask-icon" href="icons/safari-pinned-tab.svg" color="#5bbad5" />
<link rel="shortcut icon" href="icons/favicon.ico" />
<meta name="msapplication-TileColor" content="#ffffff" />
<meta name="msapplication-config" content="icons/browserconfig.xml" />
<meta name="theme-color" content="#2a2424" />
<meta content="Portfolio" property="og:title" />
<meta content="Portfolio d'Anri Kennel" property="og:description" />
<meta content="icons/apple-touch-icon.png" property="og:image" />
<meta content="#43B581" data-react-helmet="true" name="theme-color" />
</head>
<body> <body>
{{#data}}
<h1 id="title">Projets qui me tiennent à coeur</h1> <h1 id="title">Projets qui me tiennent à coeur</h1>
<div id="content"> <div id="content">
<h2 class="subtitle">Bots</h2> <h2 class="subtitle">Bots</h2>
<div class="subcontent"> <div class="subcontent">
{{#bots_app}} {{#metadata}} {{#info}}
<h3 class="subsubtitle"> <h3 class="subsubtitle">
<a href="https://git.mylloon.fr/ConfrerieDuKassoulait/KassouBot" <a href="{{link}}">{{title}}</a>
>KassouBot</a
>
</h3> </h3>
<div class="subcontent"> {{/info}} {{/metadata}}
<p> <div class="subcontent">{{&content }}</div>
✨ Basé sur une {{/bots_app}}
<a href="https://git.mylloon.fr/Anri/ravaBot">ancienne version</a>,
permet de faire plusieurs choses comme maintenir des reminders, des
todos, écouter de la musique, etc.
</p>
</div>
<h3 class="subsubtitle">
<a href="https://git.mylloon.fr/Anri/feurBot">feurBot</a>
</h3>
<div class="subcontent">
<p>
Réponds à certains tweets (exemple : si un tweet fini par
<em>quoi</em>, le bot répondra <em>feur</em>).
</p>
</div>
<h3 class="subsubtitle">
<a href="https://git.mylloon.fr/ConfrerieDuKassoulait/Bot-Tom"
>Bot-Tom</a
>
</h3>
<div class="subcontent">
<p>
Utilise SQLite pour avoir des commandes personnalisables sur Twitch.
</p>
</div>
<h3 class="subsubtitle">
<a href="https://git.mylloon.fr/ConfrerieDuKassoulait/Botanique"
>Botanique</a
>
</h3>
<div class="subcontent">
<p>
<a href="https://git.mylloon.fr/ConfrerieDuKassoulait/KassouBot"
>Pas ma première expérience</a
>&nbsp;en matière de bot Discord. Actuellement en actif
développement. Complètement libre et écrit en Typescript.
</p>
</div>
<br /> <br />
</div> </div>
<h2 class="subtitle"> <h2 class="subtitle">
<a href="https://git.mylloon.fr/Paris8/">Projet de l'université</a> <a href="https://git.mylloon.fr/Paris8">Projet de l'université</a>
</h2> </h2>
<div class="subcontent"> <div class="subcontent">{{&univ_content}}</div>
<p>
✨ Parce que j'ai fait plusieurs projets dont je suis fier mais qui ne
mérite pas une place entière sur cette page comme mon
<a href="https://git.mylloon.fr/Paris8/penduEnC">premier pendu</a
>&nbsp;ou une jolie
<a href="https://git.mylloon.fr/Paris8/GesMag"
>interface manager/caisser</a
>, vous pouvez simplement aller voir la liste des projets en vrac qui
sont disponibles sur mon
<a href="https://git.mylloon.fr/Paris8/">git</a>.
</p>
</div>
<h2 class="subtitle">Projets perso</h2> <h2 class="subtitle">Projets perso</h2>
<div class="subcontent"> <div class="subcontent">
{{#persos_app}} {{#metadata}} {{#info}}
<h3 class="subsubtitle"> <h3 class="subsubtitle">
<a href="https://git.mylloon.fr/Anri/Constnium">Constnium</a> <a href="{{link}}">{{title}}</a>
</h3> </h3>
<div class="subcontent"> {{/info}} {{/metadata}}
<p> <div class="subcontent">{{&content }}</div>
Calculez votre propre constante sur la base de votre prénom en {{/persos_app}}
multipliant de vraies constantes mathématiques entre elles. Une <br />
<a href="https://constnium.mylloon.fr/">démo est disponible ici</a>.
</p>
</div>
<h3 class="subsubtitle">
<a href="https://git.mylloon.fr/Anri/cal8tor">cal8tor</a>
</h3>
<div class="subcontent">
<p>
Lecteur de l'emploi du temps pour la licence d'informatique de Paris
8, avec possibilité d'exporter le calendrier en ICS.
</p>
</div>
<h3 class="subsubtitle">
<a href="https://git.mylloon.fr/Anri/prose_dl">prose_dl</a>
</h3>
<div class="subcontent">
<p>
Permets de télécharger tous les posts d'un utilisateur depuis
<a href="https://prose.sh/">prose.sh</a>. J'ai
<a href="https://anri.prose.sh/prose_dl">écrit ici</a>&nbsp;sur son
développement.
</p>
</div>
<h3 class="subsubtitle">
<a href="https://git.mylloon.fr/Anri/downloadcodium"
>downloadCodium</a
>
</h3>
<div class="subcontent">
<p>
Petit script qui permet de télécharger et garder à-jour facilement
la version .AppImage VSCodium.
</p>
</div>
<h3 class="subsubtitle">
<a href="https://git.mylloon.fr/Anri/confOS">confOS</a>
</h3>
<div class="subcontent">
<p>
Scripts et fichiers de configuration pour me simplifier la vie quand
je réinstalle mes systèmes d'exploitation.
</p>
</div>
<h3 class="subsubtitle">
<a href="https://git.mylloon.fr/Anri/mobilismScrap">mobilismScrap</a>
</h3>
<div class="subcontent">
<p>Deux versions, une en python et une en Kotlin :</p>
<ul id="listecontent">
<li>
Celle en Python permet juste de lancer, en ligne de commande, une
recherche qui va récupérer sur le forum Mobilism des versions
crackées d'applications mobiles.
</li>
<li>
✨ Celle en Kotlin est une application android qui fait
basiquement la même chose mais avec une interface plus sympa.
</li>
</ul>
</div>
<h3 class="subsubtitle">
<a href="https://git.mylloon.fr/Anri/CleanTemporaryFiles"
>cleanTemporaryFiles</a
>
</h3>
<div class="subcontent">
<p>
Petit script Windows qui lance quelques commandes pour supprimer les
fichiers temporaires.
</p>
</div>
<h3 class="subsubtitle">
<a href="https://git.mylloon.fr/Anri/microphonePopcat"
>microphonePopcat</a
>
</h3>
<div class="subcontent">
<p>
Petit programme en python qui permet d'ouvrir la bouche d'un chat
quand on parle.
</p>
</div>
<h3 class="subsubtitle">
<a href="https://git.mylloon.fr/Anri/RenameFilesForPlex"
>renameFilesForPlex</a
>
</h3>
<div class="subcontent">
<p>
Petit programme pour renommer des fichiers vidéo (séries) pour
qu'ils soient lisibles directement par Plex.
</p>
</div>
</div> </div>
</div> </div>
<footer class="backToIndexPage"> <footer class="backToIndexPage">
<a href="/" target="_self">Retour à la page principale</a> <a href="/" target="_self">Retour à la page principale</a>
</footer> </footer>
{{/data}}
</body> </body>
</html> </html>