summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--flake.lock91
-rw-r--r--flake.nix128
-rw-r--r--projects/site.md19
-rw-r--r--src/blog/mod.rs2
-rw-r--r--src/internal/mod.rs4
-rw-r--r--src/main.rs9
-rw-r--r--src/projects/mod.rs38
-rw-r--r--templates/bloglist.rs.html8
8 files changed, 293 insertions, 6 deletions
diff --git a/flake.lock b/flake.lock
new file mode 100644
index 0000000..c60e477
--- /dev/null
+++ b/flake.lock
@@ -0,0 +1,91 @@
+{
+ "nodes": {
+ "flake-utils": {
+ "locked": {
+ "lastModified": 1648297722,
+ "narHash": "sha256-W+qlPsiZd8F3XkzXOzAoR+mpFqzm3ekQkJNa+PIh1BQ=",
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "rev": "0f8662f1319ad6abf89b3380dd2722369fc51ade",
+ "type": "github"
+ },
+ "original": {
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "type": "github"
+ }
+ },
+ "mozillapkgs": {
+ "flake": false,
+ "locked": {
+ "lastModified": 1645464064,
+ "narHash": "sha256-YeN4bpPvHkVOpQzb8APTAfE7/R+MFMwJUMkqmfvytSk=",
+ "owner": "mozilla",
+ "repo": "nixpkgs-mozilla",
+ "rev": "15b7a05f20aab51c4ffbefddb1b448e862dccb7d",
+ "type": "github"
+ },
+ "original": {
+ "owner": "mozilla",
+ "repo": "nixpkgs-mozilla",
+ "type": "github"
+ }
+ },
+ "naersk": {
+ "inputs": {
+ "nixpkgs": "nixpkgs"
+ },
+ "locked": {
+ "lastModified": 1648544490,
+ "narHash": "sha256-EoBDcccV70tfz2LAs5lK0BjC7en5mzUVlgLsd5E6DW4=",
+ "owner": "nix-community",
+ "repo": "naersk",
+ "rev": "e30ef9a5ce9b3de8bb438f15829c50f9525ca730",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nix-community",
+ "repo": "naersk",
+ "type": "github"
+ }
+ },
+ "nixpkgs": {
+ "locked": {
+ "lastModified": 1648219316,
+ "narHash": "sha256-Ctij+dOi0ZZIfX5eMhgwugfvB+WZSrvVNAyAuANOsnQ=",
+ "owner": "NixOS",
+ "repo": "nixpkgs",
+ "rev": "30d3d79b7d3607d56546dd2a6b49e156ba0ec634",
+ "type": "github"
+ },
+ "original": {
+ "id": "nixpkgs",
+ "type": "indirect"
+ }
+ },
+ "nixpkgs_2": {
+ "locked": {
+ "lastModified": 1648219316,
+ "narHash": "sha256-Ctij+dOi0ZZIfX5eMhgwugfvB+WZSrvVNAyAuANOsnQ=",
+ "owner": "NixOS",
+ "repo": "nixpkgs",
+ "rev": "30d3d79b7d3607d56546dd2a6b49e156ba0ec634",
+ "type": "github"
+ },
+ "original": {
+ "id": "nixpkgs",
+ "type": "indirect"
+ }
+ },
+ "root": {
+ "inputs": {
+ "flake-utils": "flake-utils",
+ "mozillapkgs": "mozillapkgs",
+ "naersk": "naersk",
+ "nixpkgs": "nixpkgs_2"
+ }
+ }
+ },
+ "root": "root",
+ "version": 7
+}
diff --git a/flake.nix b/flake.nix
new file mode 100644
index 0000000..be5a1ef
--- /dev/null
+++ b/flake.nix
@@ -0,0 +1,128 @@
+{
+ inputs = {
+ flake-utils.url = "github:numtide/flake-utils";
+ naersk.url = "github:nix-community/naersk";
+ mozillapkgs = {
+ url = "github:mozilla/nixpkgs-mozilla";
+ flake = false;
+ };
+ };
+
+ outputs = { self, nixpkgs, flake-utils, naersk, mozillapkgs }:
+ flake-utils.lib.eachDefaultSystem (
+ system: let
+ pkgs = nixpkgs.legacyPackages."${system}";
+ mozilla = pkgs.callPackage (mozillapkgs + "/package-set.nix") {};
+ rust = (mozilla.rustChannelOf {
+ date = "2022-03-31";
+ channel = "nightly";
+ sha256 = "k6wD6/2qNQ7rmIvGi1ddtKSTUXjXFbIr0Sg2mqF2nYg=";
+ }).rust;
+
+ naersk-lib = naersk.lib."${system}".override {
+ cargo = rust;
+ rustc = rust;
+ };
+ in
+ rec {
+ # `nix build`
+ packages.carasite = naersk-lib.buildPackage {
+ pname = "carasite";
+ root = ./.;
+ remapPathPrefix = true;
+ buildInputs = with pkgs; [
+ git
+ ];
+ overrideMain = attrs: {
+ preBuild = ''
+ ls -alR src
+ cp -r templates /build/dummy-src/
+ cp -r statics /build/dummy-src/
+ '';
+
+ postInstall = ''
+ mv $out/bin/site $out/bin/carasite
+
+ cp -rf $src/blog $out/blog
+ cp -rf $src/statics $out/css
+ cp -rf $src/projects $out/projects
+ '';
+
+ };
+ };
+ defaultPackage = packages.carasite;
+
+ # `nix run`
+ apps.carasite = flake-utils.lib.mkApp {
+ drv = packages.carasite;
+ };
+ defaultApp = apps.carasite;
+
+ nixosModules.site = { config, lib, ... }: {
+ options = {
+ cara.services.carasite.enable = lib.mkEnableOption "enable cara's site";
+ cara.services.carasite.domain = lib.mkOption {
+ type = lib.types.str;
+ default = "devcara.com";
+ description = "The domain to use";
+ };
+
+ cara.services.carasite.port = lib.mkOption {
+ type = lib.types.port;
+ default = 3000;
+ description = "The port to bind to";
+ };
+ };
+
+ config = lib.mkIf config.cara.services.carasite.enable {
+ users.users.cara-site = {
+ createHome = true;
+ isSystemUser = true;
+ home = "/var/lib/cara-site";
+ group = "cara-site";
+ };
+
+ systemd.services.cara-site = {
+ wantedBy = [ "multi-user.target" ];
+ environment = {
+ PORT = "${config.cara.services.carasite.port}";
+ };
+ serviceConfig = {
+ User = "cara-site";
+ Group = "cara-site";
+ Restart = "always";
+ WorkingDirectory = "/var/lib/cara-site";
+ script = let site = defaultPackage;
+ in ''
+ export PORT=${config.cara.services.carasite.port}
+ cd ${site}
+ exec ${site/bin/xesite}
+ '';
+ };
+ };
+
+ services.nginx = {
+ enable = true;
+ recommendedProxySettings = true;
+ recommendedTlsSettings = true;
+ virtualHosts."${config.cara.services.carasite.domain}" = {
+ addSSL = true;
+ forceSSL = true;
+ enableACME = true;
+
+ locations."/" = {
+ proxyPass = "http://127.0.0.1:${config.cara.services.carasite.port}";
+ };
+ };
+ };
+ };
+ };
+
+
+ # `nix develop`
+ devShell = pkgs.mkShell {
+ nativeBuildInputs = with pkgs; [ rustc cargo ];
+ };
+ }
+ );
+}
diff --git a/projects/site.md b/projects/site.md
new file mode 100644
index 0000000..4f6ae85
--- /dev/null
+++ b/projects/site.md
@@ -0,0 +1,19 @@
+---
+title: Website
+date: 2022-03-29
+---
+
+# Overview
+
+This site used to be written using [Hugo][hugo], and written in Markdown. It's now
+written in Rust, with content remaining in Markdown. I mostly chose to do this
+so I could explore more of frontend development and especially the Rust web
+ecosystem.
+
+[hugo]: https://gohugo.io
+
+# Architecture
+
+The Rust backend is hosted at
+[muirrum/site](https://git.devcara.com/muirrum/site). It loads the markdown into
+HTML and stores it in global state that's then passed to each handler.
diff --git a/src/blog/mod.rs b/src/blog/mod.rs
index 811de15..ac1413e 100644
--- a/src/blog/mod.rs
+++ b/src/blog/mod.rs
@@ -14,7 +14,7 @@ pub mod handlers {
pub async fn list(state: Arc<SiteState>) -> Result<impl Reply, Rejection> {
let state = state.clone();
- Response::builder().html(|o| templates::bloglist_html(o, state.blog.clone()))
+ Response::builder().html(|o| templates::bloglist_html(o, state.blog.clone(), "Posts".into()))
}
pub async fn post(name: String, state: Arc<SiteState>) -> Result<impl Reply, Rejection> {
diff --git a/src/internal/mod.rs b/src/internal/mod.rs
index 2a5fa56..5f42764 100644
--- a/src/internal/mod.rs
+++ b/src/internal/mod.rs
@@ -5,10 +5,12 @@ pub mod markdown;
pub struct SiteState {
pub blog: Vec<Post>,
+ pub projects: Vec<Post>,
}
pub async fn init() -> Result<SiteState> {
let blog = crate::blog::post::load("blog").await?;
+ let projects = crate::blog::post::load("projects").await?;
- Ok(SiteState { blog })
+ Ok(SiteState { blog, projects })
}
diff --git a/src/main.rs b/src/main.rs
index 21eac18..b4801ad 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -8,6 +8,7 @@ use warp::{path, Filter};
use std::str::FromStr;
pub mod blog;
+pub mod projects;
mod internal;
pub mod misc;
@@ -35,9 +36,17 @@ async fn main() -> Result<()> {
.and(give_site_state(state.clone()))
.and_then(blog::handlers::post);
+ let project_index = warp::path!("projects")
+ .and(give_site_state(state.clone()))
+ .and_then(projects::handlers::list);
+ let project = warp::path!("projects" / String)
+ .and(give_site_state(state.clone()))
+ .and_then(projects::handlers::project);
+
let static_files = warp::path("static").and(warp::fs::dir("./statics"));
let site = index.or(about)
.or(blog_index.or(blog_post))
+ .or(project_index.or(project))
.or(static_files)
.with(warp::log("site"));
diff --git a/src/projects/mod.rs b/src/projects/mod.rs
new file mode 100644
index 0000000..f69c2c0
--- /dev/null
+++ b/src/projects/mod.rs
@@ -0,0 +1,38 @@
+use crate::blog::post;
+pub mod handlers {
+
+ use color_eyre::eyre::eyre;
+ use std::sync::Arc;
+
+ use crate::templates::{self, Html, RenderRucte};
+ use warp::http::Response;
+ use warp::{Rejection, Reply};
+
+ use crate::internal::SiteState;
+
+ use crate::blog::post::Post;
+
+ pub async fn list(state: Arc<SiteState>) -> Result<impl Reply, Rejection> {
+ let state = state.clone();
+ Response::builder().html(|o| templates::bloglist_html(o, state.projects.clone(), "Projects".into()))
+ }
+
+ pub async fn project(name: String, state: Arc<SiteState>) -> Result<impl Reply, Rejection> {
+ let mut want: Option<Post> = None;
+
+ for post in &state.projects {
+ if post.link == format!("projects/{}", name) {
+ want = Some(post.clone());
+ break;
+ }
+ }
+
+ match want {
+ Some(post) => {
+ let body = Html(post.body_html.clone());
+ Response::builder().html(|o| templates::post_html(o, post, body))
+ }
+ None => panic!("No post found"),
+ }
+ }
+}
diff --git a/templates/bloglist.rs.html b/templates/bloglist.rs.html
index 505f9a7..4621f3f 100644
--- a/templates/bloglist.rs.html
+++ b/templates/bloglist.rs.html
@@ -1,16 +1,16 @@
@use crate::blog::post::Post;
@use super::{header_html, footer_html};
-@(posts: Vec<Post>)
+@(posts: Vec<Post>, kind: String)
-@:header_html(Some("Posts"), None)
+@:header_html(Some(&kind), None)
-<h1>Posts</h1>
+<h1>@kind.clone()</h1>
<p>
<ul class="post-list">
@for post in posts {
- <li class="post-item">@post.date.format("%B %d %Y") -
+ <li class="post-item">@post.date.format("%d %B %Y") -
<a href="/@post.link">@post.front_matter.title</a></li>
}
</ul>