diff --git a/Cargo.lock b/Cargo.lock
index 9009c1e..89d1244 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -757,7 +757,9 @@ dependencies = [
"futures",
"minijinja",
"notify",
+ "pathdiff",
"redact",
+ "serde",
"sled",
"tokio",
"tower",
@@ -765,6 +767,7 @@ dependencies = [
"tower-livereload",
"tracing",
"tracing-subscriber",
+ "walkdir",
]
[[package]]
@@ -1232,18 +1235,18 @@ checksum = "d369a96f978623eb3dc28807c4852d6cc617fed53da5d3c400feff1ef34a714a"
[[package]]
name = "serde"
-version = "1.0.200"
+version = "1.0.201"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ddc6f9cc94d67c0e21aaf7eda3a010fd3af78ebf6e096aa6e2e13c79749cce4f"
+checksum = "780f1cebed1629e4753a1a38a3c72d30b97ec044f0aef68cb26650a3c5cf363c"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.200"
+version = "1.0.201"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "856f046b9400cee3c8c94ed572ecdb752444c24528c035cd35882aad6f492bcb"
+checksum = "c5e405930b9796f1c00bee880d03fc7e0bb4b9a11afc776885ffe84320da2865"
dependencies = [
"proc-macro2",
"quote",
diff --git a/Cargo.toml b/Cargo.toml
index b1bc9d5..a6d93d8 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -12,7 +12,9 @@ config = "0.14.0"
futures = "0.3.30"
minijinja = { version = "2.0.1", features = ["loader"] }
notify = "6.1.1"
+pathdiff = "0.2.1"
redact = { version = "0.1.9", features = ["serde"] }
+serde = "1.0.201"
sled = "0.34.7"
tokio = { version = "1.37.0", features = ["full"] }
tower = "0.4.13"
@@ -20,3 +22,4 @@ tower-http = { version = "0.5.2", features = ["fs"] }
tower-livereload = "0.9.2"
tracing = "0.1.40"
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
+walkdir = "2.5.0"
diff --git a/flake.nix b/flake.nix
index 1c3eb57..527cccd 100644
--- a/flake.nix
+++ b/flake.nix
@@ -28,6 +28,7 @@
pkg-config
inotify-tools
tailwindcss
+ nodePackages.typescript-language-server
];
};
diff --git a/pages/index.html.jinja b/pages/index.html.jinja
deleted file mode 100644
index afa4658..0000000
--- a/pages/index.html.jinja
+++ /dev/null
@@ -1,7 +0,0 @@
-{% extends "page.html.jinja" %}
-{% block body %}
-
Index
-
- Welcome to my awesome homepage.
-
-{% endblock %}
diff --git a/src/main.rs b/src/main.rs
index 130140b..348c07e 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -2,14 +2,11 @@ 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 minijinja::context;
use notify::{Config, RecommendedWatcher, RecursiveMode, Watcher};
-use std::process::Stdio;
-use std::sync::Arc;
use std::{path::PathBuf, str::FromStr, sync::OnceLock};
-use tokio::io::{AsyncBufReadExt, BufReader};
+use templates::Templates;
use tokio::sync::mpsc::channel;
-use tokio::sync::Mutex;
use tower_http::services::ServeDir;
use tower_livereload::{LiveReloadLayer, Reloader};
pub use tracing::{debug, error, event, info, span, warn, Level};
@@ -18,19 +15,9 @@ pub use tracing::{debug, error, event, info, span, warn, Level};
struct Berr(Box);
type Besult = std::result::Result;
-mod observe {
- pub fn setup_logging() {
- color_eyre::install().expect("Failed to install color_eyre");
-
- let filter = tracing_subscriber::EnvFilter::builder()
- .with_default_directive(::from(
- tracing::level_filters::LevelFilter::TRACE,
- ))
- .parse_lossy("info,lyrs=trace");
-
- tracing_subscriber::fmt().with_env_filter(filter).init();
- }
-}
+mod observe;
+mod tailwind;
+mod templates;
fn static_file_dir() -> &'static PathBuf {
static STATIC_FILE_DIR: OnceLock = OnceLock::new();
@@ -39,53 +26,22 @@ fn static_file_dir() -> &'static PathBuf {
#[derive(Clone)]
struct AppState {
- templates: Arc>>,
+ templates: Templates,
}
#[tokio::main]
async fn main() -> Besult<()> {
// load configuration?
- observe::setup_logging();
+ let _setup_logging = observe::setup_logging();
+
+ // TODO: reload templates when they change? separate watcher?
+ let templates = Templates::try_load().await?;
+ let mut tt = templates.clone();
+ let templates_watcher = tt.start_watcher();
// TODO: only start tailwind if in dev mode?
- tokio::spawn(async move {
- info!("Starting tailwind...");
- match tokio::process::Command::new("tailwindcss")
- .args(["-i", "src/style.css", "-o", "static/style.css", "--watch"])
- .stdout(Stdio::piped())
- .stderr(Stdio::piped())
- .spawn()
- {
- Ok(mut tw) => {
- info!("Tailwind spawned!");
- let mut stdout_reader = BufReader::new(tw.stdout.take().unwrap()).lines();
- tokio::spawn(async move {
- while let Ok(Some(l)) = stdout_reader.next_line().await {
- if l.trim().len() > 0 {
- event!(target: "tailwind::stdout", Level::INFO, "{l}");
- }
- }
- });
- let mut stderr_reader = BufReader::new(tw.stderr.take().unwrap()).lines();
- tokio::spawn(async move {
- while let Ok(Some(l)) = stderr_reader.next_line().await {
- if l.trim().len() > 0 {
- event!(target: "tailwind::stderr", Level::INFO, "{l}");
- }
- }
- });
- }
- Err(e) => error!("Failed to spawn Tailwind: {e}"),
- }
- });
-
- let 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_owned(
- d.file_name().into_string().unwrap(),
- std::fs::read_to_string(d.path())?,
- )?;
- }
+ tokio::spawn(async { tailwind::start_watcher() });
+ tokio::spawn(async move { templates_watcher.await });
// pulling the watcher into main's scope lets it live until the program dies
let (rl_layer, _watcher) = live_reload_layer()?;
@@ -105,10 +61,8 @@ async fn index(State(state): State) -> Besult> {
Ok(Html(
state
.templates
- .lock()
- .await
- .get_template("page.html")?
- .render(context!())?,
+ .render("pages/index.html.jinja", context!())
+ .await?,
))
}
@@ -142,9 +96,7 @@ fn static_file_watcher(
watcher.watch(static_file_dir(), RecursiveMode::Recursive)?;
tokio::spawn(async move {
- info!("Recieving...");
while let Some(res) = rx.recv().await {
- info!("Recieved! {res:#?}");
match res {
Ok(event) => {
info!("fs event: {event:#?}");
diff --git a/src/observe.rs b/src/observe.rs
new file mode 100644
index 0000000..6e10124
--- /dev/null
+++ b/src/observe.rs
@@ -0,0 +1,11 @@
+pub fn setup_logging() {
+ color_eyre::install().expect("Failed to install color_eyre");
+
+ let filter = tracing_subscriber::EnvFilter::builder()
+ .with_default_directive(::from(
+ tracing::level_filters::LevelFilter::TRACE,
+ ))
+ .parse_lossy("info,lyrs=trace");
+
+ tracing_subscriber::fmt().with_env_filter(filter).init();
+}
diff --git a/src/tailwind.rs b/src/tailwind.rs
new file mode 100644
index 0000000..23080d3
--- /dev/null
+++ b/src/tailwind.rs
@@ -0,0 +1,37 @@
+use std::process::Stdio;
+use tokio::{
+ io::{AsyncBufReadExt, BufReader},
+ process::Command,
+};
+use tracing::{error, event, info, Level};
+
+pub fn start_watcher() {
+ info!("Starting tailwind...");
+ match Command::new("tailwindcss")
+ .args(["-i", "src/style.css", "-o", "static/style.css", "--watch"])
+ .stdout(Stdio::piped())
+ .stderr(Stdio::piped())
+ .spawn()
+ {
+ Ok(mut tw) => {
+ info!("Tailwind spawned!");
+ let mut stdout_reader = BufReader::new(tw.stdout.take().unwrap()).lines();
+ tokio::spawn(async move {
+ while let Ok(Some(l)) = stdout_reader.next_line().await {
+ if l.trim().len() > 0 {
+ event!(target: "tailwind::stdout", Level::INFO, "{l}");
+ }
+ }
+ });
+ let mut stderr_reader = BufReader::new(tw.stderr.take().unwrap()).lines();
+ tokio::spawn(async move {
+ while let Ok(Some(l)) = stderr_reader.next_line().await {
+ if l.trim().len() > 0 {
+ event!(target: "tailwind::stderr", Level::INFO, "{l}");
+ }
+ }
+ });
+ }
+ Err(e) => error!("Failed to spawn Tailwind: {e}"),
+ }
+}
diff --git a/src/templates.rs b/src/templates.rs
new file mode 100644
index 0000000..b1b0c03
--- /dev/null
+++ b/src/templates.rs
@@ -0,0 +1,68 @@
+use std::sync::Arc;
+
+use minijinja::Environment;
+use pathdiff::diff_paths;
+use tokio::sync::Mutex;
+use tracing::info;
+
+#[derive(Clone)]
+pub struct Templates {
+ env: Arc>>,
+}
+
+pub type Error = Box;
+
+impl Templates {
+ pub fn empty() -> Self {
+ let env = Arc::new(Mutex::new(Environment::new()));
+ Self { env }
+ }
+
+ pub async fn try_load() -> Result {
+ let mut result = Self::empty();
+ result.load_env().await?;
+ Ok(result)
+ }
+
+ pub async fn start_watcher(&mut self) {
+ info!("TODO: Implement template watcher");
+ }
+
+ pub async fn load_env(&mut self) -> Result<(), Error> {
+ info!("Loading templates...");
+ for d in walkdir::WalkDir::new("src/templates") {
+ match d {
+ Ok(d) => {
+ if d.file_type().is_dir() {
+ continue;
+ }
+ let filename: String = diff_paths(d.path(), "src/templates")
+ .unwrap()
+ .to_string_lossy()
+ .into_owned();
+ info!("Loading template {filename:#?} ({d:#?})");
+ self.env
+ .clone()
+ .lock()
+ .await
+ .add_template_owned(filename, std::fs::read_to_string(d.path())?)?;
+ }
+ Err(_) => todo!(),
+ }
+ }
+ info!("Done loading templates!");
+ Ok(())
+ }
+
+ pub async fn render(
+ &self,
+ template_name: &str,
+ context: S,
+ ) -> Result {
+ self.env
+ .lock()
+ .await
+ .get_template(template_name)?
+ .render(context)
+ }
+}
diff --git a/templates/page.html.jinja b/src/templates/page.html.jinja
similarity index 100%
rename from templates/page.html.jinja
rename to src/templates/page.html.jinja
diff --git a/src/templates/pages/index.html.jinja b/src/templates/pages/index.html.jinja
new file mode 100644
index 0000000..796b34b
--- /dev/null
+++ b/src/templates/pages/index.html.jinja
@@ -0,0 +1,7 @@
+{% extends "page.html.jinja" %}
+{% block body %}
+ Index
+
+ Welcome to my awesome homepage!
+
+{% endblock %}
diff --git a/tailwind.config.js b/tailwind.config.js
index fa9e25e..fdc6d81 100644
--- a/tailwind.config.js
+++ b/tailwind.config.js
@@ -1,38 +1,35 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
- content: ["./src/**/*.rs","./static/**/*.{html,js}"], theme: {
+ content: ["./src/**/*"], 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)",
-
+ 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: [],