diff --git a/.gitignore b/.gitignore index 0484576..b45faab 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ /target /.direnv - +/static/style.css # Added by cargo # diff --git a/Cargo.lock b/Cargo.lock index a8b4e24..3a92c16 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -156,6 +156,12 @@ dependencies = [ "generic-array", ] +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "bytes" version = "1.6.0" @@ -259,6 +265,15 @@ dependencies = [ "libc", ] +[[package]] +name = "crc32fast" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" +dependencies = [ + "cfg-if", +] + [[package]] name = "crossbeam-channel" version = "0.5.12" @@ -268,6 +283,15 @@ dependencies = [ "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]] name = "crossbeam-utils" version = "0.8.19" @@ -352,6 +376,16 @@ dependencies = [ "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]] name = "fsevent-sys" version = "4.1.0" @@ -450,6 +484,15 @@ dependencies = [ "slab", ] +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -624,6 +667,15 @@ dependencies = [ "libc", ] +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + [[package]] name = "itoa" version = "1.0.11" @@ -703,8 +755,10 @@ dependencies = [ "color-eyre", "config", "futures", + "minijinja", "notify", "redact", + "sled", "tokio", "tower", "tower-http", @@ -750,6 +804,15 @@ dependencies = [ "unicase", ] +[[package]] +name = "minijinja" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7165d0e94806d52ad5295e4b54a95176d831814840bc067298ca647e1c956338" +dependencies = [ + "serde", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -863,6 +926,17 @@ version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" 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]] name = "parking_lot" version = "0.12.2" @@ -870,7 +944,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" dependencies = [ "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]] @@ -1002,6 +1090,15 @@ dependencies = [ "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]] name = "redox_syscall" version = "0.4.1" @@ -1219,6 +1316,22 @@ dependencies = [ "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]] name = "smallvec" version = "1.13.2" @@ -1308,7 +1421,7 @@ dependencies = [ "libc", "mio", "num_cpus", - "parking_lot", + "parking_lot 0.12.2", "pin-project-lite", "signal-hook-registry", "socket2", diff --git a/Cargo.toml b/Cargo.toml index 924680b..d60806f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,8 +10,10 @@ axum = { version = "0.7.5", features = ["macros", "tokio"] } color-eyre = "0.6.3" config = "0.14.0" futures = "0.3.30" +minijinja = "2.0.1" notify = "6.1.1" redact = { version = "0.1.9", features = ["serde"] } +sled = "0.34.7" tokio = { version = "1.37.0", features = ["full"] } tower = "0.4.13" tower-http = { version = "0.5.2", features = ["fs"] } diff --git a/flake.nix b/flake.nix index a9a858e..1c3eb57 100644 --- a/flake.nix +++ b/flake.nix @@ -27,6 +27,7 @@ lldb pkg-config inotify-tools + tailwindcss ]; }; diff --git a/src/main.rs b/src/main.rs index 43ea837..3b27f18 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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 std::sync::Arc; use std::{path::PathBuf, str::FromStr, sync::OnceLock}; use tokio::sync::mpsc::channel; +use tokio::sync::Mutex; use tower_http::services::ServeDir; use tower_livereload::{LiveReloadLayer, Reloader}; pub use tracing::{debug, error, info, warn}; -type Berr = Box; -type Besult = Result; +#[derive(Debug)] +struct Berr(Box); +type Besult = std::result::Result; mod observe { 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()) } +#[derive(Clone)] +struct AppState { + templates: Arc>>, +} + #[tokio::main] async fn main() -> Besult<()> { // load configuration? 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 let (rl_layer, _watcher) = live_reload_layer()?; let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap(); info!("Listening on {listener:#?}"); let router = Router::new() + .route("/", get(index)) .nest_service("/static", ServeDir::new(static_file_dir())) - .layer(rl_layer); + .layer(rl_layer) + .with_state(AppState { templates }); Ok(serve(listener, router).await?) } +async fn index(State(state): State) -> Besult> { + Ok(Html( + state + .templates + .lock() + .await + .get_template("page.html")? + .render(context!())?, + )) +} + fn live_reload_layer() -> Besult<(LiveReloadLayer, RecommendedWatcher)> { let rl_layer = LiveReloadLayer::new(); let rl = rl_layer.reloader(); @@ -90,3 +132,26 @@ fn static_file_watcher( Ok(watcher) } + +impl IntoResponse for Berr { + fn into_response(self) -> axum::http::Response { + 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 From for Berr +where + E: Into>, +{ + fn from(err: E) -> Self { + Self(err.into()) + } +} diff --git a/src/style.css b/src/style.css new file mode 100644 index 0000000..e86027e --- /dev/null +++ b/src/style.css @@ -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; + } +} \ No newline at end of file diff --git a/static/index.html b/static/index.html deleted file mode 100644 index 834bdd7..0000000 --- a/static/index.html +++ /dev/null @@ -1,2 +0,0 @@ - -Sup Dawg diff --git a/tailwind.config.js b/tailwind.config.js new file mode 100644 index 0000000..fa9e25e --- /dev/null +++ b/tailwind.config.js @@ -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: [], +} + diff --git a/templates/page.html b/templates/page.html new file mode 100644 index 0000000..f05da38 --- /dev/null +++ b/templates/page.html @@ -0,0 +1,12 @@ + + + + + Sup + + + + + + +