Compare commits
2 commits
Author | SHA1 | Date | |
---|---|---|---|
ba4b5b6b54 | |||
2400d33f56 |
15 changed files with 377 additions and 511 deletions
|
@ -1,47 +0,0 @@
|
||||||
name: Publish latest version
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
container:
|
|
||||||
image: ghcr.io/catthehacker/ubuntu:act-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout Code
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Checkout LFS
|
|
||||||
run: |
|
|
||||||
# Replace double auth header, see https://github.com/actions/checkout/issues/1830
|
|
||||||
AUTH=$(git config --local http.${{ github.server_url }}/.extraheader)
|
|
||||||
git config --local --unset http.${{ github.server_url }}/.extraheader
|
|
||||||
git config --local http.${{ github.server_url }}/${{ github.repository }}.git/info/lfs/objects/batch.extraheader "$AUTH"
|
|
||||||
|
|
||||||
# Get files
|
|
||||||
git lfs fetch
|
|
||||||
git lfs checkout
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v3
|
|
||||||
|
|
||||||
- name: Sanitize metadata
|
|
||||||
id: meta
|
|
||||||
uses: docker/metadata-action@v5
|
|
||||||
with:
|
|
||||||
tags: latest
|
|
||||||
images: git.mylloon.fr/${{ github.repository }}
|
|
||||||
|
|
||||||
- name: Login to Registry
|
|
||||||
uses: docker/login-action@v3
|
|
||||||
with:
|
|
||||||
registry: ${{ github.server_url }}
|
|
||||||
username: ${{ github.actor }}
|
|
||||||
password: ${{ secrets.TOKEN }}
|
|
||||||
|
|
||||||
- name: Build and push
|
|
||||||
uses: docker/build-push-action@v6
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
push: ${{ github.event_name != 'pull_request' }}
|
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
|
15
.woodpecker/publish.yml
Normal file
15
.woodpecker/publish.yml
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
steps:
|
||||||
|
publish:
|
||||||
|
image: woodpeckerci/plugin-docker-buildx:2
|
||||||
|
settings:
|
||||||
|
labels:
|
||||||
|
platform: linux/amd64
|
||||||
|
repo: git.mylloon.fr/${CI_REPO,,}
|
||||||
|
auto_tag: true
|
||||||
|
registry: git.mylloon.fr
|
||||||
|
username: ${CI_REPO_OWNER}
|
||||||
|
password:
|
||||||
|
from_secret: cb_token
|
||||||
|
when:
|
||||||
|
event: push
|
||||||
|
branch: main
|
582
Cargo.lock
generated
582
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -10,9 +10,9 @@ publish = false
|
||||||
license = "AGPL-3.0-or-later"
|
license = "AGPL-3.0-or-later"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix-web = { version = "4.9", default-features = false, features = ["macros", "compress-brotli"] }
|
actix-web = { version = "4.6", default-features = false, features = ["macros", "compress-brotli"] }
|
||||||
actix-files = "0.6"
|
actix-files = "0.6"
|
||||||
cached = { version = "0.53", features = ["async", "ahash"] }
|
cached = { version = "0.51", features = ["async", "ahash"] }
|
||||||
ramhorns = "1.0"
|
ramhorns = "1.0"
|
||||||
toml = "0.8"
|
toml = "0.8"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
@ -21,17 +21,16 @@ serde_json = "1.0"
|
||||||
minify-html = "0.15"
|
minify-html = "0.15"
|
||||||
minify-js = "0.6"
|
minify-js = "0.6"
|
||||||
glob = "0.3"
|
glob = "0.3"
|
||||||
comrak = "0.28"
|
comrak = "0.24"
|
||||||
reqwest = { version = "0.12", features = ["json"] }
|
reqwest = { version = "0.12", features = ["json"] }
|
||||||
chrono = { version = "0.4.38", default-features = false, features = ["clock"]}
|
chrono = { version = "0.4.38", default-features = false, features = ["clock"]}
|
||||||
chrono-tz = "0.10"
|
chrono-tz = "0.9"
|
||||||
rss = { version = "2.0", features = ["atom"] }
|
rss = { version = "2.0", features = ["atom"] }
|
||||||
lol_html = "1.2"
|
lol_html = "1.2"
|
||||||
base64 = "0.22"
|
base64 = "0.22"
|
||||||
mime_guess = "2.0"
|
mime_guess = "2.0"
|
||||||
urlencoding = "2.1"
|
urlencoding = "2.1"
|
||||||
regex = "1.10"
|
regex = "1.10"
|
||||||
cyborgtime = "2.1.1"
|
|
||||||
|
|
||||||
[lints.clippy]
|
[lints.clippy]
|
||||||
pedantic = "warn"
|
pedantic = "warn"
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
Easy WebPage generator
|
Easy WebPage generator
|
||||||
|
|
||||||
[![dependency status](https://deps.rs/repo/gitea/git.mylloon.fr/Anri/mylloon.fr/status.svg)](https://deps.rs/repo/gitea/git.mylloon.fr/Anri/mylloon.fr)
|
[![dependency status](https://deps.rs/repo/gitea/git.mylloon.fr/Anri/mylloon.fr/status.svg)](https://deps.rs/repo/gitea/git.mylloon.fr/Anri/mylloon.fr)
|
||||||
[![status-badge](https://git.mylloon.fr/Anri/mylloon.fr/badges/workflows/publish.yml/badge.svg)](https://git.mylloon.fr/Anri/mylloon.fr/actions?workflow=publish.yml)
|
[![status-badge](https://ci.mylloon.fr/api/badges/Anri/mylloon.fr/status.svg)](https://ci.mylloon.fr/Anri/mylloon.fr)
|
||||||
|
|
||||||
- See [issues](https://git.mylloon.fr/Anri/mylloon.fr/issues)
|
- See [issues](https://git.mylloon.fr/Anri/mylloon.fr/issues)
|
||||||
- See [documentation](https://git.mylloon.fr/Anri/mylloon.fr/src/branch/main/Documentation.md)
|
- See [documentation](https://git.mylloon.fr/Anri/mylloon.fr/src/branch/main/Documentation.md)
|
||||||
|
|
|
@ -42,14 +42,7 @@ async fn main() -> Result<()> {
|
||||||
.add(("Server", format!("ewp/{}", env!("CARGO_PKG_VERSION"))))
|
.add(("Server", format!("ewp/{}", env!("CARGO_PKG_VERSION"))))
|
||||||
.add(("Permissions-Policy", "interest-cohort=()")),
|
.add(("Permissions-Policy", "interest-cohort=()")),
|
||||||
)
|
)
|
||||||
.service(
|
.service(web::scope("/api").service(web::scope("v1").service(api_v1::love)))
|
||||||
web::scope("/api").service(
|
|
||||||
web::scope("v1")
|
|
||||||
.service(api_v1::love)
|
|
||||||
.service(api_v1::btf)
|
|
||||||
.service(api_v1::websites),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.service(index::page)
|
.service(index::page)
|
||||||
.service(agreements::security)
|
.service(agreements::security)
|
||||||
.service(agreements::humans)
|
.service(agreements::humans)
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
use crate::misc::date::Date;
|
use crate::misc::date::Date;
|
||||||
use base64::engine::general_purpose;
|
use base64::engine::general_purpose;
|
||||||
use base64::Engine;
|
use base64::Engine;
|
||||||
use comrak::nodes::{AstNode, NodeValue};
|
use comrak::nodes::{AstNode, NodeCode, NodeMath, NodeValue};
|
||||||
use comrak::{format_html, parse_document, Arena, ComrakOptions, ListStyleType, Options};
|
use comrak::{
|
||||||
|
format_html, parse_document, Anchorizer, Arena, ComrakOptions, ListStyleType, Options,
|
||||||
|
};
|
||||||
use lol_html::html_content::ContentType;
|
use lol_html::html_content::ContentType;
|
||||||
use lol_html::{element, rewrite_str, HtmlRewriter, RewriteStrSettings, Settings};
|
use lol_html::{element, rewrite_str, HtmlRewriter, RewriteStrSettings, Settings};
|
||||||
use ramhorns::Content;
|
use ramhorns::Content;
|
||||||
|
@ -119,10 +121,11 @@ impl Metadata {
|
||||||
pub struct File {
|
pub struct File {
|
||||||
pub metadata: Metadata,
|
pub metadata: Metadata,
|
||||||
pub content: String,
|
pub content: String,
|
||||||
|
pub toc_data: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Options used for parser and compiler MD --> HTML
|
/// Options used for parser and compiler MD --> HTML
|
||||||
pub fn get_options<'a>() -> ComrakOptions<'a> {
|
pub fn get_options() -> ComrakOptions {
|
||||||
let mut options = comrak::Options::default();
|
let mut options = comrak::Options::default();
|
||||||
|
|
||||||
// Extension
|
// Extension
|
||||||
|
@ -139,18 +142,12 @@ pub fn get_options<'a>() -> ComrakOptions<'a> {
|
||||||
options.extension.multiline_block_quotes = true;
|
options.extension.multiline_block_quotes = true;
|
||||||
options.extension.math_dollars = true;
|
options.extension.math_dollars = true;
|
||||||
options.extension.math_code = false;
|
options.extension.math_code = false;
|
||||||
options.extension.wikilinks_title_after_pipe = false;
|
|
||||||
options.extension.wikilinks_title_before_pipe = false;
|
|
||||||
options.extension.underline = true;
|
|
||||||
options.extension.spoiler = false;
|
|
||||||
options.extension.greentext = false;
|
|
||||||
|
|
||||||
// Parser
|
// Parser
|
||||||
options.parse.smart = true; // could be boring
|
options.parse.smart = true; // could be boring
|
||||||
options.parse.default_info_string = Some("plaintext".into());
|
options.parse.default_info_string = Some("plaintext".into());
|
||||||
options.parse.relaxed_tasklist_matching = true;
|
options.parse.relaxed_tasklist_matching = true;
|
||||||
options.parse.relaxed_autolinks = true;
|
options.parse.relaxed_autolinks = true;
|
||||||
// options.render.broken_link_callback = ...;
|
|
||||||
|
|
||||||
// Renderer
|
// Renderer
|
||||||
options.render.hardbreaks = false; // could be true? change by metadata could be good for compatibility
|
options.render.hardbreaks = false; // could be true? change by metadata could be good for compatibility
|
||||||
|
@ -161,13 +158,7 @@ pub fn get_options<'a>() -> ComrakOptions<'a> {
|
||||||
options.render.escape = false;
|
options.render.escape = false;
|
||||||
options.render.list_style = ListStyleType::Dash;
|
options.render.list_style = ListStyleType::Dash;
|
||||||
options.render.sourcepos = false;
|
options.render.sourcepos = false;
|
||||||
options.render.experimental_inline_sourcepos = false;
|
|
||||||
options.render.escaped_char_spans = false;
|
options.render.escaped_char_spans = false;
|
||||||
options.render.ignore_setext = true;
|
|
||||||
options.render.ignore_empty_links = true;
|
|
||||||
options.render.gfm_quirks = true;
|
|
||||||
options.render.prefer_fenced = false;
|
|
||||||
options.render.figure_with_caption = false;
|
|
||||||
|
|
||||||
options
|
options
|
||||||
}
|
}
|
||||||
|
@ -179,7 +170,7 @@ fn custom_img_size(html: &str) -> String {
|
||||||
RewriteStrSettings {
|
RewriteStrSettings {
|
||||||
element_content_handlers: vec![element!("img[alt]", |el| {
|
element_content_handlers: vec![element!("img[alt]", |el| {
|
||||||
let alt = el.get_attribute("alt").unwrap();
|
let alt = el.get_attribute("alt").unwrap();
|
||||||
let possible_piece = alt.split('|').collect::<Vec<&str>>();
|
let possible_piece = alt.split(|c| c == '|').collect::<Vec<&str>>();
|
||||||
|
|
||||||
if possible_piece.len() > 1 {
|
if possible_piece.len() > 1 {
|
||||||
let data = possible_piece.last().unwrap().trim();
|
let data = possible_piece.last().unwrap().trim();
|
||||||
|
@ -302,6 +293,8 @@ pub fn read_md(
|
||||||
html_content = custom_img_size(&html_content);
|
html_content = custom_img_size(&html_content);
|
||||||
(html_content, mail_obfsucated) = mail_obfuscation(&html_content);
|
(html_content, mail_obfsucated) = mail_obfuscation(&html_content);
|
||||||
|
|
||||||
|
let toc = toc_to_html(&generate_toc(root));
|
||||||
|
|
||||||
let mut final_metadata = Metadata {
|
let mut final_metadata = Metadata {
|
||||||
info: metadata,
|
info: metadata,
|
||||||
mermaid: check_mermaid(root, mermaid_name),
|
mermaid: check_mermaid(root, mermaid_name),
|
||||||
|
@ -314,6 +307,7 @@ pub fn read_md(
|
||||||
File {
|
File {
|
||||||
metadata: final_metadata,
|
metadata: final_metadata,
|
||||||
content: html_content,
|
content: html_content,
|
||||||
|
toc_data: toc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -500,3 +494,87 @@ fn mail_obfuscation(html: &str) -> (String, bool) {
|
||||||
(new_html, is_modified)
|
(new_html, is_modified)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct TOCEntry {
|
||||||
|
id: String,
|
||||||
|
title: String,
|
||||||
|
depth: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_toc<'a>(root: &'a AstNode<'a>) -> Vec<TOCEntry> {
|
||||||
|
/// See <https://github.com/kivikakk/comrak/blob/b67d406d3b101b93539c37a1ca75bff81ff8c149/src/html.rs#L446>
|
||||||
|
fn collect_text<'a>(node: &'a AstNode<'a>, output: &mut String) {
|
||||||
|
match node.data.borrow().value {
|
||||||
|
NodeValue::Text(ref literal)
|
||||||
|
| NodeValue::Code(NodeCode { ref literal, .. })
|
||||||
|
| NodeValue::Math(NodeMath { ref literal, .. }) => {
|
||||||
|
*output = literal.to_string();
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
for n in node.children() {
|
||||||
|
if !output.is_empty() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
collect_text(n, output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut toc = vec![];
|
||||||
|
|
||||||
|
let mut anchorizer = Anchorizer::new();
|
||||||
|
|
||||||
|
// Collect headings first to avoid mutable borrow conflicts
|
||||||
|
let headings: Vec<_> = root
|
||||||
|
.children()
|
||||||
|
.filter_map(|node| {
|
||||||
|
if let NodeValue::Heading(ref nch) = &node.data.borrow().value {
|
||||||
|
Some((*nch, node))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// Now process each heading
|
||||||
|
for (nch, node) in headings {
|
||||||
|
let mut title = String::with_capacity(20);
|
||||||
|
collect_text(node, &mut title);
|
||||||
|
|
||||||
|
toc.push(TOCEntry {
|
||||||
|
id: anchorizer.anchorize(title.clone()),
|
||||||
|
title,
|
||||||
|
depth: nch.level,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
toc
|
||||||
|
}
|
||||||
|
|
||||||
|
fn toc_to_html(toc: &[TOCEntry]) -> String {
|
||||||
|
if toc.is_empty() {
|
||||||
|
return String::new();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut html = Vec::with_capacity(20 + 20 * toc.len());
|
||||||
|
|
||||||
|
html.extend_from_slice(b"<ul>");
|
||||||
|
|
||||||
|
for entry in toc {
|
||||||
|
// TODO: Use depth
|
||||||
|
html.extend_from_slice(
|
||||||
|
format!(
|
||||||
|
"<li><a href=\"{}\">{} (dbg/depth/{})</a></li>",
|
||||||
|
entry.id, entry.title, entry.depth
|
||||||
|
)
|
||||||
|
.as_bytes(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
html.extend_from_slice(b"</ul>");
|
||||||
|
|
||||||
|
String::from_utf8(html).unwrap()
|
||||||
|
}
|
||||||
|
|
|
@ -81,5 +81,6 @@ fn read_pdf(data: Vec<u8>) -> File {
|
||||||
style="width: 100%; height: 79vh";
|
style="width: 100%; height: 79vh";
|
||||||
>"#
|
>"#
|
||||||
),
|
),
|
||||||
|
toc_data: String::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,53 +1,15 @@
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
use actix_web::{get, HttpResponse, Responder};
|
use actix_web::{get, HttpResponse, Responder};
|
||||||
use chrono::Utc;
|
|
||||||
use cyborgtime::format_duration;
|
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
/// Response for /love
|
/// Response
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
struct InfoLove {
|
struct Info {
|
||||||
unix_epoch: u32,
|
unix_epoch: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/love")]
|
#[get("/love")]
|
||||||
pub async fn love() -> impl Responder {
|
pub async fn love() -> impl Responder {
|
||||||
HttpResponse::Ok().json(InfoLove {
|
HttpResponse::Ok().json(Info {
|
||||||
unix_epoch: 1_605_576_600,
|
unix_epoch: 1_605_576_600,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Response for /backtofrance
|
|
||||||
#[derive(Serialize)]
|
|
||||||
struct InfoBTF {
|
|
||||||
unix_epoch: u64,
|
|
||||||
countdown: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[get("/backtofrance")]
|
|
||||||
pub async fn btf() -> impl Responder {
|
|
||||||
let target = 1_736_618_100;
|
|
||||||
let current_time: u64 = Utc::now().timestamp().try_into().unwrap();
|
|
||||||
|
|
||||||
let info = InfoBTF {
|
|
||||||
unix_epoch: target,
|
|
||||||
countdown: if current_time > target {
|
|
||||||
"Already happened".to_owned()
|
|
||||||
} else {
|
|
||||||
let duration_epoch = target - current_time;
|
|
||||||
let duration = Duration::from_secs(duration_epoch);
|
|
||||||
format_duration(duration).to_string()
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
HttpResponse::Ok().json(info)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[get("/websites")]
|
|
||||||
pub async fn websites() -> impl Responder {
|
|
||||||
HttpResponse::Ok().json((
|
|
||||||
"http://www.bocal.cs.univ-paris8.fr/~akennel/",
|
|
||||||
"https://anri.up8.site/",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
|
@ -186,7 +186,6 @@ fn get_posts(location: &str) -> Vec<Post> {
|
||||||
struct BlogPostTemplate {
|
struct BlogPostTemplate {
|
||||||
navbar: NavBar,
|
navbar: NavBar,
|
||||||
post: Option<File>,
|
post: Option<File>,
|
||||||
toc: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/blog/p/{id}")]
|
#[get("/blog/p/{id}")]
|
||||||
|
@ -199,7 +198,7 @@ pub async fn page(path: web::Path<(String,)>, config: web::Data<Config>) -> impl
|
||||||
|
|
||||||
fn build_post(file: &str, config: Config) -> String {
|
fn build_post(file: &str, config: Config) -> String {
|
||||||
let mut post = None;
|
let mut post = None;
|
||||||
let (infos, toc) = get_post(
|
let infos = get_post(
|
||||||
&mut post,
|
&mut post,
|
||||||
file,
|
file,
|
||||||
&config.fc.name.unwrap_or_default(),
|
&config.fc.name.unwrap_or_default(),
|
||||||
|
@ -214,18 +213,12 @@ fn build_post(file: &str, config: Config) -> String {
|
||||||
..NavBar::default()
|
..NavBar::default()
|
||||||
},
|
},
|
||||||
post,
|
post,
|
||||||
toc,
|
|
||||||
},
|
},
|
||||||
infos,
|
infos,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_post(
|
fn get_post(post: &mut Option<File>, filename: &str, name: &str, data_dir: &str) -> InfosPage {
|
||||||
post: &mut Option<File>,
|
|
||||||
filename: &str,
|
|
||||||
name: &str,
|
|
||||||
data_dir: &str,
|
|
||||||
) -> (InfosPage, String) {
|
|
||||||
let blog_dir = format!("{data_dir}/{BLOG_DIR}/{POST_DIR}");
|
let blog_dir = format!("{data_dir}/{BLOG_DIR}/{POST_DIR}");
|
||||||
let ext = ".md";
|
let ext = ".md";
|
||||||
|
|
||||||
|
@ -234,13 +227,8 @@ fn get_post(
|
||||||
&TypeFileMetadata::Blog,
|
&TypeFileMetadata::Blog,
|
||||||
);
|
);
|
||||||
|
|
||||||
let default = (
|
let default = (filename, &format!("Blog d'{name}"), Vec::new());
|
||||||
filename,
|
let (title, desc, tags) = match post {
|
||||||
&format!("Blog d'{name}"),
|
|
||||||
Vec::new(),
|
|
||||||
String::new(),
|
|
||||||
);
|
|
||||||
let (title, desc, tags, toc) = match post {
|
|
||||||
Some(data) => (
|
Some(data) => (
|
||||||
match &data.metadata.info.blog.as_ref().unwrap().title {
|
match &data.metadata.info.blog.as_ref().unwrap().title {
|
||||||
Some(text) => text,
|
Some(text) => text,
|
||||||
|
@ -254,28 +242,20 @@ fn get_post(
|
||||||
Some(tags) => tags.clone(),
|
Some(tags) => tags.clone(),
|
||||||
None => default.2,
|
None => default.2,
|
||||||
},
|
},
|
||||||
match &data.metadata.info.blog.as_ref().unwrap().toc {
|
|
||||||
// TODO: Generate TOC
|
|
||||||
Some(true) => String::new(),
|
|
||||||
_ => default.3,
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
None => default,
|
None => default,
|
||||||
};
|
};
|
||||||
|
|
||||||
(
|
InfosPage {
|
||||||
InfosPage {
|
title: Some(format!("Post: {title}")),
|
||||||
title: Some(format!("Post: {title}")),
|
desc: Some(desc.clone()),
|
||||||
desc: Some(desc.clone()),
|
kw: Some(make_kw(
|
||||||
kw: Some(make_kw(
|
&["blog", "blogging", "write", "writing"]
|
||||||
&["blog", "blogging", "write", "writing"]
|
.into_iter()
|
||||||
.into_iter()
|
.chain(tags.iter().map(|t| t.name.as_str()))
|
||||||
.chain(tags.iter().map(|t| t.name.as_str()))
|
.collect::<Vec<_>>(),
|
||||||
.collect::<Vec<_>>(),
|
)),
|
||||||
)),
|
}
|
||||||
},
|
|
||||||
toc,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[routes]
|
#[routes]
|
||||||
|
|
BIN
static/badges/friends/jas.webp
(Stored with Git LFS)
Normal file
BIN
static/badges/friends/jas.webp
(Stored with Git LFS)
Normal file
Binary file not shown.
|
@ -12,7 +12,6 @@
|
||||||
--background: #f1f1f1;
|
--background: #f1f1f1;
|
||||||
--font-color: #18181b;
|
--font-color: #18181b;
|
||||||
--link-color: #df5a9c;
|
--link-color: #df5a9c;
|
||||||
--selection-color: #c5c5c560;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,6 +21,5 @@
|
||||||
--background: #171e26;
|
--background: #171e26;
|
||||||
--font-color: #bcbcc5;
|
--font-color: #bcbcc5;
|
||||||
--link-color: #ff80bf;
|
--link-color: #ff80bf;
|
||||||
--selection-color: #c5c5c530;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,10 +4,6 @@ html {
|
||||||
font-family: var(--font-family);
|
font-family: var(--font-family);
|
||||||
}
|
}
|
||||||
|
|
||||||
::selection {
|
|
||||||
background-color: var(--selection-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
body,
|
body,
|
||||||
a {
|
a {
|
||||||
color: var(--font-color);
|
color: var(--font-color);
|
||||||
|
|
|
@ -12,13 +12,12 @@ window.addEventListener("load", () => {
|
||||||
-webkit-background-clip: text; /* Chromium fix */
|
-webkit-background-clip: text; /* Chromium fix */
|
||||||
color: transparent;
|
color: transparent;
|
||||||
`;
|
`;
|
||||||
const mono = "font-family: monospace";
|
|
||||||
|
|
||||||
const tags = [
|
const tags = [
|
||||||
new Tag("Comment fonctionne un PC 😵💫"),
|
new Tag("Comment fonctionne un PC 😵💫"),
|
||||||
new Tag("undefined", mono),
|
new Tag("undefined", "font-family: monospace"),
|
||||||
new Tag("/api/v1/love", mono),
|
new Tag("/api/v1/love", "font-family: monospace"),
|
||||||
new Tag("/api/v1/websites", mono),
|
new Tag("A rater son master 🎊"),
|
||||||
new Tag("Peak D2 sur Valo 🤡"),
|
new Tag("Peak D2 sur Valo 🤡"),
|
||||||
new Tag(
|
new Tag(
|
||||||
"0x520",
|
"0x520",
|
||||||
|
@ -62,7 +61,6 @@ window.addEventListener("load", () => {
|
||||||
text-shadow: 0px 0px 20px light-dark(var(--font-color), transparent);
|
text-shadow: 0px 0px 20px light-dark(var(--font-color), transparent);
|
||||||
`
|
`
|
||||||
),
|
),
|
||||||
new Tag("s/centre/droite/g", mono),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const random = Math.round(Math.random() * (tags.length - 1));
|
const random = Math.round(Math.random() * (tags.length - 1));
|
||||||
|
|
|
@ -28,7 +28,9 @@
|
||||||
<main>
|
<main>
|
||||||
{{^post}}
|
{{^post}}
|
||||||
<p>This post doesn't exist... sorry</p>
|
<p>This post doesn't exist... sorry</p>
|
||||||
{{/post}} {{#post}} {{&toc}}
|
{{/post}} {{#post}} {{#metadata}} {{#info}} {{#blog}} {{#toc}}
|
||||||
|
<aside>{{&toc_data}}</aside>
|
||||||
|
{{/toc}} {{/blog}} {{/info}} {{/metadata}}
|
||||||
<article>{{&content}}</article>
|
<article>{{&content}}</article>
|
||||||
{{/post}}
|
{{/post}}
|
||||||
</main>
|
</main>
|
||||||
|
|
Loading…
Reference in a new issue