diff options
author | Cara Salter <cara@devcara.com> | 2021-12-22 01:06:39 -0500 |
---|---|---|
committer | Cara Salter <cara@devcara.com> | 2021-12-22 01:06:39 -0500 |
commit | 3d7cd8a7addd86b7a97a50821eb348345e0d427a (patch) | |
tree | 875aecda597c8161359005c33a147097fa36c807 | |
parent | c4d7f8f50d53057005d6bb28ac487f69ea45bd5e (diff) | |
download | site-3d7cd8a7addd86b7a97a50821eb348345e0d427a.tar.gz site-3d7cd8a7addd86b7a97a50821eb348345e0d427a.zip |
Work for the day
Post parsing, index page, navbar, CSS, blog listings
There's something weird with the path matching that's making it miss the
post view page in favor of the list view page.
-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() |