Browse Source

internal: Make footnotes work

Apparently, the footnotes and superscript extensions conflicted with
each other.
master
Cara Salter 3 months ago
parent
commit
8b2d12e799
  1. 22
      Cargo.lock
  2. 2
      blog/degoogling-part-one.md
  3. 40
      blog/draft/hello-world.md
  4. 14
      blog/how-to-plan-an-event.md
  5. 2
      blog/preparing-to-come-out.md
  6. 1
      blog/status-update-may.md
  7. 22
      src/blog/mod.rs
  8. 49
      src/blog/post.rs
  9. 2
      src/build.rs
  10. 33
      src/internal/markdown.rs
  11. 6
      src/internal/mod.rs
  12. 27
      src/main.rs
  13. 7
      src/misc/mod.rs
  14. 5
      statics/custom.css
  15. 18
      templates/index.rs.html

22
Cargo.lock generated

@ -268,9 +268,9 @@ dependencies = [ @@ -268,9 +268,9 @@ dependencies = [
[[package]]
name = "crc32fast"
version = "1.3.0"
version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "738c290dfaea84fc1ca15ad9c168d083b05a714e1efddd8edaab678dc28d2836"
checksum = "a2209c310e29876f7f0b2721e7e26b84aff178aa3da5d091f9bfbf47669e60e3"
dependencies = [
"cfg-if",
]
@ -896,6 +896,15 @@ dependencies = [ @@ -896,6 +896,15 @@ dependencies = [
"libc",
]
[[package]]
name = "num_threads"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97ba99ba6393e2c3734791401b66902d981cb03bf190af674ca69949b6d5fb15"
dependencies = [
"libc",
]
[[package]]
name = "object"
version = "0.24.0"
@ -1070,7 +1079,7 @@ dependencies = [ @@ -1070,7 +1079,7 @@ dependencies = [
"indexmap",
"line-wrap",
"serde",
"time 0.3.5",
"time 0.3.7",
"xml-rs",
]
@ -1522,12 +1531,13 @@ dependencies = [ @@ -1522,12 +1531,13 @@ dependencies = [
[[package]]
name = "time"
version = "0.3.5"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41effe7cfa8af36f439fac33861b66b049edc6f9a32331e2312660529c1c24ad"
checksum = "004cbc98f30fa233c61a38bc77e96a9106e65c88f2d3bef182ae952027e5753d"
dependencies = [
"itoa 0.4.8",
"itoa 1.0.1",
"libc",
"num_threads",
]
[[package]]

2
blog/degoogling-part-one.md

@ -3,7 +3,7 @@ title: "De-Googling Part One" @@ -3,7 +3,7 @@ title: "De-Googling Part One"
date: 2020-05-25
draft: false
series:
- degoogle
- degoogle
---
Taking a look at my use of [Google](https://google.com) and their... not-great history of privacy, I've been spending my spare time over the past few years working on, if it's not possible to *completely* get off their platform, then at least minimize my use of it. <!--more-->Frankly, I think I've been fairly successful. So far I've migrated my email from Gmail to [Migadu](https://migadu.com), and I've been working more and more on using services like [Disroot's](https://disroot.org) Nextcloud instance instead of Google Drive. [DuckDuckGo](https://duckduckgo.com) has been my default search engine for the past year. Those were really the only two Google services I used.

40
blog/draft/hello-world.md

@ -1,40 +0,0 @@ @@ -1,40 +0,0 @@
---
title: Hello World
layout: false
draft: true
---
Welcome to [Hexo](https://hexo.io/)! This is your very first post. Check [documentation](https://hexo.io/docs/) for more info. If you get any problems when using Hexo, you can find the answer in [troubleshooting](https://hexo.io/docs/troubleshooting.html) or you can ask me on [GitHub](https://github.com/hexojs/hexo/issues).
## Quick Start
### Create a new post
``` bash
$ hexo new "My New Post"
```
More info: [Writing](https://hexo.io/docs/writing.html)
### Run server
``` bash
$ hexo server
```
More info: [Server](https://hexo.io/docs/server.html)
### Generate static files
``` bash
$ hexo generate
```
More info: [Generating](https://hexo.io/docs/generating.html)
### Deploy to remote sites
``` bash
$ hexo deploy
```
More info: [Deployment](https://hexo.io/docs/one-command-deployment.html)

14
blog/how-to-plan-an-event.md

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
---
title: "How to Plan a Successful Event"
date: 2021-12-10
draft: true
date: 2022-01-21
draft: false
---
Note: This is not meant to serve as a definitive "how to plan" guide. This is
@ -24,7 +24,7 @@ service providers. @@ -24,7 +24,7 @@ service providers.
## TL;DR
Write down *everything*. Even if you think it's not important. Make sure that
more people than you have access to it. Give as much detail as you can to your
service providers.
service providers. Be prepared for sudden changes on the day of the event
## First Steps: Pre-planning (T-3 months)
The absolute first thing you should do is write down what your event will be at
@ -44,7 +44,7 @@ don't know, make sure they know that you'll be changing your answer later on. @@ -44,7 +44,7 @@ don't know, make sure they know that you'll be changing your answer later on.
Pick one or two people to serve as the point(s) of contact with the reservation
manager and any service providers. Make sure that all communication flows
through them. I can't tell you how many times I've receive conflicting
through them. I can't tell you how many times I've received conflicting
information because the planning team all emailed different documents. It's so
much easier to just have one or two people giving the same information.
@ -54,6 +54,7 @@ would go well with it? For each part, figure out: @@ -54,6 +54,7 @@ would go well with it? For each part, figure out:
- If it needs any special materials or equipment
- If it does, who will be providing it?
- Who will be in charge of making sure it happens
- What needs to happen for this to be included
Try not to overload yourself or your team with too many separate parts. Try to
keep the total number of components to around 2 per planning team member. Any
@ -63,7 +64,7 @@ Your event should have a way for all volunteers to see the status of tasks @@ -63,7 +64,7 @@ Your event should have a way for all volunteers to see the status of tasks
across the whole event and filter to certain parts. As tasks are completed, the
task owner should update the status and close it out. You can use a Trello
board, a spreadsheet, or anything else that might help you keep track of
everything.
everything. When I planned my FLL qualifier, myself and the rest of the event team had a Google Sheet that we would use to keep track of everything, with columns for the task, who it was assigned to, and when it was completed. We used the same sheet for every stage of the planning and execution process, with different tabs for "Pre-Event Tasks", "Event Setup", and "Post-Event Tasks". We also tracked the volunteers we had assigned to roles here.
This is the proper time to reach out to any service providers you may need. If
you need lighting or sound, figure out a good company or other organization that
@ -99,6 +100,9 @@ little bit, gather your planning team again. Go through your lists of roses @@ -99,6 +100,9 @@ little bit, gather your planning team again. Go through your lists of roses
into a post-mortem and share it with the entire team. Keep it around, so that
future teams can have a reference.
This is not at all tailored for a specific kind of event, but it is experience gathered over my time working on both sides of events.
[^1]: WPI Annual VEX Event
[^2]: Lens and Lights - a WPI club providing lighting, sound, and projection
services to the WPI community

2
blog/preparing-to-come-out.md

@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
title: "Preparing to Come Out"
date: 2021-04-26
series:
- coming-out
- coming-out
---
I've written about changing your deadname with Git [before](/blog/2021/3/on-deadnames-and-git), but I haven't written about how to _come out_ to other people. I'm getting ready to go to college in the fall, so I'm continuing this series as I go through the steps to come out not just to my family, but to my college and friends.

1
blog/status-update-may.md

@ -1,7 +1,6 @@ @@ -1,7 +1,6 @@
---
title: "Status Update: May 2020"
date: 2020-05-18
lastmod: 2020-05-18T16:04:30-04:00
draft: false
series:
- status

22
src/blog/mod.rs

@ -1,21 +1,20 @@ @@ -1,21 +1,20 @@
pub mod post;
pub mod handlers {
use std::sync::Arc;
use color_eyre::eyre::eyre;
use color_eyre::eyre::eyre;
use std::sync::Arc;
use warp::{Reply, Rejection};
use warp::http::Response;
use crate::templates::{self, Html, RenderRucte};
use crate::templates::{self, Html, RenderRucte};
use warp::http::Response;
use warp::{Rejection, Reply};
use crate::internal::SiteState;
use crate::internal::SiteState;
use super::post::Post;
use super::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.blog.clone()))
Response::builder().html(|o| templates::bloglist_html(o, state.blog.clone()))
}
pub async fn post(name: String, state: Arc<SiteState>) -> Result<impl Reply, Rejection> {
@ -31,9 +30,8 @@ use super::post::Post; @@ -31,9 +30,8 @@ use super::post::Post;
match want {
Some(post) => {
let body = Html(post.body_html.clone());
Response::builder()
.html(|o| templates::post_html(o, post, body))
},
Response::builder().html(|o| templates::post_html(o, post, body))
}
None => panic!("No post found"),
}
}

49
src/blog/post.rs

@ -1,11 +1,10 @@ @@ -1,11 +1,10 @@
use std::{cmp::Ordering, path::PathBuf};
use color_eyre::eyre::{eyre, Context, Result};
use glob::glob;
use color_eyre::eyre::{Result, Context, eyre};
use tokio::{fs};
use std::{cmp::Ordering, path::PathBuf};
use tokio::fs;
use chrono::prelude::*;
#[derive(Eq, PartialEq, Debug, Clone)]
pub struct Post {
pub front_matter: frontmatter::Data,
@ -42,20 +41,24 @@ async fn read_post(dir: &str, fname: PathBuf) -> Result<Post> { @@ -42,20 +41,24 @@ async fn read_post(dir: &str, fname: PathBuf) -> Result<Post> {
let link = format!("{}/{}", dir, fname.file_stem().unwrap().to_str().unwrap());
let body_html = crate::internal::markdown::render(&body)
.wrap_err_with(|| format!("can't parse markdown for {:?}", fname))?;
let date: DateTime<FixedOffset> = DateTime::<Utc>::from_utc(NaiveDateTime::new(date, NaiveTime::from_hms(0,0,0)), Utc)
.with_timezone(&Utc)
.into();
let author = &front_matter.clone().author.unwrap_or("Cara Salter".to_string());
let date: DateTime<FixedOffset> =
DateTime::<Utc>::from_utc(NaiveDateTime::new(date, NaiveTime::from_hms(0, 0, 0)), Utc)
.with_timezone(&Utc)
.into();
let author = &front_matter
.clone()
.author
.unwrap_or("Cara Salter".to_string());
let draft = &front_matter.clone().draft.unwrap_or(false);
Ok(Post {
front_matter,
body_html,
link,
link,
date,
author: author.clone(),
draft: draft.clone(),
} )
})
}
pub async fn load(dir: &str) -> Result<Vec<Post>> {
@ -78,12 +81,12 @@ pub async fn load(dir: &str) -> Result<Vec<Post>> { @@ -78,12 +81,12 @@ pub async fn load(dir: &str) -> Result<Vec<Post>> {
result.sort();
result.reverse();
Ok(result)
}
}
}
mod frontmatter {
use serde::{Serialize, Deserialize};
use color_eyre::eyre::Result;
use serde::{Deserialize, Serialize};
#[derive(Eq, PartialEq, Deserialize, Default, Debug, Serialize, Clone)]
pub struct Data {
pub title: String,
@ -129,19 +132,17 @@ mod frontmatter { @@ -129,19 +132,17 @@ mod frontmatter {
count: 1,
end: false,
};
},
'\n' | '\t' | ' ' => {
},
}
'\n' | '\t' | ' ' => {}
_ => {
panic!("Start of frontmatter not found!");
}
},
ParseState::ReadingMark {count, end } => match ch {
ParseState::ReadingMark { count, end } => match ch {
'-' => {
*count += 1;
if *count == 3 {
state = ParseState::SkipNewLine{ end: *end };
state = ParseState::SkipNewLine { end: *end };
}
}
_ => {
@ -159,29 +160,29 @@ mod frontmatter { @@ -159,29 +160,29 @@ mod frontmatter {
line_start: true,
};
}
},
_ => {
}
_ => {
panic!("Expected newline, got {:?}", ch);
}
},
ParseState::ReadingFM { buf, line_start } => match ch {
'-' if *line_start => {
let mut state_tmp = ParseState::ReadingMark {
let mut state_tmp = ParseState::ReadingMark {
count: 1,
end: true,
};
std::mem::swap(&mut state, &mut state_tmp);
if let ParseState::ReadingFM {buf, ..} = state_tmp {
if let ParseState::ReadingFM { buf, .. } = state_tmp {
payload = Some(buf);
} else {
unreachable!();
}
},
}
ch => {
buf.push(ch);
*line_start = ch == '\n';
}
}
},
}
}

2
src/build.rs

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
use std::process::Command;
use ructe::{Ructe, RucteError};
use std::process::Command;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut ructe = Ructe::from_env()?;

33
src/internal/markdown.rs

@ -1,28 +1,33 @@ @@ -1,28 +1,33 @@
use color_eyre::{Result, eyre::Context};
use comrak::{ComrakOptions, Arena, parse_document, format_html, markdown_to_html};
use color_eyre::{eyre::Context, Result};
use comrak::{format_html, nodes::AstNode, parse_document, Arena, ComrakOptions};
pub fn render(inp: &str) -> Result<String> {
let mut options = ComrakOptions::default();
options.extension.autolink = true;
options.extension.table = true;
options.extension.description_lists = true;
options.extension.superscript = true;
options.extension.strikethrough = true;
options.extension.footnotes = true;
options.render.unsafe_ = true;
info!("{:?}", options.clone());
info!("{:?}", inp.clone());
let arena = Arena::new();
let root = parse_document(&arena, inp, &options);
Ok(markdown_to_html(inp, &options))
/*
let mut html = vec![];
format_html(root, &options, &mut html).unwrap();
info!("{:?}", String::from_utf8(html.clone()));
String::from_utf8(html).wrap_err("this is somehow not UTF-8")
*/
}
/**
* Takes in a root node and a function to act on it, then recursively acts on
* all children of that node
*/
fn iter_nodes<'a, F>(node: &'a AstNode<'a>, f: &F) -> Result<()>
where
F: Fn(&'a AstNode<'a>) -> Result<()>,
{
f(node)?;
for c in node.children() {
iter_nodes(c, f)?;
}
Ok(())
}

6
src/internal/mod.rs

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
use color_eyre::eyre::Result;
use crate::blog::post::Post;
use color_eyre::eyre::Result;
pub mod markdown;
@ -10,7 +10,5 @@ pub struct SiteState { @@ -10,7 +10,5 @@ pub struct SiteState {
pub async fn init() -> Result<SiteState> {
let blog = crate::blog::post::load("blog").await?;
Ok(SiteState {
blog,
})
Ok(SiteState { blog })
}

27
src/main.rs

@ -3,13 +3,13 @@ extern crate tracing; @@ -3,13 +3,13 @@ extern crate tracing;
use color_eyre::eyre::Result;
use std::{net::IpAddr, sync::Arc};
use warp::{Filter, path};
use warp::{path, Filter};
use std::str::FromStr;
pub mod blog;
pub mod misc;
mod internal;
pub mod misc;
use internal::SiteState;
@ -19,7 +19,6 @@ async fn main() -> Result<()> { @@ -19,7 +19,6 @@ async fn main() -> Result<()> {
tracing_subscriber::fmt::init();
info!("Starting launch of {}", env!("GIT_SHA"));
// Load .env
kankyo::init();
@ -27,15 +26,19 @@ async fn main() -> Result<()> { @@ -27,15 +26,19 @@ async fn main() -> Result<()> {
let index = warp::get().and(path::end().and_then(misc::handlers::index));
let blog_index = warp::path!("blog").and(give_site_state(state.clone())).and_then(blog::handlers::list);
let blog_post = warp::path!("blog" / String).and(give_site_state(state.clone())).and_then(blog::handlers::post);
let blog_index = warp::path!("blog")
.and(give_site_state(state.clone()))
.and_then(blog::handlers::list);
let blog_post = warp::path!("blog" / String)
.and(give_site_state(state.clone()))
.and_then(blog::handlers::post);
let static_files = warp::path("static")
.and(warp::fs::dir("./statics"));
let site = index.or(blog_index.or(blog_post)).or(static_files).with(warp::log("site"));
let static_files = warp::path("static").and(warp::fs::dir("./statics"));
let site = index
.or(blog_index.or(blog_post))
.or(static_files)
.with(warp::log("site"));
let server = warp::serve(site);
@ -51,7 +54,9 @@ async fn main() -> Result<()> { @@ -51,7 +54,9 @@ async fn main() -> Result<()> {
Ok(())
}
fn give_site_state(sitestate: Arc<SiteState>) -> impl Filter<Extract = (Arc<SiteState>,), Error=std::convert::Infallible> + Clone {
fn give_site_state(
sitestate: Arc<SiteState>,
) -> impl Filter<Extract = (Arc<SiteState>,), Error = std::convert::Infallible> + Clone {
warp::any().map(move || sitestate.clone())
}

7
src/misc/mod.rs

@ -1,10 +1,9 @@ @@ -1,10 +1,9 @@
pub mod handlers {
use color_eyre::Result;
use warp::{Reply, Rejection, http::Response};
use crate::templates::{self, Html, RenderRucte};
use color_eyre::Result;
use warp::{http::Response, Rejection, Reply};
pub async fn index() -> Result<impl Reply, Rejection> {
Response::builder()
.html(|o| templates::index_html(o))
Response::builder().html(|o| templates::index_html(o))
}
}

5
statics/custom.css

@ -52,3 +52,8 @@ a { @@ -52,3 +52,8 @@ a {
.post-item {
padding: 0.5rem;
}
/* Footnotes */
.footnotes {
border-top: 1px solid;
}

18
templates/index.rs.html

@ -6,13 +6,14 @@ @@ -6,13 +6,14 @@
<link rel="canonical" href="https://devcara.com">
<h1>Cara Salter</h1>
<div class="two-column">
<div class="inner-column">
<h3>About me</h3>
I am a:
<ul>
<li>Trans woman (she/her/hers)</li>
<li>Trans woman (she/her)</li>
<li>Eagle Scout</li>
<li>Software Engineer</li>
</ul>
@ -24,7 +25,10 @@ @@ -24,7 +25,10 @@
<li>Software tinkering</li>
<li>Linux</li>
</ul>
Among other things.
Among other things. <br/><br/>
I am currently pursuing a Bachelors degree in Computer Science at
Worcester Polytechnic Institute.
</div>
<div class="inner-column">
@ -34,14 +38,22 @@ @@ -34,14 +38,22 @@
<li>Rust (Warp)</li>
<li>Go (Gin-gonic)</li>
<li>Python (Django/Flask)</li>
<li>NodeJS (Svelte)</li>
</ul>
<h4>Systems Administration</h4>
<ul>
<li>Prometheus Monitoring/Alerts</li>
<li>Prometheus & Zabbix Monitoring/Alerts</li>
<li>Ansible</li>
<li>Shell scripting</li>
<li>Nginx</li>
<li>Wireguard</li>
</ul>
<h4>Miscellaneous</h4>
<ul>
<li>Event Planning</li>
<li>Lighting Design</li>
<li>Sound Engineering</li>
</ul>
</div>
</div>

Loading…
Cancel
Save