diff options
Diffstat (limited to 'src/main.rs')
| -rw-r--r-- | src/main.rs | 76 |
1 files changed, 61 insertions, 15 deletions
diff --git a/src/main.rs b/src/main.rs index a6963c4..773c0e3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,6 @@ use std::{ collections::{HashMap, HashSet}, + env, net::SocketAddr, sync::Arc, }; @@ -50,6 +51,23 @@ fn handle_panic(err: Box<dyn std::any::Any + Send + 'static>) -> Response { #[derive(Hash, Eq, PartialEq, Copy, Clone, Debug, PartialOrd, Ord, Deserialize)] struct UserId(u64); +impl UserId { + fn funny_name(&self) -> String { + #[rustfmt::skip] + const ADJECTIVES: [&'static str; 32] = [ "Beautiful", "Brave", "Bright", "Clever", "Calm", "Dull", "Eager", "Fancy", "Gentle", "Harsh", "Humble", "Kind", "Lazy", "Loud", "Narrow", "Quiet", "Quick", "Rare", "Rough", "Shiny", "Smart", "Smooth", "Strong", "Sweet", "Tall", "Tense", "Ugly", "Vast", "Weak", "Wise", "Young", "Zealous", ]; + #[rustfmt::skip] + const VERBS: [&'static str; 32]= [ "Running", "Jumping", "Walking", "Talking", "Eating", "Drinking", "Laughing", "Crying", "Singing", "Dancing", "Writing", "Reading", "Sleeping", "Driving", "Cooking", "Building", "Breaking", "Thinking", "Speaking", "Listening", "Watching", "Throwing", "Catching", "Swimming", "Playing", "Fighting", "Working", "Learning", "Teaching", "Growing", "Loving", "Sharing", ]; + #[rustfmt::skip] + const NOUNS: [&'static str; 32]= [ "Clock", "Cloud", "Car", "Tree", "Book", "Candle", "Mirror", "Robot", "Star", "Moon", "Sun", "River", "Rock", "Mountain", "Flower", "Train", "Shoe", "House", "Boat", "Bridge", "Key", "Pencil", "Cup", "Chair", "Phone", "Lamp", "Blanket", "Door", "Toy", "Kite", "Basket", "Balloon", ]; + + let u = self.0 as usize; + let noun = NOUNS[(u >> 0) & 31]; + let verb = VERBS[(u >> 5) & 31]; + let ajd = ADJECTIVES[(u >> 10) & 31]; + format!("{} {} {}", ajd, verb, noun) + } +} + #[derive(Serialize, Deserialize, Debug, Clone)] struct NoteDatum { // Epoch time in ms @@ -248,18 +266,21 @@ impl Game { html! { script { ({PreEscaped("document.notes = []; ")})} h1 { "Playing Game" } - p { "Were playing here" } + p { "Play a tune" } canvas #canvas - height=(256) width=(256) - style="position:relative; background: cyan;" + height=(512) width=(256) + style="position:relative;" {}; - script { (PreEscaped(r#"document.getElementById("canvas").onclick = (e) => { + script { (PreEscaped(r#"cv = document.getElementById("canvas"); + cv.onclick = (e) => { const notes = JSON.parse(e.target.dataset.notes ?? "[]"); notes.push({ time: Date.now(), y: e.layerY / e.target.height}); e.target.dataset.notes = JSON.stringify(notes); - }"#))} + } + drawNoteLines(cv); + "#))} button hx-post=(format!("/game/{gid}/submit")) hx-vals=r#"js:{ "notes": document.getElementById("canvas").dataset.notes }"# @@ -301,7 +322,7 @@ impl Game { html! { h1 { (format!("Round {i}/{n}"))} - p { "Author was " (r.author.0)} + p { "Author was " (r.author.funny_name())} form #form-guess { input placeholder="Your guess..." name="guess" {}; input type="submit" hx-post=(format!("/game/{gid}/guess")) hx-target="#form-guess" {}; @@ -349,7 +370,7 @@ loadSample(soundUrl).then((sample) => { data-accept=(accept) hx-post=(post) hx-swap="outerHTML" - { (g) " (click to toggle)"} + { (g) } } } @@ -360,6 +381,7 @@ loadSample(soundUrl).then((sample) => { html! { h1 { "Mark correct answers" } + span { "Click an answer to toggle correctness"} ul #guesslist { @for &u in v { (self.guess_li(u)) @@ -394,7 +416,7 @@ loadSample(soundUrl).then((sample) => { h1 { "Leaderboard" } ol { @for (uid, score) in v { - li { span { (uid.0) ": " (score) " points" } } + li { span { (uid.funny_name()) ": " (score) " points" } } } } @@ -465,8 +487,8 @@ async fn route_index(State(st): State<Server>) -> Response { html! { "No current games"} } else { html! { - h3 { "Games" } - ul { + h3 { "Current games" } + ul .games-list { @for id in &game_ids { li { a href=(format!("/game/{id}")) { (id) } } } @@ -475,10 +497,12 @@ async fn route_index(State(st): State<Server>) -> Response { }; let html = html! { - h1 { "Good game "} - (game_list) + section .main-page { + h1 { "Good game "} + (game_list) - button hx-post="/game" { "Create game" } + button hx-post="/game" { "Create game" } + } }; html_response(html! { @@ -489,6 +513,7 @@ async fn route_index(State(st): State<Server>) -> Response { meta name="viewport" content="width=device-width, initial-scale=1" {}; script src="https://unpkg.com/htmx.org@2.0.4" {}; link rel="stylesheet" type="text/css" href="static/style.css"; + @if let Some(n) = hot_reload_script() { (n) } } body { (html) @@ -597,13 +622,14 @@ async fn get_game( link rel="stylesheet" type="text/css" href="/static/style.css"; script src="/static/main.js" {}; + @if let Some(n) = hot_reload_script() { (n) } } body hx-ext="ws" ws-connect=(format!("/game/{gid}/ws")) { - footer { } + header { } section #content { (html) } - footer { span { "You are " (uid.0) } } + footer { span { "You are " (uid.funny_name()) } } } }) } @@ -804,6 +830,25 @@ async fn identity_middleware(jar: CookieJar, mut req: Request, next: Next) -> Re res } +#[cfg(debug_assertions)] +mod hot_reload; +#[cfg(not(debug_assertions))] +mod hot_reload { + use axum::Router; + pub fn router(_: &str) -> Router<()> { + Router::new() + } +} + +pub fn hot_reload_script() -> Option<Markup> { + let is_prod = env::var("STAGE").is_ok_and(|stage| stage == "prod"); + if is_prod { + None + } else { + Some(html! { script { (PreEscaped(include_str!("./hot_reload.js"))) } }) + } +} + #[tokio::main] async fn main() -> Result<()> { let subscriber = FmtSubscriber::builder() @@ -831,6 +876,7 @@ async fn main() -> Result<()> { .route("/game/{gid}/judge", post(submit_judge)) .route("/game/{gid}/ws", get(game_ws)) .nest_service("/static", ServeDir::new("static")) + .nest_service("/dev-hr", hot_reload::router("static")) .layer(CatchPanicLayer::custom(handle_panic)) .layer( TraceLayer::new_for_http() |
