Compare commits
10 commits
Author | SHA1 | Date | |
---|---|---|---|
8e21b49a3b | |||
bd5c46d44d | |||
c2ec1d9504 | |||
7b82088d90 | |||
3192ce9eca | |||
c5457c3b63 | |||
2789edc0d6 | |||
0436136cdd | |||
91f2e4c116 | |||
fb438873d7 |
11 changed files with 643 additions and 605 deletions
1
.envrc
Normal file
1
.envrc
Normal file
|
@ -0,0 +1 @@
|
|||
use flake
|
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -26,4 +26,7 @@ dist-ssr
|
|||
# Added by cargo
|
||||
|
||||
/target
|
||||
.sass-cache/
|
||||
.sass-cache/
|
||||
|
||||
# Manual (nix flake)
|
||||
.direnv
|
|
@ -1 +0,0 @@
|
|||
nodejs 19.9.0
|
989
Cargo.lock
generated
989
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -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 }
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
85
flake.lock
Normal 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
36
flake.nix
Normal 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
|
||||
];
|
||||
};
|
||||
};
|
||||
});
|
||||
}
|
|
@ -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
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in a new issue