Compare commits

...

10 commits

11 changed files with 643 additions and 605 deletions

1
.envrc Normal file
View file

@ -0,0 +1 @@
use flake

5
.gitignore vendored
View file

@ -26,4 +26,7 @@ dist-ssr
# Added by cargo
/target
.sass-cache/
.sass-cache/
# Manual (nix flake)
.direnv

View file

@ -1 +0,0 @@
nodejs 19.9.0

989
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
[package]
name = "portfolio"
version = "0.6.0"
version = "0.6.1"
edition = "2021"
[lib]
@ -32,8 +32,8 @@ actix-files = { version = "0.6", optional = true }
actix-web = { version = "4.5", features = ["macros"], optional = true }
leptos_actix = { version = "0.6", optional = true }
futures = { version = "0.3", optional = true }
simple_logger = { version = "4.3", optional = true }
pulldown-cmark = { version = "0.10", optional = true } # Markdown parser
simple_logger = { version = "5.0", optional = true }
pulldown-cmark = { version = "0.11", optional = true } # Markdown parser
gray_matter = { version = "0.2", optional = true } # frontmatter parser
serde_yaml = { version = "0.9", optional = true }
anyhow = { version = "1.0", optional = true }

View file

@ -7,8 +7,8 @@ description: Ma première configuration et ma première contribution à l'enviro
project_link: none
draft: true
tags:
- kde
- linux
- KDE
- Linux
---
## Rapide rappel à propos de KDE

View file

@ -7,8 +7,8 @@ description: Installation de pmbootstrap et compilation d'un paquet Postmarket O
project_link: none
draft: true
tags:
- pmOS
- linux
- Postmarket OS
- Linux
---
## À propos de Postmarket OS
@ -68,11 +68,18 @@ git -C $workdir checkout [branch]
## Compilation de notre paquet Alpine
Pour compiler le paquet, on utilise la commande `pmbootstrap build [paquet_name]`.
> Avant de compiler depuis le repository Nightly, il faut d'abord rajouter la clef de signature
>
> `wget https://nightly.postmarketos.org/plasma-mobile/pmos@local-662fcd2f.rsa.pub`
>
> `mv pmos@local-662fcd2f.rsa.pub $(pmbootstrap config work)/config_apk_keys/`
>
> Source : https://wiki.postmarketos.org/wiki/Nightly
_Exemple de commande_
```bash
pmbootstrap \
-mp https://nightly.postmarketos.org/plasma-mobile/paquets/ \
-mp https://nightly.postmarketos.org/plasma-mobile/packages/ \
-mp http://mirror.postmarketos.org/postmarketos/ \
--details-to-stdout \
-j 32 \
@ -89,7 +96,7 @@ Dans cet exemple, j'ai utilisé les arguments suivants:
* `-mp` : Permet de définir un repository Alpine pour installer les paquets.
> Dans l'exemple, j'utilise deux repos
>
> `https://nightly.postmarketos.org/plasma-mobile/paquets/` : Contient la version en cours de développement de KDE Plasma Mobile
> `https://nightly.postmarketos.org/plasma-mobile/packages/` : Contient la version en cours de développement de KDE Plasma Mobile
>
> `http://mirror.postmarketos.org/postmarketos/` : Le miroir officiel de Postmarket OS

85
flake.lock Normal file
View file

@ -0,0 +1,85 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1710146030,
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1717112898,
"narHash": "sha256-7R2ZvOnvd9h8fDd65p0JnB7wXfUvreox3xFdYWd1BnY=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "6132b0f6e344ce2fe34fc051b72fb46e34f668e0",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs",
"rust-overlay": "rust-overlay"
}
},
"rust-overlay": {
"inputs": {
"flake-utils": [
"flake-utils"
],
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1717294752,
"narHash": "sha256-QhlS52cEQyx+iVcgrEoCnEEpWUA6uLdmeLRxk935inI=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "b46857a406d207a1de74e792ef3b83e800c30e08",
"type": "github"
},
"original": {
"owner": "oxalica",
"repo": "rust-overlay",
"type": "github"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

36
flake.nix Normal file
View file

@ -0,0 +1,36 @@
{
description = "Portfolio rust configuration";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
flake-utils.url = "github:numtide/flake-utils";
rust-overlay = {
url = "github:oxalica/rust-overlay";
inputs.nixpkgs.follows = "nixpkgs";
inputs.flake-utils.follows = "flake-utils";
};
};
outputs = { self, nixpkgs, flake-utils, rust-overlay }:
flake-utils.lib.eachSystem flake-utils.lib.allSystems (system:
let
overlays = [ (import rust-overlay) ];
pkgs = import nixpkgs {
inherit system overlays;
};
rust = pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml;
nodejs = pkgs.nodejs_20;
in
{
devShells = {
default = pkgs.mkShell {
buildInputs = [
(rust.override { extensions = ["rust-src" "rust-analyzer"]; })
nodejs
pkgs.cargo-leptos
pkgs.dart-sass
];
};
};
});
}

View file

@ -9,6 +9,7 @@ cfg_if::cfg_if! {
pub posts: Vec<Arc<Post>>,
pub posts_by_slug: HashMap<String, Arc<Post>>,
pub posts_by_tag: HashMap<String, Vec<Arc<Post>>>,
pub tags: Vec<String>,
}
impl Data {
@ -21,6 +22,8 @@ cfg_if::cfg_if! {
.map(Arc::new)
.collect::<Vec<_>>();
let mut tags : Vec<String> = Vec::new();
let mut posts_by_slug : HashMap<String, Arc<Post>> = HashMap::new();
let mut posts_by_tag : HashMap<String, Vec<Arc<Post>>> = HashMap::new();
@ -28,19 +31,26 @@ cfg_if::cfg_if! {
posts_by_slug.insert(post.metadata.slug.clone(), post.clone());
for tag in &post.metadata.tags {
let tag = tag.to_lowercase();
let posts = posts_by_tag.entry(tag).or_default();
let tag_lower = tag.to_lowercase();
if let None = tags.iter().find(|t| t.to_lowercase().eq(&tag_lower)) {
tags.push(tag.clone());
}
let posts = posts_by_tag.entry(tag_lower).or_default();
posts.push(post.clone());
}
}
log::info!("Loaded {} posts", posts.len());
log::info!("Found {} tags", posts_by_tag.len());
log::info!("Found {} tags in global", tags.len());
log::info!("Found {} tags from posts", posts_by_tag.len());
Ok(Self {
posts,
posts_by_slug,
posts_by_tag,
tags
})
}
}

View file

@ -16,7 +16,7 @@ pub async fn get_posts(
let default = vec![];
let posts = match tag {
Some(tag) => data.posts_by_tag.get(&tag).unwrap_or(&default),
Some(tag) => data.posts_by_tag.get(&tag.to_lowercase()).unwrap_or(&default),
None => &data.posts
};
@ -32,6 +32,16 @@ pub async fn get_posts(
)
}
#[server]
pub async fn get_tags() -> Result<Vec<String>, ServerFnError> {
let data : actix_web::web::Data<crate::app::models::Data> = leptos_actix::extract().await?;
let data = data.into_inner();
let mut tags = data.tags.clone();
tags.sort();
Ok(tags)
}
#[server]
pub async fn get_post(
slug: String
@ -117,6 +127,7 @@ pub fn PostList() -> impl IntoView {
let query = use_query_map();
let tag = move || query.with(|query| query.get("tag").cloned());
let posts = create_resource(move || tag(), move |_| get_posts(tag()));
let tags = create_resource(|| (), move |_| get_tags());
let posts_view = move || {
posts.and_then(|posts| {
@ -126,18 +137,39 @@ pub fn PostList() -> impl IntoView {
})
};
let tags_view = move || {
tags.and_then(|tags| {
tags.iter()
.map(|tag| {
let tag = tag.clone();
view! { <A class="tag" href=format!("/posts?tag={}", tag.clone())>{tag}</A> }
})
.collect_view()
})
};
let filter_view = move || {
tag().map(|tag| Some(view! {
<div class="mx-auto max-w-3xl mb-5">
Tag sélectionné : <A class="tag" href="/posts".to_string()>{tag}<leptos_icons::Icon icon=icondata::IoClose class="scale-125 ml-1 inline" /></A>
</div>
}))
match tag() {
Some(tag) => {
view! {
<><A class="tag" href="/posts".to_string()>{tag}<leptos_icons::Icon icon=icondata::IoClose class="scale-125 ml-1 inline" /></A></>
}.into_view()
},
None => {
view! {
<>{tags_view}</>
}.into_view()
}
}
};
view! {
<Suspense fallback=move || view! { <Loading title="Chargement des posts...".to_string() /> }>
<Nav/>
{filter_view}
<div class="mx-auto max-w-3xl mb-5 flex flex-wrap gap-2">
<span>Filtre : </span>
{filter_view}
</div>
<main class="posts">
<div class="posts__cards">{posts_view}</div>
</main>
@ -152,29 +184,29 @@ pub fn PostElement() -> impl IntoView {
let post = create_resource(|| (), move |_| get_post(slug()));
let post_view = move || {
let render_draft_notice = |post: &Post| -> Option<View> {
if post.metadata.draft {
return Some(view! {
<div class="bg-warning text-on_warning dark:bg-dark_warning dark:text-dart_on_warning rounded-md p-5 mb-5">
r#"
L'article est en cours d'écriture. La formulation peut ne pas être exacte et les phrases peuvent contenir des fautes.
"#
</div>
}.into_view());
}
None
};
let render_post_view = move || {
post.and_then(|post| {
let draft_notice = render_draft_notice(&post);
view! {
<>
{
if post.metadata.draft {
Some(view!{
<div class="bg-warning text-on_warning dark:bg-dark_warning dark:text-dart_on_warning rounded-md p-5 mb-5">
r#"
L'article est en cours d'écriture. La formulation peut ne pas être exacte et les phrases peuvent contenir des fautes.
"#
</div>
})
} else {
None
}
}
<PostHeader metadata=post.metadata.clone() full_element=true />
<div inner_html={post.content.clone()}></div>
</>
}
<>
{draft_notice}
<PostHeader metadata=post.metadata.clone() full_element=true />
<div inner_html={post.content.clone()}></div>
</>
}
})
};
@ -182,7 +214,7 @@ pub fn PostElement() -> impl IntoView {
<Suspense fallback=move || view! { <Loading title="Chargement du post...".to_string() /> }>
<Nav/>
<main class="post">
{post_view}
{render_post_view}
<script>load();</script>
</main>
</Suspense>