post pathing
This commit is contained in:
2625
Cargo.lock
generated
2625
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -12,3 +12,6 @@ tower-http = { version = "0.5", features = ["fs"] }
|
||||
askama = "0.14.0"
|
||||
serde_json = "1.0.149"
|
||||
serde = "1.0.228"
|
||||
typst = "0.14.2"
|
||||
typst-html = "0.14.2"
|
||||
regex = "1.12.2"
|
||||
|
||||
@@ -12,6 +12,7 @@ in
|
||||
# Replace llvmPackages with llvmPackages_X, where X is the latest LLVM version (at the time of writing, 16)
|
||||
llvmPackages.bintools
|
||||
rustup
|
||||
typst
|
||||
];
|
||||
|
||||
RUSTC_VERSION = overrides.toolchain.channel;
|
||||
|
||||
114
src/main.rs
114
src/main.rs
@@ -1,12 +1,75 @@
|
||||
use axum::{
|
||||
Router, response::Html, routing::get
|
||||
Router, extract::Path, response::Html, routing::get
|
||||
};
|
||||
use tower_http::services::ServeDir;
|
||||
use askama::Template;
|
||||
use markdown::to_html;
|
||||
use std::fs;
|
||||
// use typst::model;
|
||||
// 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
|
||||
#[derive(Template)]
|
||||
#[template(path = "home.html", ext = "html")]
|
||||
@@ -14,21 +77,58 @@ struct HomeTemplate {
|
||||
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]
|
||||
async fn main() {
|
||||
|
||||
let home_html = Html(
|
||||
HomeTemplate {
|
||||
content: to_html(&fs::read_to_string(
|
||||
"static/strings/home.md"
|
||||
content: typst_to_html(fs::read_to_string(
|
||||
"static/home.typ"
|
||||
).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()
|
||||
.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
26
static/home.typ
Normal 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.
|
||||
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
@@ -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
|
||||
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
|
||||
trying to create. Instead, the story goes that I had this random idea
|
||||
for terrain manipulation. Games like Minecraft and Terraria use squares
|
||||
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
|
||||
operations, mainly union and subtract with a second polygon. This led to
|
||||
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,
|
||||
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
|
||||
terrain generation using cellular noise. The reason I used cellular
|
||||
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
|
||||
caves without impacting their interconnectedness. By using this method
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
@@ -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
|
||||
rocket science games such as Kerbal Space Program. I was able to glide
|
||||
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
|
||||
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
|
||||
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,
|
||||
multithreaded chunk generation, gpu accelerated compute shaders to
|
||||
modify chunk density, enhanced use of object oriented programing and
|
||||
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,
|
||||
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
|
||||
@@ -1,5 +0,0 @@
|
||||
|
||||
# About me
|
||||
I'm a fungi
|
||||
|
||||
_markdown in html :0_
|
||||
@@ -58,5 +58,6 @@ nav ul {
|
||||
}
|
||||
|
||||
body {
|
||||
background-image: linear-gradient(315deg, #111, #222);
|
||||
min-height: 100vh;
|
||||
background-image: linear-gradient(330deg, #222, #040404);
|
||||
}
|
||||
|
||||
21
templates/base.html
Normal file
21
templates/base.html
Normal 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>
|
||||
@@ -1,27 +1,10 @@
|
||||
<!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">
|
||||
<div>
|
||||
<p id="name">Jeremy Janella</p>
|
||||
{% extends "base.html" %}
|
||||
|
||||
</div>
|
||||
<div>
|
||||
{{ content|safe }}
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
{% block body %}
|
||||
|
||||
<p id="name">Jeremy Janella</p>
|
||||
|
||||
{{ content|safe }}
|
||||
|
||||
|
||||
{% endblock %}
|
||||
|
||||
4
templates/post-preview.html
Normal file
4
templates/post-preview.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<div>
|
||||
<h2>{{ post.title }}</h2>
|
||||
{{ post.summary }}
|
||||
</div>
|
||||
9
templates/post.html
Normal file
9
templates/post.html
Normal file
@@ -0,0 +1,9 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block body %}
|
||||
|
||||
{{ title|safe }}
|
||||
|
||||
{{ content|safe }}
|
||||
|
||||
{% endblock %}
|
||||
13
templates/posts.html
Normal file
13
templates/posts.html
Normal 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 %}
|
||||
Reference in New Issue
Block a user