post pathing

This commit is contained in:
2026-01-25 16:09:07 -05:00
parent f9d58cbd7c
commit 552cad6b4a
19 changed files with 2834 additions and 61 deletions

2625
Cargo.lock generated
View File

File diff suppressed because it is too large Load Diff

View File

@@ -11,4 +11,7 @@ tokio = { version = "1.49.0", features = ["macros", "rt-multi-thread"] }
tower-http = { version = "0.5", features = ["fs"] } tower-http = { version = "0.5", features = ["fs"] }
askama = "0.14.0" askama = "0.14.0"
serde_json = "1.0.149" serde_json = "1.0.149"
serde = "1.0.228" serde = "1.0.228"
typst = "0.14.2"
typst-html = "0.14.2"
regex = "1.12.2"

View File

@@ -12,6 +12,7 @@ in
# Replace llvmPackages with llvmPackages_X, where X is the latest LLVM version (at the time of writing, 16) # Replace llvmPackages with llvmPackages_X, where X is the latest LLVM version (at the time of writing, 16)
llvmPackages.bintools llvmPackages.bintools
rustup rustup
typst
]; ];
RUSTC_VERSION = overrides.toolchain.channel; RUSTC_VERSION = overrides.toolchain.channel;

View File

@@ -1,12 +1,75 @@
use axum::{ use axum::{
Router, response::Html, routing::get Router, extract::Path, response::Html, routing::get
}; };
use tower_http::services::ServeDir; use tower_http::services::ServeDir;
use askama::Template; use askama::Template;
use markdown::to_html; // use typst::model;
use std::fs; // use typst_html;
use std::{collections::HashMap, fs, io::{Error, Write}, process::{Command, Stdio}};
use regex::Regex;
fn load_posts() -> Result<HashMap<String, Post>, Error> {
let dirs = fs::read_dir("static/posts")?;
let re_title = Regex::new(r#"#let\s+post_title\s*=\s*"([^"]*)""#).unwrap();
let re_summary = Regex::new(r#"#let\s+post_summary\s*=\s*"([^"]*)""#).unwrap();
let mut posts: HashMap<String, Post> = HashMap::new();
for dir in dirs {
let typst_path = dir?.path().join("post.typ");
let typst = fs::read_to_string(typst_path).expect("Failed reading post");
let title = re_title.captures(&typst)
.expect("Post title not found")
.get(1).unwrap().as_str().trim().to_string();
let summary = re_summary.captures(&typst)
.expect("Post summary not found")
.get(1).unwrap().as_str().trim().to_string();
let slug = title.clone().replace(" ", "-").to_lowercase();
posts.insert(
slug.clone(),
Post {
title: title.clone(),
slug: slug,
preview_image: "NA".to_string(),
summary: summary,
render: Html(PostTemplate {
title: title,
content: typst_to_html(typst),
}.render().expect("Failed rendering post")),
}
);
}
Ok(posts)
}
#[derive(Template)]
#[template(path = "post.html")]
struct PostTemplate {
title: String,
content: String,
}
#[derive(Clone)]
#[derive(Debug)]
struct Post {
title: String,
preview_image: String,
summary: String,
slug: String,
render: Html<String>
}
#[derive(Debug)]
#[derive(Template)]
#[template(path = "posts.html")]
struct PostsTemplate {
posts: Vec<Post>
}
// Template for home // Template for home
#[derive(Template)] #[derive(Template)]
#[template(path = "home.html", ext = "html")] #[template(path = "home.html", ext = "html")]
@@ -14,21 +77,58 @@ struct HomeTemplate {
content: String content: String
} }
fn typst_to_html(typst: String) -> String {
let mut child = Command::new("typst")
.args(["compile", "-", "-", "--format", "html", "--features", "html" ])
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn()
.expect("Failed running typst");
let mut stdin = child.stdin.take().expect("Failed opening STDIN");
stdin.write_all(typst.as_bytes()).expect("Failed writing to STDIN");
drop(stdin);
let output = child.wait_with_output().expect("Failed reading output");
String::from_utf8_lossy(&output.stdout).to_string()
}
// , posts: &Vec<Post>
async fn get_post(
Path(slug): Path<String>,
posts: HashMap<String, Post>
) -> Html<String> {
if posts.contains_key(&slug) {
return posts[&slug].render.clone()
}
else {
return Html("404".to_string());
}
}
#[tokio::main] #[tokio::main]
async fn main() { async fn main() {
let home_html = Html( let home_html = Html(
HomeTemplate { HomeTemplate {
content: to_html(&fs::read_to_string( content: typst_to_html(fs::read_to_string(
"static/strings/home.md" "static/home.typ"
).expect("Couldnt read file")) ).expect("Couldnt read file"))
}.render().unwrap() }.render().expect("Failed rendering home template")
);
let posts: HashMap<String, Post> = load_posts().expect("Failed loading posts");
let posts_html = Html(
PostsTemplate{
posts: posts.values().cloned().collect::<Vec<Post>>()
}.render().expect("Failed rendering posts")
); );
let site: Router = Router::new() let site: Router = Router::new()
.route("/", get(home_html)) .route("/", get(home_html))
.nest_service("/static", ServeDir::new("static")); .route("/posts", get(posts_html))
.route("/posts/{title}", get(|title| get_post(title, posts)))
.nest_service("/static", ServeDir::new("static"))
// .with_state(posts)
;

26
static/home.typ Normal file
View File

@@ -0,0 +1,26 @@
= About me
Hey! I'm someone that likes to know my tools well.
I also beleive in fairness and doing what is right. I'm frequently
= Skills
= Hobbies
My free time is split into working on projects and touching grass.
= What I want to do
What I've found most interesting has to be the oppurtunities I get
// Software engineering is a passion of mine, and people tend to reflect the things they do.
// My desktop and homelab run NixOS. I wrote this site in Rust, and add posts using Typst files. The whole thing is hosted on my gitea, and runs in a container defined by Nix.
// I wrote this myself. While AI communicates ideas better than I do, I want to ensure that my and only my thoughts are written.

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

@@ -1,16 +1,22 @@
#let post_title = "Game Dev"
#let post_summary = "Creating an open world multiplayer terrain destruction game in Godot and Rust"
I am currently developing an underground-submarine openworld multiplayer I am currently developing an underground-submarine openworld multiplayer
physics inspired game. As a gamer and enjoyer of large, rich maps and physics inspired game. As a gamer and enjoyer of large, rich maps and
depth to gameplay, I would really like to say thats what I started out depth to gameplay, I would really like to say thats what I started out
trying to create. Instead, the story goes that I had this random idea trying to create. Instead, the story goes that I had this random idea
for terrain manipulation. Games like Minecraft and Terraria use squares for terrain manipulation. Games like Minecraft and Terraria use squares
and cubes, which just feels boring in my opinion. I thought I could do and cubes, which just feels boring in my opinion. I thought I could do
something much more <i>visceral</i> As a sort of tech-demo/proof of something much more precise. As a sort of tech-demo/proof of
concept I programmed a shape that could be modified by boolean geometry concept I programmed a shape that could be modified by boolean geometry
operations, mainly union and subtract with a second polygon. This led to operations, mainly union and subtract with a second polygon. This led to
a very interesting, but quickly boring "game" to hop around in. However, a very interesting, but quickly boring "game" to hop around in. However,
since I could drill through and place prettymuch any shape I wanted to, since I could drill through and place prettymuch any shape I wanted to,
it felt like I could "fly" through the land, much like a submarine it felt like I could "fly" through the land, much like a submarine
"flies" through water.<br /><br />I implemented some modularly built "flies" through water.
I implemented some modularly built
vehicles with use of graphs theory and object oriented programming, and vehicles with use of graphs theory and object oriented programming, and
terrain generation using cellular noise. The reason I used cellular terrain generation using cellular noise. The reason I used cellular
noise is because if you look at the lines between cells, they form a noise is because if you look at the lines between cells, they form a
@@ -18,13 +24,17 @@ network without dead ends. Then by applying an algorithm using a density
function on depth I am able to fine tune the width and density of the function on depth I am able to fine tune the width and density of the
caves without impacting their interconnectedness. By using this method caves without impacting their interconnectedness. By using this method
chunks can generate completely independent of their neighbor, which is chunks can generate completely independent of their neighbor, which is
optimal.<br /><br />"Multiplayer is the hardest part of game dev, maybe optimal.
"Multiplayer is the hardest part of game dev, maybe
release that later" I have been told by a lot of people. However, as a release that later" I have been told by a lot of people. However, as a
hobby-server configurer and network security nerd, I thought I could hobby-server configurer and network security nerd, I thought I could
take it on. I was right, however as a network security nerd I have more take it on. I was right, however as a network security nerd I have more
layers of firewalls than I do braincells. Every single time I have an layers of firewalls than I do braincells. Every single time I have an
issue with networking, its a firewall. Once I found which ports were issue with networking, its a firewall. Once I found which ports were
blocked, yes multiplayer was easy.<br /><br />The result? I could fly blocked, yes multiplayer was easy.
The result? I could fly
drilling vehicles through terrain, pop out of the ground or into random drilling vehicles through terrain, pop out of the ground or into random
caves, mine materials, play hide and seek with friends, and even orbit caves, mine materials, play hide and seek with friends, and even orbit
the planet. One of the things important to me in this game was accurate the planet. One of the things important to me in this game was accurate
@@ -32,17 +42,21 @@ physics: thrust, torque, gravity, mass, all the fun stuff. While I am a
physics minor, I am more importantly a heavy player of physics and physics minor, I am more importantly a heavy player of physics and
rocket science games such as Kerbal Space Program. I was able to glide rocket science games such as Kerbal Space Program. I was able to glide
through AP physics simply because it through AP physics simply because it
<i>just part of the games world</i>, it included everything we would _just part of the games world_, it included everything we would
learn in the classroom. Realistic physics also added to the depth of learn in the classroom. Realistic physics also added to the depth of
gameplay I was looking for.<br /><br /> After some formal computer gameplay I was looking for.
After some formal computer
science education, I discovered new ways to more efficiently implement science education, I discovered new ways to more efficiently implement
many of the algorithms I had initially generated and rewrote them many of the algorithms I had initially generated and rewrote them
...multiple times. Currently everything runs <i>buttery smooth</i> and ...multiple times. Currently everything runs _buttery smooth_ and
framerates are high due to efficient caching of unloaded chunks, framerates are high due to efficient caching of unloaded chunks,
multithreaded chunk generation, gpu accelerated compute shaders to multithreaded chunk generation, gpu accelerated compute shaders to
modify chunk density, enhanced use of object oriented programing and modify chunk density, enhanced use of object oriented programing and
graph algorithms to build massive modular vehicles, authoritative server graph algorithms to build massive modular vehicles, authoritative server
networking to disable hackers, and other performance tweaks.<br /><br /> networking to disable hackers, and other performance tweaks.
So this sounds amazing, where's the game? Well, a game needs graphics, audio, So this sounds amazing, where's the game? Well, a game needs graphics, audio,
a sound track. As much as I'd love to release it now, its unplayable for a sound track. As much as I'd love to release it now, its unplayable for
these reasons along with a few minor implementations left such as NPC's and these reasons along with a few minor implementations left such as NPC's and

View File

@@ -1,5 +0,0 @@
# About me
I'm a fungi
_markdown in html :0_

View File

@@ -58,5 +58,6 @@ nav ul {
} }
body { body {
background-image: linear-gradient(315deg, #111, #222); min-height: 100vh;
background-image: linear-gradient(330deg, #222, #040404);
} }

21
templates/base.html Normal file
View File

@@ -0,0 +1,21 @@
<!doctype html>
<html lang="en">
<head>
<link rel="stylesheet" href="/static/style.css"
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
<body>
<header>
<nav>
<ul>
<li>Posts</li>
<li>Contact</li>
</ul>
</nav>
</header>
<div style="padding: auto">
{% block body %}{% endblock %}
</div>
</body>
</html>

View File

@@ -1,27 +1,10 @@
<!doctype html> {% extends "base.html" %}
<html lang="en">
<head> {% block body %}
<link rel="stylesheet" href="/static/style.css"
<meta charset="utf-8"/> <p id="name">Jeremy Janella</p>
<meta name="viewport" content="width=device-width, initial-scale=1" />
</head> {{ content|safe }}
<body>
<header>
<nav> {% endblock %}
<ul>
<li>Posts</li>
<li>Contact</li>
</ul>
</nav>
</header>
<div style="padding: auto">
<div>
<p id="name">Jeremy Janella</p>
</div>
<div>
{{ content|safe }}
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,4 @@
<div>
<h2>{{ post.title }}</h2>
{{ post.summary }}
</div>

9
templates/post.html Normal file
View File

@@ -0,0 +1,9 @@
{% extends "base.html" %}
{% block body %}
{{ title|safe }}
{{ content|safe }}
{% endblock %}

13
templates/posts.html Normal file
View File

@@ -0,0 +1,13 @@
{% extends "base.html" %}
{% block body %}
<div id="posts-grid">
{% for post in posts %}
{% include "post-preview.html" %}
{% endfor %}
</div>
{% endblock %}