42 Commits

Author SHA1 Message Date
fb23b004ce more images!
All checks were successful
Build / build (push) Successful in 4s
2026-01-31 21:40:17 -05:00
ce0edf6060 updated summaries
All checks were successful
Build / build (push) Successful in 2s
2026-01-31 20:57:10 -05:00
53b19fdd9b typos
All checks were successful
Build / build (push) Successful in 2s
2026-01-31 20:54:19 -05:00
463553e347 fix headings
All checks were successful
Build / build (push) Successful in 2s
2026-01-31 20:45:47 -05:00
9b4b5193c6 ci test
All checks were successful
Build / build (push) Successful in 2s
2026-01-31 20:44:11 -05:00
da0726f22f ci test
All checks were successful
Build / build (push) Successful in 3s
2026-01-31 20:42:49 -05:00
83e6dc7ccc fixed spacing css
All checks were successful
Build / build (push) Successful in 6s
2026-01-31 20:42:15 -05:00
96c1840d31 fixed spacing css
All checks were successful
Build / build (push) Successful in 7s
2026-01-31 20:41:11 -05:00
3e0850fc99 fixed name too big css
All checks were successful
Build / build (push) Successful in 6s
2026-01-31 20:36:48 -05:00
06c4c9f5f7 css post class and links
All checks were successful
Build / build (push) Successful in 8s
2026-01-31 20:27:19 -05:00
7f3b1f08e3 test actions
All checks were successful
Build / build (push) Successful in 6s
2026-01-31 20:10:38 -05:00
d67456b9d7 test actions
All checks were successful
Build / build (push) Successful in 4s
2026-01-31 20:10:12 -05:00
47b8acf976 test actions
All checks were successful
Build / build (push) Successful in 6s
2026-01-31 20:09:45 -05:00
55f7315816 test actions
All checks were successful
Build / build (push) Successful in 1s
2026-01-31 20:08:41 -05:00
d6ef911f20 test actions
All checks were successful
Build / build (push) Successful in 11s
2026-01-31 20:07:36 -05:00
000661ef3d test actions
All checks were successful
Build / build (push) Successful in 11s
2026-01-31 20:06:12 -05:00
94c07109ce longer delay in restarting
All checks were successful
Build / build (push) Successful in 11s
2026-01-31 19:17:55 -05:00
970a249775 longer delay in restarting
All checks were successful
Build / build (push) Successful in 6s
2026-01-31 19:16:40 -05:00
ecfd1b0e8d longer delay in restarting
All checks were successful
Build / build (push) Successful in 3s
2026-01-31 19:16:04 -05:00
35257bb6e0 delay in restarting
All checks were successful
Build / build (push) Successful in 2s
2026-01-31 19:15:23 -05:00
62348a5571 removed debug line
All checks were successful
Build / build (push) Successful in 3s
2026-01-31 19:14:30 -05:00
2d14dd2b93 fixed port
All checks were successful
Build / build (push) Successful in 3s
2026-01-31 19:12:29 -05:00
1ec966a9a1 redepoly
All checks were successful
Build / build (push) Successful in 2m42s
2026-01-31 19:06:56 -05:00
99e391fe91 bare-metal workflow
Some checks failed
Build / build (push) Failing after 0s
2026-01-31 19:03:59 -05:00
84d1e3e9c7 fix: workflow type
Some checks failed
Build / build (push) Failing after 2m46s
2026-01-31 18:59:52 -05:00
3a44e7c4cd trigger workflow 2026-01-31 18:58:37 -05:00
eb5cc3c3b0 dynamic pathing cache dir 2026-01-31 18:56:46 -05:00
f9d268b3e5 different caching mechanism 2026-01-31 18:55:08 -05:00
ca37894e8b fix: move -r parameter removed
Some checks failed
Build / build (push) Failing after 8s
2026-01-31 18:52:59 -05:00
e04f0a3712 cache cargo dependancies
Some checks failed
Build / build (push) Failing after 1m48s
2026-01-31 18:50:35 -05:00
2e01a32802 fix: moved directory too early
Some checks failed
Build / build (push) Failing after 2m47s
2026-01-31 18:48:24 -05:00
51e2e1eea4 fix: temp directory bug
Some checks failed
Build / build (push) Failing after 6s
2026-01-31 18:46:06 -05:00
351dfc2734 use opt
All checks were successful
Build / build (push) Successful in 2m45s
2026-01-31 18:40:05 -05:00
36a4af39f7 test location
All checks were successful
Build / build (push) Successful in 2m45s
2026-01-31 18:32:21 -05:00
ea1ee244e2 trigger workflow test
All checks were successful
Build / build (push) Successful in 2m42s
2026-01-31 18:21:49 -05:00
18023732d4 trigger workflow test
Some checks failed
Build / build (push) Failing after 7s
2026-01-31 18:18:07 -05:00
7251f68b6f change name of workflow
Some checks failed
Build / build (push) Has been cancelled
2026-01-31 16:00:44 -05:00
94b6609ea4 trigger workflow test
Some checks failed
Build and Test / build (push) Has been cancelled
2026-01-31 15:53:09 -05:00
6b94076d04 Merge pull request 'added actions' (#1) from rust-nix-refactor into main
Some checks failed
Build and Test / build (push) Has been cancelled
Reviewed-on: #1
2026-01-31 20:50:15 +00:00
aa12cbba3f fixed gitea action
Some checks failed
Build and Test / build (pull_request) Has been cancelled
2026-01-31 15:45:58 -05:00
ce4d8723ef gitea actions 2026-01-31 15:36:33 -05:00
6cb6e73b14 css & post & site-structure 2026-01-31 14:50:36 -05:00
13 changed files with 138 additions and 41 deletions

28
.gitea/workflows/ci.yaml Normal file
View File

@@ -0,0 +1,28 @@
name: Build
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
build:
runs-on: self-hosted
steps:
- name: Pull
working-directory: /opt/site
run: git pull origin main
- name: Build
working-directory: /opt/site
run: cargo build --release
- name: Restart site
working-directory: /opt/site
run: |
pkill site || true
export RUNNER_TRACKING_ID=self-managed
nohup ./target/release/site > server.log 2>&1 &
sleep 1
pgrep site && echo "Site is running!"

View File

@@ -14,34 +14,41 @@ fn load_posts() -> Result<HashMap<String, Post>, Error> {
let dirs = fs::read_dir("static/posts")?; let dirs = fs::read_dir("static/posts")?;
let re_title = Regex::new(r#"#let\s+post_title\s*=\s*"([^"]*)""#).unwrap();
let re_slug = Regex::new(r#"#let\s+post_slug\s*=\s*"([^"]*)""#).unwrap();
let re_summary = Regex::new(r#"#let\s+post_summary\s*=\s*"([^"]*)""#).unwrap(); let re_summary = Regex::new(r#"#let\s+post_summary\s*=\s*"([^"]*)""#).unwrap();
let re_img = Regex::new(r#"#let\s+post_preview_image\s*=\s*"([^"]*)""#).unwrap(); let re_img = Regex::new(r#"#let\s+post_preview_image\s*=\s*"([^"]*)""#).unwrap();
let re_title = Regex::new("(?m)^=+ (.*)").unwrap();
let mut posts: HashMap<String, Post> = HashMap::new(); let mut posts: HashMap<String, Post> = HashMap::new();
for dir in dirs { for dir in dirs {
let typst_path = dir.as_ref().unwrap().path().join("post.typ"); let dir_path = dir.as_ref().unwrap().path();
let typst_path = dir_path.join("post.typ");
let typst = fs::read_to_string(typst_path).expect("Failed reading post"); let typst = fs::read_to_string(typst_path).expect("Failed reading post");
let title = re_title.captures(&typst) let title = re_title.captures(&typst)
.expect("Post title not found") .expect(format!("Post title not found in {}", dir_path.to_str().unwrap()).as_str())
.get(1).unwrap().as_str().trim().to_string();
let slug = re_slug.captures(&typst)
.expect("Post slug not found")
.get(1).unwrap().as_str().trim().to_string(); .get(1).unwrap().as_str().trim().to_string();
let summary = re_summary.captures(&typst) let summary = re_summary.captures(&typst)
.expect("Post summary not found") .expect("Post summary not found")
.get(1).unwrap().as_str().trim().to_string(); .get(1).unwrap().as_str().trim().to_string();
let img = dir?.path().join( let img_path = "/".to_string() + dir?.path().join(
re_img.captures(&typst) re_img.captures(&typst)
.expect("Post preview image not found") .expect("Post preview image not found")
.get(1).unwrap().as_str().trim().to_string()); .get(1).unwrap().as_str().trim().to_string()
let slug = title.clone().replace(" ", "-").to_lowercase(); ).to_str().expect("Failed converting path to string");
posts.insert( posts.insert(
slug.clone(), slug.clone(),
Post { Post {
title: title.clone(),
slug: slug, slug: slug,
preview_image: img.to_str().expect("Failed converting path to string").to_string(), title: title,
preview_image: img_path.clone(),
summary: summary, summary: summary,
render: Html(PostTemplate { render: Html(PostTemplate {
content: typst_to_html(typst), content: typst_to_html(typst),
image: img_path
}.render().expect("Failed rendering post")), }.render().expect("Failed rendering post")),
} }
); );
@@ -52,6 +59,7 @@ fn load_posts() -> Result<HashMap<String, Post>, Error> {
#[derive(Template)] #[derive(Template)]
#[template(path = "post.html")] #[template(path = "post.html")]
struct PostTemplate { struct PostTemplate {
image: String,
content: String, content: String,
} }
@@ -61,8 +69,8 @@ struct Post {
title: String, title: String,
preview_image: String, preview_image: String,
summary: String, summary: String,
slug: String, render: Html<String>,
render: Html<String> slug: String
} }
@@ -128,10 +136,10 @@ async fn main() {
let site: Router = Router::new() let site: Router = Router::new()
.route("/", get(home_html)) .route("/", get(home_html))
.route("/posts", get(posts_html)) .route("/posts", get(posts_html))
.route("/posts/{title}", get(|title| get_post(title, posts))) .route("/posts/{slug}", get(|slug| get_post(slug, posts)))
.nest_service("/static", ServeDir::new("static")); .nest_service("/static", ServeDir::new("static"));
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap(); let listener = tokio::net::TcpListener::bind("0.0.0.0:42069").await.unwrap();
println!("Running on http://127.0.0.1:3000"); println!("Running on http://127.0.0.1:42069");
axum::serve(listener, site).await.unwrap(); axum::serve(listener, site).await.unwrap();
} }

View File

@@ -1,5 +1,5 @@
= About me = About me
I enjoy competeing in capture the flag competitions (cybersecurity and the backyard game), working with robotics, automating tasks and thinking about problems. I enjoy competeing in capture the flag competitions (cybersecurity and the backyard game), working with robotics, automating tasks and thinking through problems.
I've competed in a few hackathons which are cool, but I prefer spending large time frames incrementally understand solutions to much larger problems, and attempting solutions to those. I've competed in a few hackathons which are cool, but I prefer spending large time frames incrementally understand solutions to much larger problems, and attempting solutions to those.
@@ -7,7 +7,7 @@ I think automation is one of the most powerful abilities we have. As a species w
An odd and maybe abstract thing I enjoy is design philosphy. Some examples are creating software to building moral structures through logic to methods of learning new skills. An odd and maybe abstract thing I enjoy is design philosphy. Some examples are creating software to building moral structures through logic to methods of learning new skills.
NixOS has to be my favourite distribution of Linux. My attraction to its design philosphy is that if something works, it will always work anywhere, and can still be worked on long after everything around it has moved on. Its hard to put into words but this feels like debian level stability with arch-like freedom to explore software. NixOS has to be my favourite distribution of Linux. My attraction to its design philosophy is that if something works, it will always work anywhere, and can still be worked on long after everything around it has moved on. Its hard to put into words but this feels like debian level stability with arch-like freedom to explore software.
When I'm not nerding out on math, software, ethics, and optimal ways of learning things, I manage to get outdoors. I like mountain biking through trails, snowboarding, hiking through scenic areas, swimming, and basketball. The next thing I'll be getting into is likely SCUBA diving. When I'm not nerding out on math, software, ethics, and optimal ways of learning things, I manage to get outdoors. I like mountain biking through trails, snowboarding, hiking through scenic areas, swimming, and basketball. The next thing I'll be getting into is likely SCUBA diving.

View File

@@ -1,6 +1,6 @@
#let post_title = "Building a drone" #let post_slug = "building-a-drone"
#let post_preview_image = "top.jpg" #let post_preview_image = "top.jpg"
#let post_summary = "Using a raspberry pi and 3d printer to build a drone from scratch" #let post_summary = "Arduino & Pi powered 3D printed drone"
= Building a Drone = Building a Drone
@@ -21,7 +21,6 @@ wires. I went with the Elegoo Neptune 3 as the printer was open-source
and had a much better cost-to-utility than proprietary printers such as and had a much better cost-to-utility than proprietary printers such as
the Ender series. I am not sponsored I just really like the printer. the Ender series. I am not sponsored I just really like the printer.
The flight computer was the most difficult part to program. Using an The flight computer was the most difficult part to program. Using an
ultrasonic distance sensor, gyroscope, and accelerometer the drone has ultrasonic distance sensor, gyroscope, and accelerometer the drone has
enough information to probably never crash. The autopilot is implemented enough information to probably never crash. The autopilot is implemented
@@ -35,6 +34,9 @@ Pi Pico. There is also a 2.4GHz line of sight receiver for manual control.
A future upgrade may contain a SIM card for near-infinite remote control A future upgrade may contain a SIM card for near-infinite remote control
connection, but drone regulations would make this difficult. connection, but drone regulations would make this difficult.
#image("/static/posts/drone/graphing.jpg")
Testing the remote controller
The power system is the most physically challenging portion of the The power system is the most physically challenging portion of the
drone. The motors took 14.6 Volts, while the UNO microcontroller took 5 drone. The motors took 14.6 Volts, while the UNO microcontroller took 5
Volts, and the Pico and most sensors run at 3.3 Volts. All of the power Volts, and the Pico and most sensors run at 3.3 Volts. All of the power

View File

@@ -1,6 +1,6 @@
#let post_title = "Game Dev" #let post_slug = "gamedev"
#let post_preview_image = "flying.webp" #let post_preview_image = "flying.webp"
#let post_summary = "Creating an open world multiplayer terrain destruction game in Godot and Rust" #let post_summary = "Coding an open world multiplayer terrain destruction game in Godot and Rust"
= Game Development = Game Development

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generator: Adobe Illustrator 26.5.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:cc="http://creativecommons.org/ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Layer_1" inkscape:export-xdpi="299.75104" x="0px" y="0px" viewBox="0 0 127.6 62.9" style="enable-background:new 0 0 127.6 62.9;" xml:space="preserve">
<style type="text/css">
.st0{fill:#0082C9;}
</style>
<path id="path1052" inkscape:connector-curvature="0" inkscape:export-filename="Nextcloud Hub logo variants.png" inkscape:export-xdpi="300" inkscape:export-ydpi="300" class="st0" d=" M63.8,3.8c-12.6,0-23.3,8.5-26.6,20.1c-2.8-6.1-9-10.4-16.2-10.4c-9.9,0-18,8.1-18,18s8.1,18,18,18c7.2,0,13.4-4.3,16.3-10.4 c3.3,11.6,14,20.1,26.6,20.1c12.5,0,23.1-8.4,26.5-19.8c2.9,6,9.1,10.2,16.2,10.2c9.9,0,18-8.1,18-18s-8.1-18-18-18 c-7.1,0-13.2,4.2-16.2,10.2C87,12.2,76.3,3.8,63.8,3.8z M63.8,14.4c9.5,0,17.1,7.6,17.1,17.1s-7.6,17.1-17.1,17.1S46.7,41,46.7,31.5 C46.7,21.9,54.3,14.4,63.8,14.4z M21,24c4.2,0,7.4,3.3,7.4,7.4c0,4.2-3.3,7.4-7.4,7.4c-4.2,0-7.4-3.3-7.4-7.4 C13.6,27.3,16.8,24,21,24z M106.5,24c4.2,0,7.4,3.3,7.4,7.4c0,4.2-3.3,7.4-7.4,7.4c-4.2,0-7.4-3.3-7.4-7.4S102.3,24,106.5,24z"></path>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -0,0 +1,35 @@
#let post_slug = "selfhosting-nextcloud"
#let post_preview_image = "logo.svg"
#let post_summary = "Selfhosting a file server on an old laptop"
= Selfhosting Nextcloud
#link("https://nextcloud.jeremyjanella.com")[My Nextcloud]
== Why I selfhost Nextcloud
I'm a constantly-commuting university student. I primarily work on my desktop, take notes and attend lectures and events with my laptop, and review, access, and share documents from my phone. I need the same files to be accessible on all devices at all times.
Nextcloud is a self-hosted, batteries included file server primarily. It also has a working office suite for editing documents on the cloud through your browser, and numerous other extensions.
Mega, Google Drive, and OneDrive all do this. Why would I bother using nextcloud? Isn't that reinventing the wheel? Yes and no.
=== Do tech giants respect privacy? Nextcloud does.
With remotely managed cloud providers, you're trusting large corporations not to look at your data. You are, for free, letting profit-driven entities, to store your data. Of course they could claim to be implementing end-to-end encryption, or that the free tier is a trail of their paid subscription services. As far as I know none of this is open source either, so you're just trusting big-data to hold your data for free without looking at your data. I just don't trust them not to look at my assignments I guess.
I'm not a fan of subscription services. If I can at moderate difficulty not depend on a corporation to keep their subscription prices sane, I will. I'm not sure how much I save by selfhosting nextcloud, but I also have the piece of mind that that price will never change (excluding buying additional drives or electricity price fluctuations).
== How I selfhost Nextcloud
=== Network and server configurations
I already had an old laptop kicking around, a domain name, and reverse proxy on a static IP. A domain name isn't even really necessary, unless you want a polished experience.
My laptop already runs linux with docker installed, which would only take a few hours to set up otherwise.
From there I used docker compose to start the #link("https://github.com/nextcloud/all-in-one")[nextcloud all in one].
On my reverse proxy I pointed the `nextcloud` subnet at my home IP in its Caddy file. Caddy is a lot like NGINX except its easier to set up for my use case. My IP doesn't change enough to warrent setting up DDNS, however thats always an option. After the ports are opened the hard part is opening the firewall. The reason this is hard is because I always forget the firewall and spend a solid chunk of time debugging why nothing works. In the end, if nothing is working, tools like `traceroute`, `dig` and `ping` are varying degrees of useful for testing accessibility.
=== Can I get five nines?
No. 99.999% uptime won't happen. Power and network outages happen. Roommates unplug your server or brick the router or close your network ports. The thing is that when these things happen, I still have my files on any device. They just stop syncing temporarily, to resume and correct conflicts when the network is back up.
With recent cloud outages in mind, I want it to be my own fault if I can't access my files. If tech giants side against Canada in some idiocratic war, I don't want to lose data. I don't care enough to implement RAID (yet), but if the server dies or the drive does get corrupted, I can reach into my server drawr, take out the drive, and load up ddrescue on my desktop. Also, the files are already syncing to atleast 3 other devices, data loss doesn't scare me. (Knocks on wood)

View File

@@ -1,6 +1,6 @@
#let post_title = "Phobos" #let post_slug = "assembly-game"
#let post_preview_image = "phobos.png" #let post_preview_image = "phobos.png"
#let post_summary = "Making a rocket platformer in assembly" #let post_summary = "Coding a game in raw assembly"
= Phobos = Phobos

View File

@@ -19,7 +19,7 @@
border-radius: 32px; border-radius: 32px;
padding: 10px 20px; padding: 10px 20px;
margin: 0 auto; margin: 0 auto;
width: 95%; width: 85%;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
@@ -47,7 +47,6 @@
img { img {
width: 100%; width: 100%;
max-height: 400px;
object-fit: cover; object-fit: cover;
} }
@@ -55,12 +54,11 @@ img {
border: 1px solid whitesmoke; border: 1px solid whitesmoke;
border-radius: 32px; border-radius: 32px;
margin: auto; margin: auto;
margin-top: 1rem;
margin-bottom: 1rem; margin-bottom: 1rem;
padding-bottom: 1rem; padding-bottom: 1rem;
background-color: linear-gradient(150deg, #222, #040404); background-color: linear-gradient(150deg, #222, #040404);
text-align: center; text-align: center;
break-inside: avoid;
} }
.postpreview:hover { .postpreview:hover {
@@ -104,17 +102,30 @@ a {
transform: scaleX(1); transform: scaleX(1);
} }
.menu {
column-width: 300px;
column-gap: 20px;
column-gap: 1rem;
}
.content { .content {
width: 80%; width: 90%;
margin: auto; display: inline-block;
margin-top: 3.5rem;
} }
.content p { .post a {
text-decoration: underline;
color:orangered;
}
.post * {
text-align: left; text-align: left;
} }
.content li { .top-image {
text-align: left; max-height: 40vh;
max-width: 1000px;
} }
nav ul { nav ul {
@@ -137,8 +148,8 @@ nav ul {
} }
#name { #name {
font-size: 5rem; font-size: clamp(3.5rem, 12vw , 5rem);
margin: 20px; margin: 0px;
padding: 0px; padding: 0px;
animation: nameShadow 5s linear infinite; animation: nameShadow 5s linear infinite;
letter-spacing: 2px; letter-spacing: 2px;
@@ -148,6 +159,7 @@ nav ul {
text-align: center; text-align: center;
} }
body { body {
min-height: 100vh; min-height: 100vh;
background-image: linear-gradient(330deg, #222, #040404); background-image: linear-gradient(330deg, #222, #040404);

View File

@@ -16,7 +16,7 @@
</ul> </ul>
</nav> </nav>
</header> </header>
<div style="padding-top: 3rem" class="content"> <div class="content">
{% block body %}{% endblock %} {% block body %}{% endblock %}
</div> </div>
</body> </body>

View File

@@ -4,7 +4,8 @@
<p id="name">Jeremy Janella</p> <p id="name">Jeremy Janella</p>
{{ content|safe }} <div class="post">
{{ content|safe }}
</div>
{% endblock %} {% endblock %}

View File

@@ -2,6 +2,9 @@
{% block body %} {% block body %}
{{ content|safe }} <div class="post">
<img src="{{ image }}" class="top-image">
{{ content|safe }}
</div>
{% endblock %} {% endblock %}

View File

@@ -3,7 +3,7 @@
{% block body %} {% block body %}
<div class="content"> <div class="content menu">
{% for post in posts %} {% for post in posts %}
{% include "post-preview.html" %} {% include "post-preview.html" %}
{% endfor %} {% endfor %}