diff options
-rw-r--r-- | Cargo.lock | 65 | ||||
-rw-r--r-- | Cargo.toml | 4 | ||||
-rw-r--r-- | blog/fall-semester-status.md | 50 | ||||
-rw-r--r-- | src/blog/mod.rs | 25 | ||||
-rw-r--r-- | src/blog/post.rs | 18 | ||||
-rw-r--r-- | src/main.rs | 18 | ||||
-rw-r--r-- | src/misc/mod.rs | 10 | ||||
-rw-r--r-- | statics/custom.css | 41 | ||||
-rw-r--r-- | statics/gruvbox.css | 74 | ||||
-rw-r--r-- | templates/bloglist.rs.html | 19 | ||||
-rw-r--r-- | templates/footer.rs.html | 6 | ||||
-rw-r--r-- | templates/header.rs.html | 11 | ||||
-rw-r--r-- | templates/index.rs.html | 43 | ||||
-rw-r--r-- | templates/post.rs.html | 10 |
14 files changed, 379 insertions, 15 deletions
@@ -376,6 +376,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" [[package]] +name = "futures" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a12aa0eb539080d55c3f2d45a67c3b58b6b0773c1a3ca2dfec66d58c97fd66ca" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] name = "futures-channel" version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -392,6 +407,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88d1c26957f23603395cd326b0ffe64124b818f4449552f960d815cfba83a53d" [[package]] +name = "futures-executor" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45025be030969d763025784f7f355043dc6bc74093e4ecc5000ca4dc50d8745c" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f9d34af5a1aac6fb380f735fe510746c38067c5bf16c7fd250280503c971b2" + +[[package]] +name = "futures-macro" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18e4a4b95cea4b4ccbcf1c5675ca7c4ee4e9e75eb79944d07defde18068f79bb" +dependencies = [ + "autocfg", + "proc-macro-hack", + "proc-macro2", + "quote", + "syn", +] + +[[package]] name = "futures-sink" version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -410,11 +455,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "36568465210a3a6ee45e1f165136d68671471a501e632e9a98d96872222b5481" dependencies = [ "autocfg", + "futures-channel", "futures-core", + "futures-io", + "futures-macro", "futures-sink", "futures-task", + "memchr", "pin-project-lite", "pin-utils", + "proc-macro-hack", + "proc-macro-nested", "slab", ] @@ -1030,6 +1081,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba" [[package]] +name = "proc-macro-hack" +version = "0.5.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" + +[[package]] +name = "proc-macro-nested" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" + +[[package]] name = "proc-macro2" version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1308,8 +1371,10 @@ dependencies = [ "chrono", "color-eyre", "comrak", + "futures", "glob", "kankyo", + "mime", "ructe", "serde", "serde_yaml", @@ -17,6 +17,10 @@ thiserror = "1" serde_yaml = "0.8" glob = "0.3" +mime = "0.3" + +futures = "0.3" + [build-dependencies] ructe = { version = "0.13", features = ["warp03"] } diff --git a/blog/fall-semester-status.md b/blog/fall-semester-status.md new file mode 100644 index 0000000..c3bf41e --- /dev/null +++ b/blog/fall-semester-status.md @@ -0,0 +1,50 @@ +--- +title: Status Update - Fall Semester +date: 2021-12-17 +series: + - status +--- + +## Preface +Hello all! Welcome back to another status update! I realized recently that I +haven't been all that good about making monthly status updates, so I think for +at least the rest of this academic year I'll be making termly status updates, +so one every 7 weeks. Hopefully this will lead to longer status updates with +more content. + +Now, on to the Fall Semester status update! + +## Status update +As I write this, it's a day after my last final exams, and I'm sitting in the +campus library on my service desk shift. Much of my open source contributions +this semester have been to the [LNLDB](https://github.com/WPI-LNL/lnldb), which +handles events, membership, and a whole bunch of other stuff for WPI Lens and +Lights. That's a Django codebase, and I've contributed a few features: + +- Pronoun Support + - Allowed members to provide their personal pronouns on their profile pages +- Email resources for new Crew Chiefs + - When a member is assigned as a Crew Chief for the first time, send some + extra resources in the email + +I also have some pull requests pending review: + +- Position postings + - Lets executive board members post leadership roles to the active members +- Cropping Officer photos + - Officer photos are currently inconsistently cropped, this lets them resize + as needed + +With the transition to college, among other things, I haven't had the time to +do much else. I started to work on adding a tag for GPG-signed commits to +git.sr.ht, but that hasn't gone anywhere. + +Speaking of git.sr.ht... + +## New code location +I've deployed a production [sourcehut](https://sourcehut.org) instance to a new +server, available at https://git.carathe.dev. I'm waiting on WPI ITS to unblock +that domain, but it shouldn't be too long. I've already thrown things up there, +and that's where I'll put personal projects. + +That's all for this semester! Happy holidays, and see you in the new year :) diff --git a/src/blog/mod.rs b/src/blog/mod.rs index 3640bcd..c227f22 100644 --- a/src/blog/mod.rs +++ b/src/blog/mod.rs @@ -2,6 +2,7 @@ pub mod post; pub mod handlers { use std::sync::Arc; +use color_eyre::eyre::eyre; use warp::{Reply, Rejection}; use warp::http::Response; @@ -9,13 +10,31 @@ use crate::templates::{self, Html, RenderRucte}; use crate::internal::SiteState; +use super::post::Post; + pub async fn list(state: Arc<SiteState>) -> Result<impl Reply, Rejection> { let state = state.clone(); Response::builder() - .html(|o| templates::index_html(o)) + .html(|o| templates::bloglist_html(o, state.blog.clone())) } - pub async fn post(name: String) -> Result<impl Reply, Rejection> { - Ok("Post test") + pub async fn post(name: String, state: Arc<SiteState>) -> Result<impl Reply, Rejection> { + let mut want: Option<Post> = None; + + for post in &state.blog { + if post.link == format!("blog/{}", 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/src/blog/post.rs b/src/blog/post.rs index abe57aa..3c27690 100644 --- a/src/blog/post.rs +++ b/src/blog/post.rs @@ -1,7 +1,7 @@ use std::{cmp::Ordering, path::PathBuf}; use glob::glob; use color_eyre::eyre::{Result, Context, eyre}; -use tokio::fs; +use tokio::{fs}; use chrono::prelude::*; @@ -11,6 +11,7 @@ pub struct Post { pub front_matter: frontmatter::Data, pub body_html: String, pub date: DateTime<FixedOffset>, + pub link: String, } impl Ord for Post { @@ -46,6 +47,7 @@ async fn read_post(dir: &str, fname: PathBuf) -> Result<Post> { Ok(Post { front_matter, body_html, + link, date } ) } @@ -55,7 +57,19 @@ pub async fn load(dir: &str) -> Result<Vec<Post>> { .filter_map(Result::ok) .map(|fname| read_post(dir, fname)); - Ok(Vec::new()) + let mut result: Vec<Post> = futures::future::join_all(futs) + .await + .into_iter() + .map(Result::unwrap) + .collect(); + + if result.len() == 0 { + Err(eyre!("No posts found")) + } else { + result.sort(); + result.reverse(); + Ok(result) + } } mod frontmatter { diff --git a/src/main.rs b/src/main.rs index 04ab18e..e247211 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,11 +3,12 @@ extern crate tracing; use color_eyre::eyre::Result; use std::{net::IpAddr, sync::Arc}; -use warp::Filter; +use warp::{Filter, path}; use std::str::FromStr; pub mod blog; +pub mod misc; mod internal; use internal::SiteState; @@ -24,15 +25,22 @@ async fn main() -> Result<()> { let state = Arc::new(internal::init().await?); + let index = warp::get().and(path::end().and_then(misc::handlers::index)); + let blog_base = warp::path!("blog" / ..); let blog_list = blog_base.and(give_site_state(state.clone())).and_then(blog::handlers::list); let blog_post = blog_base.and( warp::path!(String) - .and(warp::get()).and_then(blog::handlers::post)); + .and(give_site_state(state.clone())) + .and_then(blog::handlers::post), + ); - let blog = blog_list.or(blog_post); + let static_files = warp::path("static") + .and(warp::fs::dir("./statics")); + let site = index + .or(blog_list.or(blog_post)) + .or(static_files).with(warp::log("site")); - let site = blog.with(warp::log("site")); let server = warp::serve(site); @@ -51,3 +59,5 @@ async fn main() -> Result<()> { fn give_site_state(sitestate: Arc<SiteState>) -> impl Filter<Extract = (Arc<SiteState>,), Error=std::convert::Infallible> + Clone { warp::any().map(move || sitestate.clone()) } + +include!(concat!(env!("OUT_DIR"), "/templates.rs")); diff --git a/src/misc/mod.rs b/src/misc/mod.rs new file mode 100644 index 0000000..5942b8c --- /dev/null +++ b/src/misc/mod.rs @@ -0,0 +1,10 @@ +pub mod handlers { + use color_eyre::Result; + use warp::{Reply, Rejection, http::Response}; + use crate::templates::{self, Html, RenderRucte}; + + pub async fn index() -> Result<impl Reply, Rejection> { + Response::builder() + .html(|o| templates::index_html(o)) + } +} diff --git a/statics/custom.css b/statics/custom.css new file mode 100644 index 0000000..827bd23 --- /dev/null +++ b/statics/custom.css @@ -0,0 +1,41 @@ +/* Element styles */ +body { + font-family: sans-serif; +} + +/* Base container */ +.container { + margin: auto; /* centered */ + width: 80%; /* looks nice */ +} + +/* Navbar */ +.navbar { + list-style-type: none; + margin: 0; + padding: 0; + border-bottom: 1px solid; + margin-bottom: 2rem; + text-align: center; + padding-bottom: 0.4rem; +} + +.navbar-item { + display: inline; + margin-right: 1rem; +} + +.footer { + border-top: 1px solid; + margin-top: 2rem; + padding-top: 0.4rem; +} + +.two-column { + display: flex; + justify-content: center; +} + +.inner-column { + flex: 50%; +} diff --git a/statics/gruvbox.css b/statics/gruvbox.css new file mode 100644 index 0000000..618eb3b --- /dev/null +++ b/statics/gruvbox.css @@ -0,0 +1,74 @@ +main { + font-family: monospace, monospace; + max-width: 38rem; + padding: 2rem; + margin: auto; +} + +@media only screen and (max-device-width: 736px) { + main { + padding: 0rem; + } +} + +::selection { + background: #d3869b; +} + +body { + background: #282828; + color: #ebdbb2; +} + +pre { + background-color: #3c3836; + padding: 1em; + border: 0; +} + +a, a:active, a:visited { + color: #b16286; + background-color: #1d2021; +} + +h1, h2, h3, h4, h5 { + margin-bottom: .1rem; +} + +blockquote { + border-left: 1px solid #bdae93; + margin: 0.5em 10px; + padding: 0.5em 10px; +} + +footer { + align: center; +} + +@media (prefers-color-scheme: light) { + body { + background: #fbf1c7; + color: #3c3836; + } + + pre { + background-color: #ebdbb2; + padding: 1em; + border: 0; + } + + a, a:active, a:visited { + color: #b16286; + background-color: #f9f5d7; + } + + h1, h2, h3, h4, h5 { + margin-bottom: .1rem; + } + + blockquote { + border-left: 1px solid #655c54; + margin: 0.5em 10px; + padding: 0.5em 10px; + } +} diff --git a/templates/bloglist.rs.html b/templates/bloglist.rs.html new file mode 100644 index 0000000..98cd171 --- /dev/null +++ b/templates/bloglist.rs.html @@ -0,0 +1,19 @@ +@use crate::blog::post::Post; +@use super::{header_html, footer_html}; + +@(posts: Vec<Post>) + +@:header_html(Some("Posts"), None) + +<h1>Posts</h1> + +<p> +<ul> + @for post in posts { + <li>@post.date.format("%B %d %Y") - + <a href="/@post.link">@post.front_matter.title</a></li> + } +</ul> +</p> + +@:footer_html() diff --git a/templates/footer.rs.html b/templates/footer.rs.html index 5029544..1574a50 100644 --- a/templates/footer.rs.html +++ b/templates/footer.rs.html @@ -1,12 +1,12 @@ @() -</div> -<hr /> -<footer> + +<footer class="footer"> <blockquote>Content copyright Cara Salter 2021, based on <a href="https://github.com/Xe/site">Xe/site</a> under the Zlib license</blockquote> <p>This server runs version @env!("GIT_SHA"), located on my <a href='https://git.carathe.dev/~muirrum/site/commit/@env!("GIT_SHA")'>sourcehut</a> </footer> +</div> </body> </html> diff --git a/templates/header.rs.html b/templates/header.rs.html index afcf445..c93566c 100644 --- a/templates/header.rs.html +++ b/templates/header.rs.html @@ -1,4 +1,4 @@ -@use chrono::{DateLike, Utc}; +@use chrono::{Datelike, Utc}; @(title: Option<&str>, styles: Option<&str>) @@ -10,7 +10,16 @@ } else { <title>cara salter</title> } + <link rel="stylesheet" href="/static/gruvbox.css"> + <link rel="stylesheet" href="/static/custom.css"> + <meta name="viewport" content="width=device-width, + initial-scale=1.0"> </head> <body> <div class="container"> + <ul class="navbar"> + <li class="navbar-item"><a href="/">Home</a></li> + <li class="navbar-item"><a + href="/blog">Posts</a></li> + </ul> diff --git a/templates/index.rs.html b/templates/index.rs.html index 6e35935..d4158a1 100644 --- a/templates/index.rs.html +++ b/templates/index.rs.html @@ -1,9 +1,48 @@ -@use super::{header_html} +@use super::{header_html, footer_html}; @() @:header_html(None, None) <link rel="canonical" href="https://devcara.com"> -Test + +<div class="two-column"> + + <div class="inner-column"> + <h3>About me</h3> + I am a: + <ul> + <li>Trans woman (she/her/hers)</li> + <li>Eagle Scout</li> + <li>Software Engineer</li> + </ul> + + My interests include: + <ul> + <li>Radio</li> + <li>Event production</li> + <li>Software tinkering</li> + <li>Linux</li> + </ul> + Among other things. + + </div> + <div class="inner-column"> + <h3>Skills</h3> + <h4>Web Development</h4> + <ul> + <li>Rust (Warp)</li> + <li>Go (Gin-gonic)</li> + <li>Python (Django/Flask)</li> + </ul> + <h4>Systems Administration</h4> + <ul> + <li>Prometheus Monitoring/Alerts</li> + <li>Ansible</li> + <li>Shell scripting</li> + <li>Nginx</li> + </ul> + </div> </div> + +@:footer_html() diff --git a/templates/post.rs.html b/templates/post.rs.html new file mode 100644 index 0000000..c638bfb --- /dev/null +++ b/templates/post.rs.html @@ -0,0 +1,10 @@ +@use super::{header_html, footer_html}; +@use crate::blog::post::Post; + +@(post: Post, body: impl ToHtml) + +@:header_html(Some(&post.front_matter.title.clone()), None)) + +@body + +@:footer_html() |