Templating?

This commit is contained in:
Daniel Flanagan 2024-05-07 21:13:46 -05:00
parent 2295b7d5ef
commit 8dd1ffbdf5
9 changed files with 305 additions and 9 deletions

2
.gitignore vendored
View file

@ -1,6 +1,6 @@
/target /target
/.direnv /.direnv
/static/style.css
# Added by cargo # Added by cargo
# #

117
Cargo.lock generated
View file

@ -156,6 +156,12 @@ dependencies = [
"generic-array", "generic-array",
] ]
[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]] [[package]]
name = "bytes" name = "bytes"
version = "1.6.0" version = "1.6.0"
@ -259,6 +265,15 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "crc32fast"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa"
dependencies = [
"cfg-if",
]
[[package]] [[package]]
name = "crossbeam-channel" name = "crossbeam-channel"
version = "0.5.12" version = "0.5.12"
@ -268,6 +283,15 @@ dependencies = [
"crossbeam-utils", "crossbeam-utils",
] ]
[[package]]
name = "crossbeam-epoch"
version = "0.9.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
dependencies = [
"crossbeam-utils",
]
[[package]] [[package]]
name = "crossbeam-utils" name = "crossbeam-utils"
version = "0.8.19" version = "0.8.19"
@ -352,6 +376,16 @@ dependencies = [
"percent-encoding", "percent-encoding",
] ]
[[package]]
name = "fs2"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213"
dependencies = [
"libc",
"winapi",
]
[[package]] [[package]]
name = "fsevent-sys" name = "fsevent-sys"
version = "4.1.0" version = "4.1.0"
@ -450,6 +484,15 @@ dependencies = [
"slab", "slab",
] ]
[[package]]
name = "fxhash"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
dependencies = [
"byteorder",
]
[[package]] [[package]]
name = "generic-array" name = "generic-array"
version = "0.14.7" version = "0.14.7"
@ -624,6 +667,15 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "instant"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
dependencies = [
"cfg-if",
]
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "1.0.11" version = "1.0.11"
@ -703,8 +755,10 @@ dependencies = [
"color-eyre", "color-eyre",
"config", "config",
"futures", "futures",
"minijinja",
"notify", "notify",
"redact", "redact",
"sled",
"tokio", "tokio",
"tower", "tower",
"tower-http", "tower-http",
@ -750,6 +804,15 @@ dependencies = [
"unicase", "unicase",
] ]
[[package]]
name = "minijinja"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7165d0e94806d52ad5295e4b54a95176d831814840bc067298ca647e1c956338"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "minimal-lexical" name = "minimal-lexical"
version = "0.2.1" version = "0.2.1"
@ -863,6 +926,17 @@ version = "3.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f"
[[package]]
name = "parking_lot"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
dependencies = [
"instant",
"lock_api",
"parking_lot_core 0.8.6",
]
[[package]] [[package]]
name = "parking_lot" name = "parking_lot"
version = "0.12.2" version = "0.12.2"
@ -870,7 +944,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb"
dependencies = [ dependencies = [
"lock_api", "lock_api",
"parking_lot_core", "parking_lot_core 0.9.10",
]
[[package]]
name = "parking_lot_core"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc"
dependencies = [
"cfg-if",
"instant",
"libc",
"redox_syscall 0.2.16",
"smallvec",
"winapi",
] ]
[[package]] [[package]]
@ -1002,6 +1090,15 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "redox_syscall"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
dependencies = [
"bitflags 1.3.2",
]
[[package]] [[package]]
name = "redox_syscall" name = "redox_syscall"
version = "0.4.1" version = "0.4.1"
@ -1219,6 +1316,22 @@ dependencies = [
"autocfg", "autocfg",
] ]
[[package]]
name = "sled"
version = "0.34.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f96b4737c2ce5987354855aed3797279def4ebf734436c6aa4552cf8e169935"
dependencies = [
"crc32fast",
"crossbeam-epoch",
"crossbeam-utils",
"fs2",
"fxhash",
"libc",
"log",
"parking_lot 0.11.2",
]
[[package]] [[package]]
name = "smallvec" name = "smallvec"
version = "1.13.2" version = "1.13.2"
@ -1308,7 +1421,7 @@ dependencies = [
"libc", "libc",
"mio", "mio",
"num_cpus", "num_cpus",
"parking_lot", "parking_lot 0.12.2",
"pin-project-lite", "pin-project-lite",
"signal-hook-registry", "signal-hook-registry",
"socket2", "socket2",

View file

@ -10,8 +10,10 @@ axum = { version = "0.7.5", features = ["macros", "tokio"] }
color-eyre = "0.6.3" color-eyre = "0.6.3"
config = "0.14.0" config = "0.14.0"
futures = "0.3.30" futures = "0.3.30"
minijinja = "2.0.1"
notify = "6.1.1" notify = "6.1.1"
redact = { version = "0.1.9", features = ["serde"] } redact = { version = "0.1.9", features = ["serde"] }
sled = "0.34.7"
tokio = { version = "1.37.0", features = ["full"] } tokio = { version = "1.37.0", features = ["full"] }
tower = "0.4.13" tower = "0.4.13"
tower-http = { version = "0.5.2", features = ["fs"] } tower-http = { version = "0.5.2", features = ["fs"] }

View file

@ -27,6 +27,7 @@
lldb lldb
pkg-config pkg-config
inotify-tools inotify-tools
tailwindcss
]; ];
}; };

View file

@ -1,13 +1,20 @@
use axum::{serve, Router}; use axum::extract::State;
use axum::response::IntoResponse;
use axum::routing::get;
use axum::{http::StatusCode, response::Html, serve, Router};
use minijinja::{context, Environment};
use notify::{Config, RecommendedWatcher, RecursiveMode, Watcher}; use notify::{Config, RecommendedWatcher, RecursiveMode, Watcher};
use std::sync::Arc;
use std::{path::PathBuf, str::FromStr, sync::OnceLock}; use std::{path::PathBuf, str::FromStr, sync::OnceLock};
use tokio::sync::mpsc::channel; use tokio::sync::mpsc::channel;
use tokio::sync::Mutex;
use tower_http::services::ServeDir; use tower_http::services::ServeDir;
use tower_livereload::{LiveReloadLayer, Reloader}; use tower_livereload::{LiveReloadLayer, Reloader};
pub use tracing::{debug, error, info, warn}; pub use tracing::{debug, error, info, warn};
type Berr = Box<dyn std::error::Error>; #[derive(Debug)]
type Besult<T> = Result<T, Berr>; struct Berr(Box<dyn std::error::Error>);
type Besult<T> = std::result::Result<T, Berr>;
mod observe { mod observe {
pub fn setup_logging() { pub fn setup_logging() {
@ -28,23 +35,58 @@ fn static_file_dir() -> &'static PathBuf {
STATIC_FILE_DIR.get_or_init(|| PathBuf::from_str("static").unwrap()) STATIC_FILE_DIR.get_or_init(|| PathBuf::from_str("static").unwrap())
} }
#[derive(Clone)]
struct AppState {
templates: Arc<Mutex<Environment<'static>>>,
}
#[tokio::main] #[tokio::main]
async fn main() -> Besult<()> { async fn main() -> Besult<()> {
// load configuration? // load configuration?
observe::setup_logging(); observe::setup_logging();
// TODO: only start tailwind if in dev mode?
tokio::spawn(async move {
info!("Starting tailwind...");
let tw = tokio::process::Command::new("tailwindcss")
.args(["-i", "src/style.css", "-o", "static/style.css", "--watch"])
.spawn();
info!("Tailwind spawned. {tw:#?}");
});
let mut templates = Arc::new(Mutex::new(Environment::new()));
while let Some(d) = tokio::fs::read_dir("templates").await?.next_entry().await? {
templates.clone().lock().await.add_template(
d.path().to_string_lossy().as_ref(),
&std::fs::read_to_string(d.path())?,
)?;
}
// pulling the watcher into main's scope lets it live until the program dies // pulling the watcher into main's scope lets it live until the program dies
let (rl_layer, _watcher) = live_reload_layer()?; let (rl_layer, _watcher) = live_reload_layer()?;
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap(); let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
info!("Listening on {listener:#?}"); info!("Listening on {listener:#?}");
let router = Router::new() let router = Router::new()
.route("/", get(index))
.nest_service("/static", ServeDir::new(static_file_dir())) .nest_service("/static", ServeDir::new(static_file_dir()))
.layer(rl_layer); .layer(rl_layer)
.with_state(AppState { templates });
Ok(serve(listener, router).await?) Ok(serve(listener, router).await?)
} }
async fn index(State(state): State<AppState>) -> Besult<Html<String>> {
Ok(Html(
state
.templates
.lock()
.await
.get_template("page.html")?
.render(context!())?,
))
}
fn live_reload_layer() -> Besult<(LiveReloadLayer, RecommendedWatcher)> { fn live_reload_layer() -> Besult<(LiveReloadLayer, RecommendedWatcher)> {
let rl_layer = LiveReloadLayer::new(); let rl_layer = LiveReloadLayer::new();
let rl = rl_layer.reloader(); let rl = rl_layer.reloader();
@ -90,3 +132,26 @@ fn static_file_watcher(
Ok(watcher) Ok(watcher)
} }
impl IntoResponse for Berr {
fn into_response(self) -> axum::http::Response<axum::body::Body> {
error!("webserver error: {:?}", self.0);
(
StatusCode::INTERNAL_SERVER_ERROR,
format!("internal server error: {}", self.0),
)
.into_response()
}
}
// This enables using `?` on functions that return `Result<_, anyhow::Error>`
// to turn them into `Result<_, AppError>`. That way you don't need to do that
// manually.
impl<E> From<E> for Berr
where
E: Into<Box<dyn std::error::Error>>,
{
fn from(err: E) -> Self {
Self(err.into())
}
}

65
src/style.css Normal file
View file

@ -0,0 +1,65 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
:root {
/* Catppuccin Mocha */
--Rosewater: #f5e0dc;
--Flamingo: #f2cdcd;
--Pink: #f5c2e7;
--Mauve: #cba6f7;
--Red: #f38ba8;
--Maroon: #eba0ac;
--Peach: #fab387;
--Yellow: #f9e2af;
--Green: #a6e3a1;
--Teal: #94e2d5;
--Sky: #89dceb;
--Sapphire: #74c7ec;
--Blue: #89b4fa;
--Lavender: #b4befe;
--Text: #cdd6f4;
--Subtext1: #bac2de;
--Subtext0: #a6adc8;
--Overlay2: #9399b2;
--Overlay1: #7f849c;
--Overlay0: #6c7086;
--Surface2: #585b70;
--Surface1: #45475a;
--Surface0: #313244;
--Base: #1e1e2e;
--Mantle: #181825;
--Crust: #11111b;
}
@media (prefers-color-scheme: light) {
:root {
/* Catppuccin Latte */
--Rosewater: #dc8a78;
--Flamingo: #dd7878;
--Pink: #ea76cb;
--Mauve: #8839ef;
--Red: #d20f39;
--Maroon: #e64553;
--Peach: #fe640b;
--Yellow: #df8e1d;
--Green: #40a02b;
--Teal: #179299;
--Sky: #04a5e5;
--Sapphire: #209fb5;
--Blue: #1e66f5;
--Lavender: #7287fd;
--Text: #4c4f69;
--Subtext1: #5c5f77;
--Subtext0: #6c6f85;
--Overlay2: #7c7f93;
--Overlay1: #8c8fa1;
--Overlay0: #9ca0b0;
--Surface2: #acb0be;
--Surface1: #bcc0cc;
--Surface0: #ccd0da;
--Base: #eff1f5;
--Mantle: #e6e9ef;
--Crust: #dce0e8;
}
}

View file

@ -1,2 +0,0 @@
<!DOCTYPE html>
Sup Dawg

40
tailwind.config.js Normal file
View file

@ -0,0 +1,40 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ["./src/**/*.rs","./static/**/*.{html,js}"], theme: {
colors: {
rosewater: "var(--Rosewater)",
flamingo: "var(--Flamingo)",
pink: "var(--Pink)",
mauve: "var(--Mauve)",
red: "var(--Red)",
maroon: "var(--Maroon)",
peach: "var(--Peach)",
yellow: "var(--Yellow)",
green: "var(--Green)",
teal: "var(--Teal)",
sky: "var(--Sky)",
sapphire: "var(--Sapphire)",
blue: "var(--Blue)",
lavender: "var(--Lavender)",
text: "var(--Text)",
subtext1: "var(--Subtext1)",
subtext0: "var(--Subtext0)",
overlay2: "var(--Overlay2)",
overlay1: "var(--Overlay1)",
overlay0: "var(--Overlay0)",
surface2: "var(--Surface2)",
surface1: "var(--Surface1)",
surface0: "var(--Surface0)",
base: "var(--Base)",
mantle: "var(--Mantle)",
crust: "var(--Crust)",
},
extend: {
},
},
plugins: [],
}

12
templates/page.html Normal file
View file

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html>
<head>
<title>Sup</title>
<link rel="stylesheet" type="text/css" href="/static/style.css" />
</head>
<body class="bg-base text-text">
</body>
</html>