Templating?
This commit is contained in:
parent
2295b7d5ef
commit
8dd1ffbdf5
9 changed files with 305 additions and 9 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,6 +1,6 @@
|
|||
/target
|
||||
/.direnv
|
||||
|
||||
/static/style.css
|
||||
|
||||
# Added by cargo
|
||||
#
|
||||
|
|
117
Cargo.lock
generated
117
Cargo.lock
generated
|
@ -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",
|
||||
|
|
|
@ -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"] }
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
lldb
|
||||
pkg-config
|
||||
inotify-tools
|
||||
tailwindcss
|
||||
];
|
||||
};
|
||||
|
||||
|
|
73
src/main.rs
73
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<dyn std::error::Error>;
|
||||
type Besult<T> = Result<T, Berr>;
|
||||
#[derive(Debug)]
|
||||
struct Berr(Box<dyn std::error::Error>);
|
||||
type Besult<T> = std::result::Result<T, Berr>;
|
||||
|
||||
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<Mutex<Environment<'static>>>,
|
||||
}
|
||||
|
||||
#[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<AppState>) -> Besult<Html<String>> {
|
||||
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<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
65
src/style.css
Normal 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;
|
||||
}
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
Sup Dawg
|
40
tailwind.config.js
Normal file
40
tailwind.config.js
Normal 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
12
templates/page.html
Normal 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>
|
Loading…
Reference in a new issue