diff --git a/Cargo.lock b/Cargo.lock index dd1bd86..94bfa3b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -335,56 +335,6 @@ dependencies = [ "libc", ] -[[package]] -name = "anstream" -version = "0.6.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" - -[[package]] -name = "anstyle-parse" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882" -dependencies = [ - "anstyle", - "once_cell_polyfill", - "windows-sys 0.59.0", -] - [[package]] name = "anyhow" version = "1.0.98" @@ -689,46 +639,6 @@ dependencies = [ "stacker", ] -[[package]] -name = "clap" -version = "4.5.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f" -dependencies = [ - "clap_builder", - "clap_derive", -] - -[[package]] -name = "clap_builder" -version = "4.5.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e" -dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim", -] - -[[package]] -name = "clap_derive" -version = "4.5.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn 2.0.103", -] - -[[package]] -name = "clap_lex" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" - [[package]] name = "color-eyre" version = "0.6.5" @@ -756,12 +666,6 @@ dependencies = [ "tracing-error", ] -[[package]] -name = "colorchoice" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" - [[package]] name = "concurrent-queue" version = "2.5.0" @@ -1720,12 +1624,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "is_terminal_polyfill" -version = "1.70.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" - [[package]] name = "itoa" version = "1.0.15" @@ -2132,12 +2030,6 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" -[[package]] -name = "once_cell_polyfill" -version = "1.70.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" - [[package]] name = "openssl" version = "0.10.73" @@ -3202,7 +3094,7 @@ dependencies = [ ] [[package]] -name = "tfcsite" +name = "tfcapi" version = "0.1.0" dependencies = [ "actix-cors", @@ -3211,7 +3103,6 @@ dependencies = [ "actix-rt", "actix-web", "async-std", - "clap", "color-eyre", "env_logger", "futures", @@ -3588,12 +3479,6 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" -[[package]] -name = "utf8parse" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" - [[package]] name = "uuid" version = "1.17.0" diff --git a/Cargo.toml b/Cargo.toml index 0d64ed5..d46a7bc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "tfcsite" +name = "tfcapi" version = "0.1.0" edition = "2021" @@ -32,7 +32,6 @@ tracing-actix-web = "0.7.14" color-eyre = "0.6.3" pretty_assertions = "1.4.1" sqlx = { version = "0.8.2", features = ["sqlite"] } -clap = { version = "4.5.40", features = ["derive"] } [profile.dev] opt-level = 0 diff --git a/config.toml b/config.toml index 1d24237..d8a7357 100644 --- a/config.toml +++ b/config.toml @@ -1,7 +1,5 @@ # The base URL of the site; the only required configuration variable. -# base_url = "https://tfcconnection.org" -# used when developing -base_url = "/" +base_url = "https://tfcconnection.org" # The site title and description; used in feeds by default. title = "TFC Connection" @@ -125,7 +123,7 @@ include_content = true # become too big to load on the site. Defaults to not being set. truncate_content_length = 100 -index_format = "elasticlunr_javascript" +index_format = "elasticlunr_json" # Optional translation object for the default language # Example: @@ -162,7 +160,6 @@ taxonomies = [ # [extra] enable_search = true -enable_sidebar = false [extra.navbar] diff --git a/content/_index.md b/content/_index.md index 1c45e2f..b4787e2 100644 --- a/content/_index.md +++ b/content/_index.md @@ -22,10 +22,10 @@ Fill out now! -{{ spacing(height="h-8") }} +{{ spacing(height="h-4") }} > If you need to fill out a camp health form, please do so [here](/camp-health-form). -{{ spacing(height="h-4") }} + > If you need to pay for your camp form, pay for registration ($100) [here](https://secure.myvanco.com/L-Z772/campaign/C-13JPJ) or pay for the full price ($200) [here](https://secure.myvanco.com/L-Z772/campaign/C-13JQE). {{ spacing(height="h-8") }} diff --git a/flake.nix b/flake.nix index 232cc95..34e4dbd 100644 --- a/flake.nix +++ b/flake.nix @@ -66,13 +66,15 @@ # cp -r ${blowfish} themes/blowfish # ls themes/blowfish # ''; - buildPhase = '' - ${pkgs.tailwindcss_4}/bin/tailwindcss -i static/css/base.css -o static/css/main.css - ${pkgs.zola}/bin/zola build - ''; - installPhase = '' - cp -r public $out/ - ''; + # buildPhase = '' + # NODE_ENV=production ./themes/blowfish/node_modules/tailwindcss/lib/cli.js -c ./themes/blowfish/tailwind.config.js -i ./themes/blowfish/assets/css/main.css -o ./assets/css/compiled/main.css --jit && hugo --gc --minify + # ${pkgs.hugo}/bin/hugo --minify + # ''; + # installPhase = '' + # ls -l + # cp -r public $out/ + # ls -l $out + # ''; buildInputs = bi; nativeBuildInputs = nbi; }; diff --git a/justfile b/justfile index b933bc9..5a39c36 100644 --- a/justfile +++ b/justfile @@ -3,7 +3,7 @@ default: build: tailwindcss -i static/css/base.css -o static/css/main.css && zola build serve: - zola serve -p 4242 + zola serve uglify: uglifyjs ./src/js/main.js --compress --mangle -o ./static/js/main.js && uglifyjs ./src/js/page.js --compress --mangle -o ./static/js/page.js && uglifyjs ./src/js/search.js --compress --mangle -o ./static/js/search.js && uglifyjs ./src/js/lang.js --compress --mangle -o ./static/js/lang.js dev: @@ -14,5 +14,3 @@ clean: cargo clean test: RUST_LOG=debug cargo test --benches --tests --all-features -- --nocapture -run: - tailwindcss -i static/css/base.css -o static/css/main.css --watch & zola build && cargo run -- -d diff --git a/src/api/camp_form.rs b/src/api/camp_form.rs index d82a5be..73937a8 100644 --- a/src/api/camp_form.rs +++ b/src/api/camp_form.rs @@ -6,8 +6,8 @@ use color_eyre::eyre::{Context, Result}; use futures::FutureExt; use lettre::{message::SinglePart, Message}; use maud::{html, Markup, DOCTYPE}; -use reqwest::{Client, Response}; -use tracing::{debug, error, info}; +use reqwest::Client; +use tracing::{error, info}; #[derive(Debug, MultipartForm)] struct CampForm { @@ -39,30 +39,27 @@ struct CampForm { health_form: Text, } -impl From<&CampForm> for HashMap<&str, String> { +impl From<&CampForm> for HashMap { fn from(form: &CampForm) -> Self { let mut map = HashMap::new(); + map.insert(63, format!("{} {}", form.first_name.0, form.last_name.0)); map.insert( - "Full_Name", - format!("{} {}", form.first_name.0, form.last_name.0), - ); - map.insert( - "Parent_Name", + 64, format!("{} {}", form.parent_first_name.0, form.parent_last_name.0), ); - map.insert("Parent_Phone", form.parent_phone.0.clone()); - map.insert("Parent_Email", form.parent_email.0.clone().clone()); - map.insert("Birth_Date", form.birthdate.0.clone()); - map.insert("Gender", form.gender.0.clone()); - map.insert("Street_Address", form.street.0.clone()); - map.insert("City", form.city.0.clone()); - map.insert("State", form.state.0.clone()); - map.insert("Zipcode", form.zip.0.clone().to_string()); - map.insert("Grade", form.grade.0.clone()); - map.insert("Week_Chosen", form.week.0.clone()); - map.insert("Shirt_Size", form.shirt.0.clone()); - map.insert("Registration", form.registration.0.clone()); - map.insert("Health_Form", form.health_form.0.clone()); + map.insert(65, form.parent_phone.0.clone()); + map.insert(66, form.parent_email.0.clone().clone()); + map.insert(67, form.birthdate.0.clone()); + map.insert(69, form.gender.0.clone()); + map.insert(70, form.street.0.clone()); + map.insert(71, form.city.0.clone()); + map.insert(72, form.state.0.clone()); + map.insert(73, form.zip.0.clone().to_string()); + map.insert(74, form.grade.0.clone()); + map.insert(75, form.week.0.clone()); + map.insert(76, form.shirt.0.clone()); + map.insert(77, form.registration.0.clone()); + map.insert(115, form.health_form.0.clone()); map } } @@ -295,21 +292,19 @@ pub async fn camp_form(MultipartForm(form): MultipartForm) -> HttpResp } } -async fn store_camp_form(map: HashMap<&str, String>) -> Result { +async fn store_camp_form(map: HashMap) -> Result<()> { let request = Client::new(); let mut json = HashMap::new(); - let mut fields = HashMap::new(); - fields.insert("fields", map); - json.insert("records", vec![fields]); - let response = request - .post("https://table.tfcconnection.org/api/docs/e8SFoTHpmJuFQsiMhRTXCi/tables/Camp_Data/records") - .bearer_auth("b8189d1b315548aa610db2fd3a43177a967cd41f") + json.insert("data", map); + request + .post("https://staff.tfcconnection.org/apps/tables/api/1/tables/5/rows") + .basic_auth("chris", Some("2VHeGxeC^Zf9KqFK^G@Pt!zu2q^6@b")) + .header("OCS-APIRequest", "true") .header("Content-Type", "application/json") .json(&json) .send() .await?; - debug!(?response); - Ok(response) + Ok(()) } #[cfg(test)] @@ -334,7 +329,7 @@ mod test { grade: Text(String::from("junior")), shirt: Text(String::from("medium")), allergies: Text(String::from("Cool beans")), - week: Text(String::from("week1")), + week: Text(String::from("1")), registration: Text(String::from("later")), health_form: Text(String::from("I guess")), } @@ -347,7 +342,7 @@ mod test { let map = HashMap::from(&form); let res = store_camp_form(map).await; match res { - Ok(r) => assert!(r.status().is_success(), "Failed to store: {:?}", r), + Ok(_) => assert!(true), Err(e) => assert!(false, "Failed storing test: {e}"), } } diff --git a/src/api/health_form.rs b/src/api/health_form.rs index d2f0300..5196a0a 100644 --- a/src/api/health_form.rs +++ b/src/api/health_form.rs @@ -12,7 +12,7 @@ use lettre::{ Message, }; use maud::{html, Markup, DOCTYPE}; -use reqwest::{Client, Response}; +use reqwest::Client; use tracing::{error, info}; use crate::email::send_email; @@ -75,46 +75,40 @@ struct HealthForm { registration: Text, } -impl From<&HealthForm> for HashMap<&str, String> { +impl From<&HealthForm> for HashMap { fn from(form: &HealthForm) -> Self { let mut map = HashMap::new(); + map.insert(37, format!("{} {}", form.first_name.0, form.last_name.0)); map.insert( - "Student_Name", - format!("{} {}", form.first_name.0, form.last_name.0), - ); - map.insert( - "Parent_Name", + 38, format!("{} {}", form.parent_first_name.0, form.parent_last_name.0), ); - map.insert("Birthdate", form.birthdate.0.clone()); - map.insert("Street", form.street.0.clone()); - map.insert("City", form.city.0.clone()); - map.insert("State", form.state.0.clone()); - map.insert("Zipcode", form.zip.0.clone()); - map.insert("Parent_Phone", form.parent_cellphone.0.clone()); - map.insert("Homephone", form.homephone.0.clone()); + map.insert(39, form.birthdate.0.clone()); + map.insert(40, form.street.0.clone()); + map.insert(41, form.city.0.clone()); + map.insert(42, form.state.0.clone()); + map.insert(43, form.zip.0.clone()); + map.insert(44, form.parent_cellphone.0.clone()); + map.insert(45, form.homephone.0.clone()); + map.insert(46, format!("{} {}", form.contact.0, form.contact_phone.0)); + map.insert(47, form.doctorname.0.clone()); + map.insert(48, form.doctorcity.0.clone()); + map.insert(49, form.doctorphone.0.clone()); + map.insert(50, form.medical.0.clone()); + map.insert(51, form.insurance.0.clone()); + map.insert(52, form.policy_number.0.clone()); + map.insert(54, form.agreement.0.clone()); map.insert( - "Emergency_Contact", - format!("{} {}", form.contact.0, form.contact_phone.0), - ); - map.insert("Doctor", form.doctorname.0.clone()); - map.insert("Doctor_City", form.doctorcity.0.clone()); - map.insert("Doctor_Phone", form.doctorphone.0.clone()); - map.insert("Medical_Coverage", form.medical.0.clone()); - map.insert("Insurance_Name", form.insurance.0.clone()); - map.insert("Policy_Number", form.policy_number.0.clone()); - map.insert("Agreement", form.agreement.0.clone()); - map.insert( - "Allergies", + 55, format!("{} \n {}", form.allergies.0, form.allergies_other.0), ); - map.insert("Specific_Allergies", form.specific_allergies.0.clone()); - map.insert("Allergic_Treatments", form.treatment.0.clone()); - map.insert("Conditions", form.conditions.0.clone()); - map.insert("Tetanus_Shot_Date", form.tetanus.0.clone()); - map.insert("Medication_Schedule", form.medication.0.clone()); - map.insert("Other_Notes", form.notes.0.clone()); - map.insert("Swimming_Ability", form.swimming.0.clone()); + map.insert(56, form.specific_allergies.0.clone()); + map.insert(57, form.treatment.0.clone()); + map.insert(58, form.conditions.0.clone()); + map.insert(59, form.tetanus.0.clone()); + map.insert(60, form.medication.0.clone()); + map.insert(61, form.notes.0.clone()); + map.insert(62, form.swimming.0.clone()); map } } @@ -437,22 +431,22 @@ pub async fn health_form(MultipartForm(mut form): MultipartForm) -> // HttpResponse::Ok().body("hi") } -async fn store_form(map: HashMap<&str, String>) -> Result { +async fn store_form(map: HashMap) -> Result<()> { let client = Client::new(); let mut json = HashMap::new(); - let mut fields = HashMap::new(); - fields.insert("fields", map); - json.insert("records", vec![fields]); + json.insert("data", map); let res = client - .post("https://table.tfcconnection.org/api/docs/e8SFoTHpmJuFQsiMhRTXCi/tables/Health_Data/records") - .bearer_auth("b8189d1b315548aa610db2fd3a43177a967cd41f") + .post("https://staff.tfcconnection.org/ocs/v2.php/apps/tables/api/2/tables/4/rows") + .basic_auth("chris", Some("2VHeGxeC^Zf9KqFK^G@Pt!zu2q^6@b")) + .header("OCS-APIRequest", "true") .header("Content-Type", "application/json") .json(&json) .send() .await?; if res.status().is_success() { - Ok(res) + let res = res.text().await.unwrap(); + Ok(()) } else { Err(eyre!( "Problem in storing data: {:?}", @@ -460,69 +454,3 @@ async fn store_form(map: HashMap<&str, String>) -> Result { )) } } - -#[cfg(test)] -mod test { - use super::*; - use actix_web::test; - - fn form() -> HealthForm { - HealthForm { - first_name: Text("Frodo".into()), - last_name: Text("Braggins".into()), - parent_first_name: Text("Bilbo".into()), - parent_last_name: Text("Braggins".into()), - birthdate: Text(String::from("1845-09-12")), - street: Text(String::from("1234 Bag End")), - city: Text(String::from("The Shire")), - state: Text(String::from("Hobbiton")), - zip: Text(String::from("88888")), - allergies: Text(String::from("Cool beans")), - registration: Text(String::from("later")), - parent_cellphone: Text(String::from("later")), - homephone: Text("test".into()), - contact: Text("test".into()), - contact_phone: Text("test".into()), - doctorname: Text("test".into()), - doctorcity: Text("test".into()), - doctorphone: Text("test".into()), - medical: Text("test".into()), - insurance: Text("test".into()), - policy_number: Text("test".into()), - allergies_other: Text("test".into()), - specific_allergies: Text("test".into()), - treatment: Text("test".into()), - conditions: Text("test".into()), - tetanus: Text("test".into()), - swimming: Text("test".into()), - medication: Text("test".into()), - notes: Text("test".into()), - agreement: Text("test".into()), - file: None, - } - } - - #[test] - async fn test_nc_post() { - let form = form(); - assert!(!form.first_name.is_empty()); - let map = HashMap::from(&form); - let res = store_form(map).await; - match res { - Ok(r) => assert!(r.status().is_success(), "Failed to store: {:?}", r), - Err(e) => assert!(false, "Failed storing test: {e}"), - } - } - - #[test] - async fn test_email() { - let mut form = form(); - assert!(!form.first_name.is_empty()); - match form.send_email() { - Ok(m) => { - assert!(crate::email::send_email(m).await.is_ok()) - } - Err(e) => assert!(false, "Failed emailing test: {e}"), - } - } -} diff --git a/src/main.rs b/src/main.rs index 9b9a00c..9c8e783 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,7 +7,7 @@ use actix_web::body::MessageBody; use actix_web::dev::{ServiceRequest, ServiceResponse}; use actix_web::{web, App, Error, HttpServer}; use api::camp_form::camp_form; -use api::contact::contact_form; +use api::contact::{self, contact_form}; use api::health_form::health_form; use api::local_trip_form::local_form; use api::mt_form::mt_form; @@ -15,7 +15,6 @@ use api::{ mt_church_form::mt_church_form, mt_parent_form::mt_parent_form, mt_teacher_form::mt_teacher_form, }; -use clap::Parser; use color_eyre::eyre::Context; use color_eyre::Result; use sqlx::{Connection, SqliteConnection}; @@ -46,65 +45,46 @@ impl RootSpanBuilder for DomainRootSpanBuilder { fn on_request_end(_span: Span, _outcome: &Result, Error>) {} } -#[derive(Debug, Parser)] -#[command(name = "tfcsite", version, about)] -struct Cli { - #[arg(short, long)] - dev: bool, -} - #[actix_web::main] async fn main() -> std::io::Result<()> { - let site; - let temp; - let logs; - if Cli::parse().dev { - site = "./public"; - logs = "/tmp/tfcsite"; - temp = "/tmp/tfcsite"; - } else { - site = "../public"; - logs = "/storage/logs/tfcsite"; - temp = "/tmp/tfcsite"; - } - - std::fs::create_dir_all(&logs)?; - std::fs::create_dir_all(&temp)?; - let timer = tracing_subscriber::fmt::time::ChronoLocal::new("%Y-%m-%d_%I:%M:%S%.6f %P".to_owned()); let logfile = RollingFileAppender::builder() .rotation(Rotation::DAILY) .filename_prefix("api") .filename_suffix("log") - .build(&logs) + .build(if DEV_MODE { + "/tmp/tfcsite" + } else { + "/storage/logs/tfcsite" + }) .expect("Shouldn't"); - let file_filter = EnvFilter::builder() + let filter = EnvFilter::builder() .with_default_directive(LevelFilter::WARN.into()) - .parse_lossy("tfcsite=debug"); + .parse_lossy("tfcapi=debug"); let logfile_layer = tracing_subscriber::fmt::layer() .with_writer(logfile) .with_line_number(true) .with_level(true) .with_target(true) .with_ansi(false) - .with_timer(timer.clone()) - .with_filter(file_filter); - - let stdout_filter = EnvFilter::builder() - .with_default_directive(LevelFilter::WARN.into()) - .parse_lossy("tfcsite=debug"); + .with_timer(timer.clone()); let stdout_layer = tracing_subscriber::fmt::layer() .pretty() .with_line_number(true) .with_target(true) .with_timer(timer) - .with_filter(stdout_filter); - - let subscriber = tracing_subscriber::registry().with(logfile_layer.and_then(stdout_layer)); + .with_filter(filter); + let filter = EnvFilter::builder() + .with_default_directive(LevelFilter::WARN.into()) + .parse_lossy("tfcapi=debug"); + let subscriber = tracing_subscriber::registry() + .with(logfile_layer.with_filter(filter).and_then(stdout_layer)); let _ = tracing::subscriber::set_global_default(subscriber).wrap_err("Tracing broked"); + std::fs::create_dir_all("/tmp/tfcsite")?; + info!("starting HTTP server at http://localhost:4242"); let conn = SqliteConnection::connect("sqlite://./data.db") @@ -116,7 +96,11 @@ async fn main() -> std::io::Result<()> { App::new() .app_data(data.clone()) .wrap(TracingLogger::::new()) - .app_data(TempFileConfig::default().directory(&temp)) + .app_data(TempFileConfig::default().directory(if DEV_MODE { + "/tmp/tfcsite" + } else { + "/storage/logs/tfcsite" + })) .service(mt_form) .service(health_form) .service(mt_parent_form) @@ -125,7 +109,7 @@ async fn main() -> std::io::Result<()> { .service(local_form) .service(camp_form) .service(contact_form) - .service(Files::new("/", &site).index_file("index.html")) + .service(Files::new("/", "./public").index_file("index.html")) }) .bind(("localhost", 4242))? .workers(4) diff --git a/static/css/base.css b/static/css/base.css index 3e6e3bb..b1c3020 100644 --- a/static/css/base.css +++ b/static/css/base.css @@ -27,17 +27,6 @@ li::marker { color: var(--color-gray-600); } - - blockquote { - list-style-type: disc; - border-left-width: .25rem; - border-left-color: var(--color-blue-600); - font-style: italic; - font-weight: 500; - padding-left: 1em; - margin-top: 1.6em; - margin-bottom: 1.6em; - } img { @apply py-0; diff --git a/static/css/main.css b/static/css/main.css index cd17749..d674cf8 100644 --- a/static/css/main.css +++ b/static/css/main.css @@ -7,7 +7,6 @@ 'Noto Color Emoji'; --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace; - --color-blue-200: oklch(88.2% 0.059 254.128); --color-blue-400: oklch(70.7% 0.165 254.624); --color-blue-500: oklch(62.3% 0.214 259.815); --color-blue-600: oklch(54.6% 0.245 262.881); @@ -352,6 +351,9 @@ .mt-16 { margin-top: calc(var(--spacing) * 16); } + .mt-20 { + margin-top: calc(var(--spacing) * 20); + } .mt-40 { margin-top: calc(var(--spacing) * 40); } @@ -388,9 +390,6 @@ .ml-4 { margin-left: calc(var(--spacing) * 4); } - .ml-\[-0\.2em\] { - margin-left: -0.2em; - } .ml-auto { margin-left: auto; } @@ -458,6 +457,9 @@ .h-24 { height: calc(var(--spacing) * 24); } + .h-36 { + height: calc(var(--spacing) * 36); + } .h-40 { height: calc(var(--spacing) * 40); } @@ -765,6 +767,9 @@ .bg-indigo-500 { background-color: var(--color-indigo-500); } + .bg-transparent { + background-color: transparent; + } .bg-white { background-color: var(--color-white); } @@ -942,6 +947,9 @@ .text-gray-900 { color: var(--color-gray-900); } + .text-indigo-500 { + color: var(--color-indigo-500); + } .text-white { color: var(--color-white); } @@ -1012,6 +1020,9 @@ --tw-blur: blur(8px); filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,); } + .filter { + filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,); + } .transition { transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter; transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); @@ -1187,6 +1198,13 @@ } } } + .hover\:bg-gray-100 { + &:hover { + @media (hover: hover) { + background-color: var(--color-gray-100); + } + } + } .hover\:bg-gray-200 { &:hover { @media (hover: hover) { @@ -1222,14 +1240,6 @@ } } } - .hover\:text-3xl { - &:hover { - @media (hover: hover) { - font-size: var(--text-3xl); - line-height: var(--tw-leading, var(--text-3xl--line-height)); - } - } - } .hover\:text-blue-500 { &:hover { @media (hover: hover) { @@ -1251,6 +1261,13 @@ } } } + .hover\:text-indigo-400 { + &:hover { + @media (hover: hover) { + color: var(--color-indigo-400); + } + } + } .hover\:text-white { &:hover { @media (hover: hover) { @@ -1611,11 +1628,6 @@ background-color: var(--color-gray-900); } } - .dark\:text-blue-200 { - @media (prefers-color-scheme: dark) { - color: var(--color-blue-200); - } - } .dark\:text-gray-200 { @media (prefers-color-scheme: dark) { color: var(--color-gray-200); @@ -1704,16 +1716,6 @@ li::marker { color: var(--color-gray-600); } - blockquote { - list-style-type: disc; - border-left-width: .25rem; - border-left-color: var(--color-blue-600); - font-style: italic; - font-weight: 500; - padding-left: 1em; - margin-top: 1.6em; - margin-bottom: 1.6em; - } img { padding-block: calc(var(--spacing) * 0); border-radius: var(--radius-lg); diff --git a/static/js/elasticlunr.min.js b/static/js/elasticlunr.min.js deleted file mode 100644 index 94b20dd..0000000 --- a/static/js/elasticlunr.min.js +++ /dev/null @@ -1,10 +0,0 @@ -/** - * elasticlunr - http://weixsong.github.io - * Lightweight full-text search engine in Javascript for browser search and offline search. - 0.9.5 - * - * Copyright (C) 2017 Oliver Nightingale - * Copyright (C) 2017 Wei Song - * MIT Licensed - * @license - */ -!function(){function e(e){if(null===e||"object"!=typeof e)return e;var t=e.constructor();for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n]);return t}var t=function(e){var n=new t.Index;return n.pipeline.add(t.trimmer,t.stopWordFilter,t.stemmer),e&&e.call(n,n),n};t.version="0.9.5",lunr=t,t.utils={},t.utils.warn=function(e){return function(t){e.console&&console.warn&&console.warn(t)}}(this),t.utils.toString=function(e){return void 0===e||null===e?"":e.toString()},t.EventEmitter=function(){this.events={}},t.EventEmitter.prototype.addListener=function(){var e=Array.prototype.slice.call(arguments),t=e.pop(),n=e;if("function"!=typeof t)throw new TypeError("last argument must be a function");n.forEach(function(e){this.hasHandler(e)||(this.events[e]=[]),this.events[e].push(t)},this)},t.EventEmitter.prototype.removeListener=function(e,t){if(this.hasHandler(e)){var n=this.events[e].indexOf(t);-1!==n&&(this.events[e].splice(n,1),0==this.events[e].length&&delete this.events[e])}},t.EventEmitter.prototype.emit=function(e){if(this.hasHandler(e)){var t=Array.prototype.slice.call(arguments,1);this.events[e].forEach(function(e){e.apply(void 0,t)},this)}},t.EventEmitter.prototype.hasHandler=function(e){return e in this.events},t.tokenizer=function(e){if(!arguments.length||null===e||void 0===e)return[];if(Array.isArray(e)){var n=e.filter(function(e){return null===e||void 0===e?!1:!0});n=n.map(function(e){return t.utils.toString(e).toLowerCase()});var i=[];return n.forEach(function(e){var n=e.split(t.tokenizer.seperator);i=i.concat(n)},this),i}return e.toString().trim().toLowerCase().split(t.tokenizer.seperator)},t.tokenizer.defaultSeperator=/[\s\-]+/,t.tokenizer.seperator=t.tokenizer.defaultSeperator,t.tokenizer.setSeperator=function(e){null!==e&&void 0!==e&&"object"==typeof e&&(t.tokenizer.seperator=e)},t.tokenizer.resetSeperator=function(){t.tokenizer.seperator=t.tokenizer.defaultSeperator},t.tokenizer.getSeperator=function(){return t.tokenizer.seperator},t.Pipeline=function(){this._queue=[]},t.Pipeline.registeredFunctions={},t.Pipeline.registerFunction=function(e,n){n in t.Pipeline.registeredFunctions&&t.utils.warn("Overwriting existing registered function: "+n),e.label=n,t.Pipeline.registeredFunctions[n]=e},t.Pipeline.getRegisteredFunction=function(e){return e in t.Pipeline.registeredFunctions!=!0?null:t.Pipeline.registeredFunctions[e]},t.Pipeline.warnIfFunctionNotRegistered=function(e){var n=e.label&&e.label in this.registeredFunctions;n||t.utils.warn("Function is not registered with pipeline. This may cause problems when serialising the index.\n",e)},t.Pipeline.load=function(e){var n=new t.Pipeline;return e.forEach(function(e){var i=t.Pipeline.getRegisteredFunction(e);if(!i)throw new Error("Cannot load un-registered function: "+e);n.add(i)}),n},t.Pipeline.prototype.add=function(){var e=Array.prototype.slice.call(arguments);e.forEach(function(e){t.Pipeline.warnIfFunctionNotRegistered(e),this._queue.push(e)},this)},t.Pipeline.prototype.after=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var i=this._queue.indexOf(e);if(-1===i)throw new Error("Cannot find existingFn");this._queue.splice(i+1,0,n)},t.Pipeline.prototype.before=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var i=this._queue.indexOf(e);if(-1===i)throw new Error("Cannot find existingFn");this._queue.splice(i,0,n)},t.Pipeline.prototype.remove=function(e){var t=this._queue.indexOf(e);-1!==t&&this._queue.splice(t,1)},t.Pipeline.prototype.run=function(e){for(var t=[],n=e.length,i=this._queue.length,o=0;n>o;o++){for(var r=e[o],s=0;i>s&&(r=this._queue[s](r,o,e),void 0!==r&&null!==r);s++);void 0!==r&&null!==r&&t.push(r)}return t},t.Pipeline.prototype.reset=function(){this._queue=[]},t.Pipeline.prototype.get=function(){return this._queue},t.Pipeline.prototype.toJSON=function(){return this._queue.map(function(e){return t.Pipeline.warnIfFunctionNotRegistered(e),e.label})},t.Index=function(){this._fields=[],this._ref="id",this.pipeline=new t.Pipeline,this.documentStore=new t.DocumentStore,this.index={},this.eventEmitter=new t.EventEmitter,this._idfCache={},this.on("add","remove","update",function(){this._idfCache={}}.bind(this))},t.Index.prototype.on=function(){var e=Array.prototype.slice.call(arguments);return this.eventEmitter.addListener.apply(this.eventEmitter,e)},t.Index.prototype.off=function(e,t){return this.eventEmitter.removeListener(e,t)},t.Index.load=function(e){e.version!==t.version&&t.utils.warn("version mismatch: current "+t.version+" importing "+e.version);var n=new this;n._fields=e.fields,n._ref=e.ref,n.documentStore=t.DocumentStore.load(e.documentStore),n.pipeline=t.Pipeline.load(e.pipeline),n.index={};for(var i in e.index)n.index[i]=t.InvertedIndex.load(e.index[i]);return n},t.Index.prototype.addField=function(e){return this._fields.push(e),this.index[e]=new t.InvertedIndex,this},t.Index.prototype.setRef=function(e){return this._ref=e,this},t.Index.prototype.saveDocument=function(e){return this.documentStore=new t.DocumentStore(e),this},t.Index.prototype.addDoc=function(e,n){if(e){var n=void 0===n?!0:n,i=e[this._ref];this.documentStore.addDoc(i,e),this._fields.forEach(function(n){var o=this.pipeline.run(t.tokenizer(e[n]));this.documentStore.addFieldLength(i,n,o.length);var r={};o.forEach(function(e){e in r?r[e]+=1:r[e]=1},this);for(var s in r){var u=r[s];u=Math.sqrt(u),this.index[n].addToken(s,{ref:i,tf:u})}},this),n&&this.eventEmitter.emit("add",e,this)}},t.Index.prototype.removeDocByRef=function(e){if(e&&this.documentStore.isDocStored()!==!1&&this.documentStore.hasDoc(e)){var t=this.documentStore.getDoc(e);this.removeDoc(t,!1)}},t.Index.prototype.removeDoc=function(e,n){if(e){var n=void 0===n?!0:n,i=e[this._ref];this.documentStore.hasDoc(i)&&(this.documentStore.removeDoc(i),this._fields.forEach(function(n){var o=this.pipeline.run(t.tokenizer(e[n]));o.forEach(function(e){this.index[n].removeToken(e,i)},this)},this),n&&this.eventEmitter.emit("remove",e,this))}},t.Index.prototype.updateDoc=function(e,t){var t=void 0===t?!0:t;this.removeDocByRef(e[this._ref],!1),this.addDoc(e,!1),t&&this.eventEmitter.emit("update",e,this)},t.Index.prototype.idf=function(e,t){var n="@"+t+"/"+e;if(Object.prototype.hasOwnProperty.call(this._idfCache,n))return this._idfCache[n];var i=this.index[t].getDocFreq(e),o=1+Math.log(this.documentStore.length/(i+1));return this._idfCache[n]=o,o},t.Index.prototype.getFields=function(){return this._fields.slice()},t.Index.prototype.search=function(e,n){if(!e)return[];e="string"==typeof e?{any:e}:JSON.parse(JSON.stringify(e));var i=null;null!=n&&(i=JSON.stringify(n));for(var o=new t.Configuration(i,this.getFields()).get(),r={},s=Object.keys(e),u=0;u0&&t.push(e);for(var i in n)"docs"!==i&&"df"!==i&&this.expandToken(e+i,t,n[i]);return t},t.InvertedIndex.prototype.toJSON=function(){return{root:this.root}},t.Configuration=function(e,n){var e=e||"";if(void 0==n||null==n)throw new Error("fields should not be null");this.config={};var i;try{i=JSON.parse(e),this.buildUserConfig(i,n)}catch(o){t.utils.warn("user configuration parse failed, will use default configuration"),this.buildDefaultConfig(n)}},t.Configuration.prototype.buildDefaultConfig=function(e){this.reset(),e.forEach(function(e){this.config[e]={boost:1,bool:"OR",expand:!1}},this)},t.Configuration.prototype.buildUserConfig=function(e,n){var i="OR",o=!1;if(this.reset(),"bool"in e&&(i=e.bool||i),"expand"in e&&(o=e.expand||o),"fields"in e)for(var r in e.fields)if(n.indexOf(r)>-1){var s=e.fields[r],u=o;void 0!=s.expand&&(u=s.expand),this.config[r]={boost:s.boost||0===s.boost?s.boost:1,bool:s.bool||i,expand:u}}else t.utils.warn("field name in user configuration not found in index instance fields");else this.addAllFields2UserConfig(i,o,n)},t.Configuration.prototype.addAllFields2UserConfig=function(e,t,n){n.forEach(function(n){this.config[n]={boost:1,bool:e,expand:t}},this)},t.Configuration.prototype.get=function(){return this.config},t.Configuration.prototype.reset=function(){this.config={}},lunr.SortedSet=function(){this.length=0,this.elements=[]},lunr.SortedSet.load=function(e){var t=new this;return t.elements=e,t.length=e.length,t},lunr.SortedSet.prototype.add=function(){var e,t;for(e=0;e1;){if(r===e)return o;e>r&&(t=o),r>e&&(n=o),i=n-t,o=t+Math.floor(i/2),r=this.elements[o]}return r===e?o:-1},lunr.SortedSet.prototype.locationFor=function(e){for(var t=0,n=this.elements.length,i=n-t,o=t+Math.floor(i/2),r=this.elements[o];i>1;)e>r&&(t=o),r>e&&(n=o),i=n-t,o=t+Math.floor(i/2),r=this.elements[o];return r>e?o:e>r?o+1:void 0},lunr.SortedSet.prototype.intersect=function(e){for(var t=new lunr.SortedSet,n=0,i=0,o=this.length,r=e.length,s=this.elements,u=e.elements;;){if(n>o-1||i>r-1)break;s[n]!==u[i]?s[n]u[i]&&i++:(t.add(s[n]),n++,i++)}return t},lunr.SortedSet.prototype.clone=function(){var e=new lunr.SortedSet;return e.elements=this.toArray(),e.length=e.elements.length,e},lunr.SortedSet.prototype.union=function(e){var t,n,i;this.length>=e.length?(t=this,n=e):(t=e,n=this),i=t.clone();for(var o=0,r=n.toArray();o +function toggleSearchModal(){var e=document.getElementById("search-modal");e.classList.toggle("opacity-0"),e.classList.toggle("pointer-events-none"),document.body.classList.toggle("search-active"),[...document.body.classList].includes("search-active")&&(document.getElementById("search-input").value="",document.getElementById("search-input").focus())}function formatResultItem(e){return console.log(e),htmlToElement(`
  • - ${e.doc.title} -
    - ${e.doc.description} + ${e.doc.title} + ${e.doc.description}
    -
  • `) -} - -function htmlToElement(e) { - var t = document.createElement("template"); - return e = e.trim(), t.innerHTML = e, t.content.firstChild -} -document.addEventListener("DOMContentLoaded", function() { - document.getElementById("search").addEventListener("click", function(e) { - e.preventDefault(), toggleSearchModal() - }); - document.querySelector(".modal-overlay").addEventListener("click", toggleSearchModal); - for (var e = document.querySelectorAll(".modal-close"), o = 0; o < e.length; o++) e[o].addEventListener("click", toggleSearchModal); - document.onkeydown = function(e) { - let t = !1, - n = !1; - "key" in (e = e || window.event) ? (t = "Escape" === e.key || "Esc" === e.key, n = "k" === e.key && !0 === e.metaKey) : (n = 75 === e.keyCode && e.metaKey, t = 27 === e.keyCode), n && e.preventDefault(), (t && document.body.classList.contains("search-active") || n) && toggleSearchModal() - }; - let a = elasticlunr.Index.load(window.searchIndex), - l = { - bool: "AND", - fields: { - title: { - boost: 2 - }, - body: { - boost: 1 - } - } - }, - r, c, d = document.getElementById("search-input"); - document.getElementById("search-results"); - d.addEventListener("keyup", function(e) { - if ([...document.body.classList].includes("search-active") && 3 < d.value.trim().length && (r = d.value.trim(), c = a.search(r, l), Array.isArray(c)) && 0 < c.length) { - var t = document.getElementById("results-list"); - t.replaceChildren(); - for (o = 0; o < c.length; o++) { - var n = formatResultItem(c[o]); - t.appendChild(n) - } - } - }) -}); + `)}function htmlToElement(e){var t=document.createElement("template");return e=e.trim(),t.innerHTML=e,t.content.firstChild}document.addEventListener("DOMContentLoaded",function(){document.getElementById("search").addEventListener("click",function(e){e.preventDefault(),toggleSearchModal()});document.querySelector(".modal-overlay").addEventListener("click",toggleSearchModal);for(var e=document.querySelectorAll(".modal-close"),o=0;o - + @@ -113,7 +113,7 @@